From 5a8510c5c2c0a0e4710f30b536f1e2c1f5e3f565 Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Wed, 21 Jul 2021 11:42:38 +0300 Subject: [PATCH 001/432] spring.jpa.properties.hibernate.order_by.default_null_ordering: "none" (remove NULLS LAST from queries) --- application/src/main/resources/thingsboard.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index 0cede00913..93023a3d19 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -463,7 +463,7 @@ spring.servlet.multipart.max-file-size: "50MB" spring.servlet.multipart.max-request-size: "50MB" spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation: "true" -spring.jpa.properties.hibernate.order_by.default_null_ordering: "last" +spring.jpa.properties.hibernate.order_by.default_null_ordering: "none" # SQL DAO Configuration spring: From a01ac25a5ac1fc56298c620976fd5e5087057671 Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Fri, 30 Jul 2021 18:00:05 +0300 Subject: [PATCH 002/432] added parameter SPRING_JPA_PROPERTIES_HIBERNATE_ORDER_BY_DEFAULT_NULL_ORDERING to maintain possibility to override this settings. Those may be useful for existing Thingsboard instance that strictly tuned on previous setting for DESC NULLS LAST --- application/src/main/resources/thingsboard.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index 93023a3d19..33889f92f3 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -463,7 +463,7 @@ spring.servlet.multipart.max-file-size: "50MB" spring.servlet.multipart.max-request-size: "50MB" spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation: "true" -spring.jpa.properties.hibernate.order_by.default_null_ordering: "none" +spring.jpa.properties.hibernate.order_by.default_null_ordering: "${SPRING_JPA_PROPERTIES_HIBERNATE_ORDER_BY_DEFAULT_NULL_ORDERING:none}" # SQL DAO Configuration spring: From 6be0cb020a9f07b6ae62e4568be70b3b78815c09 Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Mon, 16 Aug 2021 12:41:29 +0300 Subject: [PATCH 003/432] Version set to 3.3.2-SNAPSHOT --- application/pom.xml | 2 +- common/actor/pom.xml | 2 +- common/cache/pom.xml | 2 +- common/cluster-api/pom.xml | 2 +- common/coap-server/pom.xml | 2 +- common/dao-api/pom.xml | 2 +- common/data/pom.xml | 2 +- common/edge-api/pom.xml | 2 +- common/message/pom.xml | 2 +- common/pom.xml | 2 +- common/queue/pom.xml | 2 +- common/stats/pom.xml | 2 +- common/transport/coap/pom.xml | 2 +- common/transport/http/pom.xml | 2 +- common/transport/lwm2m/pom.xml | 2 +- common/transport/mqtt/pom.xml | 2 +- common/transport/pom.xml | 2 +- common/transport/snmp/pom.xml | 2 +- common/transport/transport-api/pom.xml | 2 +- common/util/pom.xml | 2 +- dao/pom.xml | 2 +- msa/black-box-tests/pom.xml | 2 +- msa/js-executor/pom.xml | 2 +- msa/pom.xml | 2 +- msa/tb-node/pom.xml | 2 +- msa/tb/pom.xml | 2 +- msa/transport/coap/pom.xml | 2 +- msa/transport/http/pom.xml | 2 +- msa/transport/lwm2m/pom.xml | 2 +- msa/transport/mqtt/pom.xml | 2 +- msa/transport/pom.xml | 2 +- msa/transport/snmp/pom.xml | 2 +- msa/web-ui/pom.xml | 2 +- netty-mqtt/pom.xml | 4 ++-- pom.xml | 2 +- rest-client/pom.xml | 2 +- rule-engine/pom.xml | 2 +- rule-engine/rule-engine-api/pom.xml | 2 +- rule-engine/rule-engine-components/pom.xml | 2 +- tools/pom.xml | 2 +- transport/coap/pom.xml | 2 +- transport/http/pom.xml | 2 +- transport/lwm2m/pom.xml | 2 +- transport/mqtt/pom.xml | 2 +- transport/pom.xml | 2 +- transport/snmp/pom.xml | 2 +- ui-ngx/pom.xml | 2 +- 47 files changed, 48 insertions(+), 48 deletions(-) diff --git a/application/pom.xml b/application/pom.xml index 03832654fa..0c385b2194 100644 --- a/application/pom.xml +++ b/application/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.1-SNAPSHOT + 3.3.2-SNAPSHOT thingsboard application diff --git a/common/actor/pom.xml b/common/actor/pom.xml index c732b86440..1d42440afc 100644 --- a/common/actor/pom.xml +++ b/common/actor/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.1-SNAPSHOT + 3.3.2-SNAPSHOT common org.thingsboard.common diff --git a/common/cache/pom.xml b/common/cache/pom.xml index 45798eed3a..e82f0da2b9 100644 --- a/common/cache/pom.xml +++ b/common/cache/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.1-SNAPSHOT + 3.3.2-SNAPSHOT common org.thingsboard.common diff --git a/common/cluster-api/pom.xml b/common/cluster-api/pom.xml index ddb7a6065e..082d24e269 100644 --- a/common/cluster-api/pom.xml +++ b/common/cluster-api/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.1-SNAPSHOT + 3.3.2-SNAPSHOT common org.thingsboard.common diff --git a/common/coap-server/pom.xml b/common/coap-server/pom.xml index 1e799a2047..945556c188 100644 --- a/common/coap-server/pom.xml +++ b/common/coap-server/pom.xml @@ -22,7 +22,7 @@ 4.0.0 org.thingsboard - 3.3.1-SNAPSHOT + 3.3.2-SNAPSHOT common org.thingsboard.common diff --git a/common/dao-api/pom.xml b/common/dao-api/pom.xml index e6032f8b97..9fefa6f0ae 100644 --- a/common/dao-api/pom.xml +++ b/common/dao-api/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.1-SNAPSHOT + 3.3.2-SNAPSHOT common org.thingsboard.common diff --git a/common/data/pom.xml b/common/data/pom.xml index 7468469e53..9551cba4ed 100644 --- a/common/data/pom.xml +++ b/common/data/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.1-SNAPSHOT + 3.3.2-SNAPSHOT common org.thingsboard.common diff --git a/common/edge-api/pom.xml b/common/edge-api/pom.xml index 3915ea7bec..44413489f6 100644 --- a/common/edge-api/pom.xml +++ b/common/edge-api/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.1-SNAPSHOT + 3.3.2-SNAPSHOT common org.thingsboard.common diff --git a/common/message/pom.xml b/common/message/pom.xml index f191cf276e..362394a44a 100644 --- a/common/message/pom.xml +++ b/common/message/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.1-SNAPSHOT + 3.3.2-SNAPSHOT common org.thingsboard.common diff --git a/common/pom.xml b/common/pom.xml index 0c19a769f8..233046824d 100644 --- a/common/pom.xml +++ b/common/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.1-SNAPSHOT + 3.3.2-SNAPSHOT thingsboard common diff --git a/common/queue/pom.xml b/common/queue/pom.xml index f1ef7b0fdd..f5e90a5964 100644 --- a/common/queue/pom.xml +++ b/common/queue/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.1-SNAPSHOT + 3.3.2-SNAPSHOT common org.thingsboard.common diff --git a/common/stats/pom.xml b/common/stats/pom.xml index dc08e84ada..d4dc57f529 100644 --- a/common/stats/pom.xml +++ b/common/stats/pom.xml @@ -22,7 +22,7 @@ 4.0.0 org.thingsboard - 3.3.1-SNAPSHOT + 3.3.2-SNAPSHOT common org.thingsboard.common diff --git a/common/transport/coap/pom.xml b/common/transport/coap/pom.xml index d737776963..3d2beb35c7 100644 --- a/common/transport/coap/pom.xml +++ b/common/transport/coap/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard.common - 3.3.1-SNAPSHOT + 3.3.2-SNAPSHOT transport org.thingsboard.common.transport diff --git a/common/transport/http/pom.xml b/common/transport/http/pom.xml index 513d4a90c2..90f6145d6f 100644 --- a/common/transport/http/pom.xml +++ b/common/transport/http/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard.common - 3.3.1-SNAPSHOT + 3.3.2-SNAPSHOT transport org.thingsboard.common.transport diff --git a/common/transport/lwm2m/pom.xml b/common/transport/lwm2m/pom.xml index 78e6bb62aa..d1fa746d3b 100644 --- a/common/transport/lwm2m/pom.xml +++ b/common/transport/lwm2m/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard.common - 3.3.1-SNAPSHOT + 3.3.2-SNAPSHOT transport org.thingsboard.common.transport diff --git a/common/transport/mqtt/pom.xml b/common/transport/mqtt/pom.xml index e3e3d3bab7..384bd6885e 100644 --- a/common/transport/mqtt/pom.xml +++ b/common/transport/mqtt/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard.common - 3.3.1-SNAPSHOT + 3.3.2-SNAPSHOT transport org.thingsboard.common.transport diff --git a/common/transport/pom.xml b/common/transport/pom.xml index fcb8e709c7..113e7b46a9 100644 --- a/common/transport/pom.xml +++ b/common/transport/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.1-SNAPSHOT + 3.3.2-SNAPSHOT common org.thingsboard.common diff --git a/common/transport/snmp/pom.xml b/common/transport/snmp/pom.xml index 5376e76d7f..12576e9a54 100644 --- a/common/transport/snmp/pom.xml +++ b/common/transport/snmp/pom.xml @@ -21,7 +21,7 @@ org.thingsboard.common - 3.3.1-SNAPSHOT + 3.3.2-SNAPSHOT transport diff --git a/common/transport/transport-api/pom.xml b/common/transport/transport-api/pom.xml index c647964a84..965e0eb380 100644 --- a/common/transport/transport-api/pom.xml +++ b/common/transport/transport-api/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard.common - 3.3.1-SNAPSHOT + 3.3.2-SNAPSHOT transport org.thingsboard.common.transport diff --git a/common/util/pom.xml b/common/util/pom.xml index cda226ec8d..4257a01ce0 100644 --- a/common/util/pom.xml +++ b/common/util/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.1-SNAPSHOT + 3.3.2-SNAPSHOT common org.thingsboard.common diff --git a/dao/pom.xml b/dao/pom.xml index 15b329d2c1..1ef95d8358 100644 --- a/dao/pom.xml +++ b/dao/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.1-SNAPSHOT + 3.3.2-SNAPSHOT thingsboard dao diff --git a/msa/black-box-tests/pom.xml b/msa/black-box-tests/pom.xml index 6d4465f3c4..3287272b84 100644 --- a/msa/black-box-tests/pom.xml +++ b/msa/black-box-tests/pom.xml @@ -21,7 +21,7 @@ org.thingsboard - 3.3.1-SNAPSHOT + 3.3.2-SNAPSHOT msa org.thingsboard.msa diff --git a/msa/js-executor/pom.xml b/msa/js-executor/pom.xml index 07664f0f70..f08a17987a 100644 --- a/msa/js-executor/pom.xml +++ b/msa/js-executor/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.1-SNAPSHOT + 3.3.2-SNAPSHOT msa org.thingsboard.msa diff --git a/msa/pom.xml b/msa/pom.xml index 11c8f08f78..af70451a1e 100644 --- a/msa/pom.xml +++ b/msa/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.1-SNAPSHOT + 3.3.2-SNAPSHOT thingsboard msa diff --git a/msa/tb-node/pom.xml b/msa/tb-node/pom.xml index d99f598e67..90b8e4ede6 100644 --- a/msa/tb-node/pom.xml +++ b/msa/tb-node/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.1-SNAPSHOT + 3.3.2-SNAPSHOT msa org.thingsboard.msa diff --git a/msa/tb/pom.xml b/msa/tb/pom.xml index 7ad9d9f992..307d693c8e 100644 --- a/msa/tb/pom.xml +++ b/msa/tb/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.1-SNAPSHOT + 3.3.2-SNAPSHOT msa org.thingsboard.msa diff --git a/msa/transport/coap/pom.xml b/msa/transport/coap/pom.xml index b737f75ad2..f6e226802a 100644 --- a/msa/transport/coap/pom.xml +++ b/msa/transport/coap/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard.msa - 3.3.1-SNAPSHOT + 3.3.2-SNAPSHOT transport org.thingsboard.msa.transport diff --git a/msa/transport/http/pom.xml b/msa/transport/http/pom.xml index aa25015c10..b14fa3b82f 100644 --- a/msa/transport/http/pom.xml +++ b/msa/transport/http/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard.msa - 3.3.1-SNAPSHOT + 3.3.2-SNAPSHOT transport org.thingsboard.msa.transport diff --git a/msa/transport/lwm2m/pom.xml b/msa/transport/lwm2m/pom.xml index a54c2463e5..c02dc88e7e 100644 --- a/msa/transport/lwm2m/pom.xml +++ b/msa/transport/lwm2m/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard.msa - 3.3.1-SNAPSHOT + 3.3.2-SNAPSHOT transport org.thingsboard.msa.transport diff --git a/msa/transport/mqtt/pom.xml b/msa/transport/mqtt/pom.xml index 876c92a5d1..9258221754 100644 --- a/msa/transport/mqtt/pom.xml +++ b/msa/transport/mqtt/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard.msa - 3.3.1-SNAPSHOT + 3.3.2-SNAPSHOT transport org.thingsboard.msa.transport diff --git a/msa/transport/pom.xml b/msa/transport/pom.xml index 4d16d6bbb0..3a19267950 100644 --- a/msa/transport/pom.xml +++ b/msa/transport/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.1-SNAPSHOT + 3.3.2-SNAPSHOT msa org.thingsboard.msa diff --git a/msa/transport/snmp/pom.xml b/msa/transport/snmp/pom.xml index 0b0638a8bf..7be1e011a2 100644 --- a/msa/transport/snmp/pom.xml +++ b/msa/transport/snmp/pom.xml @@ -21,7 +21,7 @@ org.thingsboard.msa transport - 3.3.1-SNAPSHOT + 3.3.2-SNAPSHOT org.thingsboard.msa.transport diff --git a/msa/web-ui/pom.xml b/msa/web-ui/pom.xml index 94ae8b2a55..0a231344de 100644 --- a/msa/web-ui/pom.xml +++ b/msa/web-ui/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.1-SNAPSHOT + 3.3.2-SNAPSHOT msa org.thingsboard.msa diff --git a/netty-mqtt/pom.xml b/netty-mqtt/pom.xml index 1599cd9728..93ccb59913 100644 --- a/netty-mqtt/pom.xml +++ b/netty-mqtt/pom.xml @@ -19,11 +19,11 @@ 4.0.0 org.thingsboard - 3.3.1-SNAPSHOT + 3.3.2-SNAPSHOT thingsboard netty-mqtt - 3.3.1-SNAPSHOT + 3.3.2-SNAPSHOT jar Netty MQTT Client diff --git a/pom.xml b/pom.xml index 687b6031fd..fe45ea9993 100755 --- a/pom.xml +++ b/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard thingsboard - 3.3.1-SNAPSHOT + 3.3.2-SNAPSHOT pom Thingsboard diff --git a/rest-client/pom.xml b/rest-client/pom.xml index e6fd392e79..87d3b6fa9d 100644 --- a/rest-client/pom.xml +++ b/rest-client/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.1-SNAPSHOT + 3.3.2-SNAPSHOT thingsboard rest-client diff --git a/rule-engine/pom.xml b/rule-engine/pom.xml index 8679b1926e..941188b24a 100644 --- a/rule-engine/pom.xml +++ b/rule-engine/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.1-SNAPSHOT + 3.3.2-SNAPSHOT thingsboard rule-engine diff --git a/rule-engine/rule-engine-api/pom.xml b/rule-engine/rule-engine-api/pom.xml index 03fa42b606..d08b7db679 100644 --- a/rule-engine/rule-engine-api/pom.xml +++ b/rule-engine/rule-engine-api/pom.xml @@ -22,7 +22,7 @@ 4.0.0 org.thingsboard - 3.3.1-SNAPSHOT + 3.3.2-SNAPSHOT rule-engine org.thingsboard.rule-engine diff --git a/rule-engine/rule-engine-components/pom.xml b/rule-engine/rule-engine-components/pom.xml index ccd905f897..23a4dd30bc 100644 --- a/rule-engine/rule-engine-components/pom.xml +++ b/rule-engine/rule-engine-components/pom.xml @@ -22,7 +22,7 @@ 4.0.0 org.thingsboard - 3.3.1-SNAPSHOT + 3.3.2-SNAPSHOT rule-engine org.thingsboard.rule-engine diff --git a/tools/pom.xml b/tools/pom.xml index 17244cf351..51c4dd689b 100644 --- a/tools/pom.xml +++ b/tools/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.1-SNAPSHOT + 3.3.2-SNAPSHOT thingsboard tools diff --git a/transport/coap/pom.xml b/transport/coap/pom.xml index 756e4bbeaa..cdbe5123a5 100644 --- a/transport/coap/pom.xml +++ b/transport/coap/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.1-SNAPSHOT + 3.3.2-SNAPSHOT transport org.thingsboard.transport diff --git a/transport/http/pom.xml b/transport/http/pom.xml index efaef36edb..5b461277ab 100644 --- a/transport/http/pom.xml +++ b/transport/http/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.1-SNAPSHOT + 3.3.2-SNAPSHOT transport org.thingsboard.transport diff --git a/transport/lwm2m/pom.xml b/transport/lwm2m/pom.xml index bd1b9a22b4..0fbdf4ffc1 100644 --- a/transport/lwm2m/pom.xml +++ b/transport/lwm2m/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.1-SNAPSHOT + 3.3.2-SNAPSHOT transport org.thingsboard.transport diff --git a/transport/mqtt/pom.xml b/transport/mqtt/pom.xml index aa3ea2598a..2eac21ee93 100644 --- a/transport/mqtt/pom.xml +++ b/transport/mqtt/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.1-SNAPSHOT + 3.3.2-SNAPSHOT transport org.thingsboard.transport diff --git a/transport/pom.xml b/transport/pom.xml index c8d3caf5dc..9347afe94f 100644 --- a/transport/pom.xml +++ b/transport/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.1-SNAPSHOT + 3.3.2-SNAPSHOT thingsboard transport diff --git a/transport/snmp/pom.xml b/transport/snmp/pom.xml index 6788eb0bf5..72201e25dd 100644 --- a/transport/snmp/pom.xml +++ b/transport/snmp/pom.xml @@ -21,7 +21,7 @@ org.thingsboard - 3.3.1-SNAPSHOT + 3.3.2-SNAPSHOT transport diff --git a/ui-ngx/pom.xml b/ui-ngx/pom.xml index 6fa06162c0..59e85024fd 100644 --- a/ui-ngx/pom.xml +++ b/ui-ngx/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.1-SNAPSHOT + 3.3.2-SNAPSHOT thingsboard org.thingsboard From f2b58fd939044ef40966a8c2ad36f60a6793afce Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Fri, 27 Aug 2021 11:44:09 +0300 Subject: [PATCH 004/432] Lwm2m: tests5 --- .../lwm2m/client/LwM2MTestClient.java | 9 +- .../LwM2MTransportBootstrapService.java | 16 +- .../secure/LwM2MBootstrapConfig.java | 2 + .../secure/LwM2MBootstrapSecurityStore.java | 19 +- .../LwM2MInMemoryBootstrapConfigStore.java | 11 +- .../secure/LwM2MServerBootstrap.java | 2 - .../LwM2mDefaultBootstrapSessionManager.java | 178 +++++++- .../config/LwM2MTransportServerConfig.java | 7 - .../AbstractLwM2mTransportResource.java | 3 - .../server/DefaultLwM2mTransportService.java | 8 +- .../lwm2m/server/LwM2mOperationType.java | 15 +- .../lwm2m/server/LwM2mServerListener.java | 2 +- .../lwm2m/server/LwM2mSessionMsgListener.java | 1 - .../server/LwM2mTransportServerHelper.java | 4 +- .../lwm2m/server/LwM2mTransportUtil.java | 72 +++ .../DefaultLwM2MAttributesService.java | 113 ++++- .../attributes/LwM2MAttributesService.java | 2 +- .../lwm2m/server/client/LwM2mClient.java | 121 +++-- .../server/client/LwM2mClientContext.java | 5 +- .../server/client/LwM2mClientContextImpl.java | 34 +- .../lwm2m/server/client/ResourceValue.java | 44 +- ...urce.java => TbLwM2mMultipleResource.java} | 6 +- .../common/LwM2MExecutorAwareService.java | 1 - .../DefaultLwM2mDownlinkMsgHandler.java | 423 ++++++++++++------ .../server/downlink/HasContentFormat.java | 4 +- .../downlink/LwM2mDownlinkMsgHandler.java | 8 +- .../TbLwM2MCancelObserveCallback.java | 4 +- .../server/downlink/TbLwM2MCreateRequest.java | 50 +++ .../TbLwM2MCreateResponseCallback.java | 36 ++ .../downlink/TbLwM2MDeleteCallback.java | 1 - .../downlink/TbLwM2MDiscoverCallback.java | 3 +- .../downlink/TbLwM2MExecuteCallback.java | 3 +- .../downlink/TbLwM2MObserveCallback.java | 2 +- .../downlink/TbLwM2MObserveRequest.java | 13 +- .../server/downlink/TbLwM2MReadRequest.java | 13 +- .../downlink/TbLwM2MTargetedCallback.java | 27 +- .../TbLwM2MWriteAttributesCallback.java | 1 - .../TbLwM2MReadCompositeRequest.java | 13 +- .../log/DefaultLwM2MTelemetryLogService.java | 1 - .../ota/DefaultLwM2MOtaUpdateService.java | 3 +- .../ota/software/LwM2MClientSwOtaInfo.java | 4 - .../rpc/DefaultLwM2MRpcRequestHandler.java | 103 ++++- ...equest.java => LwM2MRpcRequestHeader.java} | 3 +- .../rpc/RpcCancelAllObserveCallback.java | 1 - .../server/rpc/RpcCancelObserveCallback.java | 7 - .../rpc/RpcCreateRequest.java} | 18 +- .../server/rpc/RpcCreateResponseCallback.java | 38 ++ .../lwm2m/server/rpc/RpcDiscoverCallback.java | 6 - .../lwm2m/server/rpc/RpcLinkSetCallback.java | 5 - .../server/rpc/RpcWriteAttributesRequest.java | 2 +- .../server/rpc/RpcWriteReplaceRequest.java | 2 +- .../server/rpc/RpcWriteUpdateRequest.java | 3 +- .../composite/RpcReadCompositeRequest.java | 4 +- .../store/TbLwM2mRedisClientOtaInfoStore.java | 8 - .../store/TbLwM2mRedisRegistrationStore.java | 2 +- .../uplink/DefaultLwM2MUplinkMsgHandler.java | 60 ++- .../server/uplink/LwM2mUplinkMsgHandler.java | 3 + .../lwm2m/utils/LwM2mValueConverterImpl.java | 12 +- pom.xml | 2 +- 59 files changed, 1145 insertions(+), 418 deletions(-) rename common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/{TbLwM2MMultipleResource.java => TbLwM2mMultipleResource.java} (82%) create mode 100644 common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MCreateRequest.java create mode 100644 common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MCreateResponseCallback.java rename common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/{IdOrKeyRequest.java => LwM2MRpcRequestHeader.java} (92%) rename common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/{bootstrap/secure/LwM2MInMemoryBootstrapConfigurationAdapter.java => server/rpc/RpcCreateRequest.java} (59%) create mode 100644 common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcCreateResponseCallback.java diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2MTestClient.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2MTestClient.java index c4f22ff5bb..72f9b014b7 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2MTestClient.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2MTestClient.java @@ -39,12 +39,13 @@ import org.eclipse.leshan.core.model.LwM2mModel; import org.eclipse.leshan.core.model.ObjectLoader; import org.eclipse.leshan.core.model.ObjectModel; import org.eclipse.leshan.core.model.StaticModel; -import org.eclipse.leshan.core.node.codec.DefaultLwM2mNodeDecoder; -import org.eclipse.leshan.core.node.codec.DefaultLwM2mNodeEncoder; +import org.eclipse.leshan.core.node.codec.DefaultLwM2mDecoder; +import org.eclipse.leshan.core.node.codec.DefaultLwM2mEncoder; import org.eclipse.leshan.core.request.BootstrapRequest; import org.eclipse.leshan.core.request.DeregisterRequest; import org.eclipse.leshan.core.request.RegisterRequest; import org.eclipse.leshan.core.request.UpdateRequest; +import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl; import java.io.IOException; import java.net.InetSocketAddress; @@ -130,8 +131,8 @@ public class LwM2MTestClient { builder.setRegistrationEngineFactory(engineFactory); builder.setEndpointFactory(endpointFactory); builder.setSharedExecutor(executor); - builder.setDecoder(new DefaultLwM2mNodeDecoder(true)); - builder.setEncoder(new DefaultLwM2mNodeEncoder(true)); + builder.setDecoder(new DefaultLwM2mDecoder(false)); + builder.setEncoder(new DefaultLwM2mEncoder(new LwM2mValueConverterImpl(), false)); client = builder.build(); LwM2mClientObserver observer = new LwM2mClientObserver() { diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportBootstrapService.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportBootstrapService.java index 16f9443547..0026392ece 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportBootstrapService.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportBootstrapService.java @@ -19,17 +19,14 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.eclipse.californium.elements.util.SslContextUtil; import org.eclipse.californium.scandium.config.DtlsConnectorConfig; -import org.eclipse.leshan.core.model.ObjectLoader; -import org.eclipse.leshan.core.model.ObjectModel; -import org.eclipse.leshan.core.model.StaticModel; import org.eclipse.leshan.server.bootstrap.BootstrapSessionManager; import org.eclipse.leshan.server.californium.bootstrap.LeshanBootstrapServer; import org.eclipse.leshan.server.californium.bootstrap.LeshanBootstrapServerBuilder; import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.stereotype.Component; +import org.thingsboard.server.common.transport.TransportService; import org.thingsboard.server.transport.lwm2m.bootstrap.secure.LwM2MBootstrapSecurityStore; import org.thingsboard.server.transport.lwm2m.bootstrap.secure.LwM2MInMemoryBootstrapConfigStore; -import org.thingsboard.server.transport.lwm2m.bootstrap.secure.LwM2MInMemoryBootstrapConfigurationAdapter; import org.thingsboard.server.transport.lwm2m.bootstrap.secure.LwM2mDefaultBootstrapSessionManager; import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportBootstrapConfig; import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; @@ -42,7 +39,6 @@ import java.security.KeyStoreException; import java.security.PrivateKey; import java.security.PublicKey; import java.security.cert.X509Certificate; -import java.util.List; import static org.thingsboard.server.transport.lwm2m.server.LwM2mNetworkConfig.getCoapConfig; @@ -57,7 +53,7 @@ public class LwM2MTransportBootstrapService { private final LwM2MTransportBootstrapConfig bootstrapConfig; private final LwM2MBootstrapSecurityStore lwM2MBootstrapSecurityStore; private final LwM2MInMemoryBootstrapConfigStore lwM2MInMemoryBootstrapConfigStore; - + private final TransportService transportService; private LeshanBootstrapServer server; @PostConstruct @@ -83,15 +79,11 @@ public class LwM2MTransportBootstrapService { /* Create CoAP Config */ builder.setCoapConfig(getCoapConfig(bootstrapConfig.getPort(), bootstrapConfig.getSecurePort(), serverConfig)); - /* Define model provider (Create Models )*/ - List models = ObjectLoader.loadDefault(); - builder.setModel(new StaticModel(models)); - /* Create credentials */ this.setServerWithCredentials(builder); /* Set securityStore with new ConfigStore */ - builder.setConfigStore(new LwM2MInMemoryBootstrapConfigurationAdapter(lwM2MInMemoryBootstrapConfigStore)); + builder.setConfigStore(lwM2MInMemoryBootstrapConfigStore); /* SecurityStore */ builder.setSecurityStore(lwM2MBootstrapSecurityStore); @@ -106,7 +98,7 @@ public class LwM2MTransportBootstrapService { /* Set DTLS Config */ builder.setDtlsConfig(dtlsConfig); - BootstrapSessionManager sessionManager = new LwM2mDefaultBootstrapSessionManager(lwM2MBootstrapSecurityStore); + BootstrapSessionManager sessionManager = new LwM2mDefaultBootstrapSessionManager(lwM2MBootstrapSecurityStore, lwM2MInMemoryBootstrapConfigStore, transportService); builder.setSessionManager(sessionManager); /* Create BootstrapServer */ diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapConfig.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapConfig.java index 7dca87458b..ab96228600 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapConfig.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapConfig.java @@ -15,6 +15,7 @@ */ package org.thingsboard.server.transport.lwm2m.bootstrap.secure; +import com.fasterxml.jackson.annotation.JsonIgnore; import lombok.Data; import org.eclipse.leshan.core.SecurityMode; import org.eclipse.leshan.core.request.BindingMode; @@ -59,6 +60,7 @@ public class LwM2MBootstrapConfig implements Serializable { LwM2MServerBootstrap lwm2mServer; + @JsonIgnore public BootstrapConfig getLwM2MBootstrapConfig() { BootstrapConfig configBs = new BootstrapConfig(); /* Delete old security objects */ diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapSecurityStore.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapSecurityStore.java index c7ec42d879..fb6149a796 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapSecurityStore.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapSecurityStore.java @@ -39,7 +39,9 @@ import java.io.IOException; import java.security.GeneralSecurityException; import java.util.Collections; import java.util.Iterator; +import java.util.Map; import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LWM2M_ERROR; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LWM2M_INFO; @@ -58,6 +60,7 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore { private final LwM2mTransportContext context; private final LwM2mTransportServerHelper helper; + private final Map bsSessions = new ConcurrentHashMap<>(); public LwM2MBootstrapSecurityStore(EditableBootstrapConfigStore bootstrapConfigStore, LwM2mCredentialsSecurityInfoValidator lwM2MCredentialsSecurityInfoValidator, LwM2mTransportContext context, LwM2mTransportServerHelper helper) { this.bootstrapConfigStore = bootstrapConfigStore; @@ -82,7 +85,12 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore { } bootstrapConfigStore.add(endPoint, bsConfigNew); } catch (InvalidConfigurationException e) { - log.error("", e); + if (e.getMessage().contains("Psk identity") && e.getMessage().contains("already used for this bootstrap server")) { + log.trace("", e); + } + else { + log.error("", e); + } } return store.getSecurityInfo() == null ? null : Collections.singletonList(store.getSecurityInfo()).iterator(); } @@ -155,6 +163,7 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore { LwM2MServerBootstrap profileLwm2mServer = JacksonUtil.fromString(JacksonUtil.toString(bootstrapObject.getLwm2mServer()), LwM2MServerBootstrap.class); UUID sessionUUiD = UUID.randomUUID(); TransportProtos.SessionInfoProto sessionInfo = helper.getValidateSessionInfo(store.getMsg(), sessionUUiD.getMostSignificantBits(), sessionUUiD.getLeastSignificantBits()); + bsSessions.put(store.getEndpoint(), sessionInfo); context.getTransportService().registerAsyncSession(sessionInfo, new LwM2mSessionMsgListener(null, null, null, sessionInfo, context.getTransportService())); if (this.getValidatedSecurityMode(lwM2MBootstrapConfig.bootstrapServer, profileServerBootstrap, lwM2MBootstrapConfig.lwm2mServer, profileLwm2mServer)) { lwM2MBootstrapConfig.bootstrapServer = new LwM2MServerBootstrap(lwM2MBootstrapConfig.bootstrapServer, profileServerBootstrap); @@ -189,4 +198,12 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore { return (bootstrapFromCredential.getSecurityMode().equals(profileServerBootstrap.getSecurityMode()) && lwm2mFromCredential.getSecurityMode().equals(profileLwm2mServer.getSecurityMode())); } + + public TransportProtos.SessionInfoProto getSessionByEndpoint(String endpoint) { + return bsSessions.get(endpoint); + } + + public TransportProtos.SessionInfoProto removeSessionByEndpoint(String endpoint) { + return bsSessions.remove(endpoint); + } } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MInMemoryBootstrapConfigStore.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MInMemoryBootstrapConfigStore.java index bc44922fcf..ba3880c6bc 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MInMemoryBootstrapConfigStore.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MInMemoryBootstrapConfigStore.java @@ -16,7 +16,9 @@ package org.thingsboard.server.transport.lwm2m.bootstrap.secure; import lombok.extern.slf4j.Slf4j; +import org.eclipse.leshan.core.request.Identity; import org.eclipse.leshan.server.bootstrap.BootstrapConfig; +import org.eclipse.leshan.server.bootstrap.BootstrapSession; import org.eclipse.leshan.server.bootstrap.InMemoryBootstrapConfigStore; import org.eclipse.leshan.server.bootstrap.InvalidConfigurationException; import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; @@ -35,6 +37,11 @@ public class LwM2MInMemoryBootstrapConfigStore extends InMemoryBootstrapConfigSt private final Lock readLock = readWriteLock.readLock(); private final Lock writeLock = readWriteLock.writeLock(); + @Override + public BootstrapConfig get(String endpoint, Identity deviceIdentity, BootstrapSession session) { + return bootstrapByEndpoint.get(endpoint); + } + @Override public Map getAll() { readLock.lock(); @@ -56,10 +63,10 @@ public class LwM2MInMemoryBootstrapConfigStore extends InMemoryBootstrapConfigSt } @Override - public BootstrapConfig remove(String enpoint) { + public BootstrapConfig remove(String endpoint) { writeLock.lock(); try { - return super.remove(enpoint); + return super.remove(endpoint); } finally { writeLock.unlock(); } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MServerBootstrap.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MServerBootstrap.java index c8a004f52c..0e425f2a05 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MServerBootstrap.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MServerBootstrap.java @@ -42,8 +42,6 @@ public class LwM2MServerBootstrap { public LwM2MServerBootstrap() { } - ; - public LwM2MServerBootstrap(LwM2MServerBootstrap bootstrapFromCredential, LwM2MServerBootstrap profileServerBootstrap) { this.clientPublicKeyOrId = bootstrapFromCredential.getClientPublicKeyOrId(); this.clientSecretKey = bootstrapFromCredential.getClientSecretKey(); diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2mDefaultBootstrapSessionManager.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2mDefaultBootstrapSessionManager.java index 4e34c3dc6d..2e41d17635 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2mDefaultBootstrapSessionManager.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2mDefaultBootstrapSessionManager.java @@ -16,23 +16,39 @@ package org.thingsboard.server.transport.lwm2m.bootstrap.secure; import lombok.extern.slf4j.Slf4j; +import org.eclipse.leshan.core.request.BootstrapDownlinkRequest; +import org.eclipse.leshan.core.request.BootstrapFinishRequest; import org.eclipse.leshan.core.request.BootstrapRequest; import org.eclipse.leshan.core.request.Identity; +import org.eclipse.leshan.core.response.LwM2mResponse; +import org.eclipse.leshan.server.bootstrap.BootstrapConfigStore; +import org.eclipse.leshan.server.bootstrap.BootstrapConfigStoreTaskProvider; +import org.eclipse.leshan.server.bootstrap.BootstrapFailureCause; import org.eclipse.leshan.server.bootstrap.BootstrapSession; +import org.eclipse.leshan.server.bootstrap.BootstrapTaskProvider; import org.eclipse.leshan.server.bootstrap.DefaultBootstrapSession; import org.eclipse.leshan.server.bootstrap.DefaultBootstrapSessionManager; +import org.eclipse.leshan.server.model.LwM2mBootstrapModelProvider; +import org.eclipse.leshan.server.model.StandardBootstrapModelProvider; import org.eclipse.leshan.server.security.BootstrapSecurityStore; import org.eclipse.leshan.server.security.SecurityChecker; import org.eclipse.leshan.server.security.SecurityInfo; +import org.thingsboard.server.common.transport.TransportService; -import java.util.Collections; +import java.util.ArrayList; import java.util.Iterator; +import java.util.List; + +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LWM2M_INFO; @Slf4j public class LwM2mDefaultBootstrapSessionManager extends DefaultBootstrapSessionManager { private BootstrapSecurityStore bsSecurityStore; private SecurityChecker securityChecker; + private BootstrapTaskProvider tasksProvider; + private LwM2mBootstrapModelProvider modelProvider; + private TransportService transportService; /** * Create a {@link DefaultBootstrapSessionManager} using a default {@link SecurityChecker} to accept or refuse new @@ -40,29 +56,169 @@ public class LwM2mDefaultBootstrapSessionManager extends DefaultBootstrapSession * * @param bsSecurityStore the {@link BootstrapSecurityStore} used by default {@link SecurityChecker}. */ - public LwM2mDefaultBootstrapSessionManager(BootstrapSecurityStore bsSecurityStore) { - this(bsSecurityStore, new SecurityChecker()); + public LwM2mDefaultBootstrapSessionManager(BootstrapSecurityStore bsSecurityStore, BootstrapConfigStore configStore, TransportService transportService) { + this(bsSecurityStore, new SecurityChecker(), new BootstrapConfigStoreTaskProvider(configStore), + new StandardBootstrapModelProvider()); + this.transportService = transportService; } - public LwM2mDefaultBootstrapSessionManager(BootstrapSecurityStore bsSecurityStore, SecurityChecker securityChecker) { - super(bsSecurityStore); + /** + * Create a {@link DefaultBootstrapSessionManager}. + * + * @param bsSecurityStore the {@link BootstrapSecurityStore} used by {@link SecurityChecker}. + * @param securityChecker used to accept or refuse new {@link BootstrapSession}. + */ + public LwM2mDefaultBootstrapSessionManager(BootstrapSecurityStore bsSecurityStore, SecurityChecker securityChecker, + BootstrapTaskProvider tasksProvider, LwM2mBootstrapModelProvider modelProvider) { + super(bsSecurityStore, securityChecker, tasksProvider, modelProvider); this.bsSecurityStore = bsSecurityStore; this.securityChecker = securityChecker; + this.tasksProvider = tasksProvider; + this.modelProvider = modelProvider; } - @SuppressWarnings("deprecation") + @Override public BootstrapSession begin(BootstrapRequest request, Identity clientIdentity) { boolean authorized; - if (bsSecurityStore != null) { - Iterator securityInfos = (clientIdentity.getPskIdentity() != null && !clientIdentity.getPskIdentity().isEmpty()) ? - Collections.singletonList(bsSecurityStore.getByIdentity(clientIdentity.getPskIdentity())).iterator() : bsSecurityStore.getAllByEndpoint(request.getEndpointName()); - log.info("Bootstrap session started securityInfos: [{}]", securityInfos); + Iterator securityInfos; + if (bsSecurityStore != null && securityChecker != null) { + if (clientIdentity.isSecure() && clientIdentity.isPSK()) { + securityInfos = bsSecurityStore.getAllByEndpoint(clientIdentity.getPskIdentity()); + } else { + securityInfos = bsSecurityStore.getAllByEndpoint(request.getEndpointName()); + } authorized = securityChecker.checkSecurityInfos(request.getEndpointName(), clientIdentity, securityInfos); } else { authorized = true; } DefaultBootstrapSession session = new DefaultBootstrapSession(request, clientIdentity, authorized); - log.info("Bootstrap session started : {}", session); + if (authorized) { + this.sendLogs (request.getEndpointName(), + String.format("%s: Bootstrap session started endpoint: %s, session: %s ", LOG_LWM2M_INFO, request.getEndpointName(), + session.toString())); + } return session; } + + @Override + public boolean hasConfigFor(BootstrapSession session) { + BootstrapTaskProvider.Tasks firstTasks = tasksProvider.getTasks(session, null); + if (firstTasks == null) return false; + initTasks(session, firstTasks); + return true; + } + + protected void initTasks(BootstrapSession bssession, BootstrapTaskProvider.Tasks tasks) { + DefaultBootstrapSession session = (DefaultBootstrapSession) bssession; + // set models + if (tasks.supportedObjects != null) + session.setModel(modelProvider.getObjectModel(session, tasks.supportedObjects)); + + // set Requests to Send + session.setRequests(tasks.requestsToSend); + + // prepare list where we will store Responses + session.setResponses(new ArrayList(tasks.requestsToSend.size())); + + // is last Tasks ? + session.setMoreTasks(!tasks.last); + } + + @Override + public BootstrapDownlinkRequest getFirstRequest(BootstrapSession bsSession) { + return nextRequest(bsSession); + } + + protected BootstrapDownlinkRequest nextRequest(BootstrapSession bsSession) { + DefaultBootstrapSession session = (DefaultBootstrapSession) bsSession; + List> requestsToSend = session.getRequests(); + + if (!requestsToSend.isEmpty()) { + // get next requests + return requestsToSend.remove(0); + } else { + if (session.hasMoreTasks()) { + BootstrapTaskProvider.Tasks nextTasks = tasksProvider.getTasks(session, session.getResponses()); + if (nextTasks == null) { + session.setMoreTasks(false); + return new BootstrapFinishRequest(); + } + + initTasks(session, nextTasks); + return nextRequest(bsSession); + } else { + return new BootstrapFinishRequest(); + } + } + } + + @Override + public BootstrapPolicy onResponseSuccess(BootstrapSession bsSession, + BootstrapDownlinkRequest request, LwM2mResponse response) { + if (!(request instanceof BootstrapFinishRequest)) { + // store response + DefaultBootstrapSession session = (DefaultBootstrapSession) bsSession; + session.getResponses().add(response); + this.sendLogs (bsSession.getEndpoint(), + String.format("%s: %s %s receives success response %s for %s : %s", LOG_LWM2M_INFO, + request.getClass().getSimpleName(), request.getPath().toString(), response.toString(), bsSession.toString(), request.toString())); + // on success for NOT bootstrap finish request we send next request + return BootstrapPolicy.continueWith(nextRequest(bsSession)); + } else { + // on success for bootstrap finish request we stop the session + this.sendLogs (bsSession.getEndpoint(), + String.format("%s: %s receives success response for bootstrap finish request and stop the session: %s", LOG_LWM2M_INFO, + request.getClass().getSimpleName(), bsSession.toString())); + return BootstrapPolicy.finished(); + } + } + + @Override + public BootstrapPolicy onResponseError(BootstrapSession bsSession, + BootstrapDownlinkRequest request, LwM2mResponse response) { + if (!(request instanceof BootstrapFinishRequest)) { + // store response + DefaultBootstrapSession session = (DefaultBootstrapSession) bsSession; + session.getResponses().add(response); + this.sendLogs (bsSession.getEndpoint(), + String.format("%s: %s %s receives error response %s for %s : %s", LOG_LWM2M_INFO, + request.getClass().getSimpleName(), + request.getPath().toString(), response.toString(), bsSession.toString(), request.toString())); + // on response error for NOT bootstrap finish request we continue any sending next request + return BootstrapPolicy.continueWith(nextRequest(bsSession)); + } else { + // on response error for bootstrap finish request we stop the session + this.sendLogs (bsSession.getEndpoint(), + String.format("%s: %s %s error response %s for request %s bootstrap finish. Stop the session: %s", LOG_LWM2M_INFO, + request.getClass().getSimpleName(), + request.getPath().toString(), response.toString(), request.toString(), bsSession.toString())); + return BootstrapPolicy.failed(); + } + } + + @Override + public BootstrapPolicy onRequestFailure(BootstrapSession bsSession, + BootstrapDownlinkRequest request, Throwable cause) { + this.sendLogs (bsSession.getEndpoint(), + String.format("%s: %s %s failed because of %s for %s : %s", LOG_LWM2M_INFO, + request.getClass().getSimpleName(), request.getPath().toString(), cause.toString(), bsSession.toString(), request.toString())); + return BootstrapPolicy.failed(); + } + + @Override + public void end(BootstrapSession bsSession) { + this.sendLogs (bsSession.getEndpoint(), + String.format("%s: Bootstrap session finished : %s", LOG_LWM2M_INFO, bsSession.toString())); + } + + @Override + public void failed(BootstrapSession bsSession, BootstrapFailureCause cause) { + this.sendLogs (bsSession.getEndpoint(), + String.format("%s: Bootstrap session failed by %s: %s", LOG_LWM2M_INFO, cause.toString(), bsSession.toString())); + } + + private void sendLogs (String endpointName, String logMsg) { + log.trace(logMsg); + transportService.log(((LwM2MBootstrapSecurityStore) bsSecurityStore).getSessionByEndpoint(endpointName), logMsg); + } } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/config/LwM2MTransportServerConfig.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/config/LwM2MTransportServerConfig.java index b0cb237e42..6cd1ce05b2 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/config/LwM2MTransportServerConfig.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/config/LwM2MTransportServerConfig.java @@ -15,24 +15,17 @@ */ package org.thingsboard.server.transport.lwm2m.config; -import com.google.common.io.Resources; import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; import org.eclipse.leshan.server.model.LwM2mModelProvider; -import org.jetbrains.annotations.NotNull; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.stereotype.Component; import org.thingsboard.server.common.data.ResourceUtils; import javax.annotation.PostConstruct; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; import java.io.InputStream; -import java.net.URI; -import java.net.URISyntaxException; import java.security.KeyStore; @Slf4j diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/AbstractLwM2mTransportResource.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/AbstractLwM2mTransportResource.java index f23b84488b..5aed494934 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/AbstractLwM2mTransportResource.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/AbstractLwM2mTransportResource.java @@ -16,11 +16,8 @@ package org.thingsboard.server.transport.lwm2m.server; import lombok.extern.slf4j.Slf4j; -import org.eclipse.californium.core.coap.CoAP; -import org.eclipse.californium.core.coap.Response; import org.eclipse.californium.core.server.resources.CoapExchange; import org.eclipse.leshan.core.californium.LwM2mCoapResource; -import org.thingsboard.server.common.transport.TransportServiceCallback; @Slf4j public abstract class AbstractLwM2mTransportResource extends LwM2mCoapResource { diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2mTransportService.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2mTransportService.java index 356548b2bd..c099d7ad17 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2mTransportService.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2mTransportService.java @@ -20,8 +20,8 @@ import lombok.extern.slf4j.Slf4j; import org.eclipse.californium.elements.util.SslContextUtil; import org.eclipse.californium.scandium.config.DtlsConnectorConfig; import org.eclipse.californium.scandium.dtls.cipher.CipherSuite; -import org.eclipse.leshan.core.node.codec.DefaultLwM2mNodeDecoder; -import org.eclipse.leshan.core.node.codec.DefaultLwM2mNodeEncoder; +import org.eclipse.leshan.core.node.codec.DefaultLwM2mDecoder; +import org.eclipse.leshan.core.node.codec.DefaultLwM2mEncoder; import org.eclipse.leshan.server.californium.LeshanServer; import org.eclipse.leshan.server.californium.LeshanServerBuilder; import org.eclipse.leshan.server.californium.registration.CaliforniumRegistrationStore; @@ -110,9 +110,9 @@ public class DefaultLwM2mTransportService implements LwM2MTransportService { LeshanServerBuilder builder = new LeshanServerBuilder(); builder.setLocalAddress(config.getHost(), config.getPort()); builder.setLocalSecureAddress(config.getSecureHost(), config.getSecurePort()); - builder.setDecoder(new DefaultLwM2mNodeDecoder()); + builder.setDecoder(new DefaultLwM2mDecoder()); /* Use a magic converter to support bad type send by the UI. */ - builder.setEncoder(new DefaultLwM2mNodeEncoder(LwM2mValueConverterImpl.getInstance())); + builder.setEncoder(new DefaultLwM2mEncoder(LwM2mValueConverterImpl.getInstance())); /* Create CoAP Config */ builder.setCoapConfig(getCoapConfig(config.getPort(), config.getSecurePort(), config)); diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mOperationType.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mOperationType.java index 6cd204299a..7ac959605a 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mOperationType.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mOperationType.java @@ -52,12 +52,15 @@ public enum LwM2mOperationType { DELETE(16, "Delete", true), // only for RPC - FW_UPDATE(17, "FirmwareUpdate", false); + FW_UPDATE(17, "FirmwareUpdate", false), + // FW_READ_INFO(18, "FirmwareReadInfo", false), + SW_UPDATE(19, "SoftwareUpdate", false), + // SW_READ_INFO(20, "SoftwareReadInfo", false), + SW_UNINSTALL(21, "SoftwareUninstall", false), + CREATE(11, "Create", true); + + -// FW_READ_INFO(18, "FirmwareReadInfo"), -// SW_READ_INFO(19, "SoftwareReadInfo"), -// SW_UPDATE(20, "SoftwareUpdate"), -// SW_UNINSTALL(21, "SoftwareUninstall"); @Getter private final int code; @@ -78,7 +81,7 @@ public enum LwM2mOperationType { this.type = type; this.hasObjectId = hasObjectId; this.composite = composite; - if(hasObjectId && composite){ + if (hasObjectId && composite) { throw new IllegalArgumentException("Can't set both Composite and hasObjectId for the same operation!"); } } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mServerListener.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mServerListener.java index 2ece617666..898a1ad8b2 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mServerListener.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mServerListener.java @@ -98,7 +98,7 @@ public class LwM2mServerListener { @Override public void onError(Observation observation, Registration registration, Exception error) { - log.error("Unable to handle notification of [{}:{}]", observation.getRegistrationId(), observation.getPath(), error); + log.error("Unable to handle notification of [{}:{}] [{}]", observation.getRegistrationId(), observation.getPath(), error.getMessage()); } @Override diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mSessionMsgListener.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mSessionMsgListener.java index e9b0391250..463823e583 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mSessionMsgListener.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mSessionMsgListener.java @@ -25,7 +25,6 @@ import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.ResourceType; import org.thingsboard.server.common.transport.SessionMsgListener; import org.thingsboard.server.common.transport.TransportService; -import org.thingsboard.server.common.transport.TransportServiceCallback; import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.gen.transport.TransportProtos.AttributeUpdateNotificationMsg; import org.thingsboard.server.gen.transport.TransportProtos.GetAttributeResponseMsg; diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportServerHelper.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportServerHelper.java index f91aea84f7..cd12e2129d 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportServerHelper.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportServerHelper.java @@ -15,6 +15,7 @@ */ package org.thingsboard.server.transport.lwm2m.server; +import com.google.gson.JsonParser; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.eclipse.leshan.core.model.DDFFileParser; @@ -50,6 +51,7 @@ import static org.thingsboard.server.gen.transport.TransportProtos.KeyValueType. public class LwM2mTransportServerHelper { private final LwM2mTransportContext context; + private final static JsonParser JSON_PARSER = new JsonParser();; public void sendParametersOnThingsboardAttribute(List result, SessionInfoProto sessionInfo) { PostAttributeMsg.Builder request = PostAttributeMsg.newBuilder(); @@ -229,7 +231,7 @@ public class LwM2mTransportServerHelper { case STRING_V: return kv.getStringV(); case JSON_V: - return kv.getJsonV(); + return JSON_PARSER.parse(kv.getJsonV()); } return null; } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportUtil.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportUtil.java index 6fb5fd195e..8b65e55ad5 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportUtil.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportUtil.java @@ -16,6 +16,9 @@ package org.thingsboard.server.transport.lwm2m.server; import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.gson.Gson; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.eclipse.leshan.core.attributes.Attribute; @@ -26,6 +29,7 @@ import org.eclipse.leshan.core.node.LwM2mMultipleResource; import org.eclipse.leshan.core.node.LwM2mPath; import org.eclipse.leshan.core.node.LwM2mResource; import org.eclipse.leshan.core.node.LwM2mSingleResource; +import org.eclipse.leshan.core.node.ObjectLink; import org.eclipse.leshan.core.node.codec.CodecException; import org.eclipse.leshan.core.request.SimpleDownlinkRequest; import org.eclipse.leshan.core.request.WriteAttributesRequest; @@ -39,18 +43,23 @@ import org.thingsboard.server.common.data.device.profile.Lwm2mDeviceProfileTrans import org.thingsboard.server.transport.lwm2m.config.LwM2mVersion; import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; import org.thingsboard.server.transport.lwm2m.server.client.ResourceValue; +import org.thingsboard.server.transport.lwm2m.server.downlink.HasVersionedId; import org.thingsboard.server.transport.lwm2m.server.ota.firmware.FirmwareUpdateResult; import org.thingsboard.server.transport.lwm2m.server.ota.firmware.FirmwareUpdateState; import org.thingsboard.server.transport.lwm2m.server.ota.software.SoftwareUpdateResult; import org.thingsboard.server.transport.lwm2m.server.ota.software.SoftwareUpdateState; import org.thingsboard.server.transport.lwm2m.server.uplink.DefaultLwM2MUplinkMsgHandler; +import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl; import java.util.ArrayList; import java.util.Arrays; import java.util.Date; +import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import static org.eclipse.leshan.core.attributes.Attribute.DIMENSION; @@ -302,6 +311,12 @@ public class LwM2mTransportUtil { return attributeLists.toArray(Attribute[]::new); } + /** + * "UNSIGNED_INTEGER": // Number -> Integer Example: + * Alarm Timestamp [32-bit unsigned integer] + * Short Server ID, Object ID, Object Instance ID, Resource ID, Resource Instance ID + * "CORELINK": // String used in Attribute + */ public static ResourceModel.Type equalsResourceTypeGetSimpleName(Object value) { switch (value.getClass().getSimpleName()) { case "Double": @@ -323,6 +338,63 @@ public class LwM2mTransportUtil { } } + public static void validateVersionedId(LwM2mClient client, HasVersionedId request) { + String msgExceptionStr = ""; + if (request.getObjectId() == null) { + msgExceptionStr = "Specified object id is null!"; + } else { + msgExceptionStr = client.isValidObjectVersion(request.getVersionedId()); + } + if (!msgExceptionStr.isEmpty() ) { + throw new IllegalArgumentException(msgExceptionStr); + } + } + + public static String getMsgException(String keyName, Set msgException) { + if (msgException.size() == 1) { + msgException.add(" is not configured in the device profile!"); + } + msgException.remove(""); + return String.format("%s %s", keyName, String.join(",", msgException)).trim(); + } + + public static Map convertMultiResourceValuesFromRpcBody(LinkedHashMap value, ResourceModel.Type type, String versionedId) { + Gson gson = new Gson(); + JsonParser JSON_PARSER = new JsonParser(); + String json = gson.toJson(value, LinkedHashMap.class); + return convertMultiResourceValuesFromJson((JsonObject) JSON_PARSER.parse(json), type, versionedId); + } + + public static Map convertMultiResourceValuesFromJson(JsonObject newValProto, ResourceModel.Type type, String versionedId) { + Map newValues = equalsMultiResourceValuesResourceType(type); + newValProto.getAsJsonObject().entrySet().forEach((obj) -> { + newValues.put(Integer.valueOf(obj.getKey()), LwM2mValueConverterImpl.getInstance().convertValue(obj.getValue().getAsString(), + STRING, type, new LwM2mPath(fromVersionedIdToObjectId(versionedId)))); + }); + return newValues; + } + + public static Map equalsMultiResourceValuesResourceType(ResourceModel.Type type) { + switch (type) { + case FLOAT: + return new HashMap(); + case INTEGER: + return new HashMap(); + case STRING: + return new HashMap(); + case BOOLEAN: + return new HashMap(); + case OPAQUE: + return new HashMap(); + case TIME: + return new HashMap(); + case OBJLNK: + return new HashMap(); + default: + return null; + } + } + public static Object convertWriteAttributes(String type, Object value, DefaultLwM2MUplinkMsgHandler serviceImpl, String target) { switch (type) { /** Integer [0:255]; */ diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/attributes/DefaultLwM2MAttributesService.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/attributes/DefaultLwM2MAttributesService.java index 8cba658859..3d27621c00 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/attributes/DefaultLwM2MAttributesService.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/attributes/DefaultLwM2MAttributesService.java @@ -17,11 +17,14 @@ package org.thingsboard.server.transport.lwm2m.server.attributes; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.SettableFuture; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.eclipse.leshan.core.model.ResourceModel; import org.eclipse.leshan.core.node.LwM2mPath; import org.eclipse.leshan.core.node.LwM2mResource; +import org.eclipse.leshan.core.node.LwM2mResourceInstance; import org.springframework.stereotype.Service; import org.thingsboard.server.common.transport.TransportService; import org.thingsboard.server.common.transport.TransportServiceCallback; @@ -43,14 +46,19 @@ import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandle import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicInteger; +import static org.eclipse.leshan.core.model.ResourceModel.Type.OPAQUE; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportServerHelper.getValueFromKvProto; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LWM2M_ERROR; +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LWM2M_INFO; +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertMultiResourceValuesFromJson; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.fromVersionedIdToObjectId; @Slf4j @@ -145,7 +153,7 @@ public class DefaultLwM2MAttributesService implements LwM2MAttributesService { newSoftwareTag = getStrValue(tsKvProto); } else if (DefaultLwM2MOtaUpdateService.SOFTWARE_URL.equals(attrName)) { newSoftwareUrl = getStrValue(tsKvProto); - }else { + } else { otherAttributes.add(tsKvProto); } } @@ -156,7 +164,7 @@ public class DefaultLwM2MAttributesService implements LwM2MAttributesService { otaUpdateService.onTargetSoftwareUpdate(lwM2MClient, newSoftwareTitle, newSoftwareVersion, Optional.ofNullable(newSoftwareUrl), Optional.ofNullable(newSoftwareTag)); } if (!otherAttributes.isEmpty()) { - onAttributesUpdate(lwM2MClient, otherAttributes); + onAttributesUpdate(lwM2MClient, otherAttributes, true); } } else if (lwM2MClient == null) { log.error("OnAttributeUpdate, lwM2MClient is null"); @@ -169,42 +177,97 @@ public class DefaultLwM2MAttributesService implements LwM2MAttributesService { * => send to client Request Update of value (new value from shared attribute) * and LwM2MClient.delayedRequests.add(path) * #2.1 if there is not a difference in values between the current resource values and the shared attribute values - * */ @Override - public void onAttributesUpdate(LwM2mClient lwM2MClient, List tsKvProtos) { + public void onAttributesUpdate(LwM2mClient lwM2MClient, List tsKvProtos, boolean logFailedUpdateOfNonChangedValue) { log.trace("[{}] onAttributesUpdate [{}]", lwM2MClient.getEndpoint(), tsKvProtos); + Map attributesUpdate = new ConcurrentHashMap<>(); tsKvProtos.forEach(tsKvProto -> { - String pathIdVer = clientContext.getObjectIdByKeyNameFromProfile(lwM2MClient, tsKvProto.getKv().getKey()); - if (pathIdVer != null) { - // #1.1 - if (lwM2MClient.getSharedAttributes().containsKey(pathIdVer)) { - if (tsKvProto.getTs() > lwM2MClient.getSharedAttributes().get(pathIdVer).getTs()) { + try { + String pathIdVer = clientContext.getObjectIdByKeyNameFromProfile(lwM2MClient, tsKvProto.getKv().getKey(), false); + if (pathIdVer != null) { + // #1.1 + if (lwM2MClient.getSharedAttributes().containsKey(pathIdVer)) { + if (tsKvProto.getTs() >= lwM2MClient.getSharedAttributes().get(pathIdVer).getTs()) { + lwM2MClient.getSharedAttributes().put(pathIdVer, tsKvProto); + attributesUpdate.put(pathIdVer, tsKvProto); + } + } else { lwM2MClient.getSharedAttributes().put(pathIdVer, tsKvProto); + attributesUpdate.put(pathIdVer, tsKvProto); } - } else { - lwM2MClient.getSharedAttributes().put(pathIdVer, tsKvProto); } + } catch (IllegalArgumentException e){ + log.error("Failed update resource [{}] onAttributesUpdate [{}]", lwM2MClient.getEndpoint(), e.getMessage()); + String logMsg = String.format("%s: Failed update resource onAttributesUpdate %s.", + LOG_LWM2M_ERROR, e.getMessage()); + logService.log(lwM2MClient, logMsg); } }); clientContext.update(lwM2MClient); // #2.1 - lwM2MClient.getSharedAttributes().forEach((pathIdVer, tsKvProto) -> { - this.pushUpdateToClientIfNeeded(lwM2MClient, this.getResourceValueFormatKv(lwM2MClient, pathIdVer), - getValueFromKvProto(tsKvProto.getKv()), pathIdVer); + attributesUpdate.forEach((pathIdVer, tsKvProto) -> { + ResourceModel resourceModel = lwM2MClient.getResourceModel(pathIdVer, this.config.getModelProvider()); + Object newValProto = getValueFromKvProto(tsKvProto.getKv()); + Object oldResourceValue = this.getResourceValueFormatKv(lwM2MClient, pathIdVer); + if (!resourceModel.multiple || !(newValProto instanceof JsonElement)) { + this.pushUpdateToClientIfNeeded(lwM2MClient, oldResourceValue, newValProto, pathIdVer, logFailedUpdateOfNonChangedValue); + } else { + pushUpdateMultiToClientIfNeeded(lwM2MClient, resourceModel, (JsonElement) newValProto, + (Map) oldResourceValue, pathIdVer); + } }); } - private void pushUpdateToClientIfNeeded(LwM2mClient lwM2MClient, Object valueOld, Object newValue, String versionedId) { - if (newValue != null && (valueOld == null || !newValue.toString().equals(valueOld.toString()))) { + private void pushUpdateToClientIfNeeded(LwM2mClient lwM2MClient, Object valueOld, Object newValue, + String versionedId, boolean logFailedUpdateOfNonChangedValue) { + if (newValue == null) { + String logMsg = String.format("%s: Failed update resource versionedId - %s value - %s. New value is bad", + LOG_LWM2M_ERROR, versionedId, "null"); + logService.log(lwM2MClient, logMsg); + log.error("Failed update resource [{}] [{}]", versionedId, newValue); + } else if ((valueOld != null && newValue.toString().equals(valueOld.toString()))){ + if (logFailedUpdateOfNonChangedValue) { + String logMsg = String.format("%s: Failed update resource versionedId - %s value - %s. Value is not changed", + LOG_LWM2M_INFO, versionedId, newValue); + logService.log(lwM2MClient, logMsg); + log.info("Failed update resource [{}] [{}]. Value is not changed", versionedId, newValue); + } + } else { TbLwM2MWriteReplaceRequest request = TbLwM2MWriteReplaceRequest.builder().versionedId(versionedId).value(newValue).timeout(clientContext.getRequestTimeout(lwM2MClient)).build(); downlinkHandler.sendWriteReplaceRequest(lwM2MClient, request, new TbLwM2MWriteResponseCallback(uplinkHandler, logService, lwM2MClient, versionedId)); + } + } + + private void pushUpdateMultiToClientIfNeeded(LwM2mClient client, ResourceModel resourceModel, JsonElement newValProto, + Map valueOld, String versionedId) { + Map newValues = convertMultiResourceValuesFromJson((JsonObject)newValProto, resourceModel.type, versionedId); + if (newValues.size() > 0) { + if (valueOld != null && valueOld.size() > 0) { + valueOld.values().stream().forEach((v) -> { + if (newValues.containsKey(v.getId())) { + boolean isValueEquals; + if (OPAQUE.equals(v.getType())) { + isValueEquals = Arrays.equals((byte [])newValues.get(v.getId()), (byte[]) v.getValue()); + } else { + isValueEquals = newValues.get(v.getId()).toString().equals(v.getValue().toString()); + } + if (isValueEquals) { + newValues.remove(v.getId()); + } + } + }); + } + } + + if (newValues.size() > 0) { + TbLwM2MWriteReplaceRequest request = TbLwM2MWriteReplaceRequest.builder().versionedId(versionedId).value(newValues).timeout(this.config.getTimeout()).build(); + downlinkHandler.sendWriteReplaceRequest(client, request, new TbLwM2MWriteResponseCallback(uplinkHandler, logService, client, versionedId)); } else { - log.error("Failed update resource [{}] [{}]", versionedId, newValue); + log.error("Failed update resource [{}] [{}]", versionedId, newValProto); String logMsg = String.format("%s: Failed update resource versionedId - %s value - %s. Value is not changed or bad", - LOG_LWM2M_ERROR, versionedId, newValue); - logService.log(lwM2MClient, logMsg); - log.info("Failed update resource [{}] [{}]", versionedId, newValue); + LOG_LWM2M_ERROR, versionedId, newValProto); + logService.log(client, logMsg); } } @@ -217,8 +280,14 @@ public class DefaultLwM2MAttributesService implements LwM2MAttributesService { if (resourceValue != null) { ResourceModel.Type currentType = resourceValue.getType(); ResourceModel.Type expectedType = helper.getResourceModelTypeEqualsKvProtoValueType(currentType, pathIdVer); - return LwM2mValueConverterImpl.getInstance().convertValue(resourceValue.getValue(), currentType, expectedType, - new LwM2mPath(fromVersionedIdToObjectId(pathIdVer))); + if (!resourceValue.isMultiInstances()) { + return LwM2mValueConverterImpl.getInstance().convertValue(resourceValue.getValue(), currentType, expectedType, + new LwM2mPath(fromVersionedIdToObjectId(pathIdVer))); + } else if (resourceValue.getInstances().size() > 0) { + return resourceValue.getInstances(); + } else { + return null; + } } else { return null; } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/attributes/LwM2MAttributesService.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/attributes/LwM2MAttributesService.java index b9d7fa9e21..cce7a29c88 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/attributes/LwM2MAttributesService.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/attributes/LwM2MAttributesService.java @@ -30,5 +30,5 @@ public interface LwM2MAttributesService { void onAttributesUpdate(TransportProtos.AttributeUpdateNotificationMsg attributeUpdateNotification, TransportProtos.SessionInfoProto sessionInfo); - void onAttributesUpdate(LwM2mClient lwM2MClient, List tsKvProtos); + void onAttributesUpdate(LwM2mClient lwM2MClient, List tsKvProtos, boolean logFailedUpdateOfNonChangedValue); } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java index 97a3d72c33..ff2757ba3b 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java @@ -27,7 +27,7 @@ import org.eclipse.leshan.core.node.LwM2mResource; import org.eclipse.leshan.core.node.LwM2mSingleResource; import org.eclipse.leshan.core.node.codec.LwM2mValueConverter; import org.eclipse.leshan.core.request.ContentFormat; -import org.eclipse.leshan.core.util.Hex; +import org.eclipse.leshan.core.request.WriteRequest.Mode; import org.eclipse.leshan.server.model.LwM2mModelProvider; import org.eclipse.leshan.server.registration.Registration; import org.thingsboard.server.common.data.Device; @@ -43,8 +43,10 @@ import org.thingsboard.server.transport.lwm2m.config.LwM2mVersion; import java.io.IOException; import java.io.ObjectInputStream; import java.io.Serializable; +import java.util.Arrays; import java.util.Collection; -import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashMap; import java.util.Map; import java.util.Optional; import java.util.Set; @@ -57,10 +59,11 @@ import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import java.util.stream.Collectors; +import java.util.stream.Stream; -import static org.eclipse.leshan.core.model.ResourceModel.Type.OPAQUE; import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPARATOR_PATH; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LWM2M_OBJECT_VERSION_DEFAULT; +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertMultiResourceValuesFromRpcBody; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertObjectIdToVersionedId; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.equalsResourceTypeGetSimpleName; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.fromVersionedIdToObjectId; @@ -101,11 +104,11 @@ public class LwM2mClient implements Serializable { @Getter private Long psmActivityTimer; @Getter - private Long edrxCycle; - @Getter private Long pagingTransmissionWindow; @Getter @Setter + private Long edrxCycle; + @Getter private Registration registration; @Getter @Setter @@ -118,6 +121,10 @@ public class LwM2mClient implements Serializable { private boolean firstEdrxDownlink = true; + @Getter + Set clientSupportContentFormats; + @Getter + ContentFormat defaultContentFormat; @Getter private final AtomicInteger retryAttempts; @@ -147,6 +154,12 @@ public class LwM2mClient implements Serializable { this.pagingTransmissionWindow = credentials.getDeviceInfo().getPagingTransmissionWindow(); } + public void setRegistration(Registration registration) { + this.registration = registration; + this.clientSupportContentFormats = clientSupportContentFormat(registration); + this.defaultContentFormat = calculateDefaultContentFormat(registration); + } + public void lock() { lock.lock(); } @@ -210,15 +223,16 @@ public class LwM2mClient implements Serializable { .build(); } - public boolean saveResourceValue(String pathRezIdVer, LwM2mResource rez, LwM2mModelProvider modelProvider) { - if (this.resources.get(pathRezIdVer) != null && this.resources.get(pathRezIdVer).getResourceModel() != null) { - this.resources.get(pathRezIdVer).setLwM2mResource(rez); + public boolean saveResourceValue(String pathRezIdVer, LwM2mResource resource, LwM2mModelProvider modelProvider, Mode mode) { + if (this.resources.get(pathRezIdVer) != null && this.resources.get(pathRezIdVer).getResourceModel() != null && + resourceEqualsModel(resource, this.resources.get(pathRezIdVer).getResourceModel())) { + this.resources.get(pathRezIdVer).updateLwM2mResource(resource, mode); return true; } else { LwM2mPath pathIds = new LwM2mPath(fromVersionedIdToObjectId(pathRezIdVer)); ResourceModel resourceModel = modelProvider.getObjectModel(registration).getResourceModel(pathIds.getObjectId(), pathIds.getResourceId()); - if (resourceModel != null) { - this.resources.put(pathRezIdVer, new ResourceValue(rez, resourceModel)); + if (resourceModel != null && resourceEqualsModel(resource, resourceModel)) { + this.resources.put(pathRezIdVer, new ResourceValue(resource, resourceModel)); return true; } else { return false; @@ -226,6 +240,11 @@ public class LwM2mClient implements Serializable { } } + private boolean resourceEqualsModel(LwM2mResource resource, ResourceModel resourceModel) { + return ((!resourceModel.multiple && resource instanceof LwM2mSingleResource) || + (resourceModel.multiple && resource instanceof LwM2mMultipleResource)); + } + public Object getResourceValue(String pathRezIdVer, String pathRezId) { String pathRez = pathRezIdVer == null ? convertObjectIdToVersionedId(pathRezId, this.registration) : pathRezIdVer; if (this.resources.get(pathRez) != null) { @@ -282,7 +301,6 @@ public class LwM2mClient implements Serializable { } - public Collection getNewResourceForInstance(String pathRezIdVer, Object params, LwM2mModelProvider modelProvider, LwM2mValueConverter converter) { LwM2mPath pathIds = new LwM2mPath(fromVersionedIdToObjectId(pathRezIdVer)); @@ -299,31 +317,61 @@ public class LwM2mClient implements Serializable { return resources; } + /** + * The instance must have all the resources that have the property + * Mandatory + */ public Collection getNewResourcesForInstance(String pathRezIdVer, Object params, LwM2mModelProvider modelProvider, LwM2mValueConverter converter) { LwM2mPath pathIds = new LwM2mPath(fromVersionedIdToObjectId(pathRezIdVer)); Collection resources = ConcurrentHashMap.newKeySet(); Map resourceModels = modelProvider.getObjectModel(registration) .getObjectModel(pathIds.getObjectId()).resources; - resourceModels.forEach((resId, resourceModel) -> { - if (((Map) params).containsKey(String.valueOf(resId))) { - Object value = ((Map) params).get((String.valueOf(resId))); - resources.add(LwM2mSingleResource.newResource(resId, - converter.convertValue(value, equalsResourceTypeGetSimpleName(value), resourceModel.type, pathIds), resourceModel.type)); - - } - }); + if (params != null) { + resourceModels.forEach((resourceId, resourceModel) -> { + if (((Map) params).containsKey(String.valueOf(resourceId))) { + Object value = ((Map) params).get((String.valueOf(resourceId))); + LwM2mResource resource = null; + if (resourceModel.multiple) { + if (value instanceof LinkedHashMap) { + Map values = convertMultiResourceValuesFromRpcBody((LinkedHashMap) value, resourceModel.type, pathRezIdVer); + resource = LwM2mMultipleResource.newResource(resourceId, (Map) values, resourceModel.type); + } + } else { + Object valueRez = value.getClass().getSimpleName().equals("Integer") ? ((Integer) value).longValue() : value; + resource = LwM2mSingleResource.newResource(resourceId, + converter.convertValue(valueRez, equalsResourceTypeGetSimpleName(value), resourceModel.type, pathIds), resourceModel.type); + } + if (resource != null) { + resources.add(resource); + } else if (resourceModel.operations.isWritable() && resourceModel.mandatory) { + throw new IllegalArgumentException("Resource id=" + resourceId + " is mandatory. The value of this resource must not be null."); + } + } + else if (resourceModel.operations.isWritable() && resourceModel.mandatory) { + throw new IllegalArgumentException("Resource id=" + resourceId + " is mandatory. The value of this resource must not be null."); + } + }); + } + else { + throw new IllegalArgumentException("The value of this resource must not be null."); + } return resources; } - public void isValidObjectVersion(String path) { + public String isValidObjectVersion(String path) { LwM2mPath pathIds = new LwM2mPath(fromVersionedIdToObjectId(path)); String verSupportedObject = registration.getSupportedObject().get(pathIds.getObjectId()); - String verRez = getVerFromPathIdVerOrId(path); - if ((verRez != null && !verRez.equals(verSupportedObject)) || - (verRez == null && !LWM2M_OBJECT_VERSION_DEFAULT.equals(verSupportedObject))) { - throw new IllegalArgumentException(String.format("Specified resource id %s is not valid version! Must be version: %s", path, verSupportedObject)); + if (verSupportedObject == null) { + return String.format("Specified resource id %s is missing from the client!", path); + } else { + String verRez = getVerFromPathIdVerOrId(path); + if ((verRez != null && !verRez.equals(verSupportedObject)) || + (verRez == null && !LWM2M_OBJECT_VERSION_DEFAULT.equals(verSupportedObject))) { + return String.format("Specified resource id %s is not valid version! Must be version: %s", path, verSupportedObject); + } } + return ""; } /** @@ -365,12 +413,33 @@ public class LwM2mClient implements Serializable { .collect(Collectors.toSet()); } - public ContentFormat getDefaultContentFormat() { + private ContentFormat calculateDefaultContentFormat(Registration registration) { if (registration == null) { return ContentFormat.DEFAULT; + } else{ + return LwM2mVersion.fromVersion(registration.getLwM2mVersion()).getContentFormat(); + } + } + + private Set clientSupportContentFormat(Registration registration) { + Set contentFormats = new HashSet<>(); + if (registration == null) { + contentFormats.add(ContentFormat.DEFAULT); } else { - return LwM2mVersion.fromVersionStr(registration.getLwM2mVersion()).getContentFormat(); + String code = Arrays.stream(registration.getObjectLinks()).filter(link -> link.getUrl().equals("/")). + findFirst().get().getAttributes().get("ct"); + if (code != null) { + Set codes = Stream.of(code.replaceAll("\"", "").split(" ", -1)) + .map(String::trim) + .map(Integer::parseInt) + .map(ContentFormat::fromCode) + .collect(Collectors.toSet()); + contentFormats.addAll(codes); + } else { + contentFormats.add(ContentFormat.DEFAULT); + } } + return contentFormats; } private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContext.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContext.java index c05148017c..5b720a8b66 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContext.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContext.java @@ -15,6 +15,7 @@ */ package org.thingsboard.server.transport.lwm2m.server.client; +import org.eclipse.leshan.core.request.ContentFormat; import org.eclipse.leshan.server.registration.Registration; import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.device.profile.Lwm2mDeviceProfileTransportConfiguration; @@ -51,7 +52,7 @@ public interface LwM2mClientContext { LwM2mClient getClientByDeviceId(UUID deviceId); - String getObjectIdByKeyNameFromProfile(LwM2mClient lwM2mClient, String keyName); + String getObjectIdByKeyNameFromProfile(LwM2mClient lwM2mClient, String keyName, boolean isCompositeOperation); void registerClient(Registration registration, ValidateDeviceCredentialsResponse credentials); @@ -61,7 +62,7 @@ public interface LwM2mClientContext { void sendMsgsAfterSleeping(LwM2mClient lwM2MClient); - boolean isComposite(LwM2mClient client); + ContentFormat getContentFormatComposite(LwM2mClient client); void onUplink(LwM2mClient client); diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java index e29dcdd1dd..ebf9c11155 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java @@ -18,8 +18,8 @@ package org.thingsboard.server.transport.lwm2m.server.client; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.eclipse.leshan.core.SecurityMode; -import org.eclipse.leshan.core.model.ResourceModel; import org.eclipse.leshan.core.node.LwM2mPath; +import org.eclipse.leshan.core.request.ContentFormat; import org.eclipse.leshan.server.registration.Registration; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Lazy; @@ -36,7 +36,6 @@ import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.queue.util.AfterStartUp; import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; -import org.thingsboard.server.transport.lwm2m.config.LwM2mVersion; import org.thingsboard.server.transport.lwm2m.secure.TbLwM2MSecurityInfo; import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportContext; import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil; @@ -59,8 +58,7 @@ import java.util.function.Predicate; import static org.eclipse.leshan.core.SecurityMode.NO_SEC; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertObjectIdToVersionedId; -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.fromVersionedIdToObjectId; -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.validateObjectVerFromKey; +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.getMsgException; @Slf4j @Service @@ -291,12 +289,13 @@ public class LwM2mClientContextImpl implements LwM2mClientContext { } @Override - public String getObjectIdByKeyNameFromProfile(LwM2mClient client, String keyName) { + public String getObjectIdByKeyNameFromProfile(LwM2mClient client, String keyName, boolean isCompositeOperation) { Lwm2mDeviceProfileTransportConfiguration profile = getProfile(client.getProfileId()); - + Set msgException = ConcurrentHashMap.newKeySet(); + msgException.add(""); return profile.getObserveAttr().getKeyName().entrySet().stream() - .filter(e -> e.getValue().equals(keyName) && validateResourceInModel(client, e.getKey(), false)).findFirst().orElseThrow( - () -> new IllegalArgumentException(keyName + " is not configured in the device profile!") + .filter(e -> e.getValue().equals(keyName) && (isCompositeOperation || !msgException.add(client.isValidObjectVersion(e.getKey())))).findFirst().orElseThrow( + () -> new IllegalArgumentException(getMsgException (keyName, msgException)) ).getKey(); } @@ -336,7 +335,7 @@ public class LwM2mClientContextImpl implements LwM2mClientContext { if (LwM2MClientState.REGISTERED.equals(lwM2MClient.getState())) { PowerMode powerMode = getPowerMode(lwM2MClient); if (PowerMode.PSM.equals(powerMode) || PowerMode.E_DRX.equals(powerMode)) { - defaultLwM2MUplinkMsgHandler.initAttributes(lwM2MClient); + defaultLwM2MUplinkMsgHandler.initAttributes(lwM2MClient, false); TransportProtos.TransportToDeviceActorMsg persistentRpcRequestMsg = TransportProtos.TransportToDeviceActorMsg .newBuilder() .setSessionInfo(lwM2MClient.getSession()) @@ -412,9 +411,9 @@ public class LwM2mClientContextImpl implements LwM2mClientContext { } @Override - public boolean isComposite(LwM2mClient client) { - return LwM2mVersion.fromVersionStr(client.getRegistration().getLwM2mVersion()).isComposite() & - getProfile(client.getProfileId()).getClientLwM2mSettings().isCompositeOperationsSupport(); + public ContentFormat getContentFormatComposite(LwM2mClient client) { + return client.getClientSupportContentFormats().contains(ContentFormat.SENML_JSON) ? ContentFormat.SENML_JSON : + client.getClientSupportContentFormats().contains(ContentFormat.SENML_CBOR) ? ContentFormat.SENML_CBOR : null; } @Override @@ -541,15 +540,4 @@ public class LwM2mClientContextImpl implements LwM2mClientContext { } return timeout; } - - private boolean validateResourceInModel(LwM2mClient lwM2mClient, String pathIdVer, boolean isWritableNotOptional) { - ResourceModel resourceModel = lwM2mClient.getResourceModel(pathIdVer, this.config - .getModelProvider()); - Integer objectId = new LwM2mPath(fromVersionedIdToObjectId(pathIdVer)).getObjectId(); - String objectVer = validateObjectVerFromKey(pathIdVer); - return resourceModel != null && (isWritableNotOptional ? - objectId != null && objectVer != null && objectVer.equals(lwM2mClient.getRegistration().getSupportedVersion(objectId)) && resourceModel.operations.isWritable() : - objectId != null && objectVer != null && objectVer.equals(lwM2mClient.getRegistration().getSupportedVersion(objectId))); - } - } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/ResourceValue.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/ResourceValue.java index 7f61caf58a..700c589202 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/ResourceValue.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/ResourceValue.java @@ -16,13 +16,20 @@ package org.thingsboard.server.transport.lwm2m.server.client; import lombok.Data; +import lombok.extern.slf4j.Slf4j; import org.eclipse.leshan.core.model.ResourceModel; +import org.eclipse.leshan.core.node.LwM2mMultipleResource; import org.eclipse.leshan.core.node.LwM2mResource; import org.eclipse.leshan.core.node.LwM2mResourceInstance; +import org.eclipse.leshan.core.node.LwM2mSingleResource; +import org.eclipse.leshan.core.request.WriteRequest.Mode; import java.io.Serializable; +import java.util.Map; +import java.util.Set; import java.util.stream.Collectors; +@Slf4j @Data public class ResourceValue implements Serializable { @@ -32,32 +39,35 @@ public class ResourceValue implements Serializable { private TbResourceModel resourceModel; public ResourceValue(LwM2mResource lwM2mResource, ResourceModel resourceModel) { - this.lwM2mResource = toTbLwM2MResource(lwM2mResource); this.resourceModel = toTbResourceModel(resourceModel); + updateLwM2mResource(lwM2mResource, Mode.UPDATE); } - public void setLwM2mResource(LwM2mResource lwM2mResource) { - this.lwM2mResource = toTbLwM2MResource(lwM2mResource); + public void updateLwM2mResource(LwM2mResource lwM2mResource, Mode mode) { + if (lwM2mResource instanceof LwM2mSingleResource) { + this.lwM2mResource = new TbLwM2MSingleResource(lwM2mResource.getId(), lwM2mResource.getValue(), lwM2mResource.getType()); + + } else if (lwM2mResource instanceof LwM2mMultipleResource) { + if (lwM2mResource.getInstances().values().size() > 0) { + Set instancesSet = lwM2mResource.getInstances().values().stream().map(ResourceValue::toTbLwM2MResourceInstance).collect(Collectors.toSet()); + if (Mode.REPLACE.equals(mode) && this.lwM2mResource != null) { + Map oldInstances = this.lwM2mResource.getInstances(); + oldInstances.values().forEach(v -> { + if (instancesSet.stream().filter(vIns -> v.getId() == vIns.getId()).collect(Collectors.toList()).size() == 0){ + instancesSet.add(toTbLwM2MResourceInstance(v)); + } + }); + } + TbLwM2MResourceInstance[] instances = instancesSet.toArray(new TbLwM2MResourceInstance[0]); + this.lwM2mResource = new TbLwM2mMultipleResource(lwM2mResource.getId(), lwM2mResource.getType(), instances); + } + } } public void setResourceModel(ResourceModel resourceModel) { this.resourceModel = toTbResourceModel(resourceModel); } - private static TbLwM2MResource toTbLwM2MResource(LwM2mResource lwM2mResource) { - if (lwM2mResource.isMultiInstances()) { - if ( lwM2mResource.getInstances().values().size() > 0) { - TbLwM2MResourceInstance [] instances = lwM2mResource.getInstances().values().stream().map(ResourceValue::toTbLwM2MResourceInstance).collect(Collectors.toSet()).toArray(new TbLwM2MResourceInstance[0]); - return new TbLwM2MMultipleResource(lwM2mResource.getId(), lwM2mResource.getType(), instances); - } - else { - return new TbLwM2MMultipleResource(lwM2mResource.getId(), lwM2mResource.getType(), new TbLwM2MResourceInstance[0]); - } - } else { - return new TbLwM2MSingleResource(lwM2mResource.getId(), lwM2mResource.getValue(), lwM2mResource.getType()); - } - } - private static TbLwM2MResourceInstance toTbLwM2MResourceInstance(LwM2mResourceInstance instance) { return new TbLwM2MResourceInstance(instance.getId(), instance.getValue(), instance.getType()); } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/TbLwM2MMultipleResource.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/TbLwM2mMultipleResource.java similarity index 82% rename from common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/TbLwM2MMultipleResource.java rename to common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/TbLwM2mMultipleResource.java index ad5431b383..dce642f336 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/TbLwM2MMultipleResource.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/TbLwM2mMultipleResource.java @@ -17,16 +17,14 @@ package org.thingsboard.server.transport.lwm2m.server.client; import org.eclipse.leshan.core.model.ResourceModel; import org.eclipse.leshan.core.node.LwM2mMultipleResource; -import org.eclipse.leshan.core.node.LwM2mResourceInstance; import java.io.Serializable; -import java.util.Collection; -public class TbLwM2MMultipleResource extends LwM2mMultipleResource implements TbLwM2MResource, Serializable { +public class TbLwM2mMultipleResource extends LwM2mMultipleResource implements TbLwM2MResource, Serializable { private static final long serialVersionUID = 4658477128628087186L; - public TbLwM2MMultipleResource(int id, ResourceModel.Type type, TbLwM2MResourceInstance... instances) { + public TbLwM2mMultipleResource(int id, ResourceModel.Type type, TbLwM2MResourceInstance... instances) { super(id, type, instances); } } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/common/LwM2MExecutorAwareService.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/common/LwM2MExecutorAwareService.java index 1f1dff784f..52dd7221d1 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/common/LwM2MExecutorAwareService.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/common/LwM2MExecutorAwareService.java @@ -17,7 +17,6 @@ package org.thingsboard.server.transport.lwm2m.server.common; import org.thingsboard.common.util.ThingsBoardExecutors; -import javax.annotation.PreDestroy; import java.util.concurrent.ExecutorService; public abstract class LwM2MExecutorAwareService { diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2mDownlinkMsgHandler.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2mDownlinkMsgHandler.java index 82ea0c5fbe..5a6ac6b466 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2mDownlinkMsgHandler.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2mDownlinkMsgHandler.java @@ -18,16 +18,19 @@ package org.thingsboard.server.transport.lwm2m.server.downlink; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.eclipse.leshan.core.Link; +import org.eclipse.leshan.core.LwM2m; import org.eclipse.leshan.core.attributes.Attribute; import org.eclipse.leshan.core.attributes.AttributeSet; +import org.eclipse.leshan.core.model.ObjectModel; import org.eclipse.leshan.core.model.ResourceModel; +import org.eclipse.leshan.core.node.LwM2mObjectInstance; import org.eclipse.leshan.core.node.LwM2mPath; import org.eclipse.leshan.core.node.LwM2mResource; import org.eclipse.leshan.core.node.ObjectLink; -import org.eclipse.leshan.core.node.codec.CodecException; import org.eclipse.leshan.core.observation.Observation; import org.eclipse.leshan.core.request.CompositeDownlinkRequest; import org.eclipse.leshan.core.request.ContentFormat; +import org.eclipse.leshan.core.request.CreateRequest; import org.eclipse.leshan.core.request.DeleteRequest; import org.eclipse.leshan.core.request.DiscoverRequest; import org.eclipse.leshan.core.request.DownlinkRequest; @@ -40,7 +43,9 @@ import org.eclipse.leshan.core.request.WriteAttributesRequest; import org.eclipse.leshan.core.request.WriteCompositeRequest; import org.eclipse.leshan.core.request.WriteRequest; import org.eclipse.leshan.core.request.exception.ClientSleepingException; +import org.eclipse.leshan.core.request.exception.InvalidRequestException; import org.eclipse.leshan.core.request.exception.TimeoutException; +import org.eclipse.leshan.core.response.CreateResponse; import org.eclipse.leshan.core.response.DeleteResponse; import org.eclipse.leshan.core.response.DiscoverResponse; import org.eclipse.leshan.core.response.ExecuteResponse; @@ -55,7 +60,6 @@ import org.eclipse.leshan.core.util.Hex; import org.eclipse.leshan.server.model.LwM2mModelProvider; import org.eclipse.leshan.server.registration.Registration; import org.springframework.stereotype.Service; -import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.device.data.lwm2m.ObjectAttributes; import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; @@ -73,9 +77,12 @@ import javax.annotation.PreDestroy; import java.util.Arrays; import java.util.Collection; import java.util.Date; +import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; +import java.util.Map; import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; import java.util.function.Function; import java.util.function.Predicate; import java.util.stream.Collectors; @@ -85,7 +92,11 @@ import static org.eclipse.leshan.core.attributes.Attribute.LESSER_THAN; import static org.eclipse.leshan.core.attributes.Attribute.MAXIMUM_PERIOD; import static org.eclipse.leshan.core.attributes.Attribute.MINIMUM_PERIOD; import static org.eclipse.leshan.core.attributes.Attribute.STEP; +import static org.eclipse.leshan.core.model.ResourceModel.Type.OBJLNK; +import static org.eclipse.leshan.core.model.ResourceModel.Type.OPAQUE; +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertMultiResourceValuesFromRpcBody; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.fromVersionedIdToObjectId; +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.validateVersionedId; @Slf4j @Service @@ -123,40 +134,49 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im @Override public void sendReadRequest(LwM2mClient client, TbLwM2MReadRequest request, DownlinkRequestCallback callback) { - validateVersionedId(client, request); - ReadRequest downlink = new ReadRequest(getRequestContentFormat(client, request, this.config.getModelProvider()), request.getObjectId()); - sendSimpleRequest(client, downlink, request.getTimeout(), callback); + try { + validateVersionedId(client, request); + ReadRequest downlink = new ReadRequest(getReadRequestContentFormat(client, request, this.config.getModelProvider()), request.getObjectId()); + sendSimpleRequest(client, downlink, request.getTimeout(), callback); + } catch (InvalidRequestException e) { + callback.onValidationError(request.toString(), e.getMessage()); + } } @Override - public void sendReadCompositeRequest(LwM2mClient client, TbLwM2MReadCompositeRequest request, DownlinkRequestCallback callback) { - validateVersionedIds(client, request); - ContentFormat requestContentFormat = ContentFormat.SENML_JSON; - ContentFormat responseContentFormat = ContentFormat.SENML_JSON; - - ReadCompositeRequest downlink = new ReadCompositeRequest(requestContentFormat, responseContentFormat, request.getObjectIds()); - sendCompositeRequest(client, downlink, request.getTimeout(), callback); + public void sendReadCompositeRequest(LwM2mClient client, TbLwM2MReadCompositeRequest request, + DownlinkRequestCallback callback, ContentFormat contentFormatComposite) { + try { + ReadCompositeRequest downlink = new ReadCompositeRequest(contentFormatComposite, contentFormatComposite, request.getObjectIds()); + sendCompositeRequest(client, downlink, this.config.getTimeout(), callback); + } catch (InvalidRequestException e) { + callback.onValidationError(request.toString(), e.getMessage()); + } } @Override public void sendObserveRequest(LwM2mClient client, TbLwM2MObserveRequest request, DownlinkRequestCallback callback) { - validateVersionedId(client, request); - LwM2mPath resultIds = new LwM2mPath(request.getObjectId()); - Set observations = context.getServer().getObservationService().getObservations(client.getRegistration()); - if (observations.stream().noneMatch(observation -> observation.getPath().equals(resultIds))) { - ObserveRequest downlink; - ContentFormat contentFormat = getRequestContentFormat(client, request, this.config.getModelProvider()); - if (resultIds.isResource()) { - downlink = new ObserveRequest(contentFormat, resultIds.getObjectId(), resultIds.getObjectInstanceId(), resultIds.getResourceId()); - } else if (resultIds.isObjectInstance()) { - downlink = new ObserveRequest(contentFormat, resultIds.getObjectId(), resultIds.getObjectInstanceId()); + try { + validateVersionedId(client, request); + LwM2mPath resultIds = new LwM2mPath(request.getObjectId()); + Set observations = context.getServer().getObservationService().getObservations(client.getRegistration()); + if (observations.stream().noneMatch(observation -> observation.getPath().equals(resultIds))) { + ObserveRequest downlink; + ContentFormat contentFormat = getReadRequestContentFormat(client, request, this.config.getModelProvider()); + if (resultIds.isResource()) { + downlink = new ObserveRequest(contentFormat, resultIds.getObjectId(), resultIds.getObjectInstanceId(), resultIds.getResourceId()); + } else if (resultIds.isObjectInstance()) { + downlink = new ObserveRequest(contentFormat, resultIds.getObjectId(), resultIds.getObjectInstanceId()); + } else { + downlink = new ObserveRequest(contentFormat, resultIds.getObjectId()); + } + log.info("[{}] Send observation: {}.", client.getEndpoint(), request.getVersionedId()); + sendSimpleRequest(client, downlink, request.getTimeout(), callback); } else { - downlink = new ObserveRequest(contentFormat, resultIds.getObjectId()); + callback.onValidationError(resultIds.toString(), "Observation is already registered!"); } - log.info("[{}] Send observation: {}.", client.getEndpoint(), request.getVersionedId()); - sendSimpleRequest(client, downlink, request.getTimeout(), callback); - } else { - callback.onValidationError(resultIds.toString(), "Observation is already registered!"); + } catch (InvalidRequestException e) { + callback.onValidationError(request.toString(), e.getMessage()); } } @@ -174,25 +194,36 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im @Override public void sendExecuteRequest(LwM2mClient client, TbLwM2MExecuteRequest request, DownlinkRequestCallback callback) { - ResourceModel resourceModelExecute = client.getResourceModel(request.getVersionedId(), this.config.getModelProvider()); - if (resourceModelExecute != null) { - ExecuteRequest downlink; - if (request.getParams() != null && !resourceModelExecute.multiple) { - downlink = new ExecuteRequest(request.getVersionedId(), (String) this.converter.convertValue(request.getParams(), resourceModelExecute.type, ResourceModel.Type.STRING, new LwM2mPath(request.getObjectId()))); - } else { - downlink = new ExecuteRequest(request.getVersionedId()); + try { + ResourceModel resourceModelExecute = client.getResourceModel(request.getVersionedId(), this.config.getModelProvider()); + if (resourceModelExecute != null) { + validateVersionedId(client, request); + ExecuteRequest downlink; + if (request.getParams() != null && !resourceModelExecute.multiple) { + downlink = new ExecuteRequest(request.getObjectId(), (String) this.converter.convertValue(request.getParams(), resourceModelExecute.type, ResourceModel.Type.STRING, new LwM2mPath(request.getObjectId()))); + } else { + downlink = new ExecuteRequest(request.getObjectId()); + } + sendSimpleRequest(client, downlink, request.getTimeout(), callback); } - sendSimpleRequest(client, downlink, request.getTimeout(), callback); + } catch (InvalidRequestException e) { + callback.onValidationError(request.toString(), e.getMessage()); } } @Override public void sendDeleteRequest(LwM2mClient client, TbLwM2MDeleteRequest request, DownlinkRequestCallback callback) { - sendSimpleRequest(client, new DeleteRequest(request.getObjectId()), request.getTimeout(), callback); + try { + validateVersionedId(client, request); + sendSimpleRequest(client, new DeleteRequest(request.getObjectId()), request.getTimeout(), callback); + } catch (InvalidRequestException e) { + callback.onValidationError(request.toString(), e.getMessage()); + } } @Override public void sendCancelObserveRequest(LwM2mClient client, TbLwM2MCancelObserveRequest request, DownlinkRequestCallback callback) { + validateVersionedId(client, request); int observeCancelCnt = context.getServer().getObservationService().cancelObservations(client.getRegistration(), request.getObjectId()); callback.onSuccess(request, observeCancelCnt); } @@ -209,51 +240,86 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im sendSimpleRequest(client, new DiscoverRequest(request.getObjectId()), request.getTimeout(), callback); } + /** + * Example # 1: + * AttributeSet attributes = new AttributeSet(new Attribute(Attribute.MINIMUM_PERIOD, 10L), + * new Attribute(Attribute.MAXIMUM_PERIOD, 100L)); + * WriteAttributesRequest requestTest = new WriteAttributesRequest(3, 0, 14, attributes); + * sendSimpleRequest(client, requestTest, request.getTimeout(), callback); + *

+ * Example # 2 + * Dimension and Object version are read only attributes. + * addAttribute(attributes, DIMENSION, params.getDim(), dim -> dim >= 0 && dim <= 255); + * addAttribute(attributes, OBJECT_VERSION, params.getVer(), StringUtils::isNotEmpty, Function.identity()); + */ @Override public void sendWriteAttributesRequest(LwM2mClient client, TbLwM2MWriteAttributesRequest request, DownlinkRequestCallback callback) { - validateVersionedId(client, request); - if (request.getAttributes() == null) { - throw new IllegalArgumentException("Attributes to write are not specified!"); + try { + validateVersionedId(client, request); + if (request.getAttributes() == null) { + throw new IllegalArgumentException("Attributes to write are not specified!"); + } + ObjectAttributes params = request.getAttributes(); + List attributes = new LinkedList<>(); + addAttribute(attributes, MAXIMUM_PERIOD, params.getPmax()); + addAttribute(attributes, MINIMUM_PERIOD, params.getPmin()); + addAttribute(attributes, GREATER_THAN, params.getGt()); + addAttribute(attributes, LESSER_THAN, params.getLt()); + addAttribute(attributes, STEP, params.getSt()); + AttributeSet attributeSet = new AttributeSet(attributes); + sendSimpleRequest(client, new WriteAttributesRequest(request.getObjectId(), attributeSet), request.getTimeout(), callback); + } catch (InvalidRequestException e) { + callback.onValidationError(request.toString(), e.getMessage()); } - ObjectAttributes params = request.getAttributes(); - List attributes = new LinkedList<>(); -// Dimension and Object version are read only attributes. -// addAttribute(attributes, DIMENSION, params.getDim(), dim -> dim >= 0 && dim <= 255); -// addAttribute(attributes, OBJECT_VERSION, params.getVer(), StringUtils::isNotEmpty, Function.identity()); - addAttribute(attributes, MAXIMUM_PERIOD, params.getPmax()); - addAttribute(attributes, MINIMUM_PERIOD, params.getPmin()); - addAttribute(attributes, GREATER_THAN, params.getGt()); - addAttribute(attributes, LESSER_THAN, params.getLt()); - addAttribute(attributes, STEP, params.getSt()); - AttributeSet attributeSet = new AttributeSet(attributes); - sendSimpleRequest(client, new WriteAttributesRequest(request.getObjectId(), attributeSet), request.getTimeout(), callback); } @Override public void sendWriteReplaceRequest(LwM2mClient client, TbLwM2MWriteReplaceRequest request, DownlinkRequestCallback callback) { - ResourceModel resourceModelWrite = client.getResourceModel(request.getVersionedId(), this.config.getModelProvider()); - if (resourceModelWrite != null) { - ContentFormat contentFormat = convertResourceModelTypeToContentFormat(client, resourceModelWrite.type); - try { - LwM2mPath path = new LwM2mPath(request.getObjectId()); - WriteRequest downlink = this.getWriteRequestSingleResource(resourceModelWrite.type, contentFormat, - path.getObjectId(), path.getObjectInstanceId(), path.getResourceId(), request.getValue()); - sendSimpleRequest(client, downlink, request.getTimeout(), callback); - } catch (Exception e) { - callback.onError(toString(request), e); + LwM2mPath resultIds = new LwM2mPath(request.getObjectId()); + if (resultIds.isResource() || resultIds.isResourceInstance()) { + validateVersionedId(client, request); + ResourceModel resourceModelWrite = client.getResourceModel(request.getVersionedId(), this.config.getModelProvider()); + if (resourceModelWrite != null) { + ContentFormat contentFormat = getWriteRequestContentFormat(client, request, this.config.getModelProvider()); + try { + WriteRequest downlink = null; + if (resourceModelWrite.multiple) { + if (request.getValue() instanceof Map && ((Map) request.getValue()).size() > 0) { + downlink = new WriteRequest(contentFormat, resultIds.getObjectId(), resultIds.getObjectInstanceId(), resultIds.getResourceId(), + (Map) request.getValue(), resourceModelWrite.type); + } else { + callback.onValidationError(toString(request), "Resource value is: " + request.getValue().getClass().getSimpleName() + ". Value of Multi-Instance Resource must be in Json format!"); + } + } else { + downlink = this.getWriteRequestSingleResource(resourceModelWrite.type, contentFormat, + resultIds.getObjectId(), resultIds.getObjectInstanceId(), resultIds.getResourceId(), request.getValue()); + } + if (downlink != null) { + sendSimpleRequest(client, downlink, request.getTimeout(), callback); + } else { + callback.onValidationError(toString(request), "WriteRequest is null."); + } + } catch (Exception e) { + callback.onError(toString(request), e); + } + + } else { + callback.onValidationError(toString(request), "Resource " + request.getVersionedId() + " is not configured in the device profile!"); } } else { - callback.onValidationError(toString(request), "Resource " + request.getVersionedId() + " is not configured in the device profile!"); + callback.onValidationError(toString(request), "Resource " + request.getVersionedId() + ". This operation can only be used for Resource or ResourceInstance!"); } } @Override - public void sendWriteCompositeRequest(LwM2mClient client, RpcWriteCompositeRequest rpcWriteCompositeRequest, DownlinkRequestCallback callback) { - ContentFormat contentFormat = ContentFormat.SENML_JSON; + public void sendWriteCompositeRequest(LwM2mClient client, RpcWriteCompositeRequest rpcWriteCompositeRequest, + DownlinkRequestCallback callback, ContentFormat contentFormatComposite) { try { - WriteCompositeRequest downlink = new WriteCompositeRequest(contentFormat, rpcWriteCompositeRequest.getNodes()); + WriteCompositeRequest downlink = new WriteCompositeRequest(contentFormatComposite, rpcWriteCompositeRequest.getNodes()); //TODO: replace config.getTimeout(); - sendWriteCompositeRequest(client, downlink, config.getTimeout(), callback); + sendWriteCompositeRequest(client, downlink, this.config.getTimeout(), callback); + } catch (InvalidRequestException e) { + callback.onValidationError(rpcWriteCompositeRequest.toString(), e.getMessage()); } catch (Exception e) { callback.onError(toString(rpcWriteCompositeRequest), e); } @@ -261,38 +327,90 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im @Override public void sendWriteUpdateRequest(LwM2mClient client, TbLwM2MWriteUpdateRequest request, DownlinkRequestCallback callback) { + try { + validateVersionedId(client, request); + WriteRequest downlink = null; + LwM2mPath resultIds = new LwM2mPath(request.getObjectId()); + ContentFormat contentFormat = getWriteRequestContentFormat(client, request, this.config.getModelProvider()); + if (resultIds.isObjectInstance()) { + /* + * params = "{\"id\":0,\"value\":[{\"id\":14,\"value\":\"+5\"},{\"id\":15,\"value\":\"+9\"}]}" + * int rscId = resultIds.getObjectInstanceId(); + * contentFormat – Format of the payload (TLV or JSON). + */ + Collection resources = client.getNewResourcesForInstance(request.getVersionedId(), request.getValue(), this.config.getModelProvider(), this.converter); + if (resources.size() > 0) { + downlink = new WriteRequest(WriteRequest.Mode.UPDATE, contentFormat, resultIds.getObjectId(), resultIds.getObjectInstanceId(), resources); + } else { + callback.onValidationError(toString(request), "No resources to update!"); + } + } else if (resultIds.isResource()) { + ResourceModel resourceModelWrite = client.getResourceModel(request.getVersionedId(), this.config.getModelProvider()); + if (resourceModelWrite.multiple) { + if (request.getValue() instanceof Map && ((Map) request.getValue()).size() > 0) { + Map value = convertMultiResourceValuesFromRpcBody((LinkedHashMap) request.getValue(), resourceModelWrite.type, request.getObjectId()); + downlink = new WriteRequest(WriteRequest.Mode.UPDATE, contentFormat, resultIds.getObjectId(), resultIds.getObjectInstanceId(), resultIds.getResourceId(), + value, resourceModelWrite.type); + } else { + callback.onValidationError(toString(request), "Resource value is bad. Format: " + request.getValue().getClass().getSimpleName() + ". Value of Multi-Instance Resource must be in Json format!"); + } + } + } + if (downlink != null) { + sendSimpleRequest(client, downlink, request.getTimeout(), callback); + } else { + callback.onValidationError(toString(request), "Resource " + request.getVersionedId() + ". This operation can only be used for ObjectInstance or Multi-Instance Resource !"); + } + } catch (Exception e) { + callback.onValidationError(toString(request), e.getMessage()); + } + } + + public void sendCreateRequest(LwM2mClient client, TbLwM2MCreateRequest request, DownlinkRequestCallback callback) { + validateVersionedId(client, request); + CreateRequest downlink = null; LwM2mPath resultIds = new LwM2mPath(request.getObjectId()); - if (resultIds.isResource()) { - /* - * send request: path = '/3/0' node == wM2mObjectInstance - * with params == "\"resources\": {15: resource:{id:15. value:'+01'...}} - **/ - Collection resources = client.getNewResourceForInstance(request.getVersionedId(), request.getValue(), this.config.getModelProvider(), this.converter); - ResourceModel resourceModelWrite = client.getResourceModel(request.getVersionedId(), this.config.getModelProvider()); - ContentFormat contentFormat = request.getObjectContentFormat() != null ? request.getObjectContentFormat() : convertResourceModelTypeToContentFormat(client, resourceModelWrite.type); - WriteRequest downlink = new WriteRequest(WriteRequest.Mode.UPDATE, contentFormat, resultIds.getObjectId(), - resultIds.getObjectInstanceId(), resources); - sendSimpleRequest(client, downlink, request.getTimeout(), callback); - } else if (resultIds.isObjectInstance()) { - /* - * params = "{\"id\":0,\"resources\":[{\"id\":14,\"value\":\"+5\"},{\"id\":15,\"value\":\"+9\"}]}" - * int rscId = resultIds.getObjectInstanceId(); - * contentFormat – Format of the payload (TLV or JSON). - */ - Collection resources = client.getNewResourcesForInstance(request.getVersionedId(), request.getValue(), this.config.getModelProvider(), this.converter); - if (resources.size() > 0) { - ContentFormat contentFormat = request.getObjectContentFormat() != null ? request.getObjectContentFormat() : ContentFormat.DEFAULT; - WriteRequest downlink = new WriteRequest(WriteRequest.Mode.UPDATE, contentFormat, resultIds.getObjectId(), resultIds.getObjectInstanceId(), resources); + ObjectModel objectModel = client.getObjectModel(request.getObjectId(), this.config.getModelProvider()); + // POST /{Object ID}/{Object Instance ID} && Resources is Mandatory + if (objectModel.multiple) { + // LwM2M CBOR, SenML CBOR, SenML JSON, or TLV (see [LwM2M-CORE]) + ContentFormat contentFormat = getWriteRequestContentFormat(client, request, this.config.getModelProvider()); + if (resultIds.isObject() || resultIds.isObjectInstance()) { + Collection resources; + if (resultIds.isObject()) { +// contentFormat = ContentFormat.TLV; + if (request.getValue() != null) { + resources = client.getNewResourcesForInstance(request.getVersionedId(), request.getValue(), this.config.getModelProvider(), this.converter); + downlink = new CreateRequest(contentFormat, resultIds.getObjectId(), resources); + } else if (request.getNodes() != null && request.getNodes().size() > 0) { + Set instances = ConcurrentHashMap.newKeySet(); + request.getNodes().forEach((key, value) -> { + Collection resourcesForInstance = client.getNewResourcesForInstance(request.getVersionedId(), value, this.config.getModelProvider(), this.converter); + LwM2mObjectInstance instance = new LwM2mObjectInstance(Integer.parseInt(key), resourcesForInstance); + instances.add(instance); + }); + LwM2mObjectInstance[] instanceArrays = instances.toArray(new LwM2mObjectInstance[instances.size()]); + downlink = new CreateRequest(contentFormat, resultIds.getObjectId(), instanceArrays); + } + + } else { + resources = client.getNewResourcesForInstance(request.getVersionedId(), request.getValue(), this.config.getModelProvider(), this.converter); + LwM2mObjectInstance instance = new LwM2mObjectInstance(resultIds.getObjectInstanceId(), resources); + downlink = new CreateRequest(contentFormat, resultIds.getObjectId(), instance); + } + } + if (downlink != null) { sendSimpleRequest(client, downlink, request.getTimeout(), callback); } else { - callback.onValidationError(toString(request), "No resources to update!"); + callback.onValidationError(toString(request), "Path " + request.getVersionedId() + + ". This operation can only be used for created new ObjectInstance !"); } } else { - callback.onValidationError(toString(request), "Update of the root level object is not supported yet!"); + throw new IllegalArgumentException("Path " + request.getVersionedId() + + ". Object must be Multiple !"); } } - private , T extends LwM2mResponse> void sendSimpleRequest(LwM2mClient client, R request, long timeoutInMs, DownlinkRequestCallback callback) { sendRequest(client, request, timeoutInMs, callback, r -> request.getPath().toString()); } @@ -301,6 +419,7 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im sendRequest(client, request, timeoutInMs, callback, r -> request.getPaths().toString()); } + private , T extends LwM2mResponse> void sendRequest(LwM2mClient client, R request, long timeoutInMs, DownlinkRequestCallback callback, Function pathToStringFunction) { if (!clientContext.isDownlinkAllowed(client)) { log.trace("[{}] ignore downlink request cause client is sleeping.", client.getEndpoint()); @@ -319,7 +438,7 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im clientContext.awake(client); } }); - },e -> handleDownlinkError(client, request, callback, e)); + }, e -> handleDownlinkError(client, request, callback, e)); } catch (Exception e) { handleDownlinkError(client, request, callback, e); } @@ -366,6 +485,7 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im }); } + private WriteRequest getWriteRequestSingleResource(ResourceModel.Type type, ContentFormat contentFormat, int objectId, int instanceId, int resourceId, Object value) { switch (type) { case STRING: // String @@ -395,24 +515,6 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im } } - private void validateVersionedId(LwM2mClient client, HasVersionedId request) { - client.isValidObjectVersion(request.getVersionedId()); - if (request.getObjectId() == null) { - throw new IllegalArgumentException("Specified object id is null!"); - } - } - - private void validateVersionedIds(LwM2mClient client, HasVersionedIds request) { - for (String versionedId : request.getVersionedIds()) { - client.isValidObjectVersion(versionedId); - } - for (String objectId : request.getObjectIds()) { - if (objectId == null) { - throw new IllegalArgumentException("Specified object id is null!"); - } - } - } - private static void addAttribute(List attributes, String attributeName, T value) { addAttribute(attributes, attributeName, value, null, null); } @@ -427,52 +529,91 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im } } - private static ContentFormat convertResourceModelTypeToContentFormat(LwM2mClient client, ResourceModel.Type type) { - switch (type) { - case BOOLEAN: - case STRING: - case TIME: - case INTEGER: - case FLOAT: - return client.getDefaultContentFormat(); - case OPAQUE: - return ContentFormat.OPAQUE; - case OBJLNK: - return ContentFormat.LINK; - default: + private static ContentFormat getReadRequestContentFormat(LwM2mClient client, T request, LwM2mModelProvider modelProvider) { + if (request.getRequestContentFormat().isPresent()) { + return request.getRequestContentFormat().get(); + } else { + return getRequestContentFormat(client, request.getVersionedId(), modelProvider); } - throw new CodecException("Invalid ResourceModel_Type for %s ContentFormat.", type); } - private static ContentFormat getRequestContentFormat(LwM2mClient client, HasContentFormat request, LwM2mModelProvider modelProvider) { - if (request.getRequestContentFormat() != null) { - return request.getRequestContentFormat(); + private static ContentFormat getWriteRequestContentFormat(LwM2mClient client, TbLwM2MDownlinkRequest request, LwM2mModelProvider modelProvider) { + if (request instanceof TbLwM2MWriteReplaceRequest && ((TbLwM2MWriteReplaceRequest) request).getContentFormat() != null) { + return ((TbLwM2MWriteReplaceRequest) request).getContentFormat(); + } else if (request instanceof TbLwM2MWriteUpdateRequest && ((TbLwM2MWriteUpdateRequest) request).getObjectContentFormat() != null) { + return ((TbLwM2MWriteUpdateRequest) request).getObjectContentFormat(); } else { String versionedId = null; - if (request instanceof TbLwM2MReadRequest) { - versionedId = ((TbLwM2MReadRequest) request).getVersionedId(); - } else if (request instanceof TbLwM2MObserveRequest) { - versionedId = ((TbLwM2MObserveRequest) request).getVersionedId(); + if (request instanceof TbLwM2MWriteReplaceRequest) { + versionedId = ((TbLwM2MWriteReplaceRequest) request).getVersionedId(); + } else if (request instanceof TbLwM2MWriteUpdateRequest) { + versionedId = ((TbLwM2MWriteUpdateRequest) request).getVersionedId(); + } else if (request instanceof TbLwM2MCreateRequest) { + versionedId = ((TbLwM2MCreateRequest) request).getVersionedId(); + } + return getRequestContentFormat(client, versionedId, modelProvider); + } + } + + private static ContentFormat getRequestContentFormat(LwM2mClient client, String versionedId, LwM2mModelProvider modelProvider) { + LwM2mPath pathIds = new LwM2mPath(fromVersionedIdToObjectId(versionedId)); + if (pathIds.isResourceInstance()) { + ResourceModel resourceModel = client.getResourceModel(versionedId, modelProvider); + if (OBJLNK.equals(resourceModel.type)) { + return ContentFormat.LINK; + } else if (OPAQUE.equals(resourceModel.type)) { + return ContentFormat.OPAQUE; + } else { + return findFirst(client.getClientSupportContentFormats(), client.getDefaultContentFormat(), ContentFormat.CBOR, ContentFormat.SENML_CBOR, ContentFormat.SENML_JSON); + } + } else if (pathIds.isResource()) { + ResourceModel resourceModel = client.getResourceModel(versionedId, modelProvider); + if (!resourceModel.multiple) { + if (OBJLNK.equals(resourceModel.type)) { + return ContentFormat.LINK; + } else if (OPAQUE.equals(resourceModel.type)) { + return ContentFormat.OPAQUE; + } else { + return findFirst(client.getClientSupportContentFormats(), client.getDefaultContentFormat(), ContentFormat.CBOR, ContentFormat.SENML_CBOR, ContentFormat.SENML_JSON); + } + } else { + return getContentFormatForComplex(client); } - String id = fromVersionedIdToObjectId(versionedId); - if (id != null && new LwM2mPath(id).isResource() && !client.isResourceMultiInstances(versionedId, modelProvider)) { - return client.getDefaultContentFormat(); + } else { + return getContentFormatForComplex(client); + } + } + + private static ContentFormat getContentFormatForComplex(LwM2mClient client) { + if (LwM2m.Version.V1_0.equals(client.getRegistration().getLwM2mVersion())) { + return ContentFormat.TLV; + } else if (LwM2m.Version.V1_1.equals(client.getRegistration().getLwM2mVersion())) { + ContentFormat result = findFirst(client.getClientSupportContentFormats(), null, ContentFormat.SENML_CBOR, ContentFormat.SENML_JSON, ContentFormat.TLV, ContentFormat.JSON); + if (result != null) { + return result; } else { - return ContentFormat.DEFAULT; + throw new RuntimeException("The client does not support any of SenML CBOR, SenML JSON, TLV or JSON formats. Can't send complex requests. Try using singe-instance requests."); + } + } else { + throw new RuntimeException("The version " + client.getRegistration().getLwM2mVersion() + " is not supported!"); + } + } + + private static ContentFormat findFirst(Set supported, ContentFormat defaultValue, ContentFormat... desiredFormats) { + for (ContentFormat contentFormat : desiredFormats) { + if (supported.contains(contentFormat)) { + return contentFormat; } } + return defaultValue; } private String toString(R request) { try { - try { - return JacksonUtil.toString(request); - } catch (Exception e) { - return request.toString(); - } + return request != null ? request.toString() : ""; } catch (Exception e) { - log.warn("Failed to convert request to string", e); - return request != null ? request.getClass().getSimpleName() : ""; + log.trace("Failed to convert request to string", e); + return request.getClass().getSimpleName(); } } } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/HasContentFormat.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/HasContentFormat.java index f2618224e7..833ff76cab 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/HasContentFormat.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/HasContentFormat.java @@ -17,9 +17,11 @@ package org.thingsboard.server.transport.lwm2m.server.downlink; import org.eclipse.leshan.core.request.ContentFormat; +import java.util.Optional; + public interface HasContentFormat { - ContentFormat getRequestContentFormat(); + Optional getRequestContentFormat(); default ContentFormat getResponseContentFormat() { return null; diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/LwM2mDownlinkMsgHandler.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/LwM2mDownlinkMsgHandler.java index 871a59a63b..a4537af703 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/LwM2mDownlinkMsgHandler.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/LwM2mDownlinkMsgHandler.java @@ -16,6 +16,8 @@ package org.thingsboard.server.transport.lwm2m.server.downlink; import org.eclipse.leshan.core.Link; +import org.eclipse.leshan.core.request.ContentFormat; +import org.eclipse.leshan.core.request.CreateRequest; import org.eclipse.leshan.core.request.DeleteRequest; import org.eclipse.leshan.core.request.DiscoverRequest; import org.eclipse.leshan.core.request.ExecuteRequest; @@ -25,6 +27,7 @@ import org.eclipse.leshan.core.request.ReadRequest; import org.eclipse.leshan.core.request.WriteAttributesRequest; import org.eclipse.leshan.core.request.WriteCompositeRequest; import org.eclipse.leshan.core.request.WriteRequest; +import org.eclipse.leshan.core.response.CreateResponse; import org.eclipse.leshan.core.response.DeleteResponse; import org.eclipse.leshan.core.response.DiscoverResponse; import org.eclipse.leshan.core.response.ExecuteResponse; @@ -45,7 +48,7 @@ public interface LwM2mDownlinkMsgHandler { void sendReadRequest(LwM2mClient client, TbLwM2MReadRequest request, DownlinkRequestCallback callback); - void sendReadCompositeRequest(LwM2mClient client, TbLwM2MReadCompositeRequest request, DownlinkRequestCallback callback); + void sendReadCompositeRequest(LwM2mClient client, TbLwM2MReadCompositeRequest request, DownlinkRequestCallback callback, ContentFormat contentFormatComposite); void sendObserveRequest(LwM2mClient client, TbLwM2MObserveRequest request, DownlinkRequestCallback callback); @@ -67,9 +70,10 @@ public interface LwM2mDownlinkMsgHandler { void sendWriteReplaceRequest(LwM2mClient client, TbLwM2MWriteReplaceRequest request, DownlinkRequestCallback callback); - void sendWriteCompositeRequest(LwM2mClient client, RpcWriteCompositeRequest nodes, DownlinkRequestCallback callback); + void sendWriteCompositeRequest(LwM2mClient client, RpcWriteCompositeRequest nodes, DownlinkRequestCallback callback, ContentFormat contentFormatComposite); void sendWriteUpdateRequest(LwM2mClient client, TbLwM2MWriteUpdateRequest request, DownlinkRequestCallback callback); + void sendCreateRequest(LwM2mClient client, TbLwM2MCreateRequest request, DownlinkRequestCallback callback); } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MCancelObserveCallback.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MCancelObserveCallback.java index 311be03462..b663215078 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MCancelObserveCallback.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MCancelObserveCallback.java @@ -16,12 +16,10 @@ package org.thingsboard.server.transport.lwm2m.server.downlink; import lombok.extern.slf4j.Slf4j; -import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService; -import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler; import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; +import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LWM2M_INFO; -import static org.thingsboard.server.transport.lwm2m.server.LwM2mOperationType.OBSERVE_CANCEL; @Slf4j public class TbLwM2MCancelObserveCallback extends AbstractTbLwM2MRequestCallback { diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MCreateRequest.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MCreateRequest.java new file mode 100644 index 0000000000..9eed9381a8 --- /dev/null +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MCreateRequest.java @@ -0,0 +1,50 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.transport.lwm2m.server.downlink; + +import lombok.Builder; +import lombok.Getter; +import org.eclipse.leshan.core.request.ContentFormat; +import org.eclipse.leshan.core.response.CreateResponse; +import org.thingsboard.server.transport.lwm2m.server.LwM2mOperationType; + +import java.util.Map; + +public class TbLwM2MCreateRequest extends AbstractTbLwM2MTargetedDownlinkRequest { + + @Getter + private final Object value; + @Getter + private final ContentFormat objectContentFormat; + @Getter + private final Map nodes;; + + @Builder + private TbLwM2MCreateRequest(String versionedId, long timeout, Object value, ContentFormat objectContentFormat, Map nodes) { + super(versionedId, timeout); + this.value = value; + this.objectContentFormat = objectContentFormat; + this.nodes = nodes; + } + + @Override + public LwM2mOperationType getType() { + return LwM2mOperationType.CREATE; + } + + + +} diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MCreateResponseCallback.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MCreateResponseCallback.java new file mode 100644 index 0000000000..316bbd4636 --- /dev/null +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MCreateResponseCallback.java @@ -0,0 +1,36 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.transport.lwm2m.server.downlink; + +import org.eclipse.leshan.core.request.CreateRequest; +import org.eclipse.leshan.core.response.CreateResponse; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; +import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService; +import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler; + +public class TbLwM2MCreateResponseCallback extends TbLwM2MUplinkTargetedCallback { + + public TbLwM2MCreateResponseCallback(LwM2mUplinkMsgHandler handler, LwM2MTelemetryLogService logService, LwM2mClient client, String targetId) { + super(handler, logService, client, targetId); + } + + @Override + public void onSuccess(CreateRequest request, CreateResponse response) { + super.onSuccess(request, response); + handler.onCreateResponseOk(client, versionedId, request); + } + +} diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MDeleteCallback.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MDeleteCallback.java index 4c0a758572..2b3c544dae 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MDeleteCallback.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MDeleteCallback.java @@ -19,7 +19,6 @@ import org.eclipse.leshan.core.request.DeleteRequest; import org.eclipse.leshan.core.response.DeleteResponse; import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService; -import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler; public class TbLwM2MDeleteCallback extends TbLwM2MTargetedCallback { diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MDiscoverCallback.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MDiscoverCallback.java index 41172f0599..cc855fd3a8 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MDiscoverCallback.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MDiscoverCallback.java @@ -17,9 +17,8 @@ package org.thingsboard.server.transport.lwm2m.server.downlink; import org.eclipse.leshan.core.request.DiscoverRequest; import org.eclipse.leshan.core.response.DiscoverResponse; -import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService; -import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler; import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; +import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService; public class TbLwM2MDiscoverCallback extends TbLwM2MTargetedCallback { diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MExecuteCallback.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MExecuteCallback.java index 992cf6d616..9315e9ded6 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MExecuteCallback.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MExecuteCallback.java @@ -17,9 +17,8 @@ package org.thingsboard.server.transport.lwm2m.server.downlink; import org.eclipse.leshan.core.request.ExecuteRequest; import org.eclipse.leshan.core.response.ExecuteResponse; -import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService; -import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler; import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; +import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService; public class TbLwM2MExecuteCallback extends TbLwM2MTargetedCallback { diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MObserveCallback.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MObserveCallback.java index dde49c870d..97be9fbff3 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MObserveCallback.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MObserveCallback.java @@ -18,9 +18,9 @@ package org.thingsboard.server.transport.lwm2m.server.downlink; import lombok.extern.slf4j.Slf4j; import org.eclipse.leshan.core.request.ObserveRequest; import org.eclipse.leshan.core.response.ObserveResponse; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService; import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler; -import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; @Slf4j public class TbLwM2MObserveCallback extends TbLwM2MUplinkTargetedCallback { diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MObserveRequest.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MObserveRequest.java index 0d13b4a1ff..849d0dd2bf 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MObserveRequest.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MObserveRequest.java @@ -16,20 +16,20 @@ package org.thingsboard.server.transport.lwm2m.server.downlink; import lombok.Builder; -import lombok.Getter; import org.eclipse.leshan.core.request.ContentFormat; import org.eclipse.leshan.core.response.ObserveResponse; import org.thingsboard.server.transport.lwm2m.server.LwM2mOperationType; +import java.util.Optional; + public class TbLwM2MObserveRequest extends AbstractTbLwM2MTargetedDownlinkRequest implements HasContentFormat { - @Getter - private final ContentFormat requestContentFormat; + private final Optional requestContentFormat; @Builder private TbLwM2MObserveRequest(String versionedId, long timeout, ContentFormat requestContentFormat) { super(versionedId, timeout); - this.requestContentFormat = requestContentFormat; + this.requestContentFormat = Optional.ofNullable(requestContentFormat); } @Override @@ -38,5 +38,8 @@ public class TbLwM2MObserveRequest extends AbstractTbLwM2MTargetedDownlinkReques } - + @Override + public Optional getRequestContentFormat() { + return this.requestContentFormat; + } } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MReadRequest.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MReadRequest.java index 6f388237c2..39c4b0fb4b 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MReadRequest.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MReadRequest.java @@ -16,20 +16,20 @@ package org.thingsboard.server.transport.lwm2m.server.downlink; import lombok.Builder; -import lombok.Getter; import org.eclipse.leshan.core.request.ContentFormat; import org.eclipse.leshan.core.response.ReadResponse; import org.thingsboard.server.transport.lwm2m.server.LwM2mOperationType; +import java.util.Optional; + public class TbLwM2MReadRequest extends AbstractTbLwM2MTargetedDownlinkRequest implements HasContentFormat { - @Getter - private final ContentFormat requestContentFormat; + private final Optional requestContentFormat; @Builder private TbLwM2MReadRequest(String versionedId, long timeout, ContentFormat requestContentFormat) { super(versionedId, timeout); - this.requestContentFormat = requestContentFormat; + this.requestContentFormat = Optional.ofNullable(requestContentFormat); } @Override @@ -38,5 +38,8 @@ public class TbLwM2MReadRequest extends AbstractTbLwM2MTargetedDownlinkRequest getRequestContentFormat() { + return this.requestContentFormat; + } } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MTargetedCallback.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MTargetedCallback.java index 6b013ef9b5..92992d299c 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MTargetedCallback.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MTargetedCallback.java @@ -16,6 +16,9 @@ package org.thingsboard.server.transport.lwm2m.server.downlink; import lombok.extern.slf4j.Slf4j; +import org.eclipse.leshan.core.node.LwM2mSingleResource; +import org.eclipse.leshan.core.response.ReadResponse; +import org.eclipse.leshan.core.util.Hex; import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService; @@ -45,8 +48,28 @@ public abstract class TbLwM2MTargetedCallback extends AbstractTbLwM2MReque public void onSuccess(R request, T response) { //TODO convert camelCase to "camel case" using .split("(? 0) { + int len = ((byte[])((LwM2mSingleResource) response.getContent()).getValue()).length; + String valueReplace = len + "Bytes"; + String valueStr = Hex.encodeHexString((byte[]) (((LwM2mSingleResource) response.getContent()).getValue())); + return response.toString().replace(valueReplace, valueStr); + } + } + return response.toString(); + } + else { + return response.toString(); + } + } } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MWriteAttributesCallback.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MWriteAttributesCallback.java index e346ad965a..3e4847ce1e 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MWriteAttributesCallback.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MWriteAttributesCallback.java @@ -19,7 +19,6 @@ import org.eclipse.leshan.core.request.WriteAttributesRequest; import org.eclipse.leshan.core.response.WriteAttributesResponse; import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService; -import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler; public class TbLwM2MWriteAttributesCallback extends TbLwM2MTargetedCallback { diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/composite/TbLwM2MReadCompositeRequest.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/composite/TbLwM2MReadCompositeRequest.java index 43b55f371f..086a3d7049 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/composite/TbLwM2MReadCompositeRequest.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/composite/TbLwM2MReadCompositeRequest.java @@ -22,10 +22,12 @@ import org.eclipse.leshan.core.response.ReadCompositeResponse; import org.thingsboard.server.transport.lwm2m.server.LwM2mOperationType; import org.thingsboard.server.transport.lwm2m.server.downlink.HasContentFormat; +import java.util.Optional; + public class TbLwM2MReadCompositeRequest extends AbstractTbLwM2MTargetedDownlinkCompositeRequest implements HasContentFormat { - @Getter - private final ContentFormat requestContentFormat; + + private final Optional requestContentFormatOpt; @Getter private final ContentFormat responseContentFormat; @@ -33,7 +35,7 @@ public class TbLwM2MReadCompositeRequest extends AbstractTbLwM2MTargetedDownlink @Builder private TbLwM2MReadCompositeRequest(String [] versionedIds, long timeout, ContentFormat requestContentFormat, ContentFormat responseContentFormat) { super(versionedIds, timeout); - this.requestContentFormat = requestContentFormat; + this.requestContentFormatOpt = Optional.ofNullable(requestContentFormat); this.responseContentFormat = responseContentFormat; } @@ -41,4 +43,9 @@ public class TbLwM2MReadCompositeRequest extends AbstractTbLwM2MTargetedDownlink public LwM2mOperationType getType() { return LwM2mOperationType.READ_COMPOSITE; } + + @Override + public Optional getRequestContentFormat() { + return this.requestContentFormatOpt; + } } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/log/DefaultLwM2MTelemetryLogService.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/log/DefaultLwM2MTelemetryLogService.java index eb5dae8f4a..4e59eb5b44 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/log/DefaultLwM2MTelemetryLogService.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/log/DefaultLwM2MTelemetryLogService.java @@ -21,7 +21,6 @@ import org.springframework.stereotype.Service; import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportServerHelper; import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; -import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientContext; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LWM2M_TELEMETRY; diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/DefaultLwM2MOtaUpdateService.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/DefaultLwM2MOtaUpdateService.java index 2776b64fef..8335057caa 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/DefaultLwM2MOtaUpdateService.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/DefaultLwM2MOtaUpdateService.java @@ -180,10 +180,9 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl } var clientSettings = clientContext.getProfile(client.getProfileId()).getClientLwM2mSettings(); - onFirmwareStrategyUpdate(client, clientSettings); onCurrentSoftwareStrategyUpdate(client, clientSettings); - + if (!attributesToFetch.isEmpty()) { var future = attributesService.getSharedAttributes(client, attributesToFetch); DonAsynchron.withCallback(future, attrs -> { diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/software/LwM2MClientSwOtaInfo.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/software/LwM2MClientSwOtaInfo.java index 547d713251..e4b8336f92 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/software/LwM2MClientSwOtaInfo.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/software/LwM2MClientSwOtaInfo.java @@ -20,12 +20,8 @@ import lombok.Data; import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; import lombok.ToString; -import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.data.ota.OtaPackageType; import org.thingsboard.server.transport.lwm2m.server.ota.LwM2MClientOtaInfo; -import org.thingsboard.server.transport.lwm2m.server.ota.firmware.FirmwareUpdateResult; -import org.thingsboard.server.transport.lwm2m.server.ota.firmware.FirmwareUpdateState; -import org.thingsboard.server.transport.lwm2m.server.ota.firmware.LwM2MFirmwareUpdateStrategy; @Data @EqualsAndHashCode(callSuper = true) diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/DefaultLwM2MRpcRequestHandler.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/DefaultLwM2MRpcRequestHandler.java index 8135b5aae0..285f9796f9 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/DefaultLwM2MRpcRequestHandler.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/DefaultLwM2MRpcRequestHandler.java @@ -18,6 +18,9 @@ package org.thingsboard.server.transport.lwm2m.server.rpc; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.eclipse.leshan.core.ResponseCode; +import org.eclipse.leshan.core.model.ResourceModel; +import org.eclipse.leshan.core.node.LwM2mPath; +import org.eclipse.leshan.core.request.ContentFormat; import org.springframework.stereotype.Service; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.StringUtils; @@ -35,6 +38,8 @@ import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MCancelAllOb import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MCancelAllRequest; import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MCancelObserveCallback; import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MCancelObserveRequest; +import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MCreateRequest; +import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MCreateResponseCallback; import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MDeleteCallback; import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MDeleteRequest; import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MDiscoverAllRequest; @@ -61,11 +66,14 @@ import org.thingsboard.server.transport.lwm2m.server.rpc.composite.RpcReadRespon import org.thingsboard.server.transport.lwm2m.server.rpc.composite.RpcWriteCompositeRequest; import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler; +import java.util.HashSet; +import java.util.LinkedHashMap; import java.util.Map; import java.util.Set; import java.util.UUID; -import java.util.concurrent.ConcurrentHashMap; -import java.util.stream.Collectors; + +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertMultiResourceValuesFromRpcBody; +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.fromVersionedIdToObjectId; @Slf4j @Service @@ -95,7 +103,12 @@ public class DefaultLwM2MRpcRequestHandler implements LwM2MRpcRequestHandler { } try { if (operationType.isHasObjectId()) { - String objectId = getIdFromParameters(client, rpcRequest); + LwM2MRpcRequestHeader header = JacksonUtil.fromString(rpcRequest.getParams(), LwM2MRpcRequestHeader.class); + String objectId = getIdFromParameters(client, header); + ContentFormat contentFormat = null; + if (StringUtils.isNotEmpty(header.getContentFormat())) { + contentFormat = ContentFormat.fromName(header.getContentFormat()); + } switch (operationType) { case READ: sendReadRequest(client, rpcRequest, objectId); @@ -124,17 +137,21 @@ public class DefaultLwM2MRpcRequestHandler implements LwM2MRpcRequestHandler { case WRITE_REPLACE: sendWriteReplaceRequest(client, rpcRequest, objectId); break; + case CREATE: + sendCreateRequest(client, rpcRequest, objectId); + break; default: throw new IllegalArgumentException("Unsupported operation: " + operationType.name()); } } else if (operationType.isComposite()) { - if (clientContext.isComposite(client)) { + ContentFormat contentFormatComposite = clientContext.getContentFormatComposite(client); + if (contentFormatComposite != null) { switch (operationType) { case READ_COMPOSITE: - sendReadCompositeRequest(client, rpcRequest); + sendReadCompositeRequest(client, rpcRequest, contentFormatComposite); break; case WRITE_COMPOSITE: - sendWriteCompositeRequest(client, rpcRequest); + sendWriteCompositeRequest(client, rpcRequest, contentFormatComposite); break; default: throw new IllegalArgumentException("Unsupported operation: " + operationType.name()); @@ -173,12 +190,12 @@ public class DefaultLwM2MRpcRequestHandler implements LwM2MRpcRequestHandler { downlinkHandler.sendReadRequest(client, request, rpcCallback); } - private void sendReadCompositeRequest(LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg) { + private void sendReadCompositeRequest(LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, ContentFormat contentFormatComposite) { String[] versionedIds = getIdsFromParameters(client, requestMsg); TbLwM2MReadCompositeRequest request = TbLwM2MReadCompositeRequest.builder().versionedIds(versionedIds).timeout(clientContext.getRequestTimeout(client)).build(); var mainCallback = new TbLwM2MReadCompositeCallback(uplinkHandler, logService, client, versionedIds); var rpcCallback = new RpcReadResponseCompositeCallback(transportService, client, requestMsg, mainCallback); - downlinkHandler.sendReadCompositeRequest(client, request, rpcCallback); + downlinkHandler.sendReadCompositeRequest(client, request, rpcCallback, contentFormatComposite); } private void sendObserveRequest(LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, String versionedId) { @@ -231,8 +248,25 @@ public class DefaultLwM2MRpcRequestHandler implements LwM2MRpcRequestHandler { downlinkHandler.sendWriteUpdateRequest(client, builder.build(), rpcCallback); } + private void sendCreateRequest(LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, String versionedId) { + RpcCreateRequest requestBody = JacksonUtil.fromString(requestMsg.getParams(), RpcCreateRequest.class); + TbLwM2MCreateRequest.TbLwM2MCreateRequestBuilder builder = TbLwM2MCreateRequest.builder().versionedId(versionedId); + builder.value(requestBody.getValue()).nodes(requestBody.getNodes()).timeout(clientContext.getRequestTimeout(client)); + var mainCallback = new TbLwM2MCreateResponseCallback(uplinkHandler, logService, client, versionedId); + var rpcCallback = new RpcCreateResponseCallback<>(transportService, client, requestMsg, mainCallback); + downlinkHandler.sendCreateRequest(client, builder.build(), rpcCallback); + } + private void sendWriteReplaceRequest(LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, String versionedId) { RpcWriteReplaceRequest requestBody = JacksonUtil.fromString(requestMsg.getParams(), RpcWriteReplaceRequest.class); + LwM2mPath path = new LwM2mPath(fromVersionedIdToObjectId(versionedId)); + if (path.isResource() && requestBody.getValue() instanceof LinkedHashMap) { + ResourceModel resourceModel = client.getResourceModel(versionedId, this.config.getModelProvider()); + if (resourceModel != null && resourceModel.multiple) { + Map value = convertMultiResourceValuesFromRpcBody((LinkedHashMap) requestBody.getValue(), resourceModel.type, versionedId); + requestBody.setValue(value); + } + } TbLwM2MWriteReplaceRequest request = TbLwM2MWriteReplaceRequest.builder().versionedId(versionedId) .value(requestBody.getValue()) .timeout(clientContext.getRequestTimeout(client)).build(); @@ -249,11 +283,39 @@ public class DefaultLwM2MRpcRequestHandler implements LwM2MRpcRequestHandler { * nodes.put("/1/0/2", 100); * nodes.put("/5/0/1", "coap://localhost:5685"); */ - private void sendWriteCompositeRequest(LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg) { + private void sendWriteCompositeRequest(LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, ContentFormat contentFormatComposite) { RpcWriteCompositeRequest rpcWriteCompositeRequest = JacksonUtil.fromString(requestMsg.getParams(), RpcWriteCompositeRequest.class); - var mainCallback = new TbLwM2MWriteResponseCompositeCallback(uplinkHandler, logService, client, null); - var rpcCallback = new RpcEmptyResponseCallback<>(transportService, client, requestMsg, mainCallback); - downlinkHandler.sendWriteCompositeRequest(client, rpcWriteCompositeRequest, rpcCallback); + Map validNodes = validateNodes(client, rpcWriteCompositeRequest.getNodes()); + if (validNodes.size() > 0) { + rpcWriteCompositeRequest.setNodes(validNodes); + var mainCallback = new TbLwM2MWriteResponseCompositeCallback(uplinkHandler, logService, client, null); + var rpcCallback = new RpcEmptyResponseCallback<>(transportService, client, requestMsg, mainCallback); + downlinkHandler.sendWriteCompositeRequest(client, rpcWriteCompositeRequest, rpcCallback, contentFormatComposite); + } else { + throw new IllegalArgumentException(String.format("nodes: %s is not validate value", rpcWriteCompositeRequest.getNodes().toString())); + } + } + + private Map validateNodes(LwM2mClient client, Map nodes) { + Map newNodes = new LinkedHashMap(); + nodes.forEach((key, value) -> { + String versionedId; + try { + // validate key.toString() + new LwM2mPath(fromVersionedIdToObjectId(key.toString())); + versionedId = key.toString(); + } catch (Exception e) { + versionedId = clientContext.getObjectIdByKeyNameFromProfile(client, key.toString(), true); + } + // validate value. Must be only primitive, not Json + if (value instanceof LinkedHashMap) { + throw new IllegalArgumentException(String.format("nodes: %s is not validate value. " + + "The WriteComposite operation is only used for SingleResources or/and ResourceInstance.", nodes.toString())); + } else { + newNodes.put(fromVersionedIdToObjectId(versionedId), value); + } + }); + return newNodes; } private void sendCancelObserveRequest(LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, String versionedId) { @@ -277,13 +339,12 @@ public class DefaultLwM2MRpcRequestHandler implements LwM2MRpcRequestHandler { downlinkHandler.sendCancelAllRequest(client, downlink, rpcCallback); } - private String getIdFromParameters(LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg rpcRequst) { - IdOrKeyRequest requestParams = JacksonUtil.fromString(rpcRequst.getParams(), IdOrKeyRequest.class); + private String getIdFromParameters(LwM2mClient client, LwM2MRpcRequestHeader header) { String targetId; - if (StringUtils.isNotEmpty(requestParams.getKey())) { - targetId = clientContext.getObjectIdByKeyNameFromProfile(client, requestParams.getKey()); - } else if (StringUtils.isNotEmpty(requestParams.getId())) { - targetId = requestParams.getId(); + if (StringUtils.isNotEmpty(header.getKey())) { + targetId = clientContext.getObjectIdByKeyNameFromProfile(client, header.getKey(), false); + } else if (StringUtils.isNotEmpty(header.getId())) { + targetId = header.getId(); } else { throw new IllegalArgumentException("Can't find 'key' or 'id' in the requestParams parameters!"); } @@ -293,14 +354,14 @@ public class DefaultLwM2MRpcRequestHandler implements LwM2MRpcRequestHandler { private String[] getIdsFromParameters(LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg rpcRequst) { RpcReadCompositeRequest requestParams = JacksonUtil.fromString(rpcRequst.getParams(), RpcReadCompositeRequest.class); if (requestParams.getKeys() != null && requestParams.getKeys().length > 0) { - Set targetIds = ConcurrentHashMap.newKeySet(); + Set targetIds = new HashSet<>(); for (String key : requestParams.getKeys()) { - String targetId = clientContext.getObjectIdByKeyNameFromProfile(client, key); + String targetId = clientContext.getObjectIdByKeyNameFromProfile(client, key, true); if (targetId != null) { targetIds.add(targetId); } } - return (String[]) targetIds.toArray(String[]::new); + return targetIds.toArray(String[]::new); } else if (requestParams.getIds() != null && requestParams.getIds().length > 0) { return requestParams.getIds(); } else { diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/IdOrKeyRequest.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/LwM2MRpcRequestHeader.java similarity index 92% rename from common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/IdOrKeyRequest.java rename to common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/LwM2MRpcRequestHeader.java index bef4fa37e8..996f248ea6 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/IdOrKeyRequest.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/LwM2MRpcRequestHeader.java @@ -20,8 +20,9 @@ import lombok.Data; @Data @JsonIgnoreProperties(ignoreUnknown = true) -public class IdOrKeyRequest { +public class LwM2MRpcRequestHeader { private String key; private String id; + private String contentFormat; } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcCancelAllObserveCallback.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcCancelAllObserveCallback.java index d2b7ffb834..c40d21cc4b 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcCancelAllObserveCallback.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcCancelAllObserveCallback.java @@ -21,7 +21,6 @@ import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; import org.thingsboard.server.transport.lwm2m.server.downlink.DownlinkRequestCallback; import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MCancelAllRequest; -import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MCancelObserveRequest; public class RpcCancelAllObserveCallback extends RpcDownlinkRequestCallbackProxy { diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcCancelObserveCallback.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcCancelObserveCallback.java index 1d1f1de230..f7971783ac 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcCancelObserveCallback.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcCancelObserveCallback.java @@ -16,19 +16,12 @@ package org.thingsboard.server.transport.lwm2m.server.rpc; import org.eclipse.leshan.core.ResponseCode; -import org.eclipse.leshan.core.node.LwM2mObject; -import org.eclipse.leshan.core.node.LwM2mObjectInstance; -import org.eclipse.leshan.core.node.LwM2mResource; -import org.eclipse.leshan.core.response.ReadResponse; -import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.transport.TransportService; import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; import org.thingsboard.server.transport.lwm2m.server.downlink.DownlinkRequestCallback; import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MCancelObserveRequest; -import java.util.Optional; - public class RpcCancelObserveCallback extends RpcDownlinkRequestCallbackProxy { public RpcCancelObserveCallback(TransportService transportService, LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, DownlinkRequestCallback callback) { diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MInMemoryBootstrapConfigurationAdapter.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcCreateRequest.java similarity index 59% rename from common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MInMemoryBootstrapConfigurationAdapter.java rename to common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcCreateRequest.java index 12325f8c22..febd0f8e40 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MInMemoryBootstrapConfigurationAdapter.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcCreateRequest.java @@ -13,15 +13,19 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.transport.lwm2m.bootstrap.secure; +package org.thingsboard.server.transport.lwm2m.server.rpc; -import org.eclipse.leshan.server.bootstrap.BootstrapConfigStore; -import org.eclipse.leshan.server.bootstrap.BootstrapConfigurationStoreAdapter; +import lombok.Data; +import lombok.EqualsAndHashCode; -public class LwM2MInMemoryBootstrapConfigurationAdapter extends BootstrapConfigurationStoreAdapter { +import java.util.Map; - public LwM2MInMemoryBootstrapConfigurationAdapter(BootstrapConfigStore store) { - super(store); - } +@Data +@EqualsAndHashCode(callSuper = true) +public class RpcCreateRequest extends LwM2MRpcRequestHeader { + + private Object value; + private String contentFormat; + private Map nodes; } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcCreateResponseCallback.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcCreateResponseCallback.java new file mode 100644 index 0000000000..f27d8e89d7 --- /dev/null +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcCreateResponseCallback.java @@ -0,0 +1,38 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.transport.lwm2m.server.rpc; + +import org.eclipse.leshan.core.request.LwM2mRequest; +import org.eclipse.leshan.core.response.CreateResponse; +import org.thingsboard.server.common.transport.TransportService; +import org.thingsboard.server.gen.transport.TransportProtos; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; +import org.thingsboard.server.transport.lwm2m.server.downlink.DownlinkRequestCallback; + +import java.util.Optional; + +public class RpcCreateResponseCallback, T extends CreateResponse> extends RpcLwM2MDownlinkCallback { + + public RpcCreateResponseCallback(TransportService transportService, LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, DownlinkRequestCallback callback) { + super(transportService, client, requestMsg, callback); + } + + @Override + protected Optional serializeSuccessfulResponse(T response) { + String value = response.getLocation() != null ? "location=" + response.getLocation() : ""; + return Optional.of(value); + } +} diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcDiscoverCallback.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcDiscoverCallback.java index ba8a634de0..936d177b2b 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcDiscoverCallback.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcDiscoverCallback.java @@ -16,14 +16,8 @@ package org.thingsboard.server.transport.lwm2m.server.rpc; import org.eclipse.leshan.core.Link; -import org.eclipse.leshan.core.node.LwM2mObject; -import org.eclipse.leshan.core.node.LwM2mObjectInstance; -import org.eclipse.leshan.core.node.LwM2mResource; import org.eclipse.leshan.core.request.DiscoverRequest; import org.eclipse.leshan.core.response.DiscoverResponse; -import org.eclipse.leshan.core.response.ReadResponse; -import org.jetbrains.annotations.NotNull; -import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.transport.TransportService; import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcLinkSetCallback.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcLinkSetCallback.java index 82d880c206..115b3df90d 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcLinkSetCallback.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcLinkSetCallback.java @@ -15,18 +15,13 @@ */ package org.thingsboard.server.transport.lwm2m.server.rpc; -import org.eclipse.leshan.core.Link; import org.eclipse.leshan.core.ResponseCode; -import org.eclipse.leshan.core.response.DiscoverResponse; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.transport.TransportService; import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; import org.thingsboard.server.transport.lwm2m.server.downlink.DownlinkRequestCallback; -import java.util.Optional; -import java.util.Set; - public class RpcLinkSetCallback extends RpcDownlinkRequestCallbackProxy { public RpcLinkSetCallback(TransportService transportService, LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, DownlinkRequestCallback callback) { diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcWriteAttributesRequest.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcWriteAttributesRequest.java index 67642078c6..bfe3b3cb90 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcWriteAttributesRequest.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcWriteAttributesRequest.java @@ -21,7 +21,7 @@ import org.thingsboard.server.common.data.device.data.lwm2m.ObjectAttributes; @Data @EqualsAndHashCode(callSuper = true) -public class RpcWriteAttributesRequest extends IdOrKeyRequest { +public class RpcWriteAttributesRequest extends LwM2MRpcRequestHeader { private ObjectAttributes attributes; diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcWriteReplaceRequest.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcWriteReplaceRequest.java index 55fb2b49aa..36ad1be345 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcWriteReplaceRequest.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcWriteReplaceRequest.java @@ -20,7 +20,7 @@ import lombok.EqualsAndHashCode; @Data @EqualsAndHashCode(callSuper = true) -public class RpcWriteReplaceRequest extends IdOrKeyRequest { +public class RpcWriteReplaceRequest extends LwM2MRpcRequestHeader { private Object value; diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcWriteUpdateRequest.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcWriteUpdateRequest.java index b56fea7eb6..a38e7fb6c1 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcWriteUpdateRequest.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcWriteUpdateRequest.java @@ -17,11 +17,10 @@ package org.thingsboard.server.transport.lwm2m.server.rpc; import lombok.Data; import lombok.EqualsAndHashCode; -import org.thingsboard.server.common.data.device.data.lwm2m.ObjectAttributes; @Data @EqualsAndHashCode(callSuper = true) -public class RpcWriteUpdateRequest extends IdOrKeyRequest { +public class RpcWriteUpdateRequest extends LwM2MRpcRequestHeader { private Object value; private String contentFormat; diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/composite/RpcReadCompositeRequest.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/composite/RpcReadCompositeRequest.java index ccd4767fee..f4620e2bcf 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/composite/RpcReadCompositeRequest.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/composite/RpcReadCompositeRequest.java @@ -22,7 +22,7 @@ import lombok.Data; @JsonIgnoreProperties(ignoreUnknown = true) public class RpcReadCompositeRequest { - private String [] keys; - private String [] ids; + private String[] keys; + private String[] ids; } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mRedisClientOtaInfoStore.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mRedisClientOtaInfoStore.java index fcc588473a..f3b6629e8d 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mRedisClientOtaInfoStore.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mRedisClientOtaInfoStore.java @@ -15,21 +15,13 @@ */ package org.thingsboard.server.transport.lwm2m.server.store; -import org.eclipse.leshan.server.security.NonUniqueSecurityInfoException; -import org.eclipse.leshan.server.security.SecurityInfo; -import org.jetbrains.annotations.Nullable; -import org.nustaq.serialization.FSTConfiguration; import org.springframework.data.redis.connection.RedisConnectionFactory; -import org.springframework.integration.redis.util.RedisLockRegistry; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.ota.OtaPackageType; -import org.thingsboard.server.transport.lwm2m.secure.TbLwM2MSecurityInfo; import org.thingsboard.server.transport.lwm2m.server.ota.LwM2MClientOtaInfo; import org.thingsboard.server.transport.lwm2m.server.ota.firmware.LwM2MClientFwOtaInfo; import org.thingsboard.server.transport.lwm2m.server.ota.software.LwM2MClientSwOtaInfo; -import java.util.concurrent.locks.Lock; - public class TbLwM2mRedisClientOtaInfoStore implements TbLwM2MClientOtaInfoStore { private static final String OTA_EP = "OTA#EP#"; diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mRedisRegistrationStore.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mRedisRegistrationStore.java index 1493123bc2..b8da8467e2 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mRedisRegistrationStore.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mRedisRegistrationStore.java @@ -726,7 +726,7 @@ public class TbLwM2mRedisRegistrationStore implements CaliforniumRegistrationSto public synchronized void start() { if (!started) { started = true; - cleanerTask = schedExecutor.scheduleAtFixedRate(new TbLwM2mRedisRegistrationStore.Cleaner(), cleanPeriod, cleanPeriod, TimeUnit.SECONDS); + cleanerTask = schedExecutor.scheduleAtFixedRate(new Cleaner(), cleanPeriod, cleanPeriod, TimeUnit.SECONDS); } } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/DefaultLwM2MUplinkMsgHandler.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/DefaultLwM2MUplinkMsgHandler.java index daa1152728..2c4f911db6 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/DefaultLwM2MUplinkMsgHandler.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/DefaultLwM2MUplinkMsgHandler.java @@ -23,15 +23,20 @@ import com.google.gson.reflect.TypeToken; import lombok.extern.slf4j.Slf4j; import org.eclipse.leshan.core.model.ObjectModel; import org.eclipse.leshan.core.model.ResourceModel; +import org.eclipse.leshan.core.node.LwM2mMultipleResource; import org.eclipse.leshan.core.node.LwM2mObject; import org.eclipse.leshan.core.node.LwM2mObjectInstance; import org.eclipse.leshan.core.node.LwM2mPath; import org.eclipse.leshan.core.node.LwM2mResource; +import org.eclipse.leshan.core.node.LwM2mResourceInstance; +import org.eclipse.leshan.core.node.LwM2mSingleResource; import org.eclipse.leshan.core.observation.Observation; +import org.eclipse.leshan.core.request.CreateRequest; import org.eclipse.leshan.core.request.ObserveRequest; import org.eclipse.leshan.core.request.ReadRequest; import org.eclipse.leshan.core.request.WriteCompositeRequest; import org.eclipse.leshan.core.request.WriteRequest; +import org.eclipse.leshan.core.request.WriteRequest.Mode; import org.eclipse.leshan.core.response.ObserveResponse; import org.eclipse.leshan.core.response.ReadCompositeResponse; import org.eclipse.leshan.core.response.ReadResponse; @@ -69,8 +74,6 @@ import org.thingsboard.server.transport.lwm2m.server.downlink.DownlinkRequestCal import org.thingsboard.server.transport.lwm2m.server.downlink.LwM2mDownlinkMsgHandler; import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MCancelObserveCallback; import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MCancelObserveRequest; -import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MDiscoverCallback; -import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MDiscoverRequest; import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MLatchCallback; import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MObserveCallback; import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MObserveRequest; @@ -217,7 +220,7 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl + registration.getLwM2mVersion() + " and modes: " + registration.getQueueMode() + ", " + registration.getBindingMode()); sessionManager.register(lwM2MClient.getSession()); this.initClientTelemetry(lwM2MClient); - this.initAttributes(lwM2MClient); + this.initAttributes(lwM2MClient, true); otaService.init(lwM2MClient); lwM2MClient.getRetryAttempts().set(0); } catch (LwM2MClientStateException stateException) { @@ -319,7 +322,7 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl this.updateObjectInstanceResourceValue(lwM2MClient, lwM2mObjectInstance, path); } else if (response.getContent() instanceof LwM2mResource) { LwM2mResource lwM2mResource = (LwM2mResource) response.getContent(); - this.updateResourcesValue(lwM2MClient, lwM2mResource, path); + this.updateResourcesValue(lwM2MClient, lwM2mResource, path, Mode.UPDATE); } } if (clientContext.awake(lwM2MClient)) { @@ -342,7 +345,7 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl } else if (v instanceof LwM2mObjectInstance) { this.updateObjectInstanceResourceValue(lwM2MClient, (LwM2mObjectInstance) v, k.toString()); } else if (v instanceof LwM2mResource) { - this.updateResourcesValue(lwM2MClient, (LwM2mResource) v, k.toString()); + this.updateResourcesValue(lwM2MClient, (LwM2mResource) v, k.toString(), Mode.UPDATE); } } }); @@ -482,11 +485,6 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl } } - private void sendDiscoverRequest(LwM2mClient lwM2MClient, String targetId) { - TbLwM2MDiscoverRequest request = TbLwM2MDiscoverRequest.builder().versionedId(targetId).timeout(clientContext.getRequestTimeout(lwM2MClient)).build(); - defaultLwM2MDownlinkMsgHandler.sendDiscoverRequest(lwM2MClient, request, new TbLwM2MDiscoverCallback(logService, lwM2MClient, targetId)); - } - private void sendReadRequest(LwM2mClient lwM2MClient, String versionedId) { sendReadRequest(lwM2MClient, versionedId, new TbLwM2MReadCallback(this, logService, lwM2MClient, versionedId)); } @@ -527,7 +525,7 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl LwM2mPath pathIds = new LwM2mPath(fromVersionedIdToObjectId(pathIdVer)); lwM2mObjectInstance.getResources().forEach((resourceId, resource) -> { String pathRez = pathIds.toString() + "/" + resourceId; - this.updateResourcesValue(client, resource, pathRez); + this.updateResourcesValue(client, resource, pathRez, Mode.UPDATE); }); } @@ -537,14 +535,14 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl * #2 Update new Resources (replace old Resource Value on new Resource Value) * #3 If fr_update -> UpdateFirmware * #4 updateAttrTelemetry - * - * @param lwM2MClient - Registration LwM2M Client + * @param lwM2MClient - Registration LwM2M Client * @param lwM2mResource - LwM2mSingleResource response.getContent() * @param path - resource + * @param mode - Replace, Update */ - private void updateResourcesValue(LwM2mClient lwM2MClient, LwM2mResource lwM2mResource, String path) { + private void updateResourcesValue(LwM2mClient lwM2MClient, LwM2mResource lwM2mResource, String path, Mode mode) { Registration registration = lwM2MClient.getRegistration(); - if (lwM2MClient.saveResourceValue(path, lwM2mResource, this.config.getModelProvider())) { + if (lwM2MClient.saveResourceValue(path, lwM2mResource, this.config.getModelProvider(), mode)) { if (path.equals(convertObjectIdToVersionedId(FW_NAME_ID, registration))) { otaService.onCurrentFirmwareNameUpdate(lwM2MClient, (String) lwM2mResource.getValue()); } else if (path.equals(convertObjectIdToVersionedId(FW_3_VER_ID, registration))) { @@ -570,7 +568,7 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl } this.updateAttrTelemetry(registration, Collections.singleton(path)); } else { - log.error("Fail update Resource [{}]", lwM2mResource); + log.error("Fail update path [{}] Resource [{}]", path, lwM2mResource); } } @@ -686,7 +684,7 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl Gson gson = new GsonBuilder().create(); ResourceModel.Type finalCurrentType = currentType; resourceValue.getInstances().forEach((k, v) -> { - Object val = this.converter.convertValue(v, finalCurrentType, expectedType, + Object val = this.converter.convertValue(v.getValue(), finalCurrentType, expectedType, new LwM2mPath(fromVersionedIdToObjectId(pathIdVer))); JsonElement element = gson.toJsonTree(val, val.getClass()); ((JsonObject) finalvalueKvProto).add(String.valueOf(k), element); @@ -714,21 +712,37 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl @Override public void onWriteResponseOk(LwM2mClient client, String path, WriteRequest request) { if (request.getNode() instanceof LwM2mResource) { - this.updateResourcesValue(client, ((LwM2mResource) request.getNode()), path); + this.updateResourcesValue(client, ((LwM2mResource) request.getNode()), path, request.isReplaceRequest() ? Mode.REPLACE : Mode.UPDATE); clientContext.update(client); } else if (request.getNode() instanceof LwM2mObjectInstance) { ((LwM2mObjectInstance) request.getNode()).getResources().forEach((resId, resource) -> { - this.updateResourcesValue(client, resource, path + "/" + resId); + this.updateResourcesValue(client, resource, path + "/" + resId, request.isReplaceRequest() ? Mode.REPLACE : Mode.UPDATE); }); clientContext.update(client); } } + @Override + public void onCreateResponseOk(LwM2mClient client, String path, CreateRequest request) { + if (request.getObjectInstances() != null && request.getObjectInstances().size() > 0) { + request.getObjectInstances().forEach( instance -> + instance.getResources() + ); +// this.updateResourcesValue(client, ((LwM2mResource) request.getNode()), path, request.isReplaceRequest() ? Mode.REPLACE : Mode.UPDATE); + clientContext.update(client); + } + } @Override public void onWriteCompositeResponseOk(LwM2mClient client, WriteCompositeRequest request) { log.trace("ReadCompositeResponse: [{}]", request.getNodes()); request.getNodes().forEach((k, v) -> { - this.updateResourcesValue(client, (LwM2mResource) v, k.toString()); + if (v instanceof LwM2mSingleResource) { + this.updateResourcesValue(client, (LwM2mResource) v, k.toString(), Mode.REPLACE); + } else { + LwM2mResourceInstance resourceInstance = (LwM2mResourceInstance) v; + LwM2mMultipleResource multipleResource = new LwM2mMultipleResource(v.getId(), resourceInstance.getType(), resourceInstance); + this.updateResourcesValue(client, multipleResource, k.toString(), Mode.REPLACE); + } }); } @@ -928,14 +942,14 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl * * @param lwM2MClient - LwM2M Client */ - public void initAttributes(LwM2mClient lwM2MClient) { + public void initAttributes(LwM2mClient lwM2MClient, boolean logFailedUpdateOfNonChangedValue) { Map keyNamesMap = this.getNamesFromProfileForSharedAttributes(lwM2MClient); if (!keyNamesMap.isEmpty()) { Set keysToFetch = new HashSet<>(keyNamesMap.values()); keysToFetch.removeAll(OtaPackageUtil.ALL_FW_ATTRIBUTE_KEYS); keysToFetch.removeAll(OtaPackageUtil.ALL_SW_ATTRIBUTE_KEYS); DonAsynchron.withCallback(attributesService.getSharedAttributes(lwM2MClient, keysToFetch), - v -> attributesService.onAttributesUpdate(lwM2MClient, v), + v -> attributesService.onAttributesUpdate(lwM2MClient, v, logFailedUpdateOfNonChangedValue), t -> log.error("[{}] Failed to get attributes", lwM2MClient.getEndpoint(), t), executor); } @@ -950,7 +964,7 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl return this.config; } - private void reportActivitySubscription(TransportProtos.SessionInfoProto sessionInfo) { + private void reportActivitySubscription(SessionInfoProto sessionInfo) { transportService.process(sessionInfo, TransportProtos.SubscriptionInfoProto.newBuilder() .setAttributeSubscription(true) .setRpcSubscription(true) diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/LwM2mUplinkMsgHandler.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/LwM2mUplinkMsgHandler.java index b6fdf56a33..0749ab34f6 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/LwM2mUplinkMsgHandler.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/LwM2mUplinkMsgHandler.java @@ -16,6 +16,7 @@ package org.thingsboard.server.transport.lwm2m.server.uplink; import org.eclipse.leshan.core.observation.Observation; +import org.eclipse.leshan.core.request.CreateRequest; import org.eclipse.leshan.core.request.WriteCompositeRequest; import org.eclipse.leshan.core.request.WriteRequest; import org.eclipse.leshan.core.response.ReadCompositeResponse; @@ -56,6 +57,8 @@ public interface LwM2mUplinkMsgHandler { void onWriteResponseOk(LwM2mClient client, String path, WriteRequest request); + void onCreateResponseOk(LwM2mClient client, String path, CreateRequest request); + void onWriteCompositeResponseOk(LwM2mClient client, WriteCompositeRequest request); void onToTransportUpdateCredentials(TransportProtos.SessionInfoProto sessionInfo, TransportProtos.ToTransportUpdateCredentialsProto updateCredentials); diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2mValueConverterImpl.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2mValueConverterImpl.java index 12a256ebed..0427caa3a6 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2mValueConverterImpl.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2mValueConverterImpl.java @@ -15,6 +15,7 @@ */ package org.thingsboard.server.transport.lwm2m.utils; +import com.google.api.client.util.Base64; import lombok.extern.slf4j.Slf4j; import org.eclipse.leshan.core.model.ResourceModel.Type; import org.eclipse.leshan.core.node.LwM2mPath; @@ -166,13 +167,16 @@ public class LwM2mValueConverterImpl implements LwM2mValueConverter { case OPAQUE: if (currentType == Type.STRING) { /** let's assume we received an hexadecimal string */ - log.debug("Trying to convert hexadecimal string [{}] to byte array", value); - // TODO check if we shouldn't instead assume that the string contains Base64 encoded data + log.debug("Trying to convert hexadecimal/base64 string [{}] to byte array", value); try { return Hex.decodeHex(((String)value).toCharArray()); } catch (IllegalArgumentException e) { - throw new CodecException("Unable to convert hexastring [%s] to byte array for resource %s", value, - resourcePath); + try { + return Base64.decodeBase64(((String) value).getBytes()); + } catch (IllegalArgumentException ea) { + throw new CodecException("Unable to convert hexastring or base64 [%s] to byte array for resource %s", + value, resourcePath); + } } } break; diff --git a/pom.xml b/pom.xml index 687b6031fd..e3d4664923 100755 --- a/pom.xml +++ b/pom.xml @@ -71,7 +71,7 @@ 2.12.1 2.2.6 2.6.1 - 2.0.0-M3 + 2.0.0-M4 2.6.2 2.3.30 1.6.2 From be505765ef52c2d9acc93b2d6b8a4cbff849aae5 Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Tue, 24 Aug 2021 21:54:50 +0300 Subject: [PATCH 005/432] tests: call destroy for lwm2m devices to shut down executors inside fwLwM2MDevice and swLwM2MDevice in the test scope --- .../transport/lwm2m/client/FwLwM2MDevice.java | 2 +- .../transport/lwm2m/client/LwM2MTestClient.java | 14 ++++++++++++-- .../transport/lwm2m/client/SwLwM2MDevice.java | 2 +- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/FwLwM2MDevice.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/FwLwM2MDevice.java index 2ae1c7d572..a85b69b35f 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/FwLwM2MDevice.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/FwLwM2MDevice.java @@ -37,7 +37,7 @@ public class FwLwM2MDevice extends BaseInstanceEnabler implements Destroyable { private static final List supportedResources = Arrays.asList(0, 1, 2, 3, 5, 6, 7, 9); - private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(); + private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(ThingsBoardThreadFactory.forName(getClass().getSimpleName() + "-test-scope")); private final AtomicInteger state = new AtomicInteger(0); diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2MTestClient.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2MTestClient.java index 72f9b014b7..6ee732785a 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2MTestClient.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2MTestClient.java @@ -46,6 +46,7 @@ import org.eclipse.leshan.core.request.DeregisterRequest; import org.eclipse.leshan.core.request.RegisterRequest; import org.eclipse.leshan.core.request.UpdateRequest; import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl; +import org.junit.Assert; import java.io.IOException; import java.net.InetSocketAddress; @@ -66,8 +67,11 @@ public class LwM2MTestClient { private final ScheduledExecutorService executor; private final String endpoint; private LeshanClient client; + private FwLwM2MDevice fwLwM2MDevice; + private SwLwM2MDevice swLwM2MDevice; public void init(Security security, NetworkConfig coapConfig) throws InvalidDDFFileException, IOException { + Assert.assertNull("client already initialized", client); String[] resources = new String[]{"0.xml", "1.xml", "2.xml", "3.xml", "5.xml", "9.xml"}; List models = new ArrayList<>(); for (String resourceName : resources) { @@ -78,8 +82,8 @@ public class LwM2MTestClient { initializer.setInstancesForObject(SECURITY, security); initializer.setInstancesForObject(SERVER, new Server(123, 300)); initializer.setInstancesForObject(DEVICE, new SimpleLwM2MDevice()); - initializer.setInstancesForObject(FIRMWARE, new FwLwM2MDevice()); - initializer.setInstancesForObject(SOFTWARE_MANAGEMENT, new SwLwM2MDevice()); + initializer.setInstancesForObject(FIRMWARE, fwLwM2MDevice = new FwLwM2MDevice()); + initializer.setInstancesForObject(SOFTWARE_MANAGEMENT, swLwM2MDevice = new SwLwM2MDevice()); initializer.setClassForObject(LwM2mId.ACCESS_CONTROL, DummyInstanceEnabler.class); DtlsConnectorConfig.Builder dtlsConfig = new DtlsConnectorConfig.Builder(); @@ -230,6 +234,12 @@ public class LwM2MTestClient { public void destroy() { client.destroy(true); + if (fwLwM2MDevice != null) { + fwLwM2MDevice.destroy(); + } + if (swLwM2MDevice != null) { + swLwM2MDevice.destroy(); + } } } diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/SwLwM2MDevice.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/SwLwM2MDevice.java index 8d8f07d542..1f22cc452a 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/SwLwM2MDevice.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/SwLwM2MDevice.java @@ -38,7 +38,7 @@ public class SwLwM2MDevice extends BaseInstanceEnabler implements Destroyable { private static final List supportedResources = Arrays.asList(0, 1, 2, 3, 4, 6, 7, 9); - private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(); + private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(ThingsBoardThreadFactory.forName(getClass().getSimpleName() + "-test-scope")); private final AtomicInteger state = new AtomicInteger(0); From db3214ee541956f432d8d1b5200c3b72ce5da08b Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Tue, 24 Aug 2021 22:47:05 +0300 Subject: [PATCH 006/432] tests: Coap client destroy on processAfterTest at AbstractCoapIntegrationTest --- .../transport/coap/AbstractCoapIntegrationTest.java | 10 ++++++++++ .../AbstractCoapAttributesRequestIntegrationTest.java | 4 ++-- ...tractCoapAttributesRequestProtoIntegrationTest.java | 3 +-- .../AbstractCoapAttributesUpdatesIntegrationTest.java | 2 +- .../coap/claim/AbstractCoapClaimDeviceTest.java | 2 +- .../coap/claim/AbstractCoapClaimProtoDeviceTest.java | 2 +- .../provision/AbstractCoapProvisionJsonDeviceTest.java | 2 +- .../AbstractCoapProvisionProtoDeviceTest.java | 2 +- .../rpc/AbstractCoapServerSideRpcIntegrationTest.java | 4 ++-- .../AbstractCoapAttributesIntegrationTest.java | 2 +- .../AbstractCoapTimeseriesIntegrationTest.java | 4 ++-- 11 files changed, 23 insertions(+), 14 deletions(-) diff --git a/application/src/test/java/org/thingsboard/server/transport/coap/AbstractCoapIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/coap/AbstractCoapIntegrationTest.java index 83023e21b9..8271fc6f95 100644 --- a/application/src/test/java/org/thingsboard/server/transport/coap/AbstractCoapIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/coap/AbstractCoapIntegrationTest.java @@ -52,6 +52,16 @@ import static org.junit.Assert.assertNotNull; @Slf4j public abstract class AbstractCoapIntegrationTest extends AbstractTransportIntegrationTest { + protected CoapClient client; + + @Override + protected void processAfterTest() throws Exception { + if (client != null) { + client.shutdown(); + } + super.processAfterTest(); + } + protected void processBeforeTest(String deviceName, CoapDeviceType coapDeviceType, TransportPayloadType payloadType) throws Exception { this.processBeforeTest(deviceName, coapDeviceType, payloadType, null, null, null, null, null, null, DeviceProfileProvisionType.DISABLED); } diff --git a/application/src/test/java/org/thingsboard/server/transport/coap/attributes/request/AbstractCoapAttributesRequestIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/coap/attributes/request/AbstractCoapAttributesRequestIntegrationTest.java index 999344b5f3..bced75775e 100644 --- a/application/src/test/java/org/thingsboard/server/transport/coap/attributes/request/AbstractCoapAttributesRequestIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/coap/attributes/request/AbstractCoapAttributesRequestIntegrationTest.java @@ -75,7 +75,7 @@ public abstract class AbstractCoapAttributesRequestIntegrationTest extends Abstr String keys = "attribute1,attribute2,attribute3,attribute4,attribute5"; String featureTokenUrl = getFeatureTokenUrl(accessToken, FeatureType.ATTRIBUTES) + "?clientKeys=" + keys + "&sharedKeys=" + keys; - CoapClient client = getCoapClient(featureTokenUrl); + client = getCoapClient(featureTokenUrl); CoapResponse getAttributesResponse = client.setTimeout(CLIENT_REQUEST_TIMEOUT).get(); validateResponse(getAttributesResponse); @@ -83,7 +83,7 @@ public abstract class AbstractCoapAttributesRequestIntegrationTest extends Abstr protected void postAttributes() throws Exception { doPostAsync("/api/plugins/telemetry/DEVICE/" + savedDevice.getId().getId() + "/attributes/SHARED_SCOPE", POST_ATTRIBUTES_PAYLOAD, String.class, status().isOk()); - CoapClient client = getCoapClient(FeatureType.ATTRIBUTES); + client = getCoapClient(FeatureType.ATTRIBUTES); CoapResponse coapResponse = client.setTimeout(CLIENT_REQUEST_TIMEOUT).post(POST_ATTRIBUTES_PAYLOAD.getBytes(), MediaTypeRegistry.APPLICATION_JSON); assertEquals(CoAP.ResponseCode.CREATED, coapResponse.getCode()); } diff --git a/application/src/test/java/org/thingsboard/server/transport/coap/attributes/request/AbstractCoapAttributesRequestProtoIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/coap/attributes/request/AbstractCoapAttributesRequestProtoIntegrationTest.java index 5bef44434e..b5534cba80 100644 --- a/application/src/test/java/org/thingsboard/server/transport/coap/attributes/request/AbstractCoapAttributesRequestProtoIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/coap/attributes/request/AbstractCoapAttributesRequestProtoIntegrationTest.java @@ -21,7 +21,6 @@ import com.google.protobuf.DynamicMessage; import com.google.protobuf.InvalidProtocolBufferException; import com.squareup.wire.schema.internal.parser.ProtoFileElement; import lombok.extern.slf4j.Slf4j; -import org.eclipse.californium.core.CoapClient; import org.eclipse.californium.core.CoapResponse; import org.eclipse.californium.core.coap.CoAP; import org.eclipse.californium.core.coap.MediaTypeRegistry; @@ -124,7 +123,7 @@ public abstract class AbstractCoapAttributesRequestProtoIntegrationTest extends .setField(postAttributesMsgDescriptor.findFieldByName("attribute5"), jsonObject) .build(); byte[] payload = postAttributesMsg.toByteArray(); - CoapClient client = getCoapClient(FeatureType.ATTRIBUTES); + client = getCoapClient(FeatureType.ATTRIBUTES); CoapResponse coapResponse = client.setTimeout(CLIENT_REQUEST_TIMEOUT).post(payload, MediaTypeRegistry.APPLICATION_JSON); assertEquals(CoAP.ResponseCode.CREATED, coapResponse.getCode()); } diff --git a/application/src/test/java/org/thingsboard/server/transport/coap/attributes/updates/AbstractCoapAttributesUpdatesIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/coap/attributes/updates/AbstractCoapAttributesUpdatesIntegrationTest.java index b1a4dc3c10..025819e104 100644 --- a/application/src/test/java/org/thingsboard/server/transport/coap/attributes/updates/AbstractCoapAttributesUpdatesIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/coap/attributes/updates/AbstractCoapAttributesUpdatesIntegrationTest.java @@ -71,7 +71,7 @@ public abstract class AbstractCoapAttributesUpdatesIntegrationTest extends Abstr if (!emptyCurrentStateNotification) { doPostAsync("/api/plugins/telemetry/DEVICE/" + savedDevice.getId().getId() + "/attributes/SHARED_SCOPE", POST_ATTRIBUTES_PAYLOAD_ON_CURRENT_STATE_NOTIFICATION, String.class, status().isOk()); } - CoapClient client = getCoapClient(FeatureType.ATTRIBUTES); + client = getCoapClient(FeatureType.ATTRIBUTES); CountDownLatch latch = new CountDownLatch(1); TestCoapCallback callback = new TestCoapCallback(latch); diff --git a/application/src/test/java/org/thingsboard/server/transport/coap/claim/AbstractCoapClaimDeviceTest.java b/application/src/test/java/org/thingsboard/server/transport/coap/claim/AbstractCoapClaimDeviceTest.java index 5cdcd2559e..30c30070b9 100644 --- a/application/src/test/java/org/thingsboard/server/transport/coap/claim/AbstractCoapClaimDeviceTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/coap/claim/AbstractCoapClaimDeviceTest.java @@ -90,7 +90,7 @@ public abstract class AbstractCoapClaimDeviceTest extends AbstractCoapIntegratio protected void processTestClaimingDevice(boolean emptyPayload) throws Exception { log.warn("[testClaimingDevice] Device: {}, Transport type: {}", savedDevice.getName(), savedDevice.getType()); - CoapClient client = getCoapClient(FeatureType.CLAIM); + client = getCoapClient(FeatureType.CLAIM); byte[] payloadBytes; byte[] failurePayloadBytes; if (emptyPayload) { diff --git a/application/src/test/java/org/thingsboard/server/transport/coap/claim/AbstractCoapClaimProtoDeviceTest.java b/application/src/test/java/org/thingsboard/server/transport/coap/claim/AbstractCoapClaimProtoDeviceTest.java index a9691e6693..cd64d85bf3 100644 --- a/application/src/test/java/org/thingsboard/server/transport/coap/claim/AbstractCoapClaimProtoDeviceTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/coap/claim/AbstractCoapClaimProtoDeviceTest.java @@ -49,7 +49,7 @@ public abstract class AbstractCoapClaimProtoDeviceTest extends AbstractCoapClaim @Override protected void processTestClaimingDevice(boolean emptyPayload) throws Exception { - CoapClient client = getCoapClient(FeatureType.CLAIM); + client = getCoapClient(FeatureType.CLAIM); byte[] payloadBytes; if (emptyPayload) { TransportApiProtos.ClaimDevice claimDevice = getClaimDevice(0, emptyPayload); diff --git a/application/src/test/java/org/thingsboard/server/transport/coap/provision/AbstractCoapProvisionJsonDeviceTest.java b/application/src/test/java/org/thingsboard/server/transport/coap/provision/AbstractCoapProvisionJsonDeviceTest.java index caecaea8ec..eccba64ddc 100644 --- a/application/src/test/java/org/thingsboard/server/transport/coap/provision/AbstractCoapProvisionJsonDeviceTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/coap/provision/AbstractCoapProvisionJsonDeviceTest.java @@ -180,7 +180,7 @@ public abstract class AbstractCoapProvisionJsonDeviceTest extends AbstractCoapIn private CoapResponse createCoapClientAndPublish(String deviceCredentials) throws Exception { String provisionRequestMsg = createTestProvisionMessage(deviceCredentials); - CoapClient client = getCoapClient(FeatureType.PROVISION); + client = getCoapClient(FeatureType.PROVISION); return postProvision(client, provisionRequestMsg.getBytes()); } diff --git a/application/src/test/java/org/thingsboard/server/transport/coap/provision/AbstractCoapProvisionProtoDeviceTest.java b/application/src/test/java/org/thingsboard/server/transport/coap/provision/AbstractCoapProvisionProtoDeviceTest.java index 682d9c7e7b..7db300e721 100644 --- a/application/src/test/java/org/thingsboard/server/transport/coap/provision/AbstractCoapProvisionProtoDeviceTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/coap/provision/AbstractCoapProvisionProtoDeviceTest.java @@ -176,7 +176,7 @@ public abstract class AbstractCoapProvisionProtoDeviceTest extends AbstractCoapI } private CoapResponse createCoapClientAndPublish(byte[] provisionRequestMsg) throws Exception { - CoapClient client = getCoapClient(FeatureType.PROVISION); + client = getCoapClient(FeatureType.PROVISION); return postProvision(client, provisionRequestMsg); } diff --git a/application/src/test/java/org/thingsboard/server/transport/coap/rpc/AbstractCoapServerSideRpcIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/coap/rpc/AbstractCoapServerSideRpcIntegrationTest.java index 758dc02004..3fbc8cd214 100644 --- a/application/src/test/java/org/thingsboard/server/transport/coap/rpc/AbstractCoapServerSideRpcIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/coap/rpc/AbstractCoapServerSideRpcIntegrationTest.java @@ -54,7 +54,7 @@ public abstract class AbstractCoapServerSideRpcIntegrationTest extends AbstractC } protected void processOneWayRpcTest() throws Exception { - CoapClient client = getCoapClient(FeatureType.RPC); + client = getCoapClient(FeatureType.RPC); client.useCONs(); CountDownLatch latch = new CountDownLatch(1); @@ -82,7 +82,7 @@ public abstract class AbstractCoapServerSideRpcIntegrationTest extends AbstractC } protected void processTwoWayRpcTest(String expectedResponseResult) throws Exception { - CoapClient client = getCoapClient(FeatureType.RPC); + client = getCoapClient(FeatureType.RPC); client.useCONs(); CountDownLatch latch = new CountDownLatch(1); diff --git a/application/src/test/java/org/thingsboard/server/transport/coap/telemetry/attributes/AbstractCoapAttributesIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/coap/telemetry/attributes/AbstractCoapAttributesIntegrationTest.java index aac8933af0..b71d448e7e 100644 --- a/application/src/test/java/org/thingsboard/server/transport/coap/telemetry/attributes/AbstractCoapAttributesIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/coap/telemetry/attributes/AbstractCoapAttributesIntegrationTest.java @@ -69,7 +69,7 @@ public abstract class AbstractCoapAttributesIntegrationTest extends AbstractCoap } protected void processAttributesTest(List expectedKeys, byte[] payload, boolean presenceFieldsTest) throws Exception { - CoapClient client = getCoapClient(FeatureType.ATTRIBUTES); + client = getCoapClient(FeatureType.ATTRIBUTES); postAttributes(client, payload); diff --git a/application/src/test/java/org/thingsboard/server/transport/coap/telemetry/timeseries/AbstractCoapTimeseriesIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/coap/telemetry/timeseries/AbstractCoapTimeseriesIntegrationTest.java index 5438a7f02b..6993d73320 100644 --- a/application/src/test/java/org/thingsboard/server/transport/coap/telemetry/timeseries/AbstractCoapTimeseriesIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/coap/telemetry/timeseries/AbstractCoapTimeseriesIntegrationTest.java @@ -71,8 +71,8 @@ public abstract class AbstractCoapTimeseriesIntegrationTest extends AbstractCoap } protected void processTestPostTelemetry(byte[] payloadBytes, List expectedKeys, boolean withTs, boolean presenceFieldsTest) throws Exception { - CoapClient coapClient = getCoapClient(FeatureType.TELEMETRY); - postTelemetry(coapClient, payloadBytes); + client = getCoapClient(FeatureType.TELEMETRY); + postTelemetry(client, payloadBytes); String deviceId = savedDevice.getId().getId().toString(); From 0c3574d912b75ebac2b79600a365b7f330772aa2 Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Tue, 24 Aug 2021 22:47:05 +0300 Subject: [PATCH 007/432] tests: fixed import --- .../thingsboard/server/transport/lwm2m/client/FwLwM2MDevice.java | 1 + .../thingsboard/server/transport/lwm2m/client/SwLwM2MDevice.java | 1 + 2 files changed, 2 insertions(+) diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/FwLwM2MDevice.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/FwLwM2MDevice.java index a85b69b35f..cc097c869d 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/FwLwM2MDevice.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/FwLwM2MDevice.java @@ -23,6 +23,7 @@ import org.eclipse.leshan.core.node.LwM2mResource; import org.eclipse.leshan.core.response.ExecuteResponse; import org.eclipse.leshan.core.response.ReadResponse; import org.eclipse.leshan.core.response.WriteResponse; +import org.thingsboard.common.util.ThingsBoardThreadFactory; import javax.security.auth.Destroyable; import java.util.Arrays; diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/SwLwM2MDevice.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/SwLwM2MDevice.java index 1f22cc452a..b06a3ebbd3 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/SwLwM2MDevice.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/SwLwM2MDevice.java @@ -24,6 +24,7 @@ import org.eclipse.leshan.core.node.LwM2mResource; import org.eclipse.leshan.core.response.ExecuteResponse; import org.eclipse.leshan.core.response.ReadResponse; import org.eclipse.leshan.core.response.WriteResponse; +import org.thingsboard.common.util.ThingsBoardThreadFactory; import javax.security.auth.Destroyable; import java.util.Arrays; From b01eb2cfc57195a840ed6f4ec33a8ee7efdc6964 Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Tue, 24 Aug 2021 22:47:05 +0300 Subject: [PATCH 008/432] lwm2Tests: new structure --- .../transport/TransportSqlTestSuite.java | 2 +- .../transport/lwm2m/Lwm2mTestHelper.java | 65 ++++ .../transport/lwm2m/client/FwLwM2MDevice.java | 2 +- .../lwm2m/client/LwM2MLocationParams.java | 41 +++ .../lwm2m/client/LwM2MTestClient.java | 52 ++- .../client/LwM2mBinaryAppDataContainer.java | 231 +++++++++++++ .../transport/lwm2m/client/LwM2mLocation.java | 150 +++++++++ .../lwm2m/client/LwM2mTemperatureSensor.java | 131 ++++++++ .../lwm2m/client/SimpleLwM2MDevice.java | 10 +- .../transport/lwm2m/client/SwLwM2MDevice.java | 3 +- .../rpc/RpcAbstractLwM2MIntegrationTest.java | 307 ++++++++++++++++++ .../sql/RpcLwm2mIntegrationCreateTest.java | 77 +++++ .../AbstractLwM2MIntegrationTest.java | 17 +- .../sql/NoSecLwM2MIntegrationTest.java | 36 ++ .../sql/OtaLwM2MIntegrationTest.java} | 120 +++---- .../sql/PskLwm2mIntegrationTest.java | 9 +- .../sql/RpkLwM2MIntegrationTest.java | 9 +- .../sql/X509LwM2MIntegrationTest.java | 37 ++- application/src/test/resources/lwm2m/19.xml | 144 ++++++++ application/src/test/resources/lwm2m/3303.xml | 103 ++++++ application/src/test/resources/lwm2m/6.xml | 143 ++++++++ 21 files changed, 1578 insertions(+), 111 deletions(-) create mode 100644 application/src/test/java/org/thingsboard/server/transport/lwm2m/Lwm2mTestHelper.java create mode 100644 application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2MLocationParams.java create mode 100644 application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2mBinaryAppDataContainer.java create mode 100644 application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2mLocation.java create mode 100644 application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2mTemperatureSensor.java create mode 100644 application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/RpcAbstractLwM2MIntegrationTest.java create mode 100644 application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationCreateTest.java rename application/src/test/java/org/thingsboard/server/transport/lwm2m/{ => security}/AbstractLwM2MIntegrationTest.java (97%) create mode 100644 application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/NoSecLwM2MIntegrationTest.java rename application/src/test/java/org/thingsboard/server/transport/lwm2m/{sql/NoSecLwM2MIntegrationTest.java => security/sql/OtaLwM2MIntegrationTest.java} (71%) rename application/src/test/java/org/thingsboard/server/transport/lwm2m/{ => security}/sql/PskLwm2mIntegrationTest.java (79%) rename application/src/test/java/org/thingsboard/server/transport/lwm2m/{ => security}/sql/RpkLwM2MIntegrationTest.java (78%) rename application/src/test/java/org/thingsboard/server/transport/lwm2m/{ => security}/sql/X509LwM2MIntegrationTest.java (55%) create mode 100644 application/src/test/resources/lwm2m/19.xml create mode 100644 application/src/test/resources/lwm2m/3303.xml create mode 100644 application/src/test/resources/lwm2m/6.xml diff --git a/application/src/test/java/org/thingsboard/server/transport/TransportSqlTestSuite.java b/application/src/test/java/org/thingsboard/server/transport/TransportSqlTestSuite.java index 0fa04d0611..095321c184 100644 --- a/application/src/test/java/org/thingsboard/server/transport/TransportSqlTestSuite.java +++ b/application/src/test/java/org/thingsboard/server/transport/TransportSqlTestSuite.java @@ -33,7 +33,7 @@ import java.util.Arrays; "org.thingsboard.server.transport.*.attributes.request.sql.*Test", "org.thingsboard.server.transport.*.claim.sql.*Test", "org.thingsboard.server.transport.*.provision.sql.*Test", - "org.thingsboard.server.transport.lwm2m.sql.*Test" + "org.thingsboard.server.transport.lwm2m.*.sql.*Test" }) public class TransportSqlTestSuite { diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/Lwm2mTestHelper.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/Lwm2mTestHelper.java new file mode 100644 index 0000000000..37c126df21 --- /dev/null +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/Lwm2mTestHelper.java @@ -0,0 +1,65 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.transport.lwm2m; + +import org.eclipse.californium.core.network.config.NetworkConfig; +import org.eclipse.leshan.client.object.Security; + +import static org.eclipse.leshan.client.object.Security.noSec; + +public class Lwm2mTestHelper { + + // Server + public static final int SECURE_PORT = 5686; + public static final int SECURE_PORT_BS = 5688; + public static final String HOST = "localhost"; + public static final String HOST_BS = "localhost"; + public static final NetworkConfig SECURE_COAP_CONFIG = new NetworkConfig().setString("COAP_SECURE_PORT", Integer.toString(SECURE_PORT)); + public static final String ENDPOINT_SECURITY = "deviceAEndpoint"; + public static final String SECURE_URI = "coaps://localhost:" + SECURE_PORT; + + public static final int PORT = 5685; + public static final int PORT_BS = 5687; + public static final int SHORT_SERVER_ID = 123; + public static final int SHORT_SERVER_ID_BS = 111; + + public static final Security SECURITY = noSec("coap://localhost:" + PORT, SHORT_SERVER_ID); + public static final NetworkConfig COAP_CONFIG = new NetworkConfig().setString("COAP_PORT", Integer.toString(PORT)); + + // Models + public static final String[] resources = new String[]{"0.xml", "1.xml", "2.xml", "3.xml", "5.xml", "6.xml", "9.xml", "19.xml", "3303.xml"}; + public static final int BINARY_APP_DATA_CONTAINER = 19; + public static final int TEMPERATURE_SENSOR = 3303; + + // Ids in Client + public static final int objectInstanceId_0 = 0; + public static final int objectInstanceId_1 = 1; + public static final int objectInstanceId_12 = 12; + public static final int resourceId_0 = 0; + protected static final int resourceId_1 = 1; + protected static final int resourceId_2 = 2; + protected static final int resourceId_3 = 3; + public static final int resourceId_9 = 9; + protected static final int resourceId_11 = 11; + public static final int resourceId_14 = 14; + protected static final int resourceId_15= 15; + + public static final String resourceIdName_3_9 = "batteryLevel"; + public static final String resourceIdName_3_14 = "UtfOffset"; + public static final String resourceIdName_19_0_0 = "dataRead"; + public static final String resourceIdName_19_1_0 = "dataWrite"; + +} diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/FwLwM2MDevice.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/FwLwM2MDevice.java index cc097c869d..e95f3d4841 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/FwLwM2MDevice.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/FwLwM2MDevice.java @@ -83,7 +83,7 @@ public class FwLwM2MDevice extends BaseInstanceEnabler implements Destroyable { @Override public WriteResponse write(ServerIdentity identity, boolean replace, int resourceId, LwM2mResource value) { - log.info("Write on Device resource /{}/{}/{}", getModel().id, getId(), resourceId); + log.warn("Write on Device resource /{}/{}/{}", getModel().id, getId(), resourceId); switch (resourceId) { case 0: diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2MLocationParams.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2MLocationParams.java new file mode 100644 index 0000000000..67d1dc5749 --- /dev/null +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2MLocationParams.java @@ -0,0 +1,41 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.transport.lwm2m.client; + +import lombok.Data; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@Data +public class LwM2MLocationParams { + + private Float latitude; + private Float longitude; + private Float scaleFactor = 1.0F; + private final String locationPos = "50.4501:30.5234"; + private final Float locationScaleFactor = 1.0F; + + + protected void getPos() { + this.latitude = null; + this.longitude = null; + int c = locationPos.indexOf(':'); + this.latitude = Float.valueOf(locationPos.substring(0, c)); + this.longitude = Float.valueOf(locationPos.substring(c + 1)); + } + + +} diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2MTestClient.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2MTestClient.java index 6ee732785a..4c5406785c 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2MTestClient.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2MTestClient.java @@ -31,7 +31,6 @@ import org.eclipse.leshan.client.observer.LwM2mClientObserver; import org.eclipse.leshan.client.resource.DummyInstanceEnabler; import org.eclipse.leshan.client.resource.ObjectsInitializer; import org.eclipse.leshan.client.servers.ServerIdentity; -import org.eclipse.leshan.core.LwM2mId; import org.eclipse.leshan.core.ResponseCode; import org.eclipse.leshan.core.californium.EndpointFactory; import org.eclipse.leshan.core.model.InvalidDDFFileException; @@ -45,6 +44,7 @@ import org.eclipse.leshan.core.request.BootstrapRequest; import org.eclipse.leshan.core.request.DeregisterRequest; import org.eclipse.leshan.core.request.RegisterRequest; import org.eclipse.leshan.core.request.UpdateRequest; +import org.thingsboard.common.util.ThingsBoardThreadFactory; import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl; import org.junit.Assert; @@ -54,11 +54,20 @@ import java.util.ArrayList; import java.util.List; import java.util.concurrent.ScheduledExecutorService; +import static org.eclipse.leshan.core.LwM2mId.ACCESS_CONTROL; import static org.eclipse.leshan.core.LwM2mId.DEVICE; import static org.eclipse.leshan.core.LwM2mId.FIRMWARE; +import static org.eclipse.leshan.core.LwM2mId.LOCATION; import static org.eclipse.leshan.core.LwM2mId.SECURITY; import static org.eclipse.leshan.core.LwM2mId.SERVER; import static org.eclipse.leshan.core.LwM2mId.SOFTWARE_MANAGEMENT; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resources; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.BINARY_APP_DATA_CONTAINER; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.TEMPERATURE_SENSOR; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.objectInstanceId_0; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.objectInstanceId_1; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.objectInstanceId_12; + @Slf4j @Data @@ -67,24 +76,36 @@ public class LwM2MTestClient { private final ScheduledExecutorService executor; private final String endpoint; private LeshanClient client; + + private Server lwm2mServer; + private SimpleLwM2MDevice lwM2MDevice; private FwLwM2MDevice fwLwM2MDevice; private SwLwM2MDevice swLwM2MDevice; + private LwM2mBinaryAppDataContainer lwM2MBinaryAppDataContainer; + private LwM2MLocationParams locationParams; + private LwM2mTemperatureSensor lwM2MTemperatureSensor; - public void init(Security security, NetworkConfig coapConfig) throws InvalidDDFFileException, IOException { + public void init(Security security, NetworkConfig coapConfig, int port) throws InvalidDDFFileException, IOException { Assert.assertNull("client already initialized", client); - String[] resources = new String[]{"0.xml", "1.xml", "2.xml", "3.xml", "5.xml", "9.xml"}; List models = new ArrayList<>(); for (String resourceName : resources) { models.addAll(ObjectLoader.loadDdfFile(LwM2MTestClient.class.getClassLoader().getResourceAsStream("lwm2m/" + resourceName), resourceName)); } + LwM2mModel model = new StaticModel(models); ObjectsInitializer initializer = new ObjectsInitializer(model); initializer.setInstancesForObject(SECURITY, security); - initializer.setInstancesForObject(SERVER, new Server(123, 300)); - initializer.setInstancesForObject(DEVICE, new SimpleLwM2MDevice()); + initializer.setInstancesForObject(SERVER, lwm2mServer = new Server(123, 300)); + initializer.setInstancesForObject(DEVICE, lwM2MDevice = new SimpleLwM2MDevice()); initializer.setInstancesForObject(FIRMWARE, fwLwM2MDevice = new FwLwM2MDevice()); initializer.setInstancesForObject(SOFTWARE_MANAGEMENT, swLwM2MDevice = new SwLwM2MDevice()); - initializer.setClassForObject(LwM2mId.ACCESS_CONTROL, DummyInstanceEnabler.class); + initializer.setClassForObject(ACCESS_CONTROL, DummyInstanceEnabler.class); + initializer.setInstancesForObject(BINARY_APP_DATA_CONTAINER, lwM2MBinaryAppDataContainer = new LwM2mBinaryAppDataContainer(executor, objectInstanceId_0), + new LwM2mBinaryAppDataContainer(executor, objectInstanceId_1)); + locationParams = new LwM2MLocationParams(); + locationParams.getPos(); + initializer.setInstancesForObject(LOCATION, new LwM2mLocation(locationParams.getLatitude(), locationParams.getLongitude(), locationParams.getScaleFactor(), executor, objectInstanceId_0)); + initializer.setInstancesForObject(TEMPERATURE_SENSOR, lwM2MTemperatureSensor = new LwM2mTemperatureSensor(executor, objectInstanceId_0), new LwM2mTemperatureSensor(executor, objectInstanceId_12)); DtlsConnectorConfig.Builder dtlsConfig = new DtlsConnectorConfig.Builder(); dtlsConfig.setRecommendedCipherSuitesOnly(true); @@ -128,7 +149,7 @@ public class LwM2MTestClient { LeshanClientBuilder builder = new LeshanClientBuilder(endpoint); - builder.setLocalAddress("0.0.0.0", 11000); + builder.setLocalAddress("0.0.0.0", port); builder.setObjects(initializer.createAll()); builder.setCoapConfig(coapConfig); builder.setDtlsConfig(dtlsConfig); @@ -136,6 +157,7 @@ public class LwM2MTestClient { builder.setEndpointFactory(endpointFactory); builder.setSharedExecutor(executor); builder.setDecoder(new DefaultLwM2mDecoder(false)); + builder.setEncoder(new DefaultLwM2mEncoder(new LwM2mValueConverterImpl(), false)); client = builder.build(); @@ -233,13 +255,27 @@ public class LwM2MTestClient { } public void destroy() { - client.destroy(true); + if (client != null) { + client.destroy(true); + } + if (lwm2mServer != null) { + lwm2mServer = null; + } + if (lwM2MDevice != null) { + lwM2MDevice.destroy(); + } if (fwLwM2MDevice != null) { fwLwM2MDevice.destroy(); } if (swLwM2MDevice != null) { swLwM2MDevice.destroy(); } + if (lwM2MBinaryAppDataContainer != null) { + lwM2MBinaryAppDataContainer.destroy(); + } + if (lwM2MTemperatureSensor != null) { + lwM2MTemperatureSensor.destroy(); + } } } diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2mBinaryAppDataContainer.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2mBinaryAppDataContainer.java new file mode 100644 index 0000000000..b7ac889649 --- /dev/null +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2mBinaryAppDataContainer.java @@ -0,0 +1,231 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.transport.lwm2m.client; + +import lombok.extern.slf4j.Slf4j; +import org.eclipse.leshan.client.resource.BaseInstanceEnabler; +import org.eclipse.leshan.client.servers.ServerIdentity; +import org.eclipse.leshan.core.model.ObjectModel; +import org.eclipse.leshan.core.model.ResourceModel; +import org.eclipse.leshan.core.node.LwM2mMultipleResource; +import org.eclipse.leshan.core.node.LwM2mResource; +import org.eclipse.leshan.core.response.ReadResponse; +import org.eclipse.leshan.core.response.WriteResponse; + +import javax.security.auth.Destroyable; +import java.sql.Time; +import java.util.Arrays; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + + +@Slf4j +public class LwM2mBinaryAppDataContainer extends BaseInstanceEnabler implements Destroyable { + + /** + * id = 0 + * Multiple + * base64 + */ + + /** + * Example1: + * InNlcnZpY2VJZCI6Ik1ldGVyIiwNCiJzZXJ2aWNlRGF0YSI6ew0KImN1cnJlbnRSZWFka + * W5nIjoiNDYuMyIsDQoic2lnbmFsU3RyZW5ndGgiOjE2LA0KImRhaWx5QWN0aXZpdHlUaW1lIjo1NzA2DQo= + * "serviceId":"Meter", + * "serviceData":{ + * "currentReading":"46.3", + * "signalStrength":16, + * "dailyActivityTime":5706 + */ + + /** + * Example2: + * InNlcnZpY2VJZCI6IldhdGVyTWV0ZXIiLA0KImNtZCI6IlNFVF9URU1QRVJBVFVSRV9SRUFEX + * 1BFUklPRCIsDQoicGFyYXMiOnsNCiJ2YWx1ZSI6NA0KICAgIH0sDQoNCg0K + * "serviceId":"WaterMeter", + * "cmd":"SET_TEMPERATURE_READ_PERIOD", + * "paras":{ + * "value":4 + * }, + */ +// private String data = "InNlcnZpY2VJZCI6Ik1ldGVyIiwNCiJzZXJ2aWNlRGF0YSI6ew0KImN1cnJlbnRSZWFkaW5nIjoiNDYuMyIsDQoic2lnbmFsU3RyZW5ndGgiOjE2LA0KImRhaWx5QWN0aXZpdHlUaW1lIjo1NzA2DQo="; +// private byte[] data; + Map data; + private Integer priority = 0; + private Time timestamp; + private String description; + private String dataFormat; + private Integer appID = -1; + private static final List supportedResources = Arrays.asList(0, 1, 2, 3, 4, 5); + + public LwM2mBinaryAppDataContainer() { + } + + public LwM2mBinaryAppDataContainer(ScheduledExecutorService executorService, Integer id) { + try { + if (id != null) this.setId(id); + executorService.scheduleWithFixedDelay(() -> +// fireResourcesChange(0, 2), 5000, 5000, TimeUnit.MILLISECONDS); + fireResourcesChange(0, 2), 1800000, 1800000, TimeUnit.MILLISECONDS); // 30 MIN + } catch (Throwable e) { + log.error("[{}]Throwable", e.toString()); + e.printStackTrace(); + } + } + + @Override + public ReadResponse read(ServerIdentity identity, int resourceId) { +// log.warn("Read on Location resource /[{}]/[{}]/[{}]", getModel().id, getId(), resourceId); + try { + switch (resourceId) { + case 0: +// log.warn("Read on Location resource /[{}]/[{}]/[{}]", getModel().id, getId(), resourceId); + ReadResponse response = ReadResponse.success(resourceId, getData(), ResourceModel.Type.OPAQUE); +// log.warn("Response [{}]", response); + return response; + + case 1: + return ReadResponse.success(resourceId, getPriority()); + case 2: + return ReadResponse.success(resourceId, getTimestamp()); + case 3: + return ReadResponse.success(resourceId, getDescription()); + case 4: + return ReadResponse.success(resourceId, getDataFormat()); + case 5: + return ReadResponse.success(resourceId, getAppID()); + default: + return super.read(identity, resourceId); + } + } catch (Exception e) { + return ReadResponse.badRequest(e.getMessage()); + } + } + + @Override + public WriteResponse write(ServerIdentity identity, boolean replace, int resourceId, LwM2mResource value) { + log.info("Write on Device resource /[{}]/[{}]/[{}]", getModel().id, getId(), resourceId); + switch (resourceId) { + case 0: + if (setData(value, replace)) { + return WriteResponse.success(); + } else { + WriteResponse.badRequest("Invalidate value ..."); + } + case 1: + setPriority((Integer) (value.getValue() instanceof Long ? ((Long) value.getValue()).intValue() : value.getValue())); + fireResourcesChange(resourceId); + return WriteResponse.success(); + case 2: + setTimestamp(((Date) value.getValue()).getTime()); + fireResourcesChange(resourceId); + return WriteResponse.success(); + case 3: + setDescription((String) value.getValue()); + fireResourcesChange(resourceId); + return WriteResponse.success(); + case 4: + setDataFormat((String) value.getValue()); + fireResourcesChange(resourceId); + return WriteResponse.success(); + case 5: + setAppID((Integer) value.getValue()); + fireResourcesChange(resourceId); + return WriteResponse.success(); + default: + return super.write(identity, replace, resourceId, value); + } + } + + private Integer getAppID() { + return this.appID; + } + + private void setAppID(Integer appId) { + this.appID = appId; + } + + private void setDataFormat(String value) { + this.dataFormat = value; + } + + private String getDataFormat() { +// return this.dataFormat == null ? "base64" : this.dataFormat; + return this.dataFormat == null ? "OPAQUE" : this.dataFormat; + } + + private void setDescription(String value) { + this.description = value; + } + + private String getDescription() { + return this.description == null ? "meter reading" : this.description; + } + + private void setTimestamp(long time) { + this.timestamp = new Time(time); + } + + private Time getTimestamp() { + return this.timestamp != null ? this.timestamp : new Time(new Date().getTime()); + } + +// fireResourcesChange(resourceId); + private boolean setData(LwM2mResource value, boolean replace) { + try { + if (value instanceof LwM2mMultipleResource) { + if (replace || this.data == null) { + this.data = new HashMap<>(); + } + value.getInstances().values().forEach(v -> { + this.data.put(v.getId(), (byte[]) v.getValue()); + }); + return true; + } else { + return false; + } + } catch (Exception e) { + return false; + } + } + + private Map getData() { +// this.data.put(23, new byte[]{0,0, 2,3}); + return data; + } + + @Override + public List getAvailableResourceIds(ObjectModel model) { + return supportedResources; + } + + @Override + public void destroy() { + } + + private int getPriority() { + return this.priority; + } + + private void setPriority(int value) { + this.priority = value; + } +} diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2mLocation.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2mLocation.java new file mode 100644 index 0000000000..079cd9fdac --- /dev/null +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2mLocation.java @@ -0,0 +1,150 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.transport.lwm2m.client; + +import lombok.extern.slf4j.Slf4j; +import org.eclipse.leshan.client.resource.BaseInstanceEnabler; +import org.eclipse.leshan.client.servers.ServerIdentity; +import org.eclipse.leshan.core.model.ObjectModel; +import org.eclipse.leshan.core.response.ReadResponse; + +import javax.security.auth.Destroyable; +import java.util.Arrays; +import java.util.Date; +import java.util.List; +import java.util.Random; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +@Slf4j +public class LwM2mLocation extends BaseInstanceEnabler implements Destroyable { + + private float latitude; + private float longitude; + private float scaleFactor; + private Date timestamp; + protected static final Random RANDOM = new Random(); + private static final List supportedResources = Arrays.asList(0, 1, 5); + + public LwM2mLocation() { + this(null, null, 1.0f); + } + + public LwM2mLocation(Float latitude, Float longitude, float scaleFactor) { + + if (latitude != null) { + this.latitude = latitude + 90f; + } else { + this.latitude = RANDOM.nextInt(180); + } + if (longitude != null) { + this.longitude = longitude + 180f; + } else { + this.longitude = RANDOM.nextInt(360); + } + this.scaleFactor = scaleFactor; + timestamp = new Date(); + } + + public LwM2mLocation(Float latitude, Float longitude, float scaleFactor, ScheduledExecutorService executorService, Integer id) { + try { + if (id != null) this.setId(id); + if (latitude != null) { + this.latitude = latitude + 90f; + } else { + this.latitude = RANDOM.nextInt(180); + } + if (longitude != null) { + this.longitude = longitude + 180f; + } else { + this.longitude = RANDOM.nextInt(360); + } + this.scaleFactor = scaleFactor; + timestamp = new Date(); + executorService.scheduleWithFixedDelay(() -> + fireResourcesChange(0, 1), 10000, 10000, TimeUnit.MILLISECONDS); + } catch (Throwable e) { + log.error("[{}]Throwable", e.toString()); + e.printStackTrace(); + } + } + + @Override + public ReadResponse read(ServerIdentity identity, int resourceId) { + log.info("Read on Location resource /[{}]/[{}]/[{}]", getModel().id, getId(), resourceId); + switch (resourceId) { + case 0: + return ReadResponse.success(resourceId, getLatitude()); + case 1: + return ReadResponse.success(resourceId, getLongitude()); + case 5: + return ReadResponse.success(resourceId, getTimestamp()); + default: + return super.read(identity, resourceId); + } + } + + public void moveLocation(String nextMove) { + switch (nextMove.charAt(0)) { + case 'w': + moveLatitude(1.0f); +// log.info("Move to North [{}]/[{}]", getLatitude(), getLongitude()); + break; + case 'a': + moveLongitude(-1.0f); +// log.info("Move to East [{}]/[{}]", getLatitude(), getLongitude()); + break; + case 's': + moveLatitude(-1.0f); +// log.info("Move to South [{}]/[{}]", getLatitude(), getLongitude()); + break; + case 'd': + moveLongitude(1.0f); +// log.info("Move to West [{}]/[{}]", getLatitude(), getLongitude()); + break; + } + } + + private void moveLatitude(float delta) { + latitude = latitude + delta * scaleFactor; + timestamp = new Date(); + fireResourcesChange(0, 5); + } + + private void moveLongitude(float delta) { + longitude = longitude + delta * scaleFactor; + timestamp = new Date(); + fireResourcesChange(1, 5); + } + + public float getLatitude() { + return latitude - 90.0f; + } + + public float getLongitude() { + return longitude - 180.f; + } + + public Date getTimestamp() { + return timestamp; + } + + @Override + public List getAvailableResourceIds(ObjectModel model) { + return supportedResources; + } + +} diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2mTemperatureSensor.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2mTemperatureSensor.java new file mode 100644 index 0000000000..2e52cfc812 --- /dev/null +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2mTemperatureSensor.java @@ -0,0 +1,131 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.transport.lwm2m.client; + +import lombok.extern.slf4j.Slf4j; +import org.eclipse.leshan.client.resource.BaseInstanceEnabler; +import org.eclipse.leshan.client.servers.ServerIdentity; +import org.eclipse.leshan.core.model.ObjectModel; +import org.eclipse.leshan.core.response.ExecuteResponse; +import org.eclipse.leshan.core.response.ReadResponse; + +import javax.security.auth.Destroyable; +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.util.Arrays; +import java.util.List; +import java.util.Random; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +@Slf4j +public class LwM2mTemperatureSensor extends BaseInstanceEnabler implements Destroyable { + + private static final String UNIT_CELSIUS = "cel"; + private double currentTemp = 20d; + private double minMeasuredValue = currentTemp; + private double maxMeasuredValue = currentTemp; + protected static final Random RANDOM = new Random(); + private static final List supportedResources = Arrays.asList(5601, 5602, 5700, 5701); + + public LwM2mTemperatureSensor() { + + } + + public LwM2mTemperatureSensor(ScheduledExecutorService executorService, Integer id) { + try { + if (id != null) this.setId(id); + executorService.scheduleWithFixedDelay(this::adjustTemperature, 2000, 2000, TimeUnit.MILLISECONDS); + } catch (Throwable e) { + log.error("[{}]Throwable", e.toString()); + e.printStackTrace(); + } + } + + @Override + public synchronized ReadResponse read(ServerIdentity identity, int resourceId) { + log.info("Read on Temperature resource /[{}]/[{}]/[{}]", getModel().id, getId(), resourceId); + switch (resourceId) { + case 5601: + return ReadResponse.success(resourceId, getTwoDigitValue(minMeasuredValue)); + case 5602: + return ReadResponse.success(resourceId, getTwoDigitValue(maxMeasuredValue)); + case 5700: + return ReadResponse.success(resourceId, getTwoDigitValue(currentTemp)); + case 5701: + return ReadResponse.success(resourceId, UNIT_CELSIUS); + default: + return super.read(identity, resourceId); + } + } + + @Override + public synchronized ExecuteResponse execute(ServerIdentity identity, int resourceId, String params) { + log.info("Execute on Temperature resource /[{}]/[{}]/[{}]", getModel().id, getId(), resourceId); + switch (resourceId) { + case 5605: + resetMinMaxMeasuredValues(); + return ExecuteResponse.success(); + default: + return super.execute(identity, resourceId, params); + } + } + + private double getTwoDigitValue(double value) { + BigDecimal toBeTruncated = BigDecimal.valueOf(value); + return toBeTruncated.setScale(2, RoundingMode.HALF_UP).doubleValue(); + } + + private void adjustTemperature() { + float delta = (RANDOM.nextInt(20) - 10) / 10f; + currentTemp += delta; + Integer changedResource = adjustMinMaxMeasuredValue(currentTemp); + if (changedResource != null) { + fireResourcesChange(5700, changedResource); + } else { + fireResourcesChange(5700); + } + } + + private synchronized Integer adjustMinMaxMeasuredValue(double newTemperature) { + if (newTemperature > maxMeasuredValue) { + maxMeasuredValue = newTemperature; + return 5602; + } else if (newTemperature < minMeasuredValue) { + minMeasuredValue = newTemperature; + return 5601; + } else { + return null; + } + } + + private void resetMinMaxMeasuredValues() { + minMeasuredValue = currentTemp; + maxMeasuredValue = currentTemp; + } + + @Override + public List getAvailableResourceIds(ObjectModel model) { + return supportedResources; + } + + @Override + public void destroy() { + } + + + +} diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/SimpleLwM2MDevice.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/SimpleLwM2MDevice.java index 9ede9da80e..8d5c46a1a0 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/SimpleLwM2MDevice.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/SimpleLwM2MDevice.java @@ -40,9 +40,7 @@ public class SimpleLwM2MDevice extends BaseInstanceEnabler implements Destroyabl private static final Random RANDOM = new Random(); - private static final List supportedResources = Arrays.asList(0, 1, 2, 3 -// , 9, 10, 11, 13, 14, 15, 16, 17, 18, 19, 20, 21 - ); + private static final List supportedResources = Arrays.asList(0, 1, 2, 3, 9, 10, 11, 13, 14, 15, 16, 17, 18, 19, 20, 21); @Override public ReadResponse read(ServerIdentity identity, int resourceId) { @@ -117,7 +115,7 @@ public class SimpleLwM2MDevice extends BaseInstanceEnabler implements Destroyabl } private String getManufacturer() { - return "Leshan Demo Device"; + return "Thingsboard Demo Lwm2mDevice"; } private String getModelNumber() { @@ -125,11 +123,11 @@ public class SimpleLwM2MDevice extends BaseInstanceEnabler implements Destroyabl } private String getSerialNumber() { - return "LT-500-000-0001"; + return "Thingsboard-500-000-0001"; } private String getFirmwareVersion() { - return "1.0.0"; + return "1.0.2"; } private long getErrorCode() { diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/SwLwM2MDevice.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/SwLwM2MDevice.java index b06a3ebbd3..dc6ad348a3 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/SwLwM2MDevice.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/SwLwM2MDevice.java @@ -15,7 +15,6 @@ */ package org.thingsboard.server.transport.lwm2m.client; -import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.eclipse.leshan.client.resource.BaseInstanceEnabler; import org.eclipse.leshan.client.servers.ServerIdentity; @@ -84,7 +83,7 @@ public class SwLwM2MDevice extends BaseInstanceEnabler implements Destroyable { @Override public WriteResponse write(ServerIdentity identity, boolean replace, int resourceId, LwM2mResource value) { - log.info("Write on Device resource /{}/{}/{}", getModel().id, getId(), resourceId); + log.warn("Write on Device resource /{}/{}/{}", getModel().id, getId(), resourceId); switch (resourceId) { case 2: diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/RpcAbstractLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/RpcAbstractLwM2MIntegrationTest.java new file mode 100644 index 0000000000..36158b2640 --- /dev/null +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/RpcAbstractLwM2MIntegrationTest.java @@ -0,0 +1,307 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.transport.lwm2m.rpc; + +import com.fasterxml.jackson.core.type.TypeReference; +import org.apache.commons.io.IOUtils; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.springframework.util.SocketUtils; +import org.thingsboard.common.util.JacksonUtil; +import org.thingsboard.common.util.ThingsBoardThreadFactory; +import org.thingsboard.server.common.data.Device; +import org.thingsboard.server.common.data.DeviceProfile; +import org.thingsboard.server.common.data.DeviceProfileProvisionType; +import org.thingsboard.server.common.data.DeviceProfileType; +import org.thingsboard.server.common.data.DeviceTransportType; +import org.thingsboard.server.common.data.ResourceType; +import org.thingsboard.server.common.data.TbResource; +import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MClientCredentials; +import org.thingsboard.server.common.data.device.credentials.lwm2m.NoSecClientCredentials; +import org.thingsboard.server.common.data.device.profile.DefaultDeviceProfileConfiguration; +import org.thingsboard.server.common.data.device.profile.DeviceProfileData; +import org.thingsboard.server.common.data.device.profile.DisabledDeviceProfileProvisionConfiguration; +import org.thingsboard.server.common.data.device.profile.Lwm2mDeviceProfileTransportConfiguration; +import org.thingsboard.server.common.data.security.DeviceCredentials; +import org.thingsboard.server.common.data.security.DeviceCredentialsType; +import org.thingsboard.server.controller.AbstractWebsocketTest; +import org.thingsboard.server.controller.TbTestWebSocketClient; +import org.thingsboard.server.dao.service.DaoSqlTest; +import org.thingsboard.server.transport.lwm2m.bootstrap.secure.LwM2MBootstrapConfig; +import org.thingsboard.server.transport.lwm2m.bootstrap.secure.LwM2MBootstrapServers; +import org.thingsboard.server.transport.lwm2m.bootstrap.secure.LwM2MServerBootstrap; +import org.thingsboard.server.transport.lwm2m.client.LwM2MTestClient; +import org.thingsboard.server.transport.lwm2m.secure.credentials.LwM2MCredentials; +import org.thingsboard.server.transport.lwm2m.security.AbstractLwM2MIntegrationTest; + +import java.util.Base64; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.function.Predicate; + +import static org.eclipse.leshan.core.LwM2mId.ACCESS_CONTROL; +import static org.eclipse.leshan.core.LwM2mId.DEVICE; +import static org.eclipse.leshan.core.LwM2mId.FIRMWARE; +import static org.eclipse.leshan.core.LwM2mId.SERVER; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.COAP_CONFIG; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.HOST_BS; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.PORT_BS; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SECURE_PORT; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SECURE_PORT_BS; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SECURITY; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SHORT_SERVER_ID; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.HOST; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.PORT; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SHORT_SERVER_ID_BS; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.objectInstanceId_0; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.BINARY_APP_DATA_CONTAINER; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.TEMPERATURE_SENSOR; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.objectInstanceId_1; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceIdName_19_0_0; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceIdName_19_1_0; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceIdName_3_14; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceIdName_3_9; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_0; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_14; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_9; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resources; + +@DaoSqlTest +public class RpcAbstractLwM2MIntegrationTest extends AbstractWebsocketTest { + + protected final String RPC_TRANSPORT_CONFIGURATION = "{\n" + + " \"type\": \"LWM2M\",\n" + + " \"observeAttr\": {\n" + + " \"keyName\": {\n" + + " \"" + "/" + DEVICE + "/" + objectInstanceId_0 + "/" + resourceId_9 + "\": \"" + resourceIdName_3_9 + "\",\n" + + " \"" + "/" + DEVICE + "/" + objectInstanceId_0 + "/" + resourceId_14 + "\": \"" + resourceIdName_3_14 + "\",\n" + + " \"" + "/" + BINARY_APP_DATA_CONTAINER + "/" + objectInstanceId_0 + "/" + resourceId_0 + "\": \"" + resourceIdName_19_0_0 + "\",\n" + + " \"" + "/" + BINARY_APP_DATA_CONTAINER + "/" + objectInstanceId_1 + "/" + resourceId_0 + "\": \"" + resourceIdName_19_1_0 + "\"\n" + + " },\n" + + " \"observe\": [\n" + + " \"" + "/" + DEVICE + "/" + objectInstanceId_0 + "/" + resourceId_9 + "\",\n" + + " \"" + "/" + BINARY_APP_DATA_CONTAINER + "/" + objectInstanceId_0 + "/" + resourceId_0 + "\"\n" + + " ],\n" + + " \"attribute\": [\n" + + " ],\n" + + " \"telemetry\": [\n" + + " \"" + "/" + DEVICE + "/" + objectInstanceId_0 + "/" + resourceId_9 + "\",\n" + + " \"" + "/" + DEVICE + "/" + objectInstanceId_0 + "/" + resourceId_14 + "\",\n" + + " \"" + "/" + BINARY_APP_DATA_CONTAINER + "/" + objectInstanceId_0 + "/" + resourceId_0 + "\",\n" + + " \"" + "/" + BINARY_APP_DATA_CONTAINER + "/" + objectInstanceId_1 + "/" + resourceId_0 + "\"\n" + + " ],\n" + + " \"attributeLwm2m\": {}\n" + + " },\n" + + " \"bootstrap\": {\n" + + " \"servers\": {\n" + + " \"binding\": \"U\",\n" + + " \"shortId\": 123,\n" + + " \"lifetime\": 300,\n" + + " \"notifIfDisabled\": true,\n" + + " \"defaultMinPeriod\": 1\n" + + " },\n" + + " \"lwm2mServer\": {\n" + + " \"host\": \"localhost\",\n" + + " \"port\": 5686,\n" + + " \"serverId\": 123,\n" + + " \"serverPublicKey\": \"\",\n" + + " \"bootstrapServerIs\": false,\n" + + " \"clientHoldOffTime\": 1,\n" + + " \"bootstrapServerAccountTimeout\": 0\n" + + " },\n" + + " \"bootstrapServer\": {\n" + + " \"host\": \"localhost\",\n" + + " \"port\": 5687,\n" + + " \"serverId\": 111,\n" + + " \"securityMode\": \"NO_SEC\",\n" + + " \"serverPublicKey\": \"\",\n" + + " \"bootstrapServerIs\": true,\n" + + " \"clientHoldOffTime\": 1,\n" + + " \"bootstrapServerAccountTimeout\": 0\n" + + " }\n" + + " },\n" + + " \"clientLwM2mSettings\": {\n" + + " \"clientOnlyObserveAfterConnect\": 1,\n" + + " \"fwUpdateStrategy\": 1,\n" + + " \"swUpdateStrategy\": 1\n" + + " }\n" + + "}"; + + protected static final String ENDPOINT_RPC = "deviceEndpointRpc"; + protected ScheduledExecutorService executor; + protected TbTestWebSocketClient wsClient; + protected DeviceProfile deviceProfile; + + protected NoSecClientCredentials clientCredentials; + protected LwM2MTestClient client; + protected String deviceId; + public Set expectedObjects; + public Set expectedObjectIdVers; + public Set expectedInstances; + public Set expectedObjectIdVerInstances; + + protected String objectInstanceIdVer_1; + protected String objectIdVer_2; + private static final Predicate predicate_3 = path -> (!((String) path).contains("/" + TEMPERATURE_SENSOR) && ((String) path).contains("/" + DEVICE)); + protected String objectIdVer_3; + protected String objectInstanceIdVer_3; + protected String objectInstanceIdVer_5; + protected String objectIdVer_19; + + public RpcAbstractLwM2MIntegrationTest(){ } + + @Before + public void beforeTest() throws Exception { + executor = Executors.newScheduledThreadPool(10, ThingsBoardThreadFactory.forName("test-lwm2m-rpc-scheduled")); + loginTenantAdmin(); + wsClient = buildAndConnectWebSocketClient(); + createDeviceProfile(RPC_TRANSPORT_CONFIGURATION); + clientCredentials = new NoSecClientCredentials(); + clientCredentials.setEndpoint(ENDPOINT_RPC); + Device device = createDevice(clientCredentials); + deviceId = device.getId().getId().toString(); + client = new LwM2MTestClient(executor, ENDPOINT_RPC); + int clientPort = SocketUtils.findAvailableTcpPort(); + client.init(SECURITY, COAP_CONFIG, clientPort); + for (String resourceName : resources) { + TbResource lwModel = new TbResource(); + lwModel.setResourceType(ResourceType.LWM2M_MODEL); + lwModel.setTitle(resourceName); + lwModel.setFileName(resourceName); + lwModel.setTenantId(tenantId); + byte[] bytes = IOUtils.toByteArray(AbstractLwM2MIntegrationTest.class.getClassLoader().getResourceAsStream("lwm2m/" + resourceName)); + lwModel.setData(Base64.getEncoder().encodeToString(bytes)); + lwModel = doPostWithTypedResponse("/api/resource", lwModel, new TypeReference<>() { + }); + Assert.assertNotNull(lwModel); + } + wsClient = buildAndConnectWebSocketClient(); + expectedObjects = ConcurrentHashMap.newKeySet(); + expectedObjectIdVers = ConcurrentHashMap.newKeySet(); + expectedInstances = ConcurrentHashMap.newKeySet(); + expectedObjectIdVerInstances = ConcurrentHashMap.newKeySet(); + client.getClient().getObjectTree().getObjectEnablers().forEach((key, val) -> { + if (key > 0) { + String objectVerId = "/" + key; + if (!val.getObjectModel().version.equals("1.0")) { + objectVerId += ("_" + val.getObjectModel().version); + } + expectedObjects.add("/" + key); + expectedObjectIdVers.add(objectVerId); + String finalObjectVerId = objectVerId; + val.getAvailableInstanceIds().forEach(inststanceId -> { + expectedInstances.add("/" + key + "/" + inststanceId); + expectedObjectIdVerInstances.add(finalObjectVerId + "/" + inststanceId); + }); + } + }); + objectInstanceIdVer_1 = (String) expectedObjectIdVerInstances.stream().filter(path -> (!((String) path).contains("/" + BINARY_APP_DATA_CONTAINER) && ((String) path).contains("/" + SERVER))).findFirst().get(); + objectIdVer_2 = (String) expectedObjectIdVers.stream().filter(path -> ((String) path).contains("/" + ACCESS_CONTROL)).findFirst().get(); + objectIdVer_3 = (String) expectedObjects.stream().filter(predicate_3).findFirst().get(); + objectIdVer_19 = (String) expectedObjects.stream().filter(predicate_3).findFirst().get(); + objectInstanceIdVer_3 = (String) expectedObjectIdVerInstances.stream().filter(predicate_3).findFirst().get(); + objectInstanceIdVer_5 = (String) expectedObjectIdVerInstances.stream().filter(path -> ((String) path).contains("/" + FIRMWARE)).findFirst().get(); + objectIdVer_19 = (String) expectedObjectIdVers.stream().filter(path -> ((String) path).contains("/" + BINARY_APP_DATA_CONTAINER)).findFirst().get(); + } + + protected void createDeviceProfile(String transportConfiguration) throws Exception { + deviceProfile = new DeviceProfile(); + + deviceProfile.setName("LwM2M_RPC"); + deviceProfile.setType(DeviceProfileType.DEFAULT); + deviceProfile.setTenantId(tenantId); + deviceProfile.setTransportType(DeviceTransportType.LWM2M); + deviceProfile.setProvisionType(DeviceProfileProvisionType.DISABLED); + deviceProfile.setDescription(deviceProfile.getName()); + + DeviceProfileData deviceProfileData = new DeviceProfileData(); + deviceProfileData.setConfiguration(new DefaultDeviceProfileConfiguration()); + deviceProfileData.setProvisionConfiguration(new DisabledDeviceProfileProvisionConfiguration(null)); + deviceProfileData.setTransportConfiguration(JacksonUtil.fromString(transportConfiguration, Lwm2mDeviceProfileTransportConfiguration.class)); + deviceProfile.setProfileData(deviceProfileData); + + deviceProfile = doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class); + Assert.assertNotNull(deviceProfile); + } + + + protected Device createDevice(LwM2MClientCredentials clientCredentials) throws Exception { + Device device = new Device(); + device.setName("Device A"); + device.setDeviceProfileId(deviceProfile.getId()); + device.setTenantId(tenantId); + device = doPost("/api/device", device, Device.class); + Assert.assertNotNull(device); + DeviceCredentials deviceCredentials = + doGet("/api/device/" + device.getId().getId().toString() + "/credentials", DeviceCredentials.class); + Assert.assertEquals(device.getId(), deviceCredentials.getDeviceId()); + deviceCredentials.setCredentialsType(DeviceCredentialsType.LWM2M_CREDENTIALS); + LwM2MCredentials credentials = new LwM2MCredentials(); + credentials.setClient(clientCredentials); + credentials.setBootstrap(createBootstrapConfig()); + deviceCredentials.setCredentialsValue(JacksonUtil.toString(credentials)); + doPost("/api/device/credentials", deviceCredentials).andExpect(status().isOk()); + return device; + } + + protected LwM2MBootstrapConfig createBootstrapConfig() { + LwM2MBootstrapConfig bootstrap = new LwM2MBootstrapConfig(); + LwM2MBootstrapServers servers = new LwM2MBootstrapServers(); + servers.setShortId(SHORT_SERVER_ID); + bootstrap.setServers(servers); + LwM2MServerBootstrap server = new LwM2MServerBootstrap(); + server.setHost(HOST); + server.setPort(PORT); + server.setSecurityHost(HOST); + server.setSecurityPort(SECURE_PORT); + server.setServerId(servers.getShortId()); + server.setBootstrapServerIs(false); + bootstrap.setLwm2mServer(server); + LwM2MServerBootstrap serverBS = new LwM2MServerBootstrap(); + serverBS.setHost(HOST_BS); + serverBS.setPort(PORT_BS); + serverBS.setSecurityHost(HOST_BS); + serverBS.setSecurityPort(SECURE_PORT_BS); + serverBS.setServerId(SHORT_SERVER_ID_BS); + serverBS.setBootstrapServerIs(true); + bootstrap.setBootstrapServer(serverBS); + return bootstrap; + } + + protected String objectIdVerToObjectId(String objectIdVer) { + return objectIdVer.contains("_") ? objectIdVer.split("_")[0] : objectIdVer; + } + + protected String objectInstanceIdVerToObjectInstanceId(String objectInstanceIdVer) { + String[] objectIdVer = objectInstanceIdVer.split("/"); + return objectIdVer[1].contains("_") ? objectIdVer[1].split("_")[0] + "/" + objectIdVer[2] : objectInstanceIdVer; + } + + @After + public void after() { + if (client != null) { + client.destroy(); + } + executor.shutdownNow(); + if (wsClient != null) { + wsClient.close(); + } + } +} diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationCreateTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationCreateTest.java new file mode 100644 index 0000000000..a5672be133 --- /dev/null +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationCreateTest.java @@ -0,0 +1,77 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.transport.lwm2m.rpc.sql; + +import com.fasterxml.jackson.databind.node.ObjectNode; +import org.eclipse.leshan.core.ResponseCode; +import org.junit.Test; +import org.thingsboard.common.util.JacksonUtil; +import org.thingsboard.server.transport.lwm2m.rpc.RpcAbstractLwM2MIntegrationTest; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.objectInstanceId_0; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_0; + + +public class RpcLwm2mIntegrationCreateTest extends RpcAbstractLwM2MIntegrationTest { + + + /** + * Create {"id":"/19_1.1","value":{"0":{"0":"00AC"}, "1":1}} + * + * create_2_instances_in_object + * new ObjectInstance if Object is Multiple & Resource Single + * Create {"id":"/19_1.1/0","value":{"0":{"0":"00AC", "1":1}}} + * {"result":"BAD_REQUEST","error":"instance 0 already exists"} + * + */ + @Test + public void testCreateObjectInstanceWithInstanceIdAlreadyExistsByIdKey_Result_BAD_REQUEST() throws Exception { + String expectedPath = objectIdVer_19 + "/" + objectInstanceId_0; + String expectedValue = "{\"" + resourceId_0 + "\":{\"0\":\"00AC\"}, \"1\":1}"; + String actualResult = sendRPCreateById(expectedPath, expectedValue); + ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); + assertEquals(ResponseCode.BAD_REQUEST.getName(), rpcActualResult.get("result").asText()); + String expected = "instance " + objectInstanceId_0 + " already exists"; + String actual = rpcActualResult.get("error").asText(); + assertTrue(actual.equals(expected)); + } + + /** + * failed: cannot_create_mandatory_single_object + * Create {"id":"/3/2","value":{"0":"00AC"}} + */ + + + /** + * failed: cannot_create_instance_of_security_object + * Create {"id":"/0/2","value":{"0":"00AC"}} + */ + + /** + * failed: cannot_create_instance_of_absent_object + * Create {"id":"/50/2","value":{"0":"00AC"}} + */ + + + private String sendRPCreateById(String path, String value) throws Exception { + String setRpcRequest = "{\"method\": \"Create\", \"params\": {\"id\": \"" + path + "\", \"value\": " + value + " }}"; + return doPostAsync("/api/plugins/rpc/twoway/" + deviceId, setRpcRequest, String.class, status().isOk()); + } + +} diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/AbstractLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/AbstractLwM2MIntegrationTest.java similarity index 97% rename from application/src/test/java/org/thingsboard/server/transport/lwm2m/AbstractLwM2MIntegrationTest.java rename to application/src/test/java/org/thingsboard/server/transport/lwm2m/security/AbstractLwM2MIntegrationTest.java index e008e61f21..2c47d5cc80 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/AbstractLwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/AbstractLwM2MIntegrationTest.java @@ -13,10 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.transport.lwm2m; +package org.thingsboard.server.transport.lwm2m.security; import com.fasterxml.jackson.core.type.TypeReference; import org.apache.commons.io.IOUtils; +import org.eclipse.californium.core.CoapClient; import org.eclipse.californium.core.network.config.NetworkConfig; import org.eclipse.leshan.client.object.Security; import org.eclipse.leshan.core.util.Hex; @@ -26,6 +27,7 @@ import org.junit.Before; import org.springframework.mock.web.MockMultipartFile; import org.springframework.test.web.servlet.request.MockMultipartHttpServletRequestBuilder; import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; +import org.springframework.util.SocketUtils; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.common.util.ThingsBoardThreadFactory; import org.thingsboard.server.common.data.Device; @@ -86,6 +88,8 @@ import static org.eclipse.leshan.client.object.Security.noSec; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import static org.thingsboard.server.common.data.ota.OtaPackageType.FIRMWARE; import static org.thingsboard.server.common.data.ota.OtaPackageType.SOFTWARE; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.COAP_CONFIG; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SECURITY; @DaoSqlTest public abstract class AbstractLwM2MIntegrationTest extends AbstractWebsocketTest { @@ -169,14 +173,9 @@ public abstract class AbstractLwM2MIntegrationTest extends AbstractWebsocketTest // certificates trustedby the server (should contain rootCA) protected final Certificate[] trustedCertificates = new Certificate[1]; - protected static final int SECURE_PORT = 5686; - protected static final NetworkConfig SECURE_COAP_CONFIG = new NetworkConfig().setString("COAP_SECURE_PORT", Integer.toString(SECURE_PORT)); protected static final String ENDPOINT = "deviceAEndpoint"; - protected static final String SECURE_URI = "coaps://localhost:" + SECURE_PORT; - protected static final int PORT = 5685; - protected static final Security SECURITY = noSec("coap://localhost:" + PORT, 123); - protected static final NetworkConfig COAP_CONFIG = new NetworkConfig().setString("COAP_PORT", Integer.toString(PORT)); + protected CoapClient client; public AbstractLwM2MIntegrationTest() { // create client credentials @@ -394,8 +393,8 @@ public abstract class AbstractLwM2MIntegrationTest extends AbstractWebsocketTest wsClient.registerWaitForUpdate(); client = new LwM2MTestClient(executor, endpoint); - - client.init(security, coapConfig); + int clientPort = SocketUtils.findAvailableTcpPort(); + client.init(security, coapConfig, clientPort); String msg = wsClient.waitForUpdate(); EntityDataUpdate update = mapper.readValue(msg, EntityDataUpdate.class); diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/NoSecLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/NoSecLwM2MIntegrationTest.java new file mode 100644 index 0000000000..af13dd62c4 --- /dev/null +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/NoSecLwM2MIntegrationTest.java @@ -0,0 +1,36 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.transport.lwm2m.security.sql; + +import lombok.extern.slf4j.Slf4j; +import org.junit.Test; +import org.thingsboard.server.common.data.device.credentials.lwm2m.NoSecClientCredentials; +import org.thingsboard.server.transport.lwm2m.security.AbstractLwM2MIntegrationTest; + +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.COAP_CONFIG; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SECURITY; + +@Slf4j +public class NoSecLwM2MIntegrationTest extends AbstractLwM2MIntegrationTest { + + @Test + public void testConnectAndObserveTelemetry() throws Exception { + NoSecClientCredentials clientCredentials = new NoSecClientCredentials(); + clientCredentials.setEndpoint(ENDPOINT); + super.basicTestConnectionObserveTelemetry(SECURITY, clientCredentials, COAP_CONFIG, ENDPOINT); + } + +} diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/sql/NoSecLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/OtaLwM2MIntegrationTest.java similarity index 71% rename from application/src/test/java/org/thingsboard/server/transport/lwm2m/sql/NoSecLwM2MIntegrationTest.java rename to application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/OtaLwM2MIntegrationTest.java index 168e3cbdec..a8a23707c5 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/sql/NoSecLwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/OtaLwM2MIntegrationTest.java @@ -13,20 +13,20 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.transport.lwm2m.sql; +package org.thingsboard.server.transport.lwm2m.security.sql; import com.fasterxml.jackson.core.type.TypeReference; import lombok.extern.slf4j.Slf4j; -import org.junit.After; import org.junit.Assert; import org.junit.Test; +import org.springframework.util.SocketUtils; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.device.credentials.lwm2m.NoSecClientCredentials; import org.thingsboard.server.common.data.kv.KvEntry; import org.thingsboard.server.common.data.kv.TsKvEntry; import org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus; -import org.thingsboard.server.transport.lwm2m.AbstractLwM2MIntegrationTest; import org.thingsboard.server.transport.lwm2m.client.LwM2MTestClient; +import org.thingsboard.server.transport.lwm2m.security.AbstractLwM2MIntegrationTest; import java.util.Arrays; import java.util.Collections; @@ -48,9 +48,11 @@ import static org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus.QUEU import static org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus.UPDATED; import static org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus.UPDATING; import static org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus.VERIFIED; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.COAP_CONFIG; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SECURITY; @Slf4j -public class NoSecLwM2MIntegrationTest extends AbstractLwM2MIntegrationTest { +public class OtaLwM2MIntegrationTest extends AbstractLwM2MIntegrationTest { public static final int TIMEOUT = 30; private final String OTA_TRANSPORT_CONFIGURATION = "{\n" + @@ -130,33 +132,19 @@ public class NoSecLwM2MIntegrationTest extends AbstractLwM2MIntegrationTest { " \"type\": \"LWM2M\"\n" + "}"; - LwM2MTestClient client = null; - - @After - public void tearDown() { - if (client != null) { - client.destroy(); - } - } - - @Test - public void testConnectAndObserveTelemetry() throws Exception { - NoSecClientCredentials clientCredentials = new NoSecClientCredentials(); - clientCredentials.setEndpoint(ENDPOINT); - super.basicTestConnectionObserveTelemetry(SECURITY, clientCredentials, COAP_CONFIG, ENDPOINT); - } - @Test public void testFirmwareUpdateWithClientWithoutFirmwareInfo() throws Exception { LwM2MTestClient client = null; + String endpoint = "WithoutFirmwareInfoDevice"; try { createDeviceProfile(TRANSPORT_CONFIGURATION); NoSecClientCredentials clientCredentials = new NoSecClientCredentials(); - clientCredentials.setEndpoint(ENDPOINT); + clientCredentials.setEndpoint(endpoint); Device device = createDevice(clientCredentials); - client = new LwM2MTestClient(executor, ENDPOINT); - client.init(SECURITY, COAP_CONFIG); + client = new LwM2MTestClient(executor, endpoint); + int clientPort = SocketUtils.findAvailableTcpPort(); + client.init(SECURITY, COAP_CONFIG, clientPort); Thread.sleep(1000); @@ -183,27 +171,31 @@ public class NoSecLwM2MIntegrationTest extends AbstractLwM2MIntegrationTest { @Test public void testFirmwareUpdateByObject5() throws Exception { LwM2MTestClient client = null; + String endpoint = "Ota5_Device"; + List expectedStatuses = Arrays.asList(QUEUED, INITIATED, DOWNLOADING, DOWNLOADED, UPDATING, UPDATED); try { createDeviceProfile(OTA_TRANSPORT_CONFIGURATION); NoSecClientCredentials clientCredentials = new NoSecClientCredentials(); - clientCredentials.setEndpoint("OTA_" + ENDPOINT); + clientCredentials.setEndpoint(endpoint); Device device = createDevice(clientCredentials); device.setFirmwareId(createFirmware().getId()); - device = doPost("/api/device", device, Device.class); + Device saveDevice = doPost("/api/device", device, Device.class); Thread.sleep(1000); - client = new LwM2MTestClient(executor, "OTA_" + ENDPOINT); - client.init(SECURITY, COAP_CONFIG); + client = new LwM2MTestClient(executor, endpoint); + int clientPort = SocketUtils.findAvailableTcpPort(); + client.init(SECURITY, COAP_CONFIG, clientPort); - Thread.sleep(3000); + List ts = await("await on timeseries") + .atMost(30, TimeUnit.SECONDS) + .until(()-> toTimeseries(doGetAsyncTyped("/api/plugins/telemetry/DEVICE/" + saveDevice.getId().getId() + "/values/timeseries?orderBy=ASC&keys=fw_state&startTs=0&endTs=" + System.currentTimeMillis(), new TypeReference<>() { + })), hasSize(expectedStatuses.size())); - List ts = toTimeseries(doGetAsyncTyped("/api/plugins/telemetry/DEVICE/" + device.getId().getId() + "/values/timeseries?orderBy=ASC&keys=fw_state&startTs=0&endTs=" + System.currentTimeMillis(), new TypeReference<>() { - })); List statuses = ts.stream().sorted(Comparator.comparingLong(TsKvEntry::getTs)).map(KvEntry::getValueAsString).map(OtaPackageUpdateStatus::valueOf).collect(Collectors.toList()); - List expectedStatuses = Arrays.asList(QUEUED, INITIATED, DOWNLOADING, DOWNLOADED, UPDATING, UPDATED); + Assert.assertEquals(expectedStatuses, statuses); } finally { @@ -223,41 +215,49 @@ public class NoSecLwM2MIntegrationTest extends AbstractLwM2MIntegrationTest { //given final List expectedStatuses = List.of( QUEUED, INITIATED, DOWNLOADING, DOWNLOADING, DOWNLOADING, DOWNLOADED, VERIFIED, UPDATED); + LwM2MTestClient client = null; + String endpoint = "Ota9_Device"; + try { + createDeviceProfile(OTA_TRANSPORT_CONFIGURATION); + NoSecClientCredentials clientCredentials = new NoSecClientCredentials(); + clientCredentials.setEndpoint(endpoint); + final Device device = createDevice(clientCredentials); + device.setSoftwareId(createSoftware().getId()); + + final Device savedDevice = doPost("/api/device", device, Device.class); //sync call + assertThat(savedDevice).as("saved device").isNotNull(); + assertThat(getDeviceFromAPI(device.getId().getId())).as("fetched device").isEqualTo(savedDevice); + + //when + log.warn("Init the client..."); + client = new LwM2MTestClient(executor, endpoint); + int clientPort = SocketUtils.findAvailableTcpPort(); + client.init(SECURITY, COAP_CONFIG, clientPort); + + log.warn("AWAIT atMost {} SECONDS on timeseries List by API with list size {}...", TIMEOUT, expectedStatuses.size()); + List ts = await("await on timeseries") + .atMost(30, TimeUnit.SECONDS) + .until(() -> getSwStateTelemetryFromAPI(device.getId().getId()), hasSize(expectedStatuses.size())); + log.warn("Got the ts: {}", ts); + + ts.sort(Comparator.comparingLong(TsKvEntry::getTs)); + log.warn("Ts ordered: {}", ts); + ts.forEach((x) -> log.warn("ts: {} ", x)); - createDeviceProfile(OTA_TRANSPORT_CONFIGURATION); - NoSecClientCredentials clientCredentials = new NoSecClientCredentials(); - clientCredentials.setEndpoint("OTA_" + ENDPOINT); - final Device device = createDevice(clientCredentials); - device.setSoftwareId(createSoftware().getId()); - - final Device savedDevice = doPost("/api/device", device, Device.class); //sync call - assertThat(savedDevice).as("saved device").isNotNull(); - assertThat(getDeviceFromAPI(device.getId().getId())).as("fetched device").isEqualTo(savedDevice); - - //when - log.warn("Init the client..."); - client = new LwM2MTestClient(executor, "OTA_" + ENDPOINT); - client.init(SECURITY, COAP_CONFIG); - - log.warn("AWAIT atMost {} SECONDS on timeseries List by API with list size {}...", TIMEOUT, expectedStatuses.size()); - List ts = await("await on timeseries") - .atMost(30, TimeUnit.SECONDS) - .until(() -> getSwStateTelemetryFromAPI(device.getId().getId()), hasSize(expectedStatuses.size())); - log.warn("Got the ts: {}", ts); - - ts.sort(Comparator.comparingLong(TsKvEntry::getTs)); - log.warn("Ts ordered: {}", ts); - ts.forEach((x) -> log.warn("ts: {} ", x)); - - List statuses = ts.stream().map(KvEntry::getValueAsString).map(OtaPackageUpdateStatus::valueOf).collect(Collectors.toList()); - log.warn("Converted ts to statuses: {}", statuses); + List statuses = ts.stream().map(KvEntry::getValueAsString).map(OtaPackageUpdateStatus::valueOf).collect(Collectors.toList()); + log.warn("Converted ts to statuses: {}", statuses); - assertThat(statuses).isEqualTo(expectedStatuses); + assertThat(statuses).isEqualTo(expectedStatuses); + } finally { + if (client != null) { + client.destroy(); + } + } } private Device getDeviceFromAPI(UUID deviceId) throws Exception { final Device device = doGet("/api/device/" + deviceId, Device.class); - log.warn("Fetched device by API for deviceId {}, device is {}", deviceId, device); + log.trace("Fetched device by API for deviceId {}, device is {}", deviceId, device); return device; } diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/sql/PskLwm2mIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/PskLwm2mIntegrationTest.java similarity index 79% rename from application/src/test/java/org/thingsboard/server/transport/lwm2m/sql/PskLwm2mIntegrationTest.java rename to application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/PskLwm2mIntegrationTest.java index 63f8aab381..014ab752fe 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/sql/PskLwm2mIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/PskLwm2mIntegrationTest.java @@ -13,17 +13,20 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.transport.lwm2m.sql; +package org.thingsboard.server.transport.lwm2m.security.sql; import org.eclipse.leshan.client.object.Security; import org.eclipse.leshan.core.util.Hex; import org.junit.Test; import org.thingsboard.server.common.data.device.credentials.lwm2m.PSKClientCredentials; -import org.thingsboard.server.transport.lwm2m.AbstractLwM2MIntegrationTest; +import org.thingsboard.server.transport.lwm2m.security.AbstractLwM2MIntegrationTest; import java.nio.charset.StandardCharsets; import static org.eclipse.leshan.client.object.Security.psk; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SECURE_COAP_CONFIG; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SECURE_URI; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SHORT_SERVER_ID; public class PskLwm2mIntegrationTest extends AbstractLwM2MIntegrationTest { @@ -36,7 +39,7 @@ public class PskLwm2mIntegrationTest extends AbstractLwM2MIntegrationTest { clientCredentials.setKey(pskKey); clientCredentials.setIdentity(pskIdentity); Security security = psk(SECURE_URI, - 123, + SHORT_SERVER_ID, pskIdentity.getBytes(StandardCharsets.UTF_8), Hex.decodeHex(pskKey.toCharArray())); super.basicTestConnectionObserveTelemetry(security, clientCredentials, SECURE_COAP_CONFIG, ENDPOINT); diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/sql/RpkLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/RpkLwM2MIntegrationTest.java similarity index 78% rename from application/src/test/java/org/thingsboard/server/transport/lwm2m/sql/RpkLwM2MIntegrationTest.java rename to application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/RpkLwM2MIntegrationTest.java index 3bb83a3367..02d57d6782 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/sql/RpkLwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/RpkLwM2MIntegrationTest.java @@ -13,15 +13,18 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.transport.lwm2m.sql; +package org.thingsboard.server.transport.lwm2m.security.sql; import org.eclipse.leshan.client.object.Security; import org.eclipse.leshan.core.util.Hex; import org.junit.Test; import org.thingsboard.server.common.data.device.credentials.lwm2m.RPKClientCredentials; -import org.thingsboard.server.transport.lwm2m.AbstractLwM2MIntegrationTest; +import org.thingsboard.server.transport.lwm2m.security.AbstractLwM2MIntegrationTest; import static org.eclipse.leshan.client.object.Security.rpk; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SECURE_COAP_CONFIG; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SECURE_URI; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SHORT_SERVER_ID; public class RpkLwM2MIntegrationTest extends AbstractLwM2MIntegrationTest { @@ -31,7 +34,7 @@ public class RpkLwM2MIntegrationTest extends AbstractLwM2MIntegrationTest { rpkClientCredentials.setEndpoint(ENDPOINT); rpkClientCredentials.setKey(Hex.encodeHexString(clientPublicKey.getEncoded())); Security security = rpk(SECURE_URI, - 123, + SHORT_SERVER_ID, clientPublicKey.getEncoded(), clientPrivateKey.getEncoded(), serverX509Cert.getPublicKey().getEncoded()); diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/sql/X509LwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/X509LwM2MIntegrationTest.java similarity index 55% rename from application/src/test/java/org/thingsboard/server/transport/lwm2m/sql/X509LwM2MIntegrationTest.java rename to application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/X509LwM2MIntegrationTest.java index 7f6ac87fb9..cd172bda46 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/sql/X509LwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/X509LwM2MIntegrationTest.java @@ -13,16 +13,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.transport.lwm2m.sql; +package org.thingsboard.server.transport.lwm2m.security.sql; import org.eclipse.leshan.client.object.Security; -import org.junit.Ignore; import org.junit.Test; import org.thingsboard.server.common.data.device.credentials.lwm2m.X509ClientCredentials; -import org.thingsboard.server.common.transport.util.SslUtil; -import org.thingsboard.server.transport.lwm2m.AbstractLwM2MIntegrationTest; +import org.thingsboard.server.transport.lwm2m.security.AbstractLwM2MIntegrationTest; import static org.eclipse.leshan.client.object.Security.x509; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SECURE_COAP_CONFIG; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SECURE_URI; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SHORT_SERVER_ID; public class X509LwM2MIntegrationTest extends AbstractLwM2MIntegrationTest { @@ -31,25 +32,25 @@ public class X509LwM2MIntegrationTest extends AbstractLwM2MIntegrationTest { X509ClientCredentials credentials = new X509ClientCredentials(); credentials.setEndpoint(ENDPOINT); Security security = x509(SECURE_URI, - 123, + SHORT_SERVER_ID, clientX509Cert.getEncoded(), clientPrivateKeyFromCert.getEncoded(), serverX509Cert.getEncoded()); super.basicTestConnectionObserveTelemetry(security, credentials, SECURE_COAP_CONFIG, ENDPOINT); } - @Ignore //See LwM2mClientContextImpl.unregister - @Test - public void testConnectWithCertAndObserveTelemetry() throws Exception { - X509ClientCredentials credentials = new X509ClientCredentials(); - credentials.setEndpoint(ENDPOINT); - credentials.setCert(SslUtil.getCertificateString(clientX509CertNotTrusted)); - Security security = x509(SECURE_URI, - 123, - clientX509CertNotTrusted.getEncoded(), - clientPrivateKeyFromCert.getEncoded(), - serverX509Cert.getEncoded()); - super.basicTestConnectionObserveTelemetry(security, credentials, SECURE_COAP_CONFIG, ENDPOINT); - } +// @Ignore //See LwM2mClientContextImpl.unregister +// @Test +// public void testConnectWithCertAndObserveTelemetry() throws Exception { +// X509ClientCredentials credentials = new X509ClientCredentials(); +// credentials.setEndpoint(ENDPOINT); +// credentials.setCert(SslUtil.getCertificateString(clientX509CertNotTrusted)); +// Security security = x509(SECURE_URI, +// 123, +// clientX509CertNotTrusted.getEncoded(), +// clientPrivateKeyFromCert.getEncoded(), +// serverX509Cert.getEncoded()); +// super.basicTestConnectionObserveTelemetry(security, credentials, SECURE_COAP_CONFIG, ENDPOINT); +// } } diff --git a/application/src/test/resources/lwm2m/19.xml b/application/src/test/resources/lwm2m/19.xml new file mode 100644 index 0000000000..ffa21864b7 --- /dev/null +++ b/application/src/test/resources/lwm2m/19.xml @@ -0,0 +1,144 @@ + + + + + BinaryAppDataContainer + + 19 + urn:oma:lwm2m:oma:19:1.1 + 1.1 + 1.1 + Multiple + Optional + + Data + RW + Multiple + Mandatory + Opaque + + + + + Data Priority + RW + Single + Optional + Integer + 1 bytes + + + + Data Creation Time + RW + Single + Optional + Time + + + + + Data Description + RW + Single + Optional + String + 32 bytes + + + + Data Format + RW + Single + Optional + String + 32 bytes + + + + App ID + RW + Single + Optional + Integer + 2 bytes + + + + + + diff --git a/application/src/test/resources/lwm2m/3303.xml b/application/src/test/resources/lwm2m/3303.xml new file mode 100644 index 0000000000..a6e5406b08 --- /dev/null +++ b/application/src/test/resources/lwm2m/3303.xml @@ -0,0 +1,103 @@ + + + + + Temperature + This IPSO object should be used with a temperature sensor to report a temperature measurement. It also provides resources for minimum/maximum measured values and the minimum/maximum range that can be measured by the temperature sensor. An example measurement unit is degrees Celsius. + 3303 + urn:oma:lwm2m:ext:3303 + 1.0 + 1.0 + Multiple + Optional + + + Sensor Value + R + Single + Mandatory + Float + + + Last or Current Measured Value from the Sensor + + + Min Measured Value + R + Single + Optional + Float + + + The minimum value measured by the sensor since power ON or reset + + + Max Measured Value + R + Single + Optional + Float + + + The maximum value measured by the sensor since power ON or reset + + + Min Range Value + R + Single + Optional + Float + + + The minimum value that can be measured by the sensor + + + Max Range Value + R + Single + Optional + Float + + + The maximum value that can be measured by the sensor + + + Sensor Units + R + Single + Optional + String + + + Measurement Units Definition. + + + Reset Min and Max Measured Values + E + Single + Optional + + + + Reset the Min and Max Measured Values to Current Value + + + + + diff --git a/application/src/test/resources/lwm2m/6.xml b/application/src/test/resources/lwm2m/6.xml new file mode 100644 index 0000000000..8b1b3da625 --- /dev/null +++ b/application/src/test/resources/lwm2m/6.xml @@ -0,0 +1,143 @@ + + + + + + + Location + + 6 + urn:oma:lwm2m:oma:6 + 1.0 + 1.0 + Single + Optional + + + Latitude + R + Single + Mandatory + Float + + lat + + + + Longitude + R + Single + Mandatory + Float + + lon + + + + Altitude + R + Single + Optional + Float + + m + + + + Radius + R + Single + Optional + Float + + m + + + + Velocity + R + Single + Optional + Opaque + + + + + + Timestamp + R + Single + Mandatory + Time + + + + + Speed + R + Single + Optional + Float + + m/s + + + + + From 6f32942f37a89368dedcd6db753c533e35921142 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Mon, 30 Aug 2021 19:08:18 +0300 Subject: [PATCH 009/432] lwm2m: fix bug execute --- .../lwm2m/server/LwM2mTransportUtil.java | 7 +++++++ .../DefaultLwM2mDownlinkMsgHandler.java | 21 +++++++++++++++++-- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportUtil.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportUtil.java index 8b65e55ad5..0fe6b67642 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportUtil.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportUtil.java @@ -23,8 +23,11 @@ import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.eclipse.leshan.core.attributes.Attribute; import org.eclipse.leshan.core.attributes.AttributeSet; +import org.eclipse.leshan.core.model.LwM2mModel; +import org.eclipse.leshan.core.model.ObjectLoader; import org.eclipse.leshan.core.model.ObjectModel; import org.eclipse.leshan.core.model.ResourceModel; +import org.eclipse.leshan.core.model.StaticModel; import org.eclipse.leshan.core.node.LwM2mMultipleResource; import org.eclipse.leshan.core.node.LwM2mPath; import org.eclipse.leshan.core.node.LwM2mResource; @@ -522,4 +525,8 @@ public class LwM2mTransportUtil { return opaque.length() > 1024 ? opaque.substring(0, 1024) : opaque; } + public static LwM2mModel createModelsDefault() { + return new StaticModel(ObjectLoader.loadDefault()); + } + } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2mDownlinkMsgHandler.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2mDownlinkMsgHandler.java index 5a6ac6b466..2ef832333b 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2mDownlinkMsgHandler.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2mDownlinkMsgHandler.java @@ -21,6 +21,7 @@ import org.eclipse.leshan.core.Link; import org.eclipse.leshan.core.LwM2m; import org.eclipse.leshan.core.attributes.Attribute; import org.eclipse.leshan.core.attributes.AttributeSet; +import org.eclipse.leshan.core.model.LwM2mModel; import org.eclipse.leshan.core.model.ObjectModel; import org.eclipse.leshan.core.model.ResourceModel; import org.eclipse.leshan.core.node.LwM2mObjectInstance; @@ -95,7 +96,9 @@ import static org.eclipse.leshan.core.attributes.Attribute.STEP; import static org.eclipse.leshan.core.model.ResourceModel.Type.OBJLNK; import static org.eclipse.leshan.core.model.ResourceModel.Type.OPAQUE; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertMultiResourceValuesFromRpcBody; +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.createModelsDefault; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.fromVersionedIdToObjectId; +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.getVerFromPathIdVerOrId; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.validateVersionedId; @Slf4j @@ -195,9 +198,20 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im @Override public void sendExecuteRequest(LwM2mClient client, TbLwM2MExecuteRequest request, DownlinkRequestCallback callback) { try { + validateVersionedId(client, request); + LwM2mPath pathIds = new LwM2mPath(fromVersionedIdToObjectId(request.getVersionedId())); ResourceModel resourceModelExecute = client.getResourceModel(request.getVersionedId(), this.config.getModelProvider()); - if (resourceModelExecute != null) { - validateVersionedId(client, request); + if (resourceModelExecute == null) { + LwM2mModel model = createModelsDefault(); + if (pathIds.isResource()) { + resourceModelExecute = model.getResourceModel(pathIds.getObjectId(), pathIds.getResourceId()); + } + } + if (resourceModelExecute == null) { + callback.onValidationError(request.toString(), "ResourceModel with " + request.getVersionedId() + " is absent in system. Need ddd Lwm2m Model with id=" + + pathIds.getObjectId() + " ver=" + getVerFromPathIdVerOrId(request.getVersionedId()) + " to profile."); + } + else if (resourceModelExecute.operations.isExecutable()) { ExecuteRequest downlink; if (request.getParams() != null && !resourceModelExecute.multiple) { downlink = new ExecuteRequest(request.getObjectId(), (String) this.converter.convertValue(request.getParams(), resourceModelExecute.type, ResourceModel.Type.STRING, new LwM2mPath(request.getObjectId()))); @@ -206,6 +220,9 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im } sendSimpleRequest(client, downlink, request.getTimeout(), callback); } + else { + callback.onValidationError(request.toString(), "Resource with " + request.getVersionedId() + " is not executable."); + } } catch (InvalidRequestException e) { callback.onValidationError(request.toString(), e.getMessage()); } From bed8881d93b9a1ce90f2e9dd0546a5a506a5175f Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Mon, 30 Aug 2021 20:48:36 +0300 Subject: [PATCH 010/432] lwm2m: abstract test create --- ...a => AbstractRpcLwM2MIntegrationTest.java} | 12 +- .../sql/RpcLwm2mIntegrationCreateTest.java | 4 +- .../AbstractLwM2MIntegrationTest.java | 80 ++++++------ .../security/sql/OtaLwM2MIntegrationTest.java | 117 +++++++----------- .../DefaultLwM2MAttributesService.java | 2 +- 5 files changed, 93 insertions(+), 122 deletions(-) rename application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/{RpcAbstractLwM2MIntegrationTest.java => AbstractRpcLwM2MIntegrationTest.java} (99%) diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/RpcAbstractLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/AbstractRpcLwM2MIntegrationTest.java similarity index 99% rename from application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/RpcAbstractLwM2MIntegrationTest.java rename to application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/AbstractRpcLwM2MIntegrationTest.java index 36158b2640..f635de509b 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/RpcAbstractLwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/AbstractRpcLwM2MIntegrationTest.java @@ -60,19 +60,19 @@ import static org.eclipse.leshan.core.LwM2mId.DEVICE; import static org.eclipse.leshan.core.LwM2mId.FIRMWARE; import static org.eclipse.leshan.core.LwM2mId.SERVER; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.BINARY_APP_DATA_CONTAINER; import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.COAP_CONFIG; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.HOST; import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.HOST_BS; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.PORT; import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.PORT_BS; import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SECURE_PORT; import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SECURE_PORT_BS; import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SECURITY; import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SHORT_SERVER_ID; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.HOST; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.PORT; import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SHORT_SERVER_ID_BS; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.objectInstanceId_0; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.BINARY_APP_DATA_CONTAINER; import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.TEMPERATURE_SENSOR; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.objectInstanceId_0; import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.objectInstanceId_1; import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceIdName_19_0_0; import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceIdName_19_1_0; @@ -84,7 +84,7 @@ import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_ import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resources; @DaoSqlTest -public class RpcAbstractLwM2MIntegrationTest extends AbstractWebsocketTest { +public abstract class AbstractRpcLwM2MIntegrationTest extends AbstractWebsocketTest { protected final String RPC_TRANSPORT_CONFIGURATION = "{\n" + " \"type\": \"LWM2M\",\n" + @@ -165,7 +165,7 @@ public class RpcAbstractLwM2MIntegrationTest extends AbstractWebsocketTest { protected String objectInstanceIdVer_5; protected String objectIdVer_19; - public RpcAbstractLwM2MIntegrationTest(){ } + public AbstractRpcLwM2MIntegrationTest(){ } @Before public void beforeTest() throws Exception { diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationCreateTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationCreateTest.java index a5672be133..5997449d1f 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationCreateTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationCreateTest.java @@ -19,7 +19,7 @@ import com.fasterxml.jackson.databind.node.ObjectNode; import org.eclipse.leshan.core.ResponseCode; import org.junit.Test; import org.thingsboard.common.util.JacksonUtil; -import org.thingsboard.server.transport.lwm2m.rpc.RpcAbstractLwM2MIntegrationTest; +import org.thingsboard.server.transport.lwm2m.rpc.AbstractRpcLwM2MIntegrationTest; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; @@ -28,7 +28,7 @@ import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.objectInsta import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_0; -public class RpcLwm2mIntegrationCreateTest extends RpcAbstractLwM2MIntegrationTest { +public class RpcLwm2mIntegrationCreateTest extends AbstractRpcLwM2MIntegrationTest { /** diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/AbstractLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/AbstractLwM2MIntegrationTest.java index 2c47d5cc80..522abba65a 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/AbstractLwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/AbstractLwM2MIntegrationTest.java @@ -17,7 +17,6 @@ package org.thingsboard.server.transport.lwm2m.security; import com.fasterxml.jackson.core.type.TypeReference; import org.apache.commons.io.IOUtils; -import org.eclipse.californium.core.CoapClient; import org.eclipse.californium.core.network.config.NetworkConfig; import org.eclipse.leshan.client.object.Security; import org.eclipse.leshan.core.util.Hex; @@ -84,12 +83,9 @@ import java.util.List; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; -import static org.eclipse.leshan.client.object.Security.noSec; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import static org.thingsboard.server.common.data.ota.OtaPackageType.FIRMWARE; import static org.thingsboard.server.common.data.ota.OtaPackageType.SOFTWARE; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.COAP_CONFIG; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SECURITY; @DaoSqlTest public abstract class AbstractLwM2MIntegrationTest extends AbstractWebsocketTest { @@ -175,7 +171,7 @@ public abstract class AbstractLwM2MIntegrationTest extends AbstractWebsocketTest protected static final String ENDPOINT = "deviceAEndpoint"; - protected CoapClient client; + protected LwM2MTestClient client; public AbstractLwM2MIntegrationTest() { // create client credentials @@ -366,50 +362,46 @@ public abstract class AbstractLwM2MIntegrationTest extends AbstractWebsocketTest public void after() { executor.shutdownNow(); wsClient.close(); + if (client != null) { + client.destroy(); + } } public void basicTestConnectionObserveTelemetry(Security security, LwM2MClientCredentials credentials, NetworkConfig coapConfig, String endpoint) throws Exception { - LwM2MTestClient client = null; - try { - createDeviceProfile(TRANSPORT_CONFIGURATION); - Device device = createDevice(credentials); - - SingleEntityFilter sef = new SingleEntityFilter(); - sef.setSingleEntity(device.getId()); - LatestValueCmd latestCmd = new LatestValueCmd(); - latestCmd.setKeys(Collections.singletonList(new EntityKey(EntityKeyType.TIME_SERIES, "batteryLevel"))); - EntityDataQuery edq = new EntityDataQuery(sef, new EntityDataPageLink(1, 0, null, null), - Collections.emptyList(), Collections.emptyList(), Collections.emptyList()); - - EntityDataCmd cmd = new EntityDataCmd(1, edq, null, latestCmd, null); - TelemetryPluginCmdsWrapper wrapper = new TelemetryPluginCmdsWrapper(); - wrapper.setEntityDataCmds(Collections.singletonList(cmd)); - - wsClient.send(mapper.writeValueAsString(wrapper)); - wsClient.waitForReply(); - - wsClient.registerWaitForUpdate(); - client = new LwM2MTestClient(executor, endpoint); - int clientPort = SocketUtils.findAvailableTcpPort(); - client.init(security, coapConfig, clientPort); - String msg = wsClient.waitForUpdate(); - - EntityDataUpdate update = mapper.readValue(msg, EntityDataUpdate.class); - Assert.assertEquals(1, update.getCmdId()); - List eData = update.getUpdate(); - Assert.assertNotNull(eData); - Assert.assertEquals(1, eData.size()); - Assert.assertEquals(device.getId(), eData.get(0).getEntityId()); - Assert.assertNotNull(eData.get(0).getLatest().get(EntityKeyType.TIME_SERIES)); - var tsValue = eData.get(0).getLatest().get(EntityKeyType.TIME_SERIES).get("batteryLevel"); - Assert.assertEquals(42, Long.parseLong(tsValue.getValue())); - } finally { - if(client != null) { - client.destroy(); - } - } + createDeviceProfile(TRANSPORT_CONFIGURATION); + Device device = createDevice(credentials); + + SingleEntityFilter sef = new SingleEntityFilter(); + sef.setSingleEntity(device.getId()); + LatestValueCmd latestCmd = new LatestValueCmd(); + latestCmd.setKeys(Collections.singletonList(new EntityKey(EntityKeyType.TIME_SERIES, "batteryLevel"))); + EntityDataQuery edq = new EntityDataQuery(sef, new EntityDataPageLink(1, 0, null, null), + Collections.emptyList(), Collections.emptyList(), Collections.emptyList()); + + EntityDataCmd cmd = new EntityDataCmd(1, edq, null, latestCmd, null); + TelemetryPluginCmdsWrapper wrapper = new TelemetryPluginCmdsWrapper(); + wrapper.setEntityDataCmds(Collections.singletonList(cmd)); + + wsClient.send(mapper.writeValueAsString(wrapper)); + wsClient.waitForReply(); + + wsClient.registerWaitForUpdate(); + client = new LwM2MTestClient(executor, endpoint); + int clientPort = SocketUtils.findAvailableTcpPort(); + client.init(security, coapConfig, clientPort); + String msg = wsClient.waitForUpdate(); + + EntityDataUpdate update = mapper.readValue(msg, EntityDataUpdate.class); + Assert.assertEquals(1, update.getCmdId()); + List eData = update.getUpdate(); + Assert.assertNotNull(eData); + Assert.assertEquals(1, eData.size()); + Assert.assertEquals(device.getId(), eData.get(0).getEntityId()); + Assert.assertNotNull(eData.get(0).getLatest().get(EntityKeyType.TIME_SERIES)); + var tsValue = eData.get(0).getLatest().get(EntityKeyType.TIME_SERIES).get("batteryLevel"); + Assert.assertEquals(42, Long.parseLong(tsValue.getValue())); } } diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/OtaLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/OtaLwM2MIntegrationTest.java index a8a23707c5..ffaeb3f5c6 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/OtaLwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/OtaLwM2MIntegrationTest.java @@ -134,14 +134,11 @@ public class OtaLwM2MIntegrationTest extends AbstractLwM2MIntegrationTest { @Test public void testFirmwareUpdateWithClientWithoutFirmwareInfo() throws Exception { - LwM2MTestClient client = null; String endpoint = "WithoutFirmwareInfoDevice"; - try { createDeviceProfile(TRANSPORT_CONFIGURATION); NoSecClientCredentials clientCredentials = new NoSecClientCredentials(); clientCredentials.setEndpoint(endpoint); Device device = createDevice(clientCredentials); - client = new LwM2MTestClient(executor, endpoint); int clientPort = SocketUtils.findAvailableTcpPort(); client.init(SECURITY, COAP_CONFIG, clientPort); @@ -161,48 +158,35 @@ public class OtaLwM2MIntegrationTest extends AbstractLwM2MIntegrationTest { List expectedStatuses = Collections.singletonList(FAILED); Assert.assertEquals(expectedStatuses, statuses); - } finally { - if (client != null) { - client.destroy(); - } - } } @Test public void testFirmwareUpdateByObject5() throws Exception { - LwM2MTestClient client = null; String endpoint = "Ota5_Device"; List expectedStatuses = Arrays.asList(QUEUED, INITIATED, DOWNLOADING, DOWNLOADED, UPDATING, UPDATED); - try { - createDeviceProfile(OTA_TRANSPORT_CONFIGURATION); - NoSecClientCredentials clientCredentials = new NoSecClientCredentials(); - clientCredentials.setEndpoint(endpoint); - Device device = createDevice(clientCredentials); - - device.setFirmwareId(createFirmware().getId()); - Device saveDevice = doPost("/api/device", device, Device.class); - Thread.sleep(1000); + createDeviceProfile(OTA_TRANSPORT_CONFIGURATION); + NoSecClientCredentials clientCredentials = new NoSecClientCredentials(); + clientCredentials.setEndpoint(endpoint); + Device device = createDevice(clientCredentials); - client = new LwM2MTestClient(executor, endpoint); - int clientPort = SocketUtils.findAvailableTcpPort(); - client.init(SECURITY, COAP_CONFIG, clientPort); + device.setFirmwareId(createFirmware().getId()); + Device saveDevice = doPost("/api/device", device, Device.class); + Thread.sleep(1000); - List ts = await("await on timeseries") - .atMost(30, TimeUnit.SECONDS) - .until(()-> toTimeseries(doGetAsyncTyped("/api/plugins/telemetry/DEVICE/" + saveDevice.getId().getId() + "/values/timeseries?orderBy=ASC&keys=fw_state&startTs=0&endTs=" + System.currentTimeMillis(), new TypeReference<>() { - })), hasSize(expectedStatuses.size())); + client = new LwM2MTestClient(executor, endpoint); + int clientPort = SocketUtils.findAvailableTcpPort(); + client.init(SECURITY, COAP_CONFIG, clientPort); + List ts = await("await on timeseries") + .atMost(30, TimeUnit.SECONDS) + .until(() -> toTimeseries(doGetAsyncTyped("/api/plugins/telemetry/DEVICE/" + saveDevice.getId().getId() + "/values/timeseries?orderBy=ASC&keys=fw_state&startTs=0&endTs=" + System.currentTimeMillis(), new TypeReference<>() { + })), hasSize(expectedStatuses.size())); - List statuses = ts.stream().sorted(Comparator.comparingLong(TsKvEntry::getTs)).map(KvEntry::getValueAsString).map(OtaPackageUpdateStatus::valueOf).collect(Collectors.toList()); + List statuses = ts.stream().sorted(Comparator.comparingLong(TsKvEntry::getTs)).map(KvEntry::getValueAsString).map(OtaPackageUpdateStatus::valueOf).collect(Collectors.toList()); - Assert.assertEquals(expectedStatuses, statuses); - } finally { - if (client != null) { - client.destroy(); - } - } + Assert.assertEquals(expectedStatuses, statuses); } /** @@ -215,44 +199,39 @@ public class OtaLwM2MIntegrationTest extends AbstractLwM2MIntegrationTest { //given final List expectedStatuses = List.of( QUEUED, INITIATED, DOWNLOADING, DOWNLOADING, DOWNLOADING, DOWNLOADED, VERIFIED, UPDATED); - LwM2MTestClient client = null; String endpoint = "Ota9_Device"; - try { - createDeviceProfile(OTA_TRANSPORT_CONFIGURATION); - NoSecClientCredentials clientCredentials = new NoSecClientCredentials(); - clientCredentials.setEndpoint(endpoint); - final Device device = createDevice(clientCredentials); - device.setSoftwareId(createSoftware().getId()); - - final Device savedDevice = doPost("/api/device", device, Device.class); //sync call - assertThat(savedDevice).as("saved device").isNotNull(); - assertThat(getDeviceFromAPI(device.getId().getId())).as("fetched device").isEqualTo(savedDevice); - - //when - log.warn("Init the client..."); - client = new LwM2MTestClient(executor, endpoint); - int clientPort = SocketUtils.findAvailableTcpPort(); - client.init(SECURITY, COAP_CONFIG, clientPort); - - log.warn("AWAIT atMost {} SECONDS on timeseries List by API with list size {}...", TIMEOUT, expectedStatuses.size()); - List ts = await("await on timeseries") - .atMost(30, TimeUnit.SECONDS) - .until(() -> getSwStateTelemetryFromAPI(device.getId().getId()), hasSize(expectedStatuses.size())); - log.warn("Got the ts: {}", ts); - - ts.sort(Comparator.comparingLong(TsKvEntry::getTs)); - log.warn("Ts ordered: {}", ts); - ts.forEach((x) -> log.warn("ts: {} ", x)); - - List statuses = ts.stream().map(KvEntry::getValueAsString).map(OtaPackageUpdateStatus::valueOf).collect(Collectors.toList()); - log.warn("Converted ts to statuses: {}", statuses); - - assertThat(statuses).isEqualTo(expectedStatuses); - } finally { - if (client != null) { - client.destroy(); - } - } + createDeviceProfile(OTA_TRANSPORT_CONFIGURATION); + NoSecClientCredentials clientCredentials = new NoSecClientCredentials(); + clientCredentials.setEndpoint(endpoint); + final Device device = createDevice(clientCredentials); + device.setSoftwareId(createSoftware().getId()); + + final Device savedDevice = doPost("/api/device", device, Device.class); //sync call + Thread.sleep(1000); + + assertThat(savedDevice).as("saved device").isNotNull(); + assertThat(getDeviceFromAPI(device.getId().getId())).as("fetched device").isEqualTo(savedDevice); + + //when + log.warn("Init the client..."); + client = new LwM2MTestClient(executor, endpoint); + int clientPort = SocketUtils.findAvailableTcpPort(); + client.init(SECURITY, COAP_CONFIG, clientPort); + + log.warn("AWAIT atMost {} SECONDS on timeseries List by API with list size {}...", TIMEOUT, expectedStatuses.size()); + List ts = await("await on timeseries") + .atMost(30, TimeUnit.SECONDS) + .until(() -> getSwStateTelemetryFromAPI(device.getId().getId()), hasSize(expectedStatuses.size())); + log.warn("Got the ts: {}", ts); + + ts.sort(Comparator.comparingLong(TsKvEntry::getTs)); + log.warn("Ts ordered: {}", ts); + ts.forEach((x) -> log.warn("ts: {} ", x)); + + List statuses = ts.stream().map(KvEntry::getValueAsString).map(OtaPackageUpdateStatus::valueOf).collect(Collectors.toList()); + log.warn("Converted ts to statuses: {}", statuses); + + assertThat(statuses).isEqualTo(expectedStatuses); } private Device getDeviceFromAPI(UUID deviceId) throws Exception { diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/attributes/DefaultLwM2MAttributesService.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/attributes/DefaultLwM2MAttributesService.java index 3d27621c00..f70af7bf0e 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/attributes/DefaultLwM2MAttributesService.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/attributes/DefaultLwM2MAttributesService.java @@ -198,7 +198,7 @@ public class DefaultLwM2MAttributesService implements LwM2MAttributesService { } } } catch (IllegalArgumentException e){ - log.error("Failed update resource [{}] onAttributesUpdate [{}]", lwM2MClient.getEndpoint(), e.getMessage()); + log.error("Failed update resource ["+lwM2MClient.getEndpoint()+"] onAttributesUpdate:", e); String logMsg = String.format("%s: Failed update resource onAttributesUpdate %s.", LOG_LWM2M_ERROR, e.getMessage()); logService.log(lwM2MClient, logMsg); From c772929abc96e9eca13030d18c89a2ce253bc87d Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Tue, 31 Aug 2021 00:47:58 +0300 Subject: [PATCH 011/432] lwm2m: abstract test write, observe, discover, read --- .../transport/lwm2m/Lwm2mTestHelper.java | 10 +- .../sql/RpcLwm2mIntegrationDiscoverTest.java | 156 +++++++++ .../sql/RpcLwm2mIntegrationObserveTest.java | 190 ++++++++++ .../rpc/sql/RpcLwm2mIntegrationReadTest.java | 226 ++++++++++++ .../rpc/sql/RpcLwm2mIntegrationWriteTest.java | 330 ++++++++++++++++++ 5 files changed, 907 insertions(+), 5 deletions(-) create mode 100644 application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationDiscoverTest.java create mode 100644 application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationObserveTest.java create mode 100644 application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationReadTest.java create mode 100644 application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationWriteTest.java diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/Lwm2mTestHelper.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/Lwm2mTestHelper.java index 37c126df21..3fb5b1a1e6 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/Lwm2mTestHelper.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/Lwm2mTestHelper.java @@ -49,13 +49,13 @@ public class Lwm2mTestHelper { public static final int objectInstanceId_1 = 1; public static final int objectInstanceId_12 = 12; public static final int resourceId_0 = 0; - protected static final int resourceId_1 = 1; - protected static final int resourceId_2 = 2; - protected static final int resourceId_3 = 3; + public static final int resourceId_1 = 1; + public static final int resourceId_2 = 2; + public static final int resourceId_3 = 3; public static final int resourceId_9 = 9; - protected static final int resourceId_11 = 11; + public static final int resourceId_11 = 11; public static final int resourceId_14 = 14; - protected static final int resourceId_15= 15; + public static final int resourceId_15= 15; public static final String resourceIdName_3_9 = "batteryLevel"; public static final String resourceIdName_3_14 = "UtfOffset"; diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationDiscoverTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationDiscoverTest.java new file mode 100644 index 0000000000..64acf699ee --- /dev/null +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationDiscoverTest.java @@ -0,0 +1,156 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.transport.lwm2m.rpc.sql; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ObjectNode; +import org.eclipse.leshan.core.ResponseCode; +import org.eclipse.leshan.core.node.LwM2mPath; +import org.junit.Test; +import org.thingsboard.common.util.JacksonUtil; +import org.thingsboard.server.transport.lwm2m.rpc.AbstractRpcLwM2MIntegrationTest; + +import java.util.Arrays; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Collectors; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.objectInstanceId_0; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_2; + + +public class RpcLwm2mIntegrationDiscoverTest extends AbstractRpcLwM2MIntegrationTest { + + /** + * DiscoverAll + * + * @throws Exception + */ + @Test + public void testDiscoverAll_Return_CONTENT_LinksAllObjectsAllInstancesOfClient() throws Exception { + String setRpcRequest = "{\"method\":\"DiscoverAll\"}"; + String actualResult = doPostAsync("/api/plugins/rpc/twoway/" + deviceId, setRpcRequest, String.class, status().isOk()); + ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); + assertEquals(ResponseCode.CONTENT.getName(), rpcActualResult.get("result").asText()); + JsonNode rpcActualValue = JacksonUtil.toJsonNode(rpcActualResult.get("value").asText()); + Set actualObjects = ConcurrentHashMap.newKeySet(); + Set actualInstances = ConcurrentHashMap.newKeySet(); + rpcActualValue.forEach(node -> { + if (!node.get("url").asText().equals("/")) { + LwM2mPath path = new LwM2mPath(node.get("url").asText()); + actualObjects.add("/" + path.getObjectId()); + if (path.isObjectInstance()) { + actualInstances.add("/" + path.getObjectId() + "/" + path.getObjectInstanceId()); + } + } + }); + assertEquals(expectedInstances, actualInstances); + assertEquals(expectedObjects, actualObjects); + } + + /** + * Discover {"id":"/3"} + * + * @throws Exception + */ + @Test + public void testDiscoverObject_Return_CONTENT_LinksInstancesAndResourcesOnLyExpectedObject() { + expectedObjectIdVers.forEach(expected -> { + try { + String actualResult = sendDiscover((String) expected); + String expectedObjectId = objectIdVerToObjectId ((String) expected); + ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); + assertEquals(ResponseCode.CONTENT.getName(), rpcActualResult.get("result").asText()); + String[] actualValues = rpcActualResult.get("value").asText().split(","); + assertTrue(actualValues.length > 0); + assertEquals(0, Arrays.stream(actualValues).filter(path -> !path.contains(expectedObjectId)).collect(Collectors.toList()).size()); + } catch (Exception e) { + e.printStackTrace(); + } + }); + } + + /** + * Discover {"id":"3/0"} + * + * @throws Exception + */ + @Test + public void testDiscoverInstance_Return_CONTENT_LinksResourcesOnLyExpectedInstance() throws Exception { + String expected = (String) expectedObjectIdVerInstances.stream().findAny().get(); + String actualResult = sendDiscover(expected); + ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); + assertEquals(ResponseCode.CONTENT.getName(), rpcActualResult.get("result").asText()); + String expectedObjectInstanceId = objectInstanceIdVerToObjectInstanceId (expected); + String[] actualValues = rpcActualResult.get("value").asText().split(","); + assertTrue(actualValues.length > 0); + assertEquals(0, Arrays.stream(actualValues).filter(path -> !path.contains(expectedObjectInstanceId)).collect(Collectors.toList()).size()); + } + + /** + * Discover {"id":"3/0/14"} + * + * @throws Exception + */ + @Test + public void testDiscoverResource_Return_CONTENT_LinksResourceOnLyExpectedResource() throws Exception { + String expectedInstance = (String) expectedInstances.stream().findFirst().get(); + String expectedObjectInstanceId = objectInstanceIdVerToObjectInstanceId (expectedInstance); + LwM2mPath expectedPath = new LwM2mPath(expectedObjectInstanceId); + int expectedResource = client.getClient().getObjectTree().getObjectEnablers().get(expectedPath.getObjectId()).getObjectModel().resources.entrySet().stream().findAny().get().getKey(); + String expected = expectedInstance + "/" + expectedResource; + String actualResult = sendDiscover(expected); + ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); + assertEquals(ResponseCode.CONTENT.getName(), rpcActualResult.get("result").asText()); + String expectedResourceId = "<" + expectedObjectInstanceId + "/" + expectedResource + ">"; + String actualValue = rpcActualResult.get("value").asText(); + assertEquals(expectedResourceId, actualValue ); + + } + + /** + * Discover {"id":"2/0/2"} + * + * @throws Exception + */ + @Test + public void testDiscoverInstanceAbsentInObject_Return_NOT_FOUND() throws Exception { + String expected = objectIdVer_2 + "/" + objectInstanceId_0; + String actualResult = sendDiscover(expected); + ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); + assertEquals(ResponseCode.NOT_FOUND.getName(), rpcActualResult.get("result").asText()); + } + /** + * Discover {"id":"2/0/2"} + * + * @throws Exception + */ + @Test + public void testDiscoverResourceAbsentInObject_Return_NOT_FOUND() throws Exception { + String expected = objectIdVer_2 + "/" + objectInstanceId_0 + "/" + resourceId_2; + String actualResult = sendDiscover(expected); + ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); + assertEquals(ResponseCode.NOT_FOUND.getName(), rpcActualResult.get("result").asText()); + } + + private String sendDiscover(String path) throws Exception { + String setRpcRequest = "{\"method\": \"Discover\", \"params\": {\"id\": \"" + path + "\"}}"; + return doPostAsync("/api/plugins/rpc/twoway/" + deviceId, setRpcRequest, String.class, status().isOk()); + } +} diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationObserveTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationObserveTest.java new file mode 100644 index 0000000000..848a9563ed --- /dev/null +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationObserveTest.java @@ -0,0 +1,190 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.transport.lwm2m.rpc.sql; + +import com.fasterxml.jackson.databind.node.ObjectNode; +import org.eclipse.leshan.core.ResponseCode; +import org.eclipse.leshan.core.node.LwM2mPath; +import org.junit.Test; +import org.thingsboard.common.util.JacksonUtil; +import org.thingsboard.server.transport.lwm2m.rpc.AbstractRpcLwM2MIntegrationTest; + +import static org.eclipse.leshan.core.LwM2mId.ACCESS_CONTROL; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.BINARY_APP_DATA_CONTAINER; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.objectInstanceId_0; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_0; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_3; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_9; + +public class RpcLwm2mIntegrationObserveTest extends AbstractRpcLwM2MIntegrationTest { + + /** + * ObserveReadAll + * @throws Exception + */ + @Test + public void testObserveReadAllNothingObservation_Result_CONTENT_Value_Count_0() throws Exception { + String actualResult = sendObserve("ObserveCancelAll", null); + ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); + assertEquals(ResponseCode.CONTENT.getName(), rpcActualResult.get("result").asText()); + actualResult = sendObserve("ObserveReadAll", null); + rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); + assertEquals(ResponseCode.CONTENT.getName(), rpcActualResult.get("result").asText()); + assertEquals("[]", rpcActualResult.get("value").asText()); + } + + /** + * Observe {"id":"/3/0/9"} + * @throws Exception + */ + @Test + public void testObserveSingleResource_Result_CONTENT_Value_SingleResource() throws Exception { + String expectedIdVer = objectInstanceIdVer_3 + "/" + resourceId_9; + String actualResult = sendObserve("Observe", expectedIdVer); + ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); + assertEquals(ResponseCode.CONTENT.getName(), rpcActualResult.get("result").asText()); + assertTrue(rpcActualResult.get("value").asText().contains("LwM2mSingleResource")); + } + + /** + * Observe {"id":"/3_1.1/0/13"} + * @throws Exception + */ + @Test + public void testObserveWithBadVersion_Result_BadRequest_ErrorMsg_BadVersionMustBe1_0() throws Exception { + String expectedInstance = (String) expectedInstances.stream().filter(path -> !((String)path).contains("_")).findFirst().get(); + LwM2mPath expectedPath = new LwM2mPath(expectedInstance); + int expectedResource = client.getClient().getObjectTree().getObjectEnablers().get(expectedPath.getObjectId()).getObjectModel().resources.entrySet().stream().findAny().get().getKey(); + String expectedId = "/" + expectedPath.getObjectId() + "_1.2" + "/" + expectedPath.getObjectInstanceId() + "/" + expectedResource; + String actualResult = sendObserve("Observe", expectedId); + ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); + assertEquals(ResponseCode.BAD_REQUEST.getName(), rpcActualResult.get("result").asText()); + String expected = "Specified resource id " + expectedId +" is not valid version! Must be version: 1.0"; + assertEquals(expected, rpcActualResult.get("error").asText()); + } + + /** + * Not implemented Instance + * Observe {"id":"/2/0"} + * @throws Exception + */ + @Test + public void testObserveNoImplementedInstanceOnDevice_Result_NotFound() throws Exception { + String objectInstanceIdVer = (String) expectedObjectIdVers.stream().filter(path -> ((String)path).contains("/" + ACCESS_CONTROL)).findFirst().get(); + String expected = objectInstanceIdVer + "/" + objectInstanceId_0; + String actualResult = sendObserve("Observe", expected); + ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); + assertEquals(ResponseCode.NOT_FOUND.getName(), rpcActualResult.get("result").asText()); + } + + /** + * Not implemented Resource + * Observe {"id":"/19_1.1/0/0"} + * @throws Exception + */ + @Test + public void testObserveNoImplementedResourceOnDeviceValueNull_Result_BadRequest() throws Exception { + String objectIdVer = (String) expectedObjectIdVers.stream().filter(path -> ((String)path).contains("/" + BINARY_APP_DATA_CONTAINER)).findFirst().get(); + String expected = objectIdVer + "/" + objectInstanceId_0 + "/" + resourceId_0; + String actualResult = sendObserve("Observe", expected); + ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); + String expectedValue = "values MUST NOT be null"; + assertEquals(ResponseCode.BAD_REQUEST.getName(), rpcActualResult.get("result").asText()); + assertEquals(expectedValue, rpcActualResult.get("error").asText()); + } + + /** + * Repeated request on Observe + * Observe {"id":"/5/0/0"} + * @throws Exception + */ + @Test + public void testObserveRSourceNotRead_Result_METHOD_NOT_ALLOWED() throws Exception { + String expectedId = objectInstanceIdVer_5 + "/" + resourceId_0; + sendObserve("Observe", expectedId); + String actualResult = sendObserve("Observe", expectedId); + ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); + assertEquals(ResponseCode.METHOD_NOT_ALLOWED.getName(), rpcActualResult.get("result").asText()); + } + + /** + * Repeated request on Observe + * Observe {"id":"/3/0/0"} + * @throws Exception + */ + @Test + public void testObserveRepeatedRequestObserveOnDevice_Result_BAD_REQUEST_ErrorMsg_AlreadyRegistered() throws Exception { + String expectedId = objectInstanceIdVer_3 + "/" + resourceId_0; + sendObserve("Observe", expectedId); + String actualResult = sendObserve("Observe", expectedId); + ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); + assertEquals(ResponseCode.BAD_REQUEST.getName(), rpcActualResult.get("result").asText()); + String expected = "Observation is already registered!"; + assertEquals(expected, rpcActualResult.get("error").asText()); + } + + /** + * ObserveReadAll + * @throws Exception + */ + @Test + public void testObserveReadAll_Result_CONTENT_Value_Contains_Paths_Count_ObserveAll() throws Exception { + sendObserve("ObserveCancelAll", null); + String expectedId_0 = objectInstanceIdVer_3 + "/" + resourceId_0; + String expectedId_9 = objectInstanceIdVer_3 + "/" + resourceId_9; + sendObserve("Observe", expectedId_0); + sendObserve("Observe", expectedId_9); + String actualResult = sendObserve("ObserveReadAll", null); + ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); + assertEquals(ResponseCode.CONTENT.getName(), rpcActualResult.get("result").asText()); + String actualValues = rpcActualResult.get("value").asText(); + assertTrue(actualValues.contains(expectedId_0)); + assertTrue(actualValues.contains(expectedId_9)); + assertEquals(2, actualValues.split(",").length); + } + + + /** + * ObserveCancel {"id":"/3/0/3"} + * ObserveCancel {"id":"/5/0/3"} + */ + @Test + public void testObserveCancelOneResource_Result_CONTENT_Value_Count_1() throws Exception { + sendObserve("ObserveCancelAll", null); + String expectedId_0 = objectInstanceIdVer_3 + "/" + resourceId_0; + String expectedId_3 = objectInstanceIdVer_5 + "/" + resourceId_3; + sendObserve("Observe", expectedId_0); + sendObserve("Observe", expectedId_3); + String actualResult = sendObserve("ObserveCancel", expectedId_0); + ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); + assertEquals(ResponseCode.CONTENT.getName(), rpcActualResult.get("result").asText()); + assertEquals("1", rpcActualResult.get("value").asText()); + } + + private String sendObserve(String method, String params) throws Exception { + String sendRpcRequest; + if (params == null) { + sendRpcRequest = "{\"method\": \"" + method + "\"}"; + } + else { + sendRpcRequest = "{\"method\": \"" + method + "\", \"params\": {\"id\": \"" + params + "\"}}"; + } + return doPostAsync("/api/plugins/rpc/twoway/" + deviceId, sendRpcRequest, String.class, status().isOk()); + } +} diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationReadTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationReadTest.java new file mode 100644 index 0000000000..4f696e1c3c --- /dev/null +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationReadTest.java @@ -0,0 +1,226 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.transport.lwm2m.rpc.sql; + +import com.fasterxml.jackson.databind.node.ObjectNode; +import org.eclipse.leshan.core.ResponseCode; +import org.eclipse.leshan.core.node.LwM2mPath; +import org.junit.Test; +import org.thingsboard.common.util.JacksonUtil; +import org.thingsboard.server.transport.lwm2m.rpc.AbstractRpcLwM2MIntegrationTest; + +import static org.eclipse.leshan.core.LwM2mId.SERVER; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.BINARY_APP_DATA_CONTAINER; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.objectInstanceId_0; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.objectInstanceId_1; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceIdName_19_0_0; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceIdName_19_1_0; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceIdName_3_14; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceIdName_3_9; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_0; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_1; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_11; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_14; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_2; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_9; + + +public class RpcLwm2mIntegrationReadTest extends AbstractRpcLwM2MIntegrationTest { + + /** + * Read {"id":"/3"} + * Read {"id":"/6"}... + */ + @Test + public void testReadAllObjectsInClientById_Result_CONTENT_Value_IsLwM2mObject_IsInstances() throws Exception { + expectedObjectIdVers.forEach(expected -> { + try { + String actualResult = sendRPCById((String) expected); + String expectedObjectId = objectIdVerToObjectId ((String) expected); + LwM2mPath expectedPath = new LwM2mPath(expectedObjectId); + ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); + assertEquals(ResponseCode.CONTENT.getName(), rpcActualResult.get("result").asText()); + String expectedObjectInstances = "LwM2mObject [id=" + expectedPath.getObjectId() + ", instances={0=LwM2mObjectInstance [id=0, resources="; + if (expectedPath.getObjectId() == 2) { + expectedObjectInstances = "LwM2mObject [id=2, instances={}]"; + } + assertTrue(rpcActualResult.get("value").asText().contains(expectedObjectInstances)); + } catch (Exception e) { + e.printStackTrace(); + } + }); + } + + /** + * Read {"id":"/5/0"} + * + * @throws Exception + */ + @Test + public void testReadAllInstancesInClientById_Result_CONTENT_Value_IsInstances_IsResources() throws Exception{ + expectedObjectIdVerInstances.forEach(expected -> { + try { + String actualResult = sendRPCById((String) expected); + String expectedObjectId = objectInstanceIdVerToObjectInstanceId ((String) expected); + LwM2mPath expectedPath = new LwM2mPath(expectedObjectId); + ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); + assertEquals(ResponseCode.CONTENT.getName(), rpcActualResult.get("result").asText()); + String expectedObjectInstances = "LwM2mObjectInstance [id=" + expectedPath.getObjectInstanceId() + ", resources={"; + assertTrue(rpcActualResult.get("value").asText().contains(expectedObjectInstances)); + } catch (Exception e) { + e.printStackTrace(); + } + }); + } + + /** + * Read {"id":"/19/1/0"} + * + * @throws Exception + */ + @Test + public void testReadMultipleResourceById_Result_CONTENT_Value_IsLwM2mMultipleResource() throws Exception { + String expectedIdVer = objectInstanceIdVer_3 +"/" + resourceId_11 ; + String actualResult = sendRPCById(expectedIdVer); + ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); + assertEquals(ResponseCode.CONTENT.getName(), rpcActualResult.get("result").asText()); + String expected = "LwM2mMultipleResource [id=" + resourceId_11 + ", values={"; + assertTrue(rpcActualResult.get("value").asText().contains(expected)); + } + + /** + * Read {"id":"/3/0/14"} + */ + @Test + public void testReadSingleResourceById_Result_CONTENT_Value_IsLwM2mSingleResource() throws Exception { + String expectedIdVer = objectInstanceIdVer_3 +"/" + resourceId_14 ; + String actualResult = sendRPCById(expectedIdVer); + ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); + assertEquals(ResponseCode.CONTENT.getName(), rpcActualResult.get("result").asText()); + String expected = "LwM2mSingleResource [id=" + resourceId_14 + ", value="; + assertTrue(rpcActualResult.get("value").asText().contains(expected)); + } + + /** + * Read {"key":"UtfOffset"} + */ + @Test + public void testReadSingleResourceByKey_Result_CONTENT_Value_IsLwM2mSingleResource() throws Exception { + String expectedKey = resourceIdName_3_14 ; + String actualResult = sendRPCByKey(expectedKey); + ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); + assertEquals(ResponseCode.CONTENT.getName(), rpcActualResult.get("result").asText()); + String expected = "LwM2mSingleResource [id=" + resourceId_14 + ", value="; + assertTrue(rpcActualResult.get("value").asText().contains(expected)); + } + + /** + * ReadComposite {"ids":["/1_1.2", "/3_1.0/0/1", "/3_1.0/0/11"]} + */ + @Test + public void testReadCompositeSingleResourceByIds_Result_CONTENT_Value_IsObjectIsLwM2mSingleResourceIsLwM2mMultipleResource() throws Exception { + String expectedIdVer_1 = (String) expectedObjectIdVers.stream().filter(path -> (!((String)path).contains("/" + BINARY_APP_DATA_CONTAINER) && ((String)path).contains("/" + SERVER))).findFirst().get(); + String objectId_1 = objectIdVerToObjectId(expectedIdVer_1); + String expectedIdVer3_0_1 = objectInstanceIdVer_3 + "/" + resourceId_1; + String expectedIdVer3_0_11 = objectInstanceIdVer_3 + "/" + resourceId_11; + String objectInstanceId_3 = objectIdVerToObjectId(objectInstanceIdVer_3); + String expectedIds = "[\"" + expectedIdVer_1 + "\", \"" + expectedIdVer3_0_1 + "\", \"" + expectedIdVer3_0_11 + "\"]"; + String actualResult = sendCompositeRPCByIds(expectedIds); + ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); + assertEquals(ResponseCode.CONTENT.getName(), rpcActualResult.get("result").asText()); + String expected1 = objectId_1 + "=LwM2mObject [id=" + new LwM2mPath(objectId_1).getObjectId() + ", instances={"; + String expected3_0_1 = objectInstanceId_3 + "/" + resourceId_1 + "=LwM2mSingleResource [id=" + resourceId_1 + ", value="; + String expected3_0_11 = objectInstanceId_3 + "/" + resourceId_11 + "=LwM2mMultipleResource [id=" + resourceId_11 + ", values={"; + String actualValues = rpcActualResult.get("value").asText(); + assertTrue(actualValues.contains(expected1)); + assertTrue(actualValues.contains(expected3_0_1)); + assertTrue(actualValues.contains(expected3_0_11)); + } + + /** + * ReadComposite {"ids":["/1_1.2/0/1", "/1_1.2/0/2", "/3_1.0/0"]} + */ + @Test + public void testReadCompositeSingleResourceByIds_Result_CONTENT_Value_IsObjectInstanceIsLwM2mSingleResource() throws Exception { + String expectedIdVer3_0 = objectInstanceIdVer_3; + String expectedIdVer1_0_1 = objectInstanceIdVer_1 + "/" + resourceId_1; + String expectedIdVer1_0_2 = objectInstanceIdVer_1 + "/" + resourceId_2; + String expectedIds = "[\"" + expectedIdVer1_0_1 + "\", \"" + expectedIdVer1_0_2 + "\", \"" + expectedIdVer3_0 + "\"]"; + String actualResult = sendCompositeRPCByIds(expectedIds); + ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); + assertEquals(ResponseCode.CONTENT.getName(), rpcActualResult.get("result").asText()); + String objectInstanceId_3 = objectInstanceIdVerToObjectInstanceId(objectInstanceIdVer_3); + LwM2mPath path = new LwM2mPath(objectInstanceId_3); + String expected3_0 = objectInstanceId_3 + "=LwM2mObjectInstance [id=" + path.getObjectInstanceId() + ", resources={"; + String objectInstanceId_1 = objectInstanceIdVerToObjectInstanceId(objectInstanceIdVer_1); + String expected1_0_1 = objectInstanceId_1 + "/" + resourceId_1 + "=LwM2mSingleResource [id=" + resourceId_1 + ", value="; + String expected1_0_2 = objectInstanceId_1 + "/" + resourceId_2 + "=null"; + String actualValues = rpcActualResult.get("value").asText(); + assertTrue(actualValues.contains(expected3_0)); + assertTrue(actualValues.contains(expected1_0_1)); + assertTrue(actualValues.contains(expected1_0_2)); + } + + /** + * ReadComposite {"keys":["batteryLevel", "UtfOffset", "dataRead", "dataWrite"]} + */ + @Test + public void testReadCompositeSingleResourceByKeys_Result_CONTENT_Value_3_0_IsLwM2mSingleResource_19_0_0_AND_19_0_1_Null() throws Exception { + String expectedKey3_0_9 = resourceIdName_3_9; + String expectedKey3_0_14 = resourceIdName_3_14; + String expectedKey19_0_0 = resourceIdName_19_0_0; + String expectedKey19_1_0 = resourceIdName_19_1_0; + String expectedKeys = "[\"" + expectedKey3_0_9 + "\", \"" + expectedKey3_0_14 + "\", \"" + expectedKey19_0_0 + "\", \"" + expectedKey19_1_0 + "\"]"; + String actualResult = sendCompositeRPCByKeys(expectedKeys); + ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); + assertEquals(ResponseCode.CONTENT.getName(), rpcActualResult.get("result").asText()); + String objectInstanceId_3 = objectInstanceIdVerToObjectInstanceId(objectInstanceIdVer_3); + String objectId_19 = objectIdVerToObjectId(objectIdVer_19); + String expected3_0_9 = objectInstanceId_3 + "/" + resourceId_9 + "=LwM2mSingleResource [id=" + resourceId_9 + ", value="; + String expected3_0_14 = objectInstanceId_3 + "/" + resourceId_14 + "=LwM2mSingleResource [id=" + resourceId_14 + ", value="; + String expected19_0_0 = objectId_19 + "/" + objectInstanceId_0 + "/" + resourceId_0 + "=null"; + String expected19_1_0 = objectId_19 + "/" + objectInstanceId_1 + "/" + resourceId_0 + "=null"; + String actualValues = rpcActualResult.get("value").asText(); + assertTrue(actualValues.contains(expected3_0_9)); + assertTrue(actualValues.contains(expected3_0_14)); + assertTrue(actualValues.contains(expected19_0_0)); + assertTrue(actualValues.contains(expected19_1_0)); + } + + + private String sendRPCById(String path) throws Exception { + String setRpcRequest = "{\"method\": \"Read\", \"params\": {\"id\": \"" + path + "\"}}"; + return doPostAsync("/api/plugins/rpc/twoway/" + deviceId, setRpcRequest, String.class, status().isOk()); + } + + private String sendRPCByKey(String key) throws Exception { + String setRpcRequest = "{\"method\": \"Read\", \"params\": {\"key\": \"" + key + "\"}}"; + return doPostAsync("/api/plugins/rpc/twoway/" + deviceId, setRpcRequest, String.class, status().isOk()); + } + + private String sendCompositeRPCByIds(String paths) throws Exception { + String setRpcRequest = "{\"method\": \"ReadComposite\", \"params\": {\"ids\":" + paths + "}}"; + return doPostAsync("/api/plugins/rpc/twoway/" + deviceId, setRpcRequest, String.class, status().isOk()); + } + + private String sendCompositeRPCByKeys(String keys) throws Exception { + String setRpcRequest = "{\"method\": \"ReadComposite\", \"params\": {\"keys\":" + keys + "}}"; + return doPostAsync("/api/plugins/rpc/twoway/" + deviceId, setRpcRequest, String.class, status().isOk()); + } +} diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationWriteTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationWriteTest.java new file mode 100644 index 0000000000..0150572351 --- /dev/null +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationWriteTest.java @@ -0,0 +1,330 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.transport.lwm2m.rpc.sql; + +import com.fasterxml.jackson.databind.node.ObjectNode; +import org.eclipse.leshan.core.ResponseCode; +import org.junit.Test; +import org.thingsboard.common.util.JacksonUtil; +import org.thingsboard.server.transport.lwm2m.rpc.AbstractRpcLwM2MIntegrationTest; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.BINARY_APP_DATA_CONTAINER; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.objectInstanceId_0; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.objectInstanceId_1; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceIdName_3_14; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_0; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_14; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_15; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_9; + +public class RpcLwm2mIntegrationWriteTest extends AbstractRpcLwM2MIntegrationTest { + + + /** + * id + * WriteReplace {"id":"3/0/14","value":"+12"} + */ + @Test + public void testWriteReplaceValueSingleResourceById_Result_CHANGED() throws Exception { + String expectedPath = objectInstanceIdVer_3 + "/" + resourceId_14; + String expectedValue = "+12"; + String actualResult = sendRPCWriteStringById("WriteReplace", expectedPath, expectedValue); + ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); + assertEquals(ResponseCode.CHANGED.getName(), rpcActualResult.get("result").asText()); + actualResult = sendRPCReadById(expectedPath); + rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); + String actualValues = rpcActualResult.get("value").asText(); + String expected = "LwM2mSingleResource [id=" + resourceId_14 + ", value=" + expectedValue + ", type=STRING]"; + assertTrue(actualValues.contains(expected)); + } + + /** + * key + * WriteReplace {"key":"timezone","value":"+10"} + */ + @Test + public void testWriteReplaceValueSingleResourceByKey_Result_CHANGED() throws Exception { + String expectedKey = resourceIdName_3_14; + String expectedValue = "+09"; + String actualResult = sendRPCWriteByKey("WriteReplace", expectedKey, expectedValue); + ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); + assertEquals(ResponseCode.CHANGED.getName(), rpcActualResult.get("result").asText()); + actualResult = sendRPCReadByKey(expectedKey); + rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); + String actualValues = rpcActualResult.get("value").asText(); + String expected = "LwM2mSingleResource [id=" + resourceId_14 + ", value=" + expectedValue + ", type=STRING]"; + assertTrue(actualValues.contains(expected)); + } + + + /** + * id + * WriteReplace {"id": "/19_1.1/0/0","value": {"0":"0000ad45675600", "15":"1525ad45675600cdef"}} + */ + @Test + public void testWriteReplaceValueMultipleResource_Result_CHANGED_Value_Multi_Instance_Resource_must_in_Json_format() throws Exception { + String expectedPath = objectIdVer_19 + "/" + objectInstanceId_0 + "/" + resourceId_0; + int resourceInstanceId0 = 0; + int resourceInstanceId15 = 15; + String expectedValue0 = "0000ad45675600"; + String expectedValue15 = "1525ad45675600cdef"; + String expectedValue = "{\"" + resourceInstanceId0 + "\":\"" + expectedValue0 + "\", \"" + resourceInstanceId15 + "\":\"" + expectedValue15 + "\"}"; + String actualResult = sendRPCWriteObjectById("WriteReplace", expectedPath, expectedValue); + ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); + assertEquals(ResponseCode.CHANGED.getName(), rpcActualResult.get("result").asText()); + String expectedPath0 = expectedPath + "/" + resourceInstanceId0; + String expectedPath15 = expectedPath + "/" + resourceInstanceId15; + actualResult = sendRPCReadById(expectedPath0); + rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); + String actualValues = rpcActualResult.get("value").asText(); + String expected = "LwM2mResourceInstance [id=" + resourceInstanceId0 + ", value=" + expectedValue0.length()/2 + "Bytes, type=OPAQUE]"; + assertTrue(actualValues.contains(expected)); + actualResult = sendRPCReadById(expectedPath15); + rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); + actualValues = rpcActualResult.get("value").asText(); + expected = "LwM2mResourceInstance [id=" + resourceInstanceId15 + ", value=" + expectedValue15.length()/2 + "Bytes, type=OPAQUE]"; + assertTrue(actualValues.contains(expected)); + } + + /** + * id + * WriteReplace {"id":"/19/0/0","value":"0081"}.. + */ + @Test + public void testWriteReplaceValueMultipleResourceAsSingleResource_Result_BAD_REQUEST_Value_Multi_Instance_Resource_must_be_in_Json_format() throws Exception { + String objectInstanceIdVer_19 = (String) expectedObjectIdVerInstances.stream().filter(path -> ((String) path).contains("/" + BINARY_APP_DATA_CONTAINER)).findFirst().get(); + String expectedPath = objectInstanceIdVer_19 + "/" + resourceId_0; + String expectedValue = "0081"; + String actualResult = sendRPCWriteStringById("WriteReplace", expectedPath, expectedValue); + ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); + assertEquals(ResponseCode.BAD_REQUEST.getName(), rpcActualResult.get("result").asText()); + String actualValues = rpcActualResult.get("error").asText(); + String expected = "Resource value is: String. Value of Multi-Instance Resource must be in Json format!"; + assertTrue(actualValues.contains(expected)); + } + + + /** + * bad - only read + * WriteReplace {"id":"/3/0/9","value":90} + * {"result":"METHOD_NOT_ALLOWED"} + */ + @Test + public void testWriteReplaceValueSingleResourceR_ById_Result_CHANGED() throws Exception { + String expectedPath = objectInstanceIdVer_3 + "/" + resourceId_9; + Integer expectedValue = 90; + String actualResult = sendRPCWriteObjectById("WriteReplace", expectedPath, expectedValue); + ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); + assertEquals(ResponseCode.METHOD_NOT_ALLOWED.getName(), rpcActualResult.get("result").asText()); + } + + /** + * ids + * WriteUpdate {"id":"/3/0","value":{"14":"+5","15":"Kiyv/Europe"}} + * + */ + @Test + public void testWriteUpdateValueSingleResourceById_Result_CHANGED() throws Exception { + String expectedPath = objectInstanceIdVer_3; + String expectedValue14 = "+5"; + String expectedValue15 = "Kiyv/Europe"; + String expectedValue = "{\"" + resourceId_14 + "\":\"" + expectedValue14 + "\",\"" + resourceId_15 + "\":\"" + expectedValue15 + "\"}"; + String actualResult = sendRPCWriteObjectById("WriteUpdate", expectedPath, expectedValue); + ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); + assertEquals(ResponseCode.CHANGED.getName(), rpcActualResult.get("result").asText()); + String expectedPath14 = objectInstanceIdVer_3 + "/" + resourceId_14; + String expectedPath15 = objectInstanceIdVer_3 + "/" + resourceId_15; + actualResult = sendRPCReadById(expectedPath14); + rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); + String actualValues = rpcActualResult.get("value").asText(); + String expected = "LwM2mSingleResource [id=" + resourceId_14 + ", value=" + expectedValue14 + ", type=STRING]"; + assertTrue(actualValues.contains(expected)); + actualResult = sendRPCReadById(expectedPath15); + rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); + actualValues = rpcActualResult.get("value").asText(); + expected = "LwM2mSingleResource [id=" + resourceId_15 + ", value=" + expectedValue15 + ", type=STRING]"; + assertTrue(actualValues.contains(expected)); + } + + /** + * id + * WriteUpdate {"id": "/19_1.1/0","value": {"0":{"0":"00ad456756", "25":"25ad456756"}}} + */ + @Test + public void testWriteUpdateValueMultipleResourceById_Result_CHANGED() throws Exception { + String expectedPath = objectIdVer_19 + "/" + objectInstanceId_0; + int resourceInstanceId0 = 0; + int resourceInstanceId25 = 25; + String expectedValue0 = "00ad45675600"; + String expectedValue25 = "25ad45675600cdef"; + String expectedValue = "{\"" + resourceId_0 + "\":{\"" + resourceInstanceId0 + "\":\"" + expectedValue0 + "\", \"" + resourceInstanceId25 + "\":\"" + expectedValue25 + "\"}}"; + String actualResult = sendRPCWriteObjectById("WriteUpdate", expectedPath, expectedValue); + ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); + assertEquals(ResponseCode.CHANGED.getName(), rpcActualResult.get("result").asText()); + String expectedPath0 = expectedPath + "/" + resourceId_0 + "/" + resourceInstanceId0; + String expectedPath25 =expectedPath + "/" + resourceId_0 + "/" + resourceInstanceId25; + actualResult = sendRPCReadById(expectedPath0); + rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); + String actualValues = rpcActualResult.get("value").asText(); + String expected = "LwM2mResourceInstance [id=" + resourceInstanceId0 + ", value=" + expectedValue0.length()/2 + "Bytes, type=OPAQUE]"; + assertTrue(actualValues.contains(expected)); + actualResult = sendRPCReadById(expectedPath25); + rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); + actualValues = rpcActualResult.get("value").asText(); + expected = "LwM2mResourceInstance [id=" + resourceInstanceId25 + ", value=" + expectedValue25.length()/2 + "Bytes, type=OPAQUE]"; + assertTrue(actualValues.contains(expected)); + } + + /** + * ResourceInstance + KeySingleResource + IdSingleResource + * WriteComposite {"nodes":{"/19/1/0/2":"00001234", "UtfOffset":"+04", "/3/0/15":"Kiyv/Europe"}} + */ + @Test + public void testWriteCompositeValueSingleResourceResourceInstanceByIdKey_Result_CHANGED() throws Exception { + int resourceInstanceId2 = 2; + String expectedPath19_1_0_2 = objectIdVer_19 + "/" + objectInstanceId_1 + "/" + resourceId_0 + "/" + resourceInstanceId2; + String expectedValue19_1_0_2 = "00001234"; + String expectedKey3_0_14 = resourceIdName_3_14; + String expectedValue3_0_14 = "+04"; + String expectedPath3_0_15 = objectInstanceIdVer_3 + "/" + resourceId_15; + String expectedValue3_0_15 = "Kiyv/Europe"; + String nodes = "{\"" + expectedPath19_1_0_2 + "\":\"" + expectedValue19_1_0_2 + "\", \"" + expectedKey3_0_14 + + "\":\"" + expectedValue3_0_14 + "\", \"" + expectedPath3_0_15 + "\":\"" + expectedValue3_0_15 + "\"}"; + String actualResult = sendCompositeRPC(nodes); + ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); + assertEquals(ResponseCode.CHANGED.getName(), rpcActualResult.get("result").asText()); + actualResult = sendRPCReadById(expectedPath19_1_0_2); + rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); + String actualValues = rpcActualResult.get("value").asText(); + String expected = "LwM2mResourceInstance [id=" + resourceInstanceId2 + ", value=" + expectedValue19_1_0_2.length()/2 + "Bytes, type=OPAQUE]"; + assertTrue(actualValues.contains(expected)); + actualResult = sendRPCReadByKey(expectedKey3_0_14); + rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); + actualValues = rpcActualResult.get("value").asText(); + expected = "LwM2mSingleResource [id=" + resourceId_14 + ", value=" + expectedValue3_0_14 + ", type=STRING]"; + assertTrue(actualValues.contains(expected)); + actualResult = sendRPCReadById(expectedPath3_0_15); + rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); + actualValues = rpcActualResult.get("value").asText(); + expected = "LwM2mSingleResource [id=" + resourceId_15 + ", value=" + expectedValue3_0_15 + ", type=STRING]"; + assertTrue(actualValues.contains(expected)); + } + + /** + * multipleResource == error + * bad - cannot be used for value Json, only primitive: SingleResource, ResourceInstance (for Json: WriteUpdate, WriteReplace) + * WriteComposite {"nodes":{"/19/0/0":{"0":"abcd5678", "10":"abcd5678"}}} + */ + @Test + public void testWriteCompositeValueSingleMultipleResourceByIdKey_Result_BAD_REQUEST_WriteComposite_operation_for_SingleResources_or_and_ResourceInstance() throws Exception { + String nodes = "{\"/19/0/0\":{\"0\":\"abcd5678\", \"10\":\"abcd5678\"}}"; + String actualResult = sendCompositeRPC(nodes); + ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); + assertEquals(ResponseCode.BAD_REQUEST.getName(), rpcActualResult.get("result").asText()); + String actualValues = rpcActualResult.get("error").asText(); + String expectedNodes = nodes.replaceAll("\"", "").replaceAll(":", "="); + String expected = String.format("nodes: %s is not validate value. " + + "The WriteComposite operation is only used for SingleResources or/and ResourceInstance.", expectedNodes); + assertEquals(expected, actualValues); + } + + + /** + * create_2_instances_in_object + * new ObjectInstance if Object is Multiple & Resource Single + * Create {"id":"/19/2","value":{"1":2}} + * Create {"id":"/19/3","value":{"0":{"0":"00AC", "1":"ddff12"}}} + */ + @Test + public void testCreateObjectInstanceSingleByIdKey_Result_CHANGED() throws Exception { + int resourceInstanceId2 = 2; + String expectedPath19_1_0_2 = objectIdVer_19 + "/" + objectInstanceId_1 + "/" + resourceId_0 + "/" + resourceInstanceId2; + String expectedValue19_1_0_2 = "00001234"; + String expectedKey3_0_14 = resourceIdName_3_14; + String expectedValue3_0_14 = "+04"; + String expectedPath3_0_15 = objectInstanceIdVer_3 + "/" + resourceId_15; + String expectedValue3_0_15 = "Kiyv/Europe"; + String nodes = "{\"" + expectedPath19_1_0_2 + "\":\"" + expectedValue19_1_0_2 + "\", \"" + expectedKey3_0_14 + + "\":\"" + expectedValue3_0_14 + "\", \"" + expectedPath3_0_15 + "\":\"" + expectedValue3_0_15 + "\"}"; + String actualResult = sendCompositeRPC(nodes); + ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); + assertEquals(ResponseCode.CHANGED.getName(), rpcActualResult.get("result").asText()); + actualResult = sendRPCReadById(expectedPath19_1_0_2); + rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); + String actualValues = rpcActualResult.get("value").asText(); + String expected = "LwM2mResourceInstance [id=" + resourceInstanceId2 + ", value=" + expectedValue19_1_0_2.length()/2 + "Bytes, type=OPAQUE]"; + assertTrue(actualValues.contains(expected)); + actualResult = sendRPCReadByKey(expectedKey3_0_14); + rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); + actualValues = rpcActualResult.get("value").asText(); + expected = "LwM2mSingleResource [id=" + resourceId_14 + ", value=" + expectedValue3_0_14 + ", type=STRING]"; + assertTrue(actualValues.contains(expected)); + actualResult = sendRPCReadById(expectedPath3_0_15); + rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); + actualValues = rpcActualResult.get("value").asText(); + expected = "LwM2mSingleResource [id=" + resourceId_15 + ", value=" + expectedValue3_0_15 + ", type=STRING]"; + assertTrue(actualValues.contains(expected)); + } + + /** + * failed: cannot_create_mandatory_single_object + * Create {"id":"/3/2","value":{"0":"00AC"}} + */ + + + /** + * failed: cannot_create_instance_of_security_object + * Create {"id":"/0/2","value":{"0":"00AC"}} + */ + + /** + * failed: cannot_create_instance_of_absent_object + * Create {"id":"/50/2","value":{"0":"00AC"}} + */ + + private String sendRPCWriteStringById(String method, String path, String value) throws Exception { + String setRpcRequest = "{\"method\": \"" + method + "\", \"params\": {\"id\": \"" + path + "\", \"value\": \"" + value + "\" }}"; + return doPostAsync("/api/plugins/rpc/twoway/" + deviceId, setRpcRequest, String.class, status().isOk()); + } + + private String sendRPCWriteObjectById(String method, String path, Object value) throws Exception { + String setRpcRequest = "{\"method\": \"" + method + "\", \"params\": {\"id\": \"" + path + "\", \"value\": " + value + " }}"; + return doPostAsync("/api/plugins/rpc/twoway/" + deviceId, setRpcRequest, String.class, status().isOk()); + } + + private String sendRPCReadById(String id) throws Exception { + String setRpcRequest = "{\"method\": \"Read\", \"params\": {\"id\": \"" + id + "\"}}"; + return doPostAsync("/api/plugins/rpc/twoway/" + deviceId, setRpcRequest, String.class, status().isOk()); + } + + private String sendRPCWriteByKey(String method, String key, String value) throws Exception { + String setRpcRequest = "{\"method\": \"" + method + "\", \"params\": {\"key\": \"" + key + "\", \"value\": \"" + value + "\" }}"; + return doPostAsync("/api/plugins/rpc/twoway/" + deviceId, setRpcRequest, String.class, status().isOk()); + } + + private String sendRPCReadByKey(String key) throws Exception { + String setRpcRequest = "{\"method\": \"Read\", \"params\": {\"key\": \"" + key + "\"}}"; + return doPostAsync("/api/plugins/rpc/twoway/" + deviceId, setRpcRequest, String.class, status().isOk()); + } + + private String sendCompositeRPC(String nodes) throws Exception { + String setRpcRequest = "{\"method\": \"WriteComposite\", \"params\": {\"nodes\":" + nodes + "}}"; + return doPostAsync("/api/plugins/rpc/twoway/" + deviceId, setRpcRequest, String.class, status().isOk()); + } +} \ No newline at end of file From 0a3c626333fe58a889d6bd16d170688920e23e88 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Tue, 31 Aug 2021 23:38:31 +0300 Subject: [PATCH 012/432] lwm2m: abstract integration RPC test delete, create, writeAttribute, execute --- .../transport/lwm2m/Lwm2mTestHelper.java | 5 + .../lwm2m/client/LwM2MTestClient.java | 1 - .../rpc/AbstractRpcLwM2MIntegrationTest.java | 34 +++- .../sql/RpcLwm2mIntegrationCreateTest.java | 70 ++++++- .../sql/RpcLwm2mIntegrationDeleteTest.java | 96 +++++++++ .../sql/RpcLwm2mIntegrationDiscoverTest.java | 35 ++-- .../sql/RpcLwm2mIntegrationExecuteTest.java | 186 ++++++++++++++++++ .../rpc/sql/RpcLwm2mIntegrationReadTest.java | 16 +- ...pcLwm2mIntegrationWriteAttributesTest.java | 63 ++++++ .../rpc/sql/RpcLwm2mIntegrationWriteTest.java | 71 ++++--- .../security/sql/OtaLwM2MIntegrationTest.java | 6 +- .../device/data/lwm2m/OtherConfiguration.java | 2 - .../lwm2m/server/client/LwM2mClient.java | 2 +- 13 files changed, 520 insertions(+), 67 deletions(-) create mode 100644 application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationDeleteTest.java create mode 100644 application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationExecuteTest.java create mode 100644 application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationWriteAttributesTest.java diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/Lwm2mTestHelper.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/Lwm2mTestHelper.java index 3fb5b1a1e6..232332e554 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/Lwm2mTestHelper.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/Lwm2mTestHelper.java @@ -45,17 +45,22 @@ public class Lwm2mTestHelper { public static final int TEMPERATURE_SENSOR = 3303; // Ids in Client + public static final int objectId_0 = 0; public static final int objectInstanceId_0 = 0; public static final int objectInstanceId_1 = 1; + public static final int objectInstanceId_2 = 2; public static final int objectInstanceId_12 = 12; public static final int resourceId_0 = 0; public static final int resourceId_1 = 1; public static final int resourceId_2 = 2; public static final int resourceId_3 = 3; + public static final int resourceId_4 = 4; + public static final int resourceId_8 = 8; public static final int resourceId_9 = 9; public static final int resourceId_11 = 11; public static final int resourceId_14 = 14; public static final int resourceId_15= 15; + public static final int resourceInstanceId_2 = 2; public static final String resourceIdName_3_9 = "batteryLevel"; public static final String resourceIdName_3_14 = "UtfOffset"; diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2MTestClient.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2MTestClient.java index 4c5406785c..b79fb39799 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2MTestClient.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2MTestClient.java @@ -44,7 +44,6 @@ import org.eclipse.leshan.core.request.BootstrapRequest; import org.eclipse.leshan.core.request.DeregisterRequest; import org.eclipse.leshan.core.request.RegisterRequest; import org.eclipse.leshan.core.request.UpdateRequest; -import org.thingsboard.common.util.ThingsBoardThreadFactory; import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl; import org.junit.Assert; diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/AbstractRpcLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/AbstractRpcLwM2MIntegrationTest.java index f635de509b..13bafd39d3 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/AbstractRpcLwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/AbstractRpcLwM2MIntegrationTest.java @@ -59,6 +59,7 @@ import static org.eclipse.leshan.core.LwM2mId.ACCESS_CONTROL; import static org.eclipse.leshan.core.LwM2mId.DEVICE; import static org.eclipse.leshan.core.LwM2mId.FIRMWARE; import static org.eclipse.leshan.core.LwM2mId.SERVER; +import static org.eclipse.leshan.core.LwM2mId.SOFTWARE_MANAGEMENT; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.BINARY_APP_DATA_CONTAINER; import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.COAP_CONFIG; @@ -72,6 +73,7 @@ import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SECURITY; import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SHORT_SERVER_ID; import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SHORT_SERVER_ID_BS; import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.TEMPERATURE_SENSOR; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.objectId_0; import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.objectInstanceId_0; import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.objectInstanceId_1; import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceIdName_19_0_0; @@ -158,12 +160,16 @@ public abstract class AbstractRpcLwM2MIntegrationTest extends AbstractWebsocketT public Set expectedObjectIdVerInstances; protected String objectInstanceIdVer_1; + protected String objectIdVer_0; protected String objectIdVer_2; private static final Predicate predicate_3 = path -> (!((String) path).contains("/" + TEMPERATURE_SENSOR) && ((String) path).contains("/" + DEVICE)); protected String objectIdVer_3; protected String objectInstanceIdVer_3; protected String objectInstanceIdVer_5; + protected String objectInstanceIdVer_9; protected String objectIdVer_19; + protected String objectIdVer_50 = "/50"; + protected String objectIdVer_3303; public AbstractRpcLwM2MIntegrationTest(){ } @@ -212,13 +218,21 @@ public abstract class AbstractRpcLwM2MIntegrationTest extends AbstractWebsocketT }); } }); - objectInstanceIdVer_1 = (String) expectedObjectIdVerInstances.stream().filter(path -> (!((String) path).contains("/" + BINARY_APP_DATA_CONTAINER) && ((String) path).contains("/" + SERVER))).findFirst().get(); + String ver_Id_0 = client.getClient().getObjectTree().getModel().getObjectModel(objectId_0).version; + if ("1.0".equals(ver_Id_0)) { + objectIdVer_0 = "/" + objectId_0; + } + else { + objectIdVer_0 = "/" + objectId_0 + "_" + ver_Id_0; + } objectIdVer_2 = (String) expectedObjectIdVers.stream().filter(path -> ((String) path).contains("/" + ACCESS_CONTROL)).findFirst().get(); objectIdVer_3 = (String) expectedObjects.stream().filter(predicate_3).findFirst().get(); - objectIdVer_19 = (String) expectedObjects.stream().filter(predicate_3).findFirst().get(); + objectIdVer_19 = (String) expectedObjectIdVers.stream().filter(path -> ((String) path).contains("/" + BINARY_APP_DATA_CONTAINER)).findFirst().get(); + objectIdVer_3303 = (String) expectedObjectIdVers.stream().filter(path -> ((String) path).contains("/" + TEMPERATURE_SENSOR)).findFirst().get(); + objectInstanceIdVer_1 = (String) expectedObjectIdVerInstances.stream().filter(path -> (!((String) path).contains("/" + BINARY_APP_DATA_CONTAINER) && ((String) path).contains("/" + SERVER))).findFirst().get(); objectInstanceIdVer_3 = (String) expectedObjectIdVerInstances.stream().filter(predicate_3).findFirst().get(); objectInstanceIdVer_5 = (String) expectedObjectIdVerInstances.stream().filter(path -> ((String) path).contains("/" + FIRMWARE)).findFirst().get(); - objectIdVer_19 = (String) expectedObjectIdVers.stream().filter(path -> ((String) path).contains("/" + BINARY_APP_DATA_CONTAINER)).findFirst().get(); + objectInstanceIdVer_9 = (String) expectedObjectIdVerInstances.stream().filter(path -> ((String) path).contains("/" + SOFTWARE_MANAGEMENT)).findFirst().get(); } protected void createDeviceProfile(String transportConfiguration) throws Exception { @@ -285,13 +299,13 @@ public abstract class AbstractRpcLwM2MIntegrationTest extends AbstractWebsocketT return bootstrap; } - protected String objectIdVerToObjectId(String objectIdVer) { - return objectIdVer.contains("_") ? objectIdVer.split("_")[0] : objectIdVer; - } - - protected String objectInstanceIdVerToObjectInstanceId(String objectInstanceIdVer) { - String[] objectIdVer = objectInstanceIdVer.split("/"); - return objectIdVer[1].contains("_") ? objectIdVer[1].split("_")[0] + "/" + objectIdVer[2] : objectInstanceIdVer; + protected String pathIdVerToObjectId(String pathIdVer) { + if (pathIdVer.contains("_")){ + String [] objVer = pathIdVer.split("/"); + objVer[1] = objVer[1].split("_")[0]; + return String.join("/", objVer); + } + return pathIdVer; } @After diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationCreateTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationCreateTest.java index 5997449d1f..4ab0d68794 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationCreateTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationCreateTest.java @@ -17,6 +17,7 @@ package org.thingsboard.server.transport.lwm2m.rpc.sql; import com.fasterxml.jackson.databind.node.ObjectNode; import org.eclipse.leshan.core.ResponseCode; +import org.eclipse.leshan.core.node.LwM2mPath; import org.junit.Test; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.transport.lwm2m.rpc.AbstractRpcLwM2MIntegrationTest; @@ -25,11 +26,29 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.objectInstanceId_0; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.objectInstanceId_1; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.objectInstanceId_12; import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_0; public class RpcLwm2mIntegrationCreateTest extends AbstractRpcLwM2MIntegrationTest { + /** + * Create {"id":"/19_1.1","value":{"0":{"0":"00AC"}, "1":1}} + * + * create_2_instances_in_object + * new ObjectInstance if Object is Multiple & Resource Single + * Create {"id":"/19_1.1/12","value":{"0":{"0":"00AC", "1":1}}} + * {"{"result":"CREATED"}"} + */ + @Test + public void testCreateObjectInstanceWithInstanceIdByIdKey_Result_CREATED() throws Exception { + String expectedPath = objectIdVer_19 + "/" + objectInstanceId_12; + String expectedValue = "{\"" + resourceId_0 + "\":{\"0\":\"00AC\"}, \"1\":1}"; + String actualResult = sendRPCreateById(expectedPath, expectedValue); + ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); + assertEquals(ResponseCode.CREATED.getName(), rpcActualResult.get("result").asText()); + } /** * Create {"id":"/19_1.1","value":{"0":{"0":"00AC"}, "1":1}} @@ -38,10 +57,9 @@ public class RpcLwm2mIntegrationCreateTest extends AbstractRpcLwM2MIntegrationTe * new ObjectInstance if Object is Multiple & Resource Single * Create {"id":"/19_1.1/0","value":{"0":{"0":"00AC", "1":1}}} * {"result":"BAD_REQUEST","error":"instance 0 already exists"} - * */ @Test - public void testCreateObjectInstanceWithInstanceIdAlreadyExistsByIdKey_Result_BAD_REQUEST() throws Exception { + public void testCreateObjectInstanceWithInstanceIdAlreadyExistsById_Result_BAD_REQUEST() throws Exception { String expectedPath = objectIdVer_19 + "/" + objectInstanceId_0; String expectedValue = "{\"" + resourceId_0 + "\":{\"0\":\"00AC\"}, \"1\":1}"; String actualResult = sendRPCreateById(expectedPath, expectedValue); @@ -54,20 +72,58 @@ public class RpcLwm2mIntegrationCreateTest extends AbstractRpcLwM2MIntegrationTe /** * failed: cannot_create_mandatory_single_object - * Create {"id":"/3/2","value":{"0":"00AC"}} + * Create {"id":"/3/1,"value":{"0":"00AC"}} + * {"result":"BAD_REQUEST","error":"Path /3/1. Object must be Multiple !"} */ - + @Test + public void testCreateObjectInstanceWithInstanceIdMandatorySingleObjectById_Result_BAD_REQUEST() throws Exception { + String expectedPath = objectIdVer_3 + "/" + objectInstanceId_1; + String expectedValue = "{\"" + resourceId_0 + "\":{\"0\":\"00AC\"}}"; + String actualResult = sendRPCreateById(expectedPath, expectedValue); + ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); + assertEquals(ResponseCode.BAD_REQUEST.getName(), rpcActualResult.get("result").asText()); + String expected = "Path " + expectedPath + ". Object must be Multiple !"; + String actual = rpcActualResult.get("error").asText(); + assertTrue(actual.equals(expected)); + } /** * failed: cannot_create_instance_of_security_object - * Create {"id":"/0/2","value":{"0":"00AC"}} + * Create {"id":"/0/2","value":{"2":4}} + * {"result":"BAD_REQUEST","error":"Specified object id 0 absent in the list supported objects of the client or is security object!"} */ + @Test + public void testCreateObjectInstanceWithInstanceIdSecurityObjectById_Result_BAD_REQUEST() throws Exception { + String expectedPath = objectIdVer_0 + "/" + objectInstanceId_1; + String expectedValue = "{\"" + resourceId_0 + "\":{\"2\":4}}"; + String actualResult = sendRPCreateById(expectedPath, expectedValue); + ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); + assertEquals(ResponseCode.BAD_REQUEST.getName(), rpcActualResult.get("result").asText()); + String expectedObjectId = pathIdVerToObjectId((String) expectedPath); + LwM2mPath expectedPathId = new LwM2mPath(expectedObjectId); + String expected = "Specified object id " + expectedPathId.getObjectId() + " absent in the list supported objects of the client or is security object!"; + String actual = rpcActualResult.get("error").asText(); + assertTrue(actual.equals(expected)); + } /** * failed: cannot_create_instance_of_absent_object - * Create {"id":"/50/2","value":{"0":"00AC"}} + * Create {"id":"/50/1","value":{"0":"00AC"}} + * {"result":"BAD_REQUEST","error":"Specified object id 50 absent in the list supported objects of the client or is security object!"} */ - + @Test + public void testCreateObjectInstanceWithInstanceIdAbsentObjectById_Result_BAD_REQUEST() throws Exception { + String expectedPath = objectIdVer_50+ "/" + objectInstanceId_1; + String expectedValue = "{\"" + resourceId_0 + "\":{\"0\":\"00AC\"}}"; + String actualResult = sendRPCreateById(expectedPath, expectedValue); + ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); + assertEquals(ResponseCode.BAD_REQUEST.getName(), rpcActualResult.get("result").asText()); + String expectedObjectId = pathIdVerToObjectId((String) expectedPath); + LwM2mPath expectedPathId = new LwM2mPath(expectedObjectId); + String expected = "Specified object id " + expectedPathId.getObjectId() + " absent in the list supported objects of the client or is security object!"; + String actual = rpcActualResult.get("error").asText(); + assertTrue(actual.equals(expected)); + } private String sendRPCreateById(String path, String value) throws Exception { String setRpcRequest = "{\"method\": \"Create\", \"params\": {\"id\": \"" + path + "\", \"value\": " + value + " }}"; diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationDeleteTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationDeleteTest.java new file mode 100644 index 0000000000..6f24d7176c --- /dev/null +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationDeleteTest.java @@ -0,0 +1,96 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.transport.lwm2m.rpc.sql; + +import com.fasterxml.jackson.databind.node.ObjectNode; +import org.eclipse.leshan.core.ResponseCode; +import org.junit.Test; +import org.thingsboard.common.util.JacksonUtil; +import org.thingsboard.server.transport.lwm2m.rpc.AbstractRpcLwM2MIntegrationTest; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.objectInstanceId_0; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.objectInstanceId_12; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_9; + + +public class RpcLwm2mIntegrationDeleteTest extends AbstractRpcLwM2MIntegrationTest { + + /** + * if there is such an instance + * Delete {"id":"/3303/12"} + * {"result":"DELETE"} + */ + @Test + public void testDeleteObjectInstanceIsSuchByIdKey_Result_DELETED() throws Exception { + String expectedPath = objectIdVer_3303 + "/" + objectInstanceId_12; + String actualResult = sendRPCDeleteById(expectedPath); + ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); + assertEquals(ResponseCode.DELETED.getName(), rpcActualResult.get("result").asText()); + } + + /** + * if there is no such instance + * Delete {"id":"/19/12"} + * {"result":"NOT_FOUND"} + */ + @Test + public void testDeleteObjectInstanceIsNotSuchByIdKey_Result_NOT_FOUND() throws Exception { + String expectedPath = objectIdVer_19 + "/" + objectInstanceId_12; + String actualResult = sendRPCDeleteById(expectedPath); + ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); + assertEquals(ResponseCode.NOT_FOUND.getName(), rpcActualResult.get("result").asText()); + } + + /** + * delete object + * Delete {"id":"/19_1.1"} + * {"result":"BAD_REQUEST","error":"Invalid path /19 : Only object instances can be delete"} + */ + @Test + public void testDeleteObjectByIdKey_Result_BAD_REQUEST() throws Exception { + String expectedPath = objectIdVer_19; + String actualResult = sendRPCDeleteById(expectedPath); + ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); + assertEquals(ResponseCode.BAD_REQUEST.getName(), rpcActualResult.get("result").asText()); + String expected = "Invalid path " + pathIdVerToObjectId((String) expectedPath) + " : Only object instances can be delete"; + String actual = rpcActualResult.get("error").asText(); + assertTrue(actual.equals(expected)); + } + + + /** + * delete resource + * Delete {"id":"/3/0/9"} + * {"result":"METHOD_NOT_ALLOWED"} + */ + @Test + public void testDeleteResourceByIdKey_Result_METHOD_NOT_ALLOWED() throws Exception { + String expectedPath = objectIdVer_3 + "/" + objectInstanceId_0 + resourceId_9; + String actualResult = sendRPCDeleteById(expectedPath); + ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); + assertEquals(ResponseCode.METHOD_NOT_ALLOWED.getName(), rpcActualResult.get("result").asText()); + } + + + private String sendRPCDeleteById(String path) throws Exception { + String setRpcRequest = "{\"method\": \"Delete\", \"params\": {\"id\": \"" + path + "\"}}"; + return doPostAsync("/api/plugins/rpc/twoway/" + deviceId, setRpcRequest, String.class, status().isOk()); + } + +} diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationDiscoverTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationDiscoverTest.java index 64acf699ee..b8ca7be61f 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationDiscoverTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationDiscoverTest.java @@ -74,7 +74,7 @@ public class RpcLwm2mIntegrationDiscoverTest extends AbstractRpcLwM2MIntegration expectedObjectIdVers.forEach(expected -> { try { String actualResult = sendDiscover((String) expected); - String expectedObjectId = objectIdVerToObjectId ((String) expected); + String expectedObjectId = pathIdVerToObjectId((String) expected); ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); assertEquals(ResponseCode.CONTENT.getName(), rpcActualResult.get("result").asText()); String[] actualValues = rpcActualResult.get("value").asText().split(","); @@ -88,8 +88,12 @@ public class RpcLwm2mIntegrationDiscoverTest extends AbstractRpcLwM2MIntegration /** * Discover {"id":"3/0"} - * - * @throws Exception + * If WriteAttributes not implemented: + * {"result":"CONTENT","value":",,,,,,,,,,,,,,,,,,,,,,,"} + * If WriteAttributes implemented and WriteAttributes saved + * Discover {"id":"19/0"} + * {"result":"CONTENT","value":"[;dim=2;pmin=10;pmax=60;gt=50;lt=42.2,;pmax=120, , , , , ;lt=45]"} */ @Test public void testDiscoverInstance_Return_CONTENT_LinksResourcesOnLyExpectedInstance() throws Exception { @@ -97,7 +101,7 @@ public class RpcLwm2mIntegrationDiscoverTest extends AbstractRpcLwM2MIntegration String actualResult = sendDiscover(expected); ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); assertEquals(ResponseCode.CONTENT.getName(), rpcActualResult.get("result").asText()); - String expectedObjectInstanceId = objectInstanceIdVerToObjectInstanceId (expected); + String expectedObjectInstanceId = pathIdVerToObjectId(expected); String[] actualValues = rpcActualResult.get("value").asText().split(","); assertTrue(actualValues.length > 0); assertEquals(0, Arrays.stream(actualValues).filter(path -> !path.contains(expectedObjectInstanceId)).collect(Collectors.toList()).size()); @@ -105,13 +109,20 @@ public class RpcLwm2mIntegrationDiscoverTest extends AbstractRpcLwM2MIntegration /** * Discover {"id":"3/0/14"} - * - * @throws Exception + * If WriteAttributes implemented: + * {"result":"CONTENT","value":";pmax=100, "pmin":10, "ver"=1.0"} + * If WriteAttributes not implemented: + * {"result":"CONTENT","value":""} + * Discover {"id":"19_1.1/0/0"} + * If WriteAttributes implemented: + * {"result":"CONTENT","value":";pmax=100, "pmin":10, "ver"=1.1"} + * If WriteAttributes not implemented: + * {"result":"CONTENT","value":""} */ @Test public void testDiscoverResource_Return_CONTENT_LinksResourceOnLyExpectedResource() throws Exception { String expectedInstance = (String) expectedInstances.stream().findFirst().get(); - String expectedObjectInstanceId = objectInstanceIdVerToObjectInstanceId (expectedInstance); + String expectedObjectInstanceId = pathIdVerToObjectId(expectedInstance); LwM2mPath expectedPath = new LwM2mPath(expectedObjectInstanceId); int expectedResource = client.getClient().getObjectTree().getObjectEnablers().get(expectedPath.getObjectId()).getObjectModel().resources.entrySet().stream().findAny().get().getKey(); String expected = expectedInstance + "/" + expectedResource; @@ -125,12 +136,11 @@ public class RpcLwm2mIntegrationDiscoverTest extends AbstractRpcLwM2MIntegration } /** - * Discover {"id":"2/0/2"} - * - * @throws Exception + * Discover {"id":"2/0"} + *{"result":"NOT_FOUND"} */ @Test - public void testDiscoverInstanceAbsentInObject_Return_NOT_FOUND() throws Exception { + public void testDiscoverObjectInstanceAbsentInObject_Return_NOT_FOUND() throws Exception { String expected = objectIdVer_2 + "/" + objectInstanceId_0; String actualResult = sendDiscover(expected); ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); @@ -138,8 +148,7 @@ public class RpcLwm2mIntegrationDiscoverTest extends AbstractRpcLwM2MIntegration } /** * Discover {"id":"2/0/2"} - * - * @throws Exception + * {"result":"NOT_FOUND"} */ @Test public void testDiscoverResourceAbsentInObject_Return_NOT_FOUND() throws Exception { diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationExecuteTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationExecuteTest.java new file mode 100644 index 0000000000..73ea0fb74c --- /dev/null +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationExecuteTest.java @@ -0,0 +1,186 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.transport.lwm2m.rpc.sql; + +import com.fasterxml.jackson.databind.node.ObjectNode; +import org.eclipse.leshan.core.ResponseCode; +import org.eclipse.leshan.core.node.LwM2mPath; +import org.junit.Test; +import org.thingsboard.common.util.JacksonUtil; +import org.thingsboard.server.transport.lwm2m.rpc.AbstractRpcLwM2MIntegrationTest; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.objectInstanceId_0; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_2; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_3; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_4; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_8; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_9; + + +public class RpcLwm2mIntegrationExecuteTest extends AbstractRpcLwM2MIntegrationTest { + + + /** + * Update FW + * Execute {"id":"5/0/2"} + * {"result":"CHANGED"} + */ + @Test + public void testExecuteUpdateFWById_Result_CHANGED() throws Exception { + String expectedPath = objectInstanceIdVer_5 + "/" + resourceId_2; + String actualResult = sendRPCExecuteById(expectedPath); + ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); + assertEquals(ResponseCode.CHANGED.getName(), rpcActualResult.get("result").asText()); + } + + /** + * Update SW + * Execute {"id":"9/0/4"} + * {"result":"CHANGED"} + */ + @Test + public void testExecuteUpdateSWById_Result_CHANGED() throws Exception { + String expectedPath = objectInstanceIdVer_9 + "/" + resourceId_4; + String actualResult = sendRPCExecuteById(expectedPath); + ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); + assertEquals(ResponseCode.CHANGED.getName(), rpcActualResult.get("result").asText()); + } + + /** + * Reboot + * Execute {"id":"3/0/4"} + * {"result":"CHANGED"} + */ + @Test + public void testExecuteRebootById_Result_CHANGED() throws Exception { + String expectedPath = objectInstanceIdVer_3 + "/" + resourceId_4; + String actualResult = sendRPCExecuteById(expectedPath); + ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); + assertEquals(ResponseCode.CHANGED.getName(), rpcActualResult.get("result").asText()); + } + + /** + * Registration Update Trigger + * Execute {"id":"1/0/8"} + * {"result":"CHANGED"} + */ + @Test + public void testExecuteRegistrationUpdateTriggerById_Result_CHANGED() throws Exception { + String expectedPath = objectInstanceIdVer_1 + "/" + resourceId_8; + String actualResult = sendRPCExecuteById(expectedPath); + ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); + assertEquals(ResponseCode.CHANGED.getName(), rpcActualResult.get("result").asText()); + } + + + /** + * execute_resource_with_parameters (execute reboot after 60 seconds on device) + * Execute {"id":"3/0/4","value":60} + * {"result":"CHANGED"} + */ + @Test + public void testExecuteResourceWithParametersById_Result_CHANGED() throws Exception { + String expectedPath = objectInstanceIdVer_3 + "/" + resourceId_4; + Object expectedValue = 60; + String actualResult = sendRPCExecuteWithValueById(expectedPath, expectedValue); + ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); + assertEquals(ResponseCode.CHANGED.getName(), rpcActualResult.get("result").asText()); + } + + /** + * Bootstrap-Request Trigger + * Execute {"id":"1/0/9"} + * {"result":"BAD_REQUEST","error":"probably no bootstrap server configured"} + */ + @Test + public void testExecuteBootstrapRequestTriggerById_Result_BAD_REQUEST_Error_NoBootstrapServerConfigured() throws Exception { + String expectedPath = objectInstanceIdVer_1 + "/" + resourceId_9; + String actualResult = sendRPCExecuteById(expectedPath); + ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); + assertEquals(ResponseCode.BAD_REQUEST.getName(), rpcActualResult.get("result").asText()); + String expected = "probably no bootstrap server configured"; + String actual = rpcActualResult.get("error").asText(); + assertTrue(actual.equals(expected)); + } + + /** + * bad: resource operation not "E" + * Execute {"id":"5/0/3"} + * {"result":"BAD_REQUEST","error":"Resource with /5/0/3 is not executable."} + */ + @Test + public void testExecuteResourceWithOperationNotExecuteById_Result_METHOD_NOT_ALLOWED() throws Exception { + String expectedPath = objectInstanceIdVer_5 + "/" + resourceId_3; + String actualResult = sendRPCExecuteById(expectedPath); + ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); + assertEquals(ResponseCode.BAD_REQUEST.getName(), rpcActualResult.get("result").asText()); + String expectedObjectId = pathIdVerToObjectId((String) expectedPath); + String expected = "Resource with " + expectedObjectId + " is not executable."; + String actual = rpcActualResult.get("error").asText(); + assertTrue(actual.equals(expected)); + } + + /** + * bad: execute_non_existing_resource_on_non_existing_object + * Execute {"id":"50/0/3"} + * {"result":"BAD_REQUEST","error":"Specified object id 50 absent in the list supported objects of the client or is security object!"} + */ + @Test + public void testExecuteNonExistingResourceOnNonExistingObjectById_Result_BAD_REQUEST() throws Exception { + String expectedPath = objectIdVer_50 + "/" + objectInstanceId_0 + "/" + resourceId_3; + String actualResult = sendRPCExecuteById(expectedPath); + ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); + assertEquals(ResponseCode.BAD_REQUEST.getName(), rpcActualResult.get("result").asText()); + String expectedObjectId = pathIdVerToObjectId((String) expectedPath); + LwM2mPath expectedPathId = new LwM2mPath(expectedObjectId); + String expected = "Specified object id " + expectedPathId.getObjectId() + " absent in the list supported objects of the client or is security object!"; + String actual = rpcActualResult.get("error").asText(); + assertTrue(actual.equals(expected)); + } + + /** + * bad: execute security object + * Execute {"id":"0/0/3"} + * {"result":"BAD_REQUEST","error":"Specified object id 0 absent in the list supported objects of the client or is security object!"} + */ + @Test + public void testExecuteSecurityObjectById_Result_NOT_FOUND() throws Exception { + String expectedPath = objectIdVer_0 + "/" + objectInstanceId_0 + "/" + resourceId_3; + String actualResult = sendRPCExecuteById(expectedPath); + ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); + assertEquals(ResponseCode.BAD_REQUEST.getName(), rpcActualResult.get("result").asText()); + String expectedObjectId = pathIdVerToObjectId((String) expectedPath); + LwM2mPath expectedPathId = new LwM2mPath(expectedObjectId); + String expected = "Specified object id " + expectedPathId.getObjectId() + " absent in the list supported objects of the client or is security object!"; + String actual = rpcActualResult.get("error").asText(); + assertTrue(actual.equals(expected)); + } + + + private String sendRPCExecuteById(String path) throws Exception { + String setRpcRequest = "{\"method\": \"Execute\", \"params\": {\"id\": \"" + path + "\"}}"; + return doPostAsync("/api/plugins/rpc/twoway/" + deviceId, setRpcRequest, String.class, status().isOk()); + } + + private String sendRPCExecuteWithValueById(String path, Object value) throws Exception { + String setRpcRequest = "{\"method\": \"Execute\", \"params\": {\"id\": \"" + path + "\", \"value\": " + value + " }}"; + return doPostAsync("/api/plugins/rpc/twoway/" + deviceId, setRpcRequest, String.class, status().isOk()); + } + +} diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationReadTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationReadTest.java index 4f696e1c3c..9116659bc3 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationReadTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationReadTest.java @@ -52,7 +52,7 @@ public class RpcLwm2mIntegrationReadTest extends AbstractRpcLwM2MIntegrationTest expectedObjectIdVers.forEach(expected -> { try { String actualResult = sendRPCById((String) expected); - String expectedObjectId = objectIdVerToObjectId ((String) expected); + String expectedObjectId = pathIdVerToObjectId((String) expected); LwM2mPath expectedPath = new LwM2mPath(expectedObjectId); ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); assertEquals(ResponseCode.CONTENT.getName(), rpcActualResult.get("result").asText()); @@ -77,7 +77,7 @@ public class RpcLwm2mIntegrationReadTest extends AbstractRpcLwM2MIntegrationTest expectedObjectIdVerInstances.forEach(expected -> { try { String actualResult = sendRPCById((String) expected); - String expectedObjectId = objectInstanceIdVerToObjectInstanceId ((String) expected); + String expectedObjectId = pathIdVerToObjectId((String) expected); LwM2mPath expectedPath = new LwM2mPath(expectedObjectId); ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); assertEquals(ResponseCode.CONTENT.getName(), rpcActualResult.get("result").asText()); @@ -136,10 +136,10 @@ public class RpcLwm2mIntegrationReadTest extends AbstractRpcLwM2MIntegrationTest @Test public void testReadCompositeSingleResourceByIds_Result_CONTENT_Value_IsObjectIsLwM2mSingleResourceIsLwM2mMultipleResource() throws Exception { String expectedIdVer_1 = (String) expectedObjectIdVers.stream().filter(path -> (!((String)path).contains("/" + BINARY_APP_DATA_CONTAINER) && ((String)path).contains("/" + SERVER))).findFirst().get(); - String objectId_1 = objectIdVerToObjectId(expectedIdVer_1); + String objectId_1 = pathIdVerToObjectId(expectedIdVer_1); String expectedIdVer3_0_1 = objectInstanceIdVer_3 + "/" + resourceId_1; String expectedIdVer3_0_11 = objectInstanceIdVer_3 + "/" + resourceId_11; - String objectInstanceId_3 = objectIdVerToObjectId(objectInstanceIdVer_3); + String objectInstanceId_3 = pathIdVerToObjectId(objectInstanceIdVer_3); String expectedIds = "[\"" + expectedIdVer_1 + "\", \"" + expectedIdVer3_0_1 + "\", \"" + expectedIdVer3_0_11 + "\"]"; String actualResult = sendCompositeRPCByIds(expectedIds); ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); @@ -165,10 +165,10 @@ public class RpcLwm2mIntegrationReadTest extends AbstractRpcLwM2MIntegrationTest String actualResult = sendCompositeRPCByIds(expectedIds); ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); assertEquals(ResponseCode.CONTENT.getName(), rpcActualResult.get("result").asText()); - String objectInstanceId_3 = objectInstanceIdVerToObjectInstanceId(objectInstanceIdVer_3); + String objectInstanceId_3 = pathIdVerToObjectId(objectInstanceIdVer_3); LwM2mPath path = new LwM2mPath(objectInstanceId_3); String expected3_0 = objectInstanceId_3 + "=LwM2mObjectInstance [id=" + path.getObjectInstanceId() + ", resources={"; - String objectInstanceId_1 = objectInstanceIdVerToObjectInstanceId(objectInstanceIdVer_1); + String objectInstanceId_1 = pathIdVerToObjectId(objectInstanceIdVer_1); String expected1_0_1 = objectInstanceId_1 + "/" + resourceId_1 + "=LwM2mSingleResource [id=" + resourceId_1 + ", value="; String expected1_0_2 = objectInstanceId_1 + "/" + resourceId_2 + "=null"; String actualValues = rpcActualResult.get("value").asText(); @@ -190,8 +190,8 @@ public class RpcLwm2mIntegrationReadTest extends AbstractRpcLwM2MIntegrationTest String actualResult = sendCompositeRPCByKeys(expectedKeys); ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); assertEquals(ResponseCode.CONTENT.getName(), rpcActualResult.get("result").asText()); - String objectInstanceId_3 = objectInstanceIdVerToObjectInstanceId(objectInstanceIdVer_3); - String objectId_19 = objectIdVerToObjectId(objectIdVer_19); + String objectInstanceId_3 = pathIdVerToObjectId(objectInstanceIdVer_3); + String objectId_19 = pathIdVerToObjectId(objectIdVer_19); String expected3_0_9 = objectInstanceId_3 + "/" + resourceId_9 + "=LwM2mSingleResource [id=" + resourceId_9 + ", value="; String expected3_0_14 = objectInstanceId_3 + "/" + resourceId_14 + "=LwM2mSingleResource [id=" + resourceId_14 + ", value="; String expected19_0_0 = objectId_19 + "/" + objectInstanceId_0 + "/" + resourceId_0 + "=null"; diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationWriteAttributesTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationWriteAttributesTest.java new file mode 100644 index 0000000000..ea23ab48b9 --- /dev/null +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationWriteAttributesTest.java @@ -0,0 +1,63 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.transport.lwm2m.rpc.sql; + +import com.fasterxml.jackson.databind.node.ObjectNode; +import org.eclipse.leshan.core.ResponseCode; +import org.eclipse.leshan.core.node.LwM2mPath; +import org.junit.Test; +import org.thingsboard.common.util.JacksonUtil; +import org.thingsboard.server.transport.lwm2m.rpc.AbstractRpcLwM2MIntegrationTest; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.objectInstanceId_0; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_14; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_2; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_3; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_4; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_8; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_9; + + +public class RpcLwm2mIntegrationWriteAttributesTest extends AbstractRpcLwM2MIntegrationTest { + + /** + * WriteAttributes {"id":"/3/0/14","attributes":{"pmax":100, "pmin":10}} + * if not implemented: + * {"result":"INTERNAL_SERVER_ERROR","error":"not implemented"} + * if implemented: + * {"result":"CHANGED"} + */ + @Test + public void testWriteAttributesResourceWithParametersById_Result_INTERNAL_SERVER_ERROR() throws Exception { + String expectedPath = objectInstanceIdVer_3 + "/" + resourceId_14; + String expectedValue = "{\"pmax\":100, \"pmin\":10}"; + String actualResult = sendRPCExecuteWithValueById(expectedPath, expectedValue); + ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); + assertEquals(ResponseCode.INTERNAL_SERVER_ERROR.getName(), rpcActualResult.get("result").asText()); + String expected = "not implemented"; + String actual = rpcActualResult.get("error").asText(); + assertTrue(actual.equals(expected)); + } + + private String sendRPCExecuteWithValueById(String path, String value) throws Exception { + String setRpcRequest = "{\"method\": \"WriteAttributes\", \"params\": {\"id\": \"" + path + "\", \"attributes\": " + value + " }}"; + return doPostAsync("/api/plugins/rpc/twoway/" + deviceId, setRpcRequest, String.class, status().isOk()); + } + +} diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationWriteTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationWriteTest.java index 0150572351..3bc9c075f1 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationWriteTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationWriteTest.java @@ -17,6 +17,7 @@ package org.thingsboard.server.transport.lwm2m.rpc.sql; import com.fasterxml.jackson.databind.node.ObjectNode; import org.eclipse.leshan.core.ResponseCode; +import org.eclipse.leshan.core.node.LwM2mPath; import org.junit.Test; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.transport.lwm2m.rpc.AbstractRpcLwM2MIntegrationTest; @@ -27,18 +28,21 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.BINARY_APP_DATA_CONTAINER; import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.objectInstanceId_0; import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.objectInstanceId_1; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.objectInstanceId_2; import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceIdName_3_14; import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_0; import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_14; import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_15; import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_9; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceInstanceId_2; public class RpcLwm2mIntegrationWriteTest extends AbstractRpcLwM2MIntegrationTest { /** - * id + * update SingleResource: * WriteReplace {"id":"3/0/14","value":"+12"} + * {"result":"CHANGED"} */ @Test public void testWriteReplaceValueSingleResourceById_Result_CHANGED() throws Exception { @@ -57,6 +61,7 @@ public class RpcLwm2mIntegrationWriteTest extends AbstractRpcLwM2MIntegrationTes /** * key * WriteReplace {"key":"timezone","value":"+10"} + * {"result":"CHANGED"} */ @Test public void testWriteReplaceValueSingleResourceByKey_Result_CHANGED() throws Exception { @@ -76,6 +81,7 @@ public class RpcLwm2mIntegrationWriteTest extends AbstractRpcLwM2MIntegrationTes /** * id * WriteReplace {"id": "/19_1.1/0/0","value": {"0":"0000ad45675600", "15":"1525ad45675600cdef"}} + * {"result":"CHANGED"} */ @Test public void testWriteReplaceValueMultipleResource_Result_CHANGED_Value_Multi_Instance_Resource_must_in_Json_format() throws Exception { @@ -121,7 +127,7 @@ public class RpcLwm2mIntegrationWriteTest extends AbstractRpcLwM2MIntegrationTes /** - * bad - only read + * bad: singleResource, operation="R" - only read * WriteReplace {"id":"/3/0/9","value":90} * {"result":"METHOD_NOT_ALLOWED"} */ @@ -137,7 +143,7 @@ public class RpcLwm2mIntegrationWriteTest extends AbstractRpcLwM2MIntegrationTes /** * ids * WriteUpdate {"id":"/3/0","value":{"14":"+5","15":"Kiyv/Europe"}} - * + * {"result":"CHANGED"} */ @Test public void testWriteUpdateValueSingleResourceById_Result_CHANGED() throws Exception { @@ -165,6 +171,7 @@ public class RpcLwm2mIntegrationWriteTest extends AbstractRpcLwM2MIntegrationTes /** * id * WriteUpdate {"id": "/19_1.1/0","value": {"0":{"0":"00ad456756", "25":"25ad456756"}}} + * {"result":"CHANGED"} */ @Test public void testWriteUpdateValueMultipleResourceById_Result_CHANGED() throws Exception { @@ -194,6 +201,7 @@ public class RpcLwm2mIntegrationWriteTest extends AbstractRpcLwM2MIntegrationTes /** * ResourceInstance + KeySingleResource + IdSingleResource * WriteComposite {"nodes":{"/19/1/0/2":"00001234", "UtfOffset":"+04", "/3/0/15":"Kiyv/Europe"}} + * {"result":"CHANGED"} */ @Test public void testWriteCompositeValueSingleResourceResourceInstanceByIdKey_Result_CHANGED() throws Exception { @@ -246,15 +254,17 @@ public class RpcLwm2mIntegrationWriteTest extends AbstractRpcLwM2MIntegrationTes /** - * create_2_instances_in_object - * new ObjectInstance if Object is Multiple & Resource Single - * Create {"id":"/19/2","value":{"1":2}} - * Create {"id":"/19/3","value":{"0":{"0":"00AC", "1":"ddff12"}}} + * update_resourceInstances&update_singleResource + * new ResourceInstance if Resource is Multiple & Resource Single + * - WriteReplace {"id":"/19_1.2/1/0","value":{"2":ddff12"}} + * - WriteReplace {"key":"UtfOffset","value":"+04"} + * - WriteReplace {"id":"/3/0/15","value":"Kiyv/Europe"} + * WriteComposite {"nodes":{"/19_1.1/1/0/2":"00001234", "UtfOffset":"+04", "/3/0/15":"Kiyv/Europe"}}} + * {"result":"CHANGED"} */ @Test - public void testCreateObjectInstanceSingleByIdKey_Result_CHANGED() throws Exception { - int resourceInstanceId2 = 2; - String expectedPath19_1_0_2 = objectIdVer_19 + "/" + objectInstanceId_1 + "/" + resourceId_0 + "/" + resourceInstanceId2; + public void testWriteCompositeCreateResourceInstanceUpdateSingleResourceByIdKey_Result_CHANGED() throws Exception { + String expectedPath19_1_0_2 = objectIdVer_19 + "/" + objectInstanceId_1 + "/" + resourceId_0 + "/" + resourceInstanceId_2; String expectedValue19_1_0_2 = "00001234"; String expectedKey3_0_14 = resourceIdName_3_14; String expectedValue3_0_14 = "+04"; @@ -268,7 +278,7 @@ public class RpcLwm2mIntegrationWriteTest extends AbstractRpcLwM2MIntegrationTes actualResult = sendRPCReadById(expectedPath19_1_0_2); rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); String actualValues = rpcActualResult.get("value").asText(); - String expected = "LwM2mResourceInstance [id=" + resourceInstanceId2 + ", value=" + expectedValue19_1_0_2.length()/2 + "Bytes, type=OPAQUE]"; + String expected = "LwM2mResourceInstance [id=" + resourceInstanceId_2 + ", value=" + expectedValue19_1_0_2.length()/2 + "Bytes, type=OPAQUE]"; assertTrue(actualValues.contains(expected)); actualResult = sendRPCReadByKey(expectedKey3_0_14); rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); @@ -283,20 +293,33 @@ public class RpcLwm2mIntegrationWriteTest extends AbstractRpcLwM2MIntegrationTes } /** - * failed: cannot_create_mandatory_single_object - * Create {"id":"/3/2","value":{"0":"00AC"}} - */ - - - /** - * failed: cannot_create_instance_of_security_object - * Create {"id":"/0/2","value":{"0":"00AC"}} - */ - - /** - * failed: cannot_create_instance_of_absent_object - * Create {"id":"/50/2","value":{"0":"00AC"}} + * composite_not created_new_instance... + * new ObjectInstance if Object is Multiple - bad + * - WriteReplace {"id":"/19_1.2/2/0","value":{"2":ddff12"}} + * - WriteReplace {"key":"UtfOffset","value":"+04"} + * - WriteReplace {"id":"/3/0/15","value":"Kiyv/Europe"} + * WriteComposite {"nodes":{"/19_1.1/1/0/2":"00001234", "UtfOffset":"+04", "/3/0/15":"Kiyv/Europe"}}} + * {"result":"BAD_REQUEST","error":"object instance /19/2 not found"} */ + @Test + public void testWriteCompositeCreateObjectInstanceUpdateSingleResourceByIdKey_Result_BAD_REQUEST() throws Exception { + String expectedPath19_1_2_2 = objectIdVer_19 + "/" + objectInstanceId_2 + "/" + resourceId_0 + "/" + resourceInstanceId_2; + String expectedValue19_1_0_2 = "00001234"; + String expectedKey3_0_14 = resourceIdName_3_14; + String expectedValue3_0_14 = "+04"; + String expectedPath3_0_15 = objectInstanceIdVer_3 + "/" + resourceId_15; + String expectedValue3_0_15 = "Kiyv/Europe"; + String nodes = "{\"" + expectedPath19_1_2_2 + "\":\"" + expectedValue19_1_0_2 + "\", \"" + expectedKey3_0_14 + + "\":\"" + expectedValue3_0_14 + "\", \"" + expectedPath3_0_15 + "\":\"" + expectedValue3_0_15 + "\"}"; + String actualResult = sendCompositeRPC(nodes); + ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); + assertEquals(ResponseCode.BAD_REQUEST.getName(), rpcActualResult.get("result").asText()); + String expectedObjectId = pathIdVerToObjectId((String) expectedPath19_1_2_2); + LwM2mPath expectedPathId = new LwM2mPath(expectedObjectId); + String expected = "object instance " + "/" + expectedPathId.getObjectId() + "/" + expectedPathId.getObjectInstanceId() + " not found"; + String actual = rpcActualResult.get("error").asText(); + assertTrue(actual.equals(expected)); + } private String sendRPCWriteStringById(String method, String path, String value) throws Exception { String setRpcRequest = "{\"method\": \"" + method + "\", \"params\": {\"id\": \"" + path + "\", \"value\": \"" + value + "\" }}"; diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/OtaLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/OtaLwM2MIntegrationTest.java index ffaeb3f5c6..96006cbe67 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/OtaLwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/OtaLwM2MIntegrationTest.java @@ -24,6 +24,7 @@ import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.device.credentials.lwm2m.NoSecClientCredentials; import org.thingsboard.server.common.data.kv.KvEntry; import org.thingsboard.server.common.data.kv.TsKvEntry; +import org.thingsboard.server.common.data.ota.OtaPackageType; import org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus; import org.thingsboard.server.transport.lwm2m.client.LwM2MTestClient; import org.thingsboard.server.transport.lwm2m.security.AbstractLwM2MIntegrationTest; @@ -40,6 +41,9 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.awaitility.Awaitility.await; import static org.hamcrest.Matchers.hasSize; import static org.thingsboard.rest.client.utils.RestJsonConverter.toTimeseries; +import static org.thingsboard.server.common.data.ota.OtaPackageKey.CHECKSUM; +import static org.thingsboard.server.common.data.ota.OtaPackageKey.CHECKSUM_ALGORITHM; +import static org.thingsboard.server.common.data.ota.OtaPackageKey.SIZE; import static org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus.DOWNLOADED; import static org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus.DOWNLOADING; import static org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus.FAILED; @@ -133,7 +137,7 @@ public class OtaLwM2MIntegrationTest extends AbstractLwM2MIntegrationTest { "}"; @Test - public void testFirmwareUpdateWithClientWithoutFirmwareInfo() throws Exception { + public void testFirmwareUpdateWithClientWithoutFirmwareOtaInfoFromProfile() throws Exception { String endpoint = "WithoutFirmwareInfoDevice"; createDeviceProfile(TRANSPORT_CONFIGURATION); NoSecClientCredentials clientCredentials = new NoSecClientCredentials(); diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/data/lwm2m/OtherConfiguration.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/data/lwm2m/OtherConfiguration.java index 4722246b4f..cf841d6204 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/device/data/lwm2m/OtherConfiguration.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/data/lwm2m/OtherConfiguration.java @@ -33,6 +33,4 @@ public class OtherConfiguration extends PowerSavingConfiguration { private Long pagingTransmissionWindow; private String fwUpdateResource; private String swUpdateResource; - private boolean compositeOperationsSupport; - } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java index ff2757ba3b..8106871aee 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java @@ -363,7 +363,7 @@ public class LwM2mClient implements Serializable { LwM2mPath pathIds = new LwM2mPath(fromVersionedIdToObjectId(path)); String verSupportedObject = registration.getSupportedObject().get(pathIds.getObjectId()); if (verSupportedObject == null) { - return String.format("Specified resource id %s is missing from the client!", path); + return String.format("Specified object id %s absent in the list supported objects of the client or is security object!", pathIds.getObjectId()); } else { String verRez = getVerFromPathIdVerOrId(path); if ((verRez != null && !verRez.equals(verSupportedObject)) || From 0c5d07e3a7f160e42497f71a2be3dc2a0cdeab24 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Fri, 3 Sep 2021 18:37:13 +0300 Subject: [PATCH 013/432] lwm2m: if client reboot or new connect and sharedAttribute not change: log "warn" ...Value is not changed or bad --- .../DefaultLwM2MAttributesService.java | 35 +++++++++---------- 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/attributes/DefaultLwM2MAttributesService.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/attributes/DefaultLwM2MAttributesService.java index f70af7bf0e..1da35484af 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/attributes/DefaultLwM2MAttributesService.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/attributes/DefaultLwM2MAttributesService.java @@ -58,6 +58,7 @@ import static org.eclipse.leshan.core.model.ResourceModel.Type.OPAQUE; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportServerHelper.getValueFromKvProto; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LWM2M_ERROR; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LWM2M_INFO; +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LWM2M_WARN; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertMultiResourceValuesFromJson; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.fromVersionedIdToObjectId; @@ -241,32 +242,30 @@ public class DefaultLwM2MAttributesService implements LwM2MAttributesService { private void pushUpdateMultiToClientIfNeeded(LwM2mClient client, ResourceModel resourceModel, JsonElement newValProto, Map valueOld, String versionedId) { - Map newValues = convertMultiResourceValuesFromJson((JsonObject)newValProto, resourceModel.type, versionedId); - if (newValues.size() > 0) { - if (valueOld != null && valueOld.size() > 0) { - valueOld.values().stream().forEach((v) -> { - if (newValues.containsKey(v.getId())) { - boolean isValueEquals; - if (OPAQUE.equals(v.getType())) { - isValueEquals = Arrays.equals((byte [])newValues.get(v.getId()), (byte[]) v.getValue()); - } else { - isValueEquals = newValues.get(v.getId()).toString().equals(v.getValue().toString()); - } - if (isValueEquals) { - newValues.remove(v.getId()); - } + Map newValues = convertMultiResourceValuesFromJson((JsonObject) newValProto, resourceModel.type, versionedId); + if (newValues.size() > 0 && valueOld != null && valueOld.size() > 0) { + valueOld.values().stream().forEach((v) -> { + if (newValues.containsKey(v.getId())) { + boolean isValueEquals; + if (OPAQUE.equals(v.getType())) { + isValueEquals = Arrays.equals((byte[]) newValues.get(v.getId()), (byte[]) v.getValue()); + } else { + isValueEquals = newValues.get(v.getId()).toString().equals(v.getValue().toString()); } - }); - } + if (isValueEquals) { + newValues.remove(v.getId()); + } + } + }); } if (newValues.size() > 0) { TbLwM2MWriteReplaceRequest request = TbLwM2MWriteReplaceRequest.builder().versionedId(versionedId).value(newValues).timeout(this.config.getTimeout()).build(); downlinkHandler.sendWriteReplaceRequest(client, request, new TbLwM2MWriteResponseCallback(uplinkHandler, logService, client, versionedId)); } else { - log.error("Failed update resource [{}] [{}]", versionedId, newValProto); + log.warn("Failed update resource [{}] [{}]", versionedId, newValProto); String logMsg = String.format("%s: Failed update resource versionedId - %s value - %s. Value is not changed or bad", - LOG_LWM2M_ERROR, versionedId, newValProto); + LOG_LWM2M_WARN, versionedId, newValProto); logService.log(client, logMsg); } } From e68a713b4fc3fdf1163d3287e649a48f757a72d7 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Mon, 6 Sep 2021 11:18:27 +0300 Subject: [PATCH 014/432] lwm2m: if client reboot or new connect and sharedAttribute not change: log "warn" ...Value is not changed "error" ...Value is bad --- .../attributes/DefaultLwM2MAttributesService.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/attributes/DefaultLwM2MAttributesService.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/attributes/DefaultLwM2MAttributesService.java index 1da35484af..8752657f94 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/attributes/DefaultLwM2MAttributesService.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/attributes/DefaultLwM2MAttributesService.java @@ -226,13 +226,13 @@ public class DefaultLwM2MAttributesService implements LwM2MAttributesService { String logMsg = String.format("%s: Failed update resource versionedId - %s value - %s. New value is bad", LOG_LWM2M_ERROR, versionedId, "null"); logService.log(lwM2MClient, logMsg); - log.error("Failed update resource [{}] [{}]", versionedId, newValue); - } else if ((valueOld != null && newValue.toString().equals(valueOld.toString()))){ + log.error("Failed update resource [{}] [{}]", versionedId, "null"); + } else if (newValue.toString().equals(valueOld.toString())){ if (logFailedUpdateOfNonChangedValue) { - String logMsg = String.format("%s: Failed update resource versionedId - %s value - %s. Value is not changed", - LOG_LWM2M_INFO, versionedId, newValue); + String logMsg = String.format("%s: Didn't update the versionedId resource - %s value - %s. Value is not changed", + LOG_LWM2M_WARN, versionedId, newValue); logService.log(lwM2MClient, logMsg); - log.info("Failed update resource [{}] [{}]. Value is not changed", versionedId, newValue); + log.warn("Didn't update resource [{}] [{}]. Value is not changed", versionedId, newValue); } } else { TbLwM2MWriteReplaceRequest request = TbLwM2MWriteReplaceRequest.builder().versionedId(versionedId).value(newValue).timeout(clientContext.getRequestTimeout(lwM2MClient)).build(); @@ -263,8 +263,8 @@ public class DefaultLwM2MAttributesService implements LwM2MAttributesService { TbLwM2MWriteReplaceRequest request = TbLwM2MWriteReplaceRequest.builder().versionedId(versionedId).value(newValues).timeout(this.config.getTimeout()).build(); downlinkHandler.sendWriteReplaceRequest(client, request, new TbLwM2MWriteResponseCallback(uplinkHandler, logService, client, versionedId)); } else { - log.warn("Failed update resource [{}] [{}]", versionedId, newValProto); - String logMsg = String.format("%s: Failed update resource versionedId - %s value - %s. Value is not changed or bad", + log.warn("Didn't update resource [{}] [{}]", versionedId, newValProto); + String logMsg = String.format("%s: Didn't update resource versionedId - %s value - %s. Value is not changed", LOG_LWM2M_WARN, versionedId, newValProto); logService.log(client, logMsg); } From 58f4c7420d5f02a050ff0121dcfc65f515c893a0 Mon Sep 17 00:00:00 2001 From: Ivan Panakhno Date: Mon, 6 Sep 2021 16:56:48 +0300 Subject: [PATCH 015/432] add command IN and NOT_IN for a filter to the dashboard --- .../data/query/StringFilterPredicate.java | 4 +++- .../dao/sql/query/EntityKeyMapping.java | 24 ++++++++++++++++++- .../app/shared/models/query/query.models.ts | 8 +++++-- .../assets/locale/locale.constant-en_US.json | 4 +++- 4 files changed, 35 insertions(+), 5 deletions(-) diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/query/StringFilterPredicate.java b/common/data/src/main/java/org/thingsboard/server/common/data/query/StringFilterPredicate.java index d3a09813e3..f4da15df4e 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/query/StringFilterPredicate.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/query/StringFilterPredicate.java @@ -38,6 +38,8 @@ public class StringFilterPredicate implements SimpleKeyFilterPredicate { STARTS_WITH, ENDS_WITH, CONTAINS, - NOT_CONTAINS + NOT_CONTAINS, + IN, + NOT_IN } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/query/EntityKeyMapping.java b/dao/src/main/java/org/thingsboard/server/dao/sql/query/EntityKeyMapping.java index caed48758a..94645388b6 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/query/EntityKeyMapping.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/query/EntityKeyMapping.java @@ -537,6 +537,7 @@ public class EntityKeyMapping { value = value.toLowerCase(); operationField = String.format("lower(%s)", operationField); } + List values = new ArrayList<>(); switch (stringFilterPredicate.getOperation()) { case EQUAL: stringOperationQuery = String.format("%s = :%s)", operationField, paramName); @@ -560,8 +561,29 @@ public class EntityKeyMapping { value = "%" + value + "%"; stringOperationQuery = String.format("%s not like :%s or %s is null)", operationField, paramName, operationField); break; + case IN: + value = value.replaceAll("'","").replaceAll("\"", ""); + values = List.of(value.trim().split("\\s*,\\s*")); + System.out.println(value); + stringOperationQuery = String.format("%s in (:%s))", operationField, paramName); + break; + case NOT_IN: + value = value.replaceAll("'","").replaceAll("\"", ""); + values = List.of(value.trim().split("\\s*,\\s*")); + System.out.println(value); + stringOperationQuery = String.format("%s not in (:%s))", operationField, paramName); + } + switch (stringFilterPredicate.getOperation()) { + case IN: + case NOT_IN: + for (String str : values) { + System.out.println(str); + } + ctx.addStringListParameter(paramName, values); + break; + default: + ctx.addStringParameter(paramName, value); } - ctx.addStringParameter(paramName, value); return String.format("((%s is not null and %s)", field, stringOperationQuery); } diff --git a/ui-ngx/src/app/shared/models/query/query.models.ts b/ui-ngx/src/app/shared/models/query/query.models.ts index e504a3480d..535319e7c4 100644 --- a/ui-ngx/src/app/shared/models/query/query.models.ts +++ b/ui-ngx/src/app/shared/models/query/query.models.ts @@ -226,7 +226,9 @@ export enum StringOperation { STARTS_WITH = 'STARTS_WITH', ENDS_WITH = 'ENDS_WITH', CONTAINS = 'CONTAINS', - NOT_CONTAINS = 'NOT_CONTAINS' + NOT_CONTAINS = 'NOT_CONTAINS', + IN = 'CONTAINS', + NOT_IN = 'NOT_CONTAINS' } export const stringOperationTranslationMap = new Map( @@ -236,7 +238,9 @@ export const stringOperationTranslationMap = new Map( [StringOperation.STARTS_WITH, 'filter.operation.starts-with'], [StringOperation.ENDS_WITH, 'filter.operation.ends-with'], [StringOperation.CONTAINS, 'filter.operation.contains'], - [StringOperation.NOT_CONTAINS, 'filter.operation.not-contains'] + [StringOperation.NOT_CONTAINS, 'filter.operation.not-contains'], + [StringOperation.IN, 'filter.operation.in'], + [StringOperation.NOT_IN, 'filter.operation.not-in'] ] ); diff --git a/ui-ngx/src/assets/locale/locale.constant-en_US.json b/ui-ngx/src/assets/locale/locale.constant-en_US.json index 5cd4a38065..4e8efca115 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -2003,7 +2003,9 @@ "greater-or-equal": "greater or equal", "less-or-equal": "less or equal", "and": "and", - "or": "or" + "or": "or", + "in": "in", + "not-in": "not in" }, "ignore-case": "ignore case", "value": "Value", From e3dee573e53a0a5ba9e03d1c70360805688c91cf Mon Sep 17 00:00:00 2001 From: Ivan Panakhno Date: Mon, 6 Sep 2021 17:28:32 +0300 Subject: [PATCH 016/432] add command IN and NOT_IN for a filter to the dashboard(fix error) --- ui-ngx/src/app/shared/models/query/query.models.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ui-ngx/src/app/shared/models/query/query.models.ts b/ui-ngx/src/app/shared/models/query/query.models.ts index 535319e7c4..d72aed9798 100644 --- a/ui-ngx/src/app/shared/models/query/query.models.ts +++ b/ui-ngx/src/app/shared/models/query/query.models.ts @@ -227,8 +227,8 @@ export enum StringOperation { ENDS_WITH = 'ENDS_WITH', CONTAINS = 'CONTAINS', NOT_CONTAINS = 'NOT_CONTAINS', - IN = 'CONTAINS', - NOT_IN = 'NOT_CONTAINS' + IN = 'IN', + NOT_IN = 'NOT_IN' } export const stringOperationTranslationMap = new Map( From 7add33f3c8820364215498bc64db9c7483ca2498 Mon Sep 17 00:00:00 2001 From: Ivan Panakhno Date: Mon, 6 Sep 2021 17:29:12 +0300 Subject: [PATCH 017/432] add command IN and NOT_IN for a filter to the dashboard(fix error) --- .../org/thingsboard/server/dao/sql/query/EntityKeyMapping.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/query/EntityKeyMapping.java b/dao/src/main/java/org/thingsboard/server/dao/sql/query/EntityKeyMapping.java index 94645388b6..575bb235e7 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/query/EntityKeyMapping.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/query/EntityKeyMapping.java @@ -576,9 +576,6 @@ public class EntityKeyMapping { switch (stringFilterPredicate.getOperation()) { case IN: case NOT_IN: - for (String str : values) { - System.out.println(str); - } ctx.addStringListParameter(paramName, values); break; default: From b95b8216948a37dd3b2a2be353c3639b6cb03644 Mon Sep 17 00:00:00 2001 From: Ivan Panakhno Date: Mon, 6 Sep 2021 17:31:41 +0300 Subject: [PATCH 018/432] add command IN and NOT_IN for a filter to the dashboard(fix error) --- .../org/thingsboard/server/dao/sql/query/EntityKeyMapping.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/query/EntityKeyMapping.java b/dao/src/main/java/org/thingsboard/server/dao/sql/query/EntityKeyMapping.java index 575bb235e7..56bee96721 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/query/EntityKeyMapping.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/query/EntityKeyMapping.java @@ -564,13 +564,11 @@ public class EntityKeyMapping { case IN: value = value.replaceAll("'","").replaceAll("\"", ""); values = List.of(value.trim().split("\\s*,\\s*")); - System.out.println(value); stringOperationQuery = String.format("%s in (:%s))", operationField, paramName); break; case NOT_IN: value = value.replaceAll("'","").replaceAll("\"", ""); values = List.of(value.trim().split("\\s*,\\s*")); - System.out.println(value); stringOperationQuery = String.format("%s not in (:%s))", operationField, paramName); } switch (stringFilterPredicate.getOperation()) { From f2aab72e06acbb481436c5eb59fd0beed453479d Mon Sep 17 00:00:00 2001 From: Ivan Panakhno Date: Mon, 6 Sep 2021 18:19:14 +0300 Subject: [PATCH 019/432] add command IN and NOT_IN for a filter to the dashboard(fix error after code review) --- .../thingsboard/server/dao/sql/query/EntityKeyMapping.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/query/EntityKeyMapping.java b/dao/src/main/java/org/thingsboard/server/dao/sql/query/EntityKeyMapping.java index 56bee96721..3328ceb4fa 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/query/EntityKeyMapping.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/query/EntityKeyMapping.java @@ -537,7 +537,6 @@ public class EntityKeyMapping { value = value.toLowerCase(); operationField = String.format("lower(%s)", operationField); } - List values = new ArrayList<>(); switch (stringFilterPredicate.getOperation()) { case EQUAL: stringOperationQuery = String.format("%s = :%s)", operationField, paramName); @@ -563,18 +562,17 @@ public class EntityKeyMapping { break; case IN: value = value.replaceAll("'","").replaceAll("\"", ""); - values = List.of(value.trim().split("\\s*,\\s*")); stringOperationQuery = String.format("%s in (:%s))", operationField, paramName); break; case NOT_IN: value = value.replaceAll("'","").replaceAll("\"", ""); - values = List.of(value.trim().split("\\s*,\\s*")); stringOperationQuery = String.format("%s not in (:%s))", operationField, paramName); + break; } switch (stringFilterPredicate.getOperation()) { case IN: case NOT_IN: - ctx.addStringListParameter(paramName, values); + ctx.addStringListParameter(paramName, List.of(value.trim().split("\\s*,\\s*"))); break; default: ctx.addStringParameter(paramName, value); From be5ec4fce93e3138d28c25ff069d47f45e72af4c Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Mon, 9 Aug 2021 15:10:04 +0300 Subject: [PATCH 020/432] Lwm2m: Device validate securityKey --- .../server/controller/DeviceController.java | 1 + .../LwM2MServerSecurityInfoRepository.java | 106 ++++++++++++++++-- .../data/security/DeviceCredentials.java | 8 ++ 3 files changed, 103 insertions(+), 12 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/DeviceController.java b/application/src/main/java/org/thingsboard/server/controller/DeviceController.java index 05385ee948..f1a58e7022 100644 --- a/application/src/main/java/org/thingsboard/server/controller/DeviceController.java +++ b/application/src/main/java/org/thingsboard/server/controller/DeviceController.java @@ -291,6 +291,7 @@ public class DeviceController extends BaseController { public DeviceCredentials saveDeviceCredentials(@RequestBody DeviceCredentials deviceCredentials) throws ThingsboardException { checkNotNull(deviceCredentials); try { + lwM2MServerSecurityInfoRepository.verifySecurityKeyDevice(deviceCredentials); Device device = checkDeviceId(deviceCredentials.getDeviceId(), Operation.WRITE_CREDENTIALS); DeviceCredentials result = checkNotNull(deviceCredentialsService.updateDeviceCredentials(getCurrentUser().getTenantId(), deviceCredentials)); tbClusterService.pushMsgToCore(new DeviceCredentialsUpdateNotificationMsg(getCurrentUser().getTenantId(), deviceCredentials.getDeviceId(), result), null); diff --git a/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MServerSecurityInfoRepository.java b/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MServerSecurityInfoRepository.java index b4ac3d30fd..f8ff9a687a 100644 --- a/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MServerSecurityInfoRepository.java +++ b/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MServerSecurityInfoRepository.java @@ -16,33 +16,29 @@ package org.thingsboard.server.service.lwm2m; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.node.ObjectNode; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.eclipse.leshan.core.SecurityMode; import org.eclipse.leshan.core.util.Hex; +import org.eclipse.leshan.core.util.SecurityUtil; +import org.eclipse.leshan.server.bootstrap.InvalidConfigurationException; import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.stereotype.Service; import org.thingsboard.server.common.data.lwm2m.ServerSecurityConfig; +import org.thingsboard.server.common.data.security.DeviceCredentials; import org.thingsboard.server.transport.lwm2m.config.LwM2MSecureServerConfig; import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportBootstrapConfig; import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; -import java.math.BigInteger; -import java.security.AlgorithmParameters; +import java.io.IOException; import java.security.GeneralSecurityException; -import java.security.KeyFactory; import java.security.KeyStore; -import java.security.KeyStoreException; -import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; import java.security.PublicKey; -import java.security.UnrecoverableKeyException; -import java.security.cert.CertificateEncodingException; +import java.security.cert.Certificate; import java.security.cert.X509Certificate; -import java.security.spec.ECGenParameterSpec; -import java.security.spec.ECParameterSpec; -import java.security.spec.ECPoint; -import java.security.spec.ECPublicKeySpec; -import java.security.spec.KeySpec; @Slf4j @Service @@ -84,5 +80,91 @@ public class LwM2MServerSecurityInfoRepository { return ""; } + public void verifySecurityKeyDevice(DeviceCredentials result) throws InvalidConfigurationException, JsonProcessingException { + ObjectNode node = result.getNodeCredentialsValue(); + checkClientKey ((ObjectNode) node.get("client")); + checkServerKey ((ObjectNode) node.get("bootstrap").get("bootstrapServer"), "Client`s by bootstrapServer"); + checkServerKey ((ObjectNode) node.get("bootstrap").get("lwm2mServer"), "Client`s by lwm2mServer"); + } + + private void checkClientKey (ObjectNode node) throws InvalidConfigurationException { + String modeName = node.get("securityConfigClientMode").asText(); + // checks security config + String value = node.get("key").textValue(); + if (SecurityMode.RPK.name().equals(modeName)) { + assertIf(decodeRfc7250PublicKey(Hex.decodeHex(((String) value).toCharArray())) == null, + "raw-public-key mode, Client`s public key or id must be RFC7250 encoded public key"); + } else if (SecurityMode.X509.name().equals(modeName)) { + assertIf(decodeCertificate(Hex.decodeHex(((String) value).toCharArray())) == null, + "x509 mode, Client`s public key must be DER encoded X.509 certificate"); + } + + } + + private void checkServerKey (ObjectNode node, String serverType) throws InvalidConfigurationException { + String modeName = node.get("securityMode").asText(); + // checks security config + if (SecurityMode.RPK.name().equals(modeName)) { + checkRPKServer(node, serverType); + } else if (SecurityMode.X509.name().equals(modeName)) { + checkX509Server(node); + } + + } + + protected void checkRPKServer(ObjectNode node, String serverType) throws InvalidConfigurationException { + String value = node.get("clientSecretKey").textValue(); + assertIf(decodeRfc5958PrivateKey(Hex.decodeHex(((String) value).toCharArray())) == null, + "raw-public-key mode, " + serverType + " secret key must be RFC5958 encoded private key"); + value = node.get("clientPublicKeyOrId").textValue(); + assertIf(decodeRfc7250PublicKey(Hex.decodeHex(((String) value).toCharArray())) == null, + "raw-public-key mode, " + serverType + " public key or id must be RFC7250 encoded public key"); + } + + protected void checkX509Server(ObjectNode node) throws InvalidConfigurationException { + String value = node.get("clientSecretKey").textValue();; + assertIf(decodeRfc5958PrivateKey(Hex.decodeHex(((String) value).toCharArray())) == null, + "x509 mode, secret key must be RFC5958 encoded private key"); + value = node.get("clientPublicKeyOrId").textValue(); + assertIf(decodeCertificate(Hex.decodeHex(((String) value).toCharArray())) == null, + "x509 mode, server public key must be DER encoded X.509 certificate"); + + } + + protected PrivateKey decodeRfc5958PrivateKey(byte[] encodedKey) throws InvalidConfigurationException { + try { + return SecurityUtil.privateKey.decode(encodedKey); + } catch (IOException | GeneralSecurityException e) { + return null; + } + } + + protected PublicKey decodeRfc7250PublicKey(byte[] encodedKey) throws InvalidConfigurationException { + try { + return SecurityUtil.publicKey.decode(encodedKey); + } catch (IOException | GeneralSecurityException e) { + return null; + } + } + + protected Certificate decodeCertificate(byte[] encodedCert) throws InvalidConfigurationException { + try { + return SecurityUtil.certificate.decode(encodedCert); + } catch (IOException | GeneralSecurityException e) { + return null; + } + } + + protected static void assertIf(boolean condition, String message) throws InvalidConfigurationException { + if (condition) { + throw new InvalidConfigurationException(message); + } + } + + protected static boolean isEmpty(byte[] array) { + return array == null || array.length == 0; + } + + } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/security/DeviceCredentials.java b/common/data/src/main/java/org/thingsboard/server/common/data/security/DeviceCredentials.java index 337e6cf349..e7c5d7d19b 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/security/DeviceCredentials.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/security/DeviceCredentials.java @@ -15,6 +15,9 @@ */ package org.thingsboard.server.common.data.security; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; import lombok.EqualsAndHashCode; import org.thingsboard.server.common.data.BaseData; import org.thingsboard.server.common.data.id.DeviceCredentialsId; @@ -87,4 +90,9 @@ public class DeviceCredentials extends BaseData implements + id + "]"; } + public ObjectNode getNodeCredentialsValue () throws JsonProcessingException { + ObjectMapper mapper = new ObjectMapper(); + return (ObjectNode) mapper.readTree(this.credentialsValue); + } + } From 4b74d2bde1c8ad6e7354288b8a907c96974bf905 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Tue, 7 Sep 2021 23:16:18 +0300 Subject: [PATCH 021/432] lwm2m: fix bug WriteUpdate & updateAttributes after sleep --- .../DefaultLwM2MAttributesService.java | 23 +++--- .../DefaultLwM2mDownlinkMsgHandler.java | 72 ++++++++++++------- 2 files changed, 56 insertions(+), 39 deletions(-) diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/attributes/DefaultLwM2MAttributesService.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/attributes/DefaultLwM2MAttributesService.java index 8752657f94..38b4790216 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/attributes/DefaultLwM2MAttributesService.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/attributes/DefaultLwM2MAttributesService.java @@ -57,7 +57,6 @@ import java.util.concurrent.atomic.AtomicInteger; import static org.eclipse.leshan.core.model.ResourceModel.Type.OPAQUE; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportServerHelper.getValueFromKvProto; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LWM2M_ERROR; -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LWM2M_INFO; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LWM2M_WARN; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertMultiResourceValuesFromJson; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.fromVersionedIdToObjectId; @@ -212,7 +211,7 @@ public class DefaultLwM2MAttributesService implements LwM2MAttributesService { Object newValProto = getValueFromKvProto(tsKvProto.getKv()); Object oldResourceValue = this.getResourceValueFormatKv(lwM2MClient, pathIdVer); if (!resourceModel.multiple || !(newValProto instanceof JsonElement)) { - this.pushUpdateToClientIfNeeded(lwM2MClient, oldResourceValue, newValProto, pathIdVer, logFailedUpdateOfNonChangedValue); + this.pushUpdateToClientIfNeeded(lwM2MClient, oldResourceValue, newValProto, pathIdVer, logFailedUpdateOfNonChangedValue, resourceModel.type); } else { pushUpdateMultiToClientIfNeeded(lwM2MClient, resourceModel, (JsonElement) newValProto, (Map) oldResourceValue, pathIdVer); @@ -221,22 +220,22 @@ public class DefaultLwM2MAttributesService implements LwM2MAttributesService { } private void pushUpdateToClientIfNeeded(LwM2mClient lwM2MClient, Object valueOld, Object newValue, - String versionedId, boolean logFailedUpdateOfNonChangedValue) { + String versionedId, boolean logFailedUpdateOfNonChangedValue, ResourceModel.Type type) { if (newValue == null) { String logMsg = String.format("%s: Failed update resource versionedId - %s value - %s. New value is bad", LOG_LWM2M_ERROR, versionedId, "null"); logService.log(lwM2MClient, logMsg); - log.error("Failed update resource [{}] [{}]", versionedId, "null"); - } else if (newValue.toString().equals(valueOld.toString())){ - if (logFailedUpdateOfNonChangedValue) { - String logMsg = String.format("%s: Didn't update the versionedId resource - %s value - %s. Value is not changed", - LOG_LWM2M_WARN, versionedId, newValue); - logService.log(lwM2MClient, logMsg); - log.warn("Didn't update resource [{}] [{}]. Value is not changed", versionedId, newValue); - } - } else { + log.error("Failed update resource [{}] [{}]", versionedId, "null"); + } else if ((valueOld == null) || + ((OPAQUE.equals(type) && !Arrays.equals((byte[]) newValue, (byte[]) valueOld)) || + !newValue.equals(valueOld))) { TbLwM2MWriteReplaceRequest request = TbLwM2MWriteReplaceRequest.builder().versionedId(versionedId).value(newValue).timeout(clientContext.getRequestTimeout(lwM2MClient)).build(); downlinkHandler.sendWriteReplaceRequest(lwM2MClient, request, new TbLwM2MWriteResponseCallback(uplinkHandler, logService, lwM2MClient, versionedId)); + } else if (logFailedUpdateOfNonChangedValue) { + String logMsg = String.format("%s: Didn't update the versionedId resource - %s value - %s. Value is not changed", + LOG_LWM2M_WARN, versionedId, newValue); + logService.log(lwM2MClient, logMsg); + log.warn("Didn't update resource [{}] [{}]. Value is not changed", versionedId, newValue); } } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2mDownlinkMsgHandler.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2mDownlinkMsgHandler.java index 2ef832333b..edf1d65fa0 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2mDownlinkMsgHandler.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2mDownlinkMsgHandler.java @@ -345,39 +345,57 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im @Override public void sendWriteUpdateRequest(LwM2mClient client, TbLwM2MWriteUpdateRequest request, DownlinkRequestCallback callback) { try { - validateVersionedId(client, request); - WriteRequest downlink = null; + LwM2mPath resultIds = new LwM2mPath(request.getObjectId()); - ContentFormat contentFormat = getWriteRequestContentFormat(client, request, this.config.getModelProvider()); - if (resultIds.isObjectInstance()) { - /* - * params = "{\"id\":0,\"value\":[{\"id\":14,\"value\":\"+5\"},{\"id\":15,\"value\":\"+9\"}]}" - * int rscId = resultIds.getObjectInstanceId(); - * contentFormat – Format of the payload (TLV or JSON). - */ - Collection resources = client.getNewResourcesForInstance(request.getVersionedId(), request.getValue(), this.config.getModelProvider(), this.converter); - if (resources.size() > 0) { - downlink = new WriteRequest(WriteRequest.Mode.UPDATE, contentFormat, resultIds.getObjectId(), resultIds.getObjectInstanceId(), resources); - } else { - callback.onValidationError(toString(request), "No resources to update!"); - } - } else if (resultIds.isResource()) { + if (resultIds.isObjectInstance() || resultIds.isResource()) { + validateVersionedId(client, request); ResourceModel resourceModelWrite = client.getResourceModel(request.getVersionedId(), this.config.getModelProvider()); - if (resourceModelWrite.multiple) { - if (request.getValue() instanceof Map && ((Map) request.getValue()).size() > 0) { - Map value = convertMultiResourceValuesFromRpcBody((LinkedHashMap) request.getValue(), resourceModelWrite.type, request.getObjectId()); - downlink = new WriteRequest(WriteRequest.Mode.UPDATE, contentFormat, resultIds.getObjectId(), resultIds.getObjectInstanceId(), resultIds.getResourceId(), - value, resourceModelWrite.type); + if (resourceModelWrite != null) { + WriteRequest downlink = null; + ContentFormat contentFormat = getWriteRequestContentFormat(client, request, this.config.getModelProvider()); + if (resultIds.isObjectInstance()) { + /* + * params = "{\"id\":0,\"value\":[{\"id\":14,\"value\":\"+5\"},{\"id\":15,\"value\":\"+9\"}]}" + * int rscId = resultIds.getObjectInstanceId(); + * contentFormat – Format of the payload (TLV or JSON). + */ + Collection resources = client.getNewResourcesForInstance(request.getVersionedId(), request.getValue(), this.config.getModelProvider(), this.converter); + if (resources.size() > 0) { + downlink = new WriteRequest(WriteRequest.Mode.UPDATE, contentFormat, resultIds.getObjectId(), resultIds.getObjectInstanceId(), resources); + } else { + callback.onValidationError(toString(request), "No resources to update!"); + } + } else if (resultIds.isResource()) { + if (resourceModelWrite.multiple) { + if (request.getValue() instanceof Map && ((Map) request.getValue()).size() > 0) { + Map value = convertMultiResourceValuesFromRpcBody((LinkedHashMap) request.getValue(), resourceModelWrite.type, request.getObjectId()); + downlink = new WriteRequest(WriteRequest.Mode.UPDATE, contentFormat, resultIds.getObjectId(), resultIds.getObjectInstanceId(), resultIds.getResourceId(), + value, resourceModelWrite.type); + } else { + callback.onValidationError(toString(request), "Resource value is bad. Format: " + request.getValue().getClass().getSimpleName() + ". Value of Multi-Instance Resource must be in Json format!"); + } + } + } + if (downlink != null) { + sendSimpleRequest(client, downlink, request.getTimeout(), callback); } else { - callback.onValidationError(toString(request), "Resource value is bad. Format: " + request.getValue().getClass().getSimpleName() + ". Value of Multi-Instance Resource must be in Json format!"); + callback.onValidationError(toString(request), "Resource " + request.getVersionedId() + ". This operation can only be used for ObjectInstance or Multi-Instance Resource !"); } } + else { + callback.onValidationError(toString(request), "Resource " + request.getVersionedId() + " is not configured in the device profile!"); + } } - if (downlink != null) { - sendSimpleRequest(client, downlink, request.getTimeout(), callback); - } else { - callback.onValidationError(toString(request), "Resource " + request.getVersionedId() + ". This operation can only be used for ObjectInstance or Multi-Instance Resource !"); + else { + callback.onValidationError(toString(request), "Resource " + request.getVersionedId() + ". This operation can only be used for ObjectInstance or Resource (multiple)"); } + + + + + + + } catch (Exception e) { callback.onValidationError(toString(request), e.getMessage()); } @@ -585,7 +603,7 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im } } else if (pathIds.isResource()) { ResourceModel resourceModel = client.getResourceModel(versionedId, modelProvider); - if (!resourceModel.multiple) { + if (resourceModel!= null && !resourceModel.multiple) { if (OBJLNK.equals(resourceModel.type)) { return ContentFormat.LINK; } else if (OPAQUE.equals(resourceModel.type)) { From e4941fdd103ef2c148c44b4f7ed0b138fc801c2c Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Mon, 9 Aug 2021 18:00:08 +0300 Subject: [PATCH 022/432] Lwm2m: DeviceProfile validate securityKey --- .../controller/DeviceProfileController.java | 2 +- .../LwM2MServerSecurityInfoRepository.java | 62 +++++++++++++------ 2 files changed, 45 insertions(+), 19 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/DeviceProfileController.java b/application/src/main/java/org/thingsboard/server/controller/DeviceProfileController.java index 3a68551773..46d76299ec 100644 --- a/application/src/main/java/org/thingsboard/server/controller/DeviceProfileController.java +++ b/application/src/main/java/org/thingsboard/server/controller/DeviceProfileController.java @@ -157,7 +157,7 @@ public class DeviceProfileController extends BaseController { isSoftwareChanged = true; } } - + lwM2MServerSecurityInfoRepository.verifySecurityKeyDeviceProfile(deviceProfile); DeviceProfile savedDeviceProfile = checkNotNull(deviceProfileService.saveDeviceProfile(deviceProfile)); tbClusterService.onDeviceProfileChange(savedDeviceProfile, null); diff --git a/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MServerSecurityInfoRepository.java b/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MServerSecurityInfoRepository.java index f8ff9a687a..cb7831e2ce 100644 --- a/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MServerSecurityInfoRepository.java +++ b/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MServerSecurityInfoRepository.java @@ -26,6 +26,8 @@ import org.eclipse.leshan.core.util.SecurityUtil; import org.eclipse.leshan.server.bootstrap.InvalidConfigurationException; import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.stereotype.Service; +import org.thingsboard.server.common.data.DeviceProfile; +import org.thingsboard.server.common.data.device.profile.Lwm2mDeviceProfileTransportConfiguration; import org.thingsboard.server.common.data.lwm2m.ServerSecurityConfig; import org.thingsboard.server.common.data.security.DeviceCredentials; import org.thingsboard.server.transport.lwm2m.config.LwM2MSecureServerConfig; @@ -39,6 +41,7 @@ import java.security.PrivateKey; import java.security.PublicKey; import java.security.cert.Certificate; import java.security.cert.X509Certificate; +import java.util.Map; @Slf4j @Service @@ -80,23 +83,27 @@ public class LwM2MServerSecurityInfoRepository { return ""; } - public void verifySecurityKeyDevice(DeviceCredentials result) throws InvalidConfigurationException, JsonProcessingException { - ObjectNode node = result.getNodeCredentialsValue(); - checkClientKey ((ObjectNode) node.get("client")); - checkServerKey ((ObjectNode) node.get("bootstrap").get("bootstrapServer"), "Client`s by bootstrapServer"); - checkServerKey ((ObjectNode) node.get("bootstrap").get("lwm2mServer"), "Client`s by lwm2mServer"); + public void verifySecurityKeyDevice(DeviceCredentials deviceCredentials) throws InvalidConfigurationException, JsonProcessingException { + ObjectNode nodeCredentialsValue = deviceCredentials.getNodeCredentialsValue(); + checkClientKey ((ObjectNode) nodeCredentialsValue.get("client")); + checkServerKey ((ObjectNode) nodeCredentialsValue.get("bootstrap").get("bootstrapServer"), "Client`s by bootstrapServer"); + checkServerKey ((ObjectNode) nodeCredentialsValue.get("bootstrap").get("lwm2mServer"), "Client`s by lwm2mServer"); } private void checkClientKey (ObjectNode node) throws InvalidConfigurationException { String modeName = node.get("securityConfigClientMode").asText(); // checks security config - String value = node.get("key").textValue(); + if (SecurityMode.RPK.name().equals(modeName)) { + String value = node.get("key").textValue(); assertIf(decodeRfc7250PublicKey(Hex.decodeHex(((String) value).toCharArray())) == null, "raw-public-key mode, Client`s public key or id must be RFC7250 encoded public key"); } else if (SecurityMode.X509.name().equals(modeName)) { - assertIf(decodeCertificate(Hex.decodeHex(((String) value).toCharArray())) == null, - "x509 mode, Client`s public key must be DER encoded X.509 certificate"); + String value = node.get("cert").textValue(); + if (value != null && !value.isEmpty()) { + assertIf(decodeCertificate(Hex.decodeHex(((String) value).toCharArray())) == null, + "x509 mode, Client`s public key must be DER encoded X.509 certificate"); + } } } @@ -107,28 +114,47 @@ public class LwM2MServerSecurityInfoRepository { if (SecurityMode.RPK.name().equals(modeName)) { checkRPKServer(node, serverType); } else if (SecurityMode.X509.name().equals(modeName)) { - checkX509Server(node); + checkX509Server(node, serverType); } - } protected void checkRPKServer(ObjectNode node, String serverType) throws InvalidConfigurationException { String value = node.get("clientSecretKey").textValue(); - assertIf(decodeRfc5958PrivateKey(Hex.decodeHex(((String) value).toCharArray())) == null, + assertIf(decodeRfc5958PrivateKey(Hex.decodeHex(value.toCharArray())) == null, "raw-public-key mode, " + serverType + " secret key must be RFC5958 encoded private key"); value = node.get("clientPublicKeyOrId").textValue(); - assertIf(decodeRfc7250PublicKey(Hex.decodeHex(((String) value).toCharArray())) == null, + assertIf(decodeRfc7250PublicKey(Hex.decodeHex(value.toCharArray())) == null, "raw-public-key mode, " + serverType + " public key or id must be RFC7250 encoded public key"); } - protected void checkX509Server(ObjectNode node) throws InvalidConfigurationException { - String value = node.get("clientSecretKey").textValue();; - assertIf(decodeRfc5958PrivateKey(Hex.decodeHex(((String) value).toCharArray())) == null, - "x509 mode, secret key must be RFC5958 encoded private key"); + protected void checkX509Server(ObjectNode node, String serverType) throws InvalidConfigurationException { + String value = node.get("clientSecretKey").textValue(); + assertIf(decodeRfc5958PrivateKey(Hex.decodeHex(value.toCharArray())) == null, + "x509 mode " + serverType + " secret key must be RFC5958 encoded private key"); value = node.get("clientPublicKeyOrId").textValue(); - assertIf(decodeCertificate(Hex.decodeHex(((String) value).toCharArray())) == null, - "x509 mode, server public key must be DER encoded X.509 certificate"); + assertIf(decodeCertificate(Hex.decodeHex(value.toCharArray())) == null, + "x509 mode " + serverType + " public key must be DER encoded X.509 certificate"); + + } + public void verifySecurityKeyDeviceProfile(DeviceProfile deviceProfile) throws InvalidConfigurationException, JsonProcessingException { + Map serverBs = ((Lwm2mDeviceProfileTransportConfiguration)deviceProfile.getProfileData().getTransportConfiguration()).getBootstrap().getBootstrapServer(); + checkDeviceProfileServer (serverBs, "Servers: BootstrapServer`s"); + Map serverLwm2m = ((Lwm2mDeviceProfileTransportConfiguration)deviceProfile.getProfileData().getTransportConfiguration()).getBootstrap().getLwm2mServer(); + checkDeviceProfileServer (serverLwm2m, "Servers: Lwm2mServer`s"); + + } + + protected void checkDeviceProfileServer (Map server, String serverType) throws InvalidConfigurationException{ + // checks security config + String value = (String) server.get("serverPublicKey"); + if (SecurityMode.RPK.name().equals(server.get("securityMode"))) { + assertIf(decodeRfc7250PublicKey(Hex.decodeHex(value.toCharArray())) == null, + "raw-public-key mode, " + serverType + " public key or id must be RFC7250 encoded public key"); + } else if (SecurityMode.X509.name().equals(server.get("securityMode"))) { + assertIf(decodeCertificate(Hex.decodeHex(value.toCharArray())) == null, + "x509 mode, " + serverType + " public key must be DER encoded X.509 certificate"); + } } protected PrivateKey decodeRfc5958PrivateKey(byte[] encodedKey) throws InvalidConfigurationException { From b40d0a7ac2ebe85dda4e4df7a234ba9eb0c9424d Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Tue, 10 Aug 2021 16:58:32 +0300 Subject: [PATCH 023/432] Lwm2m: DeviceProfile validate securityKey JsonNode --- .../LwM2MServerSecurityInfoRepository.java | 18 +++++++++--------- .../data/security/DeviceCredentials.java | 6 +++--- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MServerSecurityInfoRepository.java b/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MServerSecurityInfoRepository.java index cb7831e2ce..8750fa466c 100644 --- a/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MServerSecurityInfoRepository.java +++ b/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MServerSecurityInfoRepository.java @@ -17,7 +17,7 @@ package org.thingsboard.server.service.lwm2m; import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.node.ObjectNode; +import com.fasterxml.jackson.databind.JsonNode; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.eclipse.leshan.core.SecurityMode; @@ -84,13 +84,13 @@ public class LwM2MServerSecurityInfoRepository { } public void verifySecurityKeyDevice(DeviceCredentials deviceCredentials) throws InvalidConfigurationException, JsonProcessingException { - ObjectNode nodeCredentialsValue = deviceCredentials.getNodeCredentialsValue(); - checkClientKey ((ObjectNode) nodeCredentialsValue.get("client")); - checkServerKey ((ObjectNode) nodeCredentialsValue.get("bootstrap").get("bootstrapServer"), "Client`s by bootstrapServer"); - checkServerKey ((ObjectNode) nodeCredentialsValue.get("bootstrap").get("lwm2mServer"), "Client`s by lwm2mServer"); + JsonNode nodeCredentialsValue = deviceCredentials.getNodeCredentialsValue(); + checkClientKey (nodeCredentialsValue.get("client")); + checkServerKey (nodeCredentialsValue.get("bootstrap").get("bootstrapServer"), "Client`s by bootstrapServer"); + checkServerKey (nodeCredentialsValue.get("bootstrap").get("lwm2mServer"), "Client`s by lwm2mServer"); } - private void checkClientKey (ObjectNode node) throws InvalidConfigurationException { + private void checkClientKey (JsonNode node) throws InvalidConfigurationException { String modeName = node.get("securityConfigClientMode").asText(); // checks security config @@ -108,7 +108,7 @@ public class LwM2MServerSecurityInfoRepository { } - private void checkServerKey (ObjectNode node, String serverType) throws InvalidConfigurationException { + private void checkServerKey (JsonNode node, String serverType) throws InvalidConfigurationException { String modeName = node.get("securityMode").asText(); // checks security config if (SecurityMode.RPK.name().equals(modeName)) { @@ -118,7 +118,7 @@ public class LwM2MServerSecurityInfoRepository { } } - protected void checkRPKServer(ObjectNode node, String serverType) throws InvalidConfigurationException { + protected void checkRPKServer(JsonNode node, String serverType) throws InvalidConfigurationException { String value = node.get("clientSecretKey").textValue(); assertIf(decodeRfc5958PrivateKey(Hex.decodeHex(value.toCharArray())) == null, "raw-public-key mode, " + serverType + " secret key must be RFC5958 encoded private key"); @@ -127,7 +127,7 @@ public class LwM2MServerSecurityInfoRepository { "raw-public-key mode, " + serverType + " public key or id must be RFC7250 encoded public key"); } - protected void checkX509Server(ObjectNode node, String serverType) throws InvalidConfigurationException { + protected void checkX509Server(JsonNode node, String serverType) throws InvalidConfigurationException { String value = node.get("clientSecretKey").textValue(); assertIf(decodeRfc5958PrivateKey(Hex.decodeHex(value.toCharArray())) == null, "x509 mode " + serverType + " secret key must be RFC5958 encoded private key"); diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/security/DeviceCredentials.java b/common/data/src/main/java/org/thingsboard/server/common/data/security/DeviceCredentials.java index e7c5d7d19b..d49272f2c6 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/security/DeviceCredentials.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/security/DeviceCredentials.java @@ -16,8 +16,8 @@ package org.thingsboard.server.common.data.security; import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.node.ObjectNode; import lombok.EqualsAndHashCode; import org.thingsboard.server.common.data.BaseData; import org.thingsboard.server.common.data.id.DeviceCredentialsId; @@ -90,9 +90,9 @@ public class DeviceCredentials extends BaseData implements + id + "]"; } - public ObjectNode getNodeCredentialsValue () throws JsonProcessingException { + public JsonNode getNodeCredentialsValue () throws JsonProcessingException { ObjectMapper mapper = new ObjectMapper(); - return (ObjectNode) mapper.readTree(this.credentialsValue); + return mapper.readTree(this.credentialsValue); } } From d491e0f664725404cec24f8ee4e835916b402b90 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Tue, 7 Sep 2021 23:16:18 +0300 Subject: [PATCH 024/432] lwm2m: Security key validate in dao --- .../server/controller/BaseController.java | 8 +- .../server/controller/DeviceController.java | 1 - .../controller/DeviceProfileController.java | 1 - .../server/controller/Lwm2mController.java | 2 +- .../server/service/lwm2m/LwM2MService.java | 24 +++ .../AbstractLwM2MIntegrationTest.java | 44 ++++- .../security/sql/PskLwm2mIntegrationTest.java | 2 +- .../dao/device/DeviceCredentialsService.java | 4 + .../data/security/DeviceCredentials.java | 6 - .../lwm2m/server/LwM2mServerListener.java | 6 +- .../DefaultLwM2mDownlinkMsgHandler.java | 38 ++-- .../uplink/DefaultLwM2MUplinkMsgHandler.java | 2 - .../credentials/shell/lwM2M_credentials.sh | 1 - .../service/DefaultTransportService.java | 1 - dao/pom.xml | 4 + .../device/DeviceCredentialsServiceImpl.java | 170 ++++++++++++++++++ .../dao/device/DeviceProfileServiceImpl.java | 6 + .../credentials/shell/lwM2M_credentials.sh | 2 +- .../lwm2m-observe-attr-telemetry.component.ts | 8 +- 19 files changed, 280 insertions(+), 50 deletions(-) create mode 100644 application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MService.java diff --git a/application/src/main/java/org/thingsboard/server/controller/BaseController.java b/application/src/main/java/org/thingsboard/server/controller/BaseController.java index c37587f546..d456d7026b 100644 --- a/application/src/main/java/org/thingsboard/server/controller/BaseController.java +++ b/application/src/main/java/org/thingsboard/server/controller/BaseController.java @@ -126,7 +126,7 @@ import org.thingsboard.server.service.component.ComponentDiscoveryService; import org.thingsboard.server.service.edge.EdgeLicenseService; import org.thingsboard.server.service.edge.EdgeNotificationService; import org.thingsboard.server.service.edge.rpc.EdgeRpcService; -import org.thingsboard.server.service.lwm2m.LwM2MServerSecurityInfoRepository; +import org.thingsboard.server.service.lwm2m.LwM2MServiceImpl; import org.thingsboard.server.service.ota.OtaPackageStateService; import org.thingsboard.server.service.profile.TbDeviceProfileCache; import org.thingsboard.server.service.resource.TbResourceService; @@ -185,6 +185,9 @@ public abstract class BaseController { @Autowired protected DeviceProfileService deviceProfileService; + @Autowired + protected LwM2MServiceImpl lwM2MService; + @Autowired protected AssetService assetService; @@ -263,9 +266,6 @@ public abstract class BaseController { @Autowired protected TbDeviceProfileCache deviceProfileCache; - @Autowired - protected LwM2MServerSecurityInfoRepository lwM2MServerSecurityInfoRepository; - @Autowired(required = false) protected EdgeService edgeService; diff --git a/application/src/main/java/org/thingsboard/server/controller/DeviceController.java b/application/src/main/java/org/thingsboard/server/controller/DeviceController.java index f1a58e7022..05385ee948 100644 --- a/application/src/main/java/org/thingsboard/server/controller/DeviceController.java +++ b/application/src/main/java/org/thingsboard/server/controller/DeviceController.java @@ -291,7 +291,6 @@ public class DeviceController extends BaseController { public DeviceCredentials saveDeviceCredentials(@RequestBody DeviceCredentials deviceCredentials) throws ThingsboardException { checkNotNull(deviceCredentials); try { - lwM2MServerSecurityInfoRepository.verifySecurityKeyDevice(deviceCredentials); Device device = checkDeviceId(deviceCredentials.getDeviceId(), Operation.WRITE_CREDENTIALS); DeviceCredentials result = checkNotNull(deviceCredentialsService.updateDeviceCredentials(getCurrentUser().getTenantId(), deviceCredentials)); tbClusterService.pushMsgToCore(new DeviceCredentialsUpdateNotificationMsg(getCurrentUser().getTenantId(), deviceCredentials.getDeviceId(), result), null); diff --git a/application/src/main/java/org/thingsboard/server/controller/DeviceProfileController.java b/application/src/main/java/org/thingsboard/server/controller/DeviceProfileController.java index 46d76299ec..4f74676be5 100644 --- a/application/src/main/java/org/thingsboard/server/controller/DeviceProfileController.java +++ b/application/src/main/java/org/thingsboard/server/controller/DeviceProfileController.java @@ -157,7 +157,6 @@ public class DeviceProfileController extends BaseController { isSoftwareChanged = true; } } - lwM2MServerSecurityInfoRepository.verifySecurityKeyDeviceProfile(deviceProfile); DeviceProfile savedDeviceProfile = checkNotNull(deviceProfileService.saveDeviceProfile(deviceProfile)); tbClusterService.onDeviceProfileChange(savedDeviceProfile, null); diff --git a/application/src/main/java/org/thingsboard/server/controller/Lwm2mController.java b/application/src/main/java/org/thingsboard/server/controller/Lwm2mController.java index 64537d9f5f..fb71d4ea91 100644 --- a/application/src/main/java/org/thingsboard/server/controller/Lwm2mController.java +++ b/application/src/main/java/org/thingsboard/server/controller/Lwm2mController.java @@ -46,7 +46,7 @@ public class Lwm2mController extends BaseController { @ResponseBody public ServerSecurityConfig getLwm2mBootstrapSecurityInfo(@PathVariable("isBootstrapServer") boolean bootstrapServer) throws ThingsboardException { try { - return lwM2MServerSecurityInfoRepository.getServerSecurityInfo(bootstrapServer); + return lwM2MService.getServerSecurityInfo(bootstrapServer); } catch (Exception e) { throw handleException(e); } diff --git a/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MService.java b/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MService.java new file mode 100644 index 0000000000..7d1a69d270 --- /dev/null +++ b/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MService.java @@ -0,0 +1,24 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.service.lwm2m; + +import org.thingsboard.server.common.data.lwm2m.ServerSecurityConfig; + +public interface LwM2MService { + + ServerSecurityConfig getServerSecurityInfo(boolean bootstrapServer); + +} diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/AbstractLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/AbstractLwM2MIntegrationTest.java index 522abba65a..1bd9245cb2 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/AbstractLwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/AbstractLwM2MIntegrationTest.java @@ -57,6 +57,9 @@ import org.thingsboard.server.service.telemetry.cmd.TelemetryPluginCmdsWrapper; import org.thingsboard.server.service.telemetry.cmd.v2.EntityDataCmd; import org.thingsboard.server.service.telemetry.cmd.v2.EntityDataUpdate; import org.thingsboard.server.service.telemetry.cmd.v2.LatestValueCmd; +import org.thingsboard.server.transport.lwm2m.bootstrap.secure.LwM2MBootstrapConfig; +import org.thingsboard.server.transport.lwm2m.bootstrap.secure.LwM2MBootstrapServers; +import org.thingsboard.server.transport.lwm2m.bootstrap.secure.LwM2MServerBootstrap; import org.thingsboard.server.transport.lwm2m.client.LwM2MTestClient; import org.thingsboard.server.transport.lwm2m.secure.credentials.LwM2MCredentials; @@ -83,9 +86,18 @@ import java.util.List; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; +import static org.hamcrest.Matchers.containsString; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import static org.thingsboard.server.common.data.ota.OtaPackageType.FIRMWARE; import static org.thingsboard.server.common.data.ota.OtaPackageType.SOFTWARE; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.HOST; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.HOST_BS; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.PORT; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.PORT_BS; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SECURE_PORT; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SECURE_PORT_BS; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SHORT_SERVER_ID; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SHORT_SERVER_ID_BS; @DaoSqlTest public abstract class AbstractLwM2MIntegrationTest extends AbstractWebsocketTest { @@ -312,7 +324,13 @@ public abstract class AbstractLwM2MIntegrationTest extends AbstractWebsocketTest LwM2MCredentials credentials = new LwM2MCredentials(); credentials.setClient(clientCredentials); - + // TODO + /** + * Without: credentials.setBootstrap(createBootstrapConfig()); + * doPost("/api/device/credentials", deviceCredentials).andExpect(status().isBadRequest()) + * .andExpect(statusReason(containsString("Device credentials are missing fields or mandatory value in these fields: bootstrap, bootstrapServer, lwm2mServer"))); + */ + credentials.setBootstrap(createBootstrapConfig()); deviceCredentials.setCredentialsValue(JacksonUtil.toString(credentials)); doPost("/api/device/credentials", deviceCredentials).andExpect(status().isOk()); return device; @@ -351,6 +369,30 @@ public abstract class AbstractLwM2MIntegrationTest extends AbstractWebsocketTest return savaData("/api/otaPackage/" + savedFirmwareInfo.getId().getId().toString() + "?checksum={checksum}&checksumAlgorithm={checksumAlgorithm}", testData, CHECKSUM, "SHA256"); } + protected LwM2MBootstrapConfig createBootstrapConfig() { + LwM2MBootstrapConfig bootstrap = new LwM2MBootstrapConfig(); + LwM2MBootstrapServers servers = new LwM2MBootstrapServers(); + servers.setShortId(SHORT_SERVER_ID); + bootstrap.setServers(servers); + LwM2MServerBootstrap server = new LwM2MServerBootstrap(); + server.setHost(HOST); + server.setPort(PORT); + server.setSecurityHost(HOST); + server.setSecurityPort(SECURE_PORT); + server.setServerId(servers.getShortId()); + server.setBootstrapServerIs(false); + bootstrap.setLwm2mServer(server); + LwM2MServerBootstrap serverBS = new LwM2MServerBootstrap(); + serverBS.setHost(HOST_BS); + serverBS.setPort(PORT_BS); + serverBS.setSecurityHost(HOST_BS); + serverBS.setSecurityPort(SECURE_PORT_BS); + serverBS.setServerId(SHORT_SERVER_ID_BS); + serverBS.setBootstrapServerIs(true); + bootstrap.setBootstrapServer(serverBS); + return bootstrap; + } + protected OtaPackageInfo savaData(String urlTemplate, MockMultipartFile content, String... params) throws Exception { MockMultipartHttpServletRequestBuilder postRequest = MockMvcRequestBuilders.multipart(urlTemplate, params); postRequest.file(content); diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/PskLwm2mIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/PskLwm2mIntegrationTest.java index 014ab752fe..c99f978dae 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/PskLwm2mIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/PskLwm2mIntegrationTest.java @@ -33,7 +33,7 @@ public class PskLwm2mIntegrationTest extends AbstractLwM2MIntegrationTest { @Test public void testConnectWithPSKAndObserveTelemetry() throws Exception { String pskIdentity = "SOME_PSK_ID"; - String pskKey = "73656372657450534b"; + String pskKey = "0123456789ABCDEF0123456789ABCDEF"; PSKClientCredentials clientCredentials = new PSKClientCredentials(); clientCredentials.setEndpoint(ENDPOINT); clientCredentials.setKey(pskKey); diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsService.java index e131064953..9a333058a2 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsService.java @@ -15,8 +15,10 @@ */ package org.thingsboard.server.dao.device; +import org.thingsboard.server.common.data.device.profile.Lwm2mDeviceProfileTransportConfiguration; import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.lwm2m.ServerSecurityConfig; import org.thingsboard.server.common.data.security.DeviceCredentials; public interface DeviceCredentialsService { @@ -30,4 +32,6 @@ public interface DeviceCredentialsService { DeviceCredentials createDeviceCredentials(TenantId tenantId, DeviceCredentials deviceCredentials); void deleteDeviceCredentials(TenantId tenantId, DeviceCredentials deviceCredentials); + + void verifyLwm2mSecurityKeyDeviceProfile(Lwm2mDeviceProfileTransportConfiguration transportConfiguration) ; } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/security/DeviceCredentials.java b/common/data/src/main/java/org/thingsboard/server/common/data/security/DeviceCredentials.java index d49272f2c6..4ccf07f2b0 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/security/DeviceCredentials.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/security/DeviceCredentials.java @@ -89,10 +89,4 @@ public class DeviceCredentials extends BaseData implements + credentialsId + ", credentialsValue=" + credentialsValue + ", createdTime=" + createdTime + ", id=" + id + "]"; } - - public JsonNode getNodeCredentialsValue () throws JsonProcessingException { - ObjectMapper mapper = new ObjectMapper(); - return mapper.readTree(this.credentialsValue); - } - } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mServerListener.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mServerListener.java index 898a1ad8b2..edc408a78d 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mServerListener.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mServerListener.java @@ -40,7 +40,7 @@ public class LwM2mServerListener { public final RegistrationListener registrationListener = new RegistrationListener() { /** - * Register – запрос, представленный в виде POST /rd?… + * Register – query represented as POST /rd?… */ @Override public void registered(Registration registration, Registration previousReg, @@ -49,7 +49,7 @@ public class LwM2mServerListener { } /** - * Update – представляет из себя CoAP POST запрос на URL, полученный в ответ на Register. + * Update – query represented as CoAP POST request for the URL received in response to Register. */ @Override public void updated(RegistrationUpdate update, Registration updatedRegistration, @@ -58,7 +58,7 @@ public class LwM2mServerListener { } /** - * De-register (CoAP DELETE) – отправляется клиентом в случае инициирования процедуры выключения. + * De-register (CoAP DELETE) – Sent by the client when a shutdown procedure is initiated. */ @Override public void unregistered(Registration registration, Collection observations, boolean expired, diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2mDownlinkMsgHandler.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2mDownlinkMsgHandler.java index edf1d65fa0..b99fd2ac27 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2mDownlinkMsgHandler.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2mDownlinkMsgHandler.java @@ -345,13 +345,10 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im @Override public void sendWriteUpdateRequest(LwM2mClient client, TbLwM2MWriteUpdateRequest request, DownlinkRequestCallback callback) { try { - LwM2mPath resultIds = new LwM2mPath(request.getObjectId()); if (resultIds.isObjectInstance() || resultIds.isResource()) { validateVersionedId(client, request); - ResourceModel resourceModelWrite = client.getResourceModel(request.getVersionedId(), this.config.getModelProvider()); - if (resourceModelWrite != null) { - WriteRequest downlink = null; + WriteRequest downlink = null; ContentFormat contentFormat = getWriteRequestContentFormat(client, request, this.config.getModelProvider()); if (resultIds.isObjectInstance()) { /* @@ -365,15 +362,21 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im } else { callback.onValidationError(toString(request), "No resources to update!"); } - } else if (resultIds.isResource()) { - if (resourceModelWrite.multiple) { - if (request.getValue() instanceof Map && ((Map) request.getValue()).size() > 0) { - Map value = convertMultiResourceValuesFromRpcBody((LinkedHashMap) request.getValue(), resourceModelWrite.type, request.getObjectId()); - downlink = new WriteRequest(WriteRequest.Mode.UPDATE, contentFormat, resultIds.getObjectId(), resultIds.getObjectInstanceId(), resultIds.getResourceId(), - value, resourceModelWrite.type); - } else { - callback.onValidationError(toString(request), "Resource value is bad. Format: " + request.getValue().getClass().getSimpleName() + ". Value of Multi-Instance Resource must be in Json format!"); + } + else if (resultIds.isResource()) { + ResourceModel resourceModelWrite = client.getResourceModel(request.getVersionedId(), this.config.getModelProvider()); + if (resourceModelWrite != null) { + if (resourceModelWrite.multiple) { + if (request.getValue() instanceof Map && ((Map) request.getValue()).size() > 0) { + Map value = convertMultiResourceValuesFromRpcBody((LinkedHashMap) request.getValue(), resourceModelWrite.type, request.getObjectId()); + downlink = new WriteRequest(WriteRequest.Mode.UPDATE, contentFormat, resultIds.getObjectId(), resultIds.getObjectInstanceId(), resultIds.getResourceId(), + value, resourceModelWrite.type); + } else { + callback.onValidationError(toString(request), "Resource value is bad. Format: " + request.getValue().getClass().getSimpleName() + ". Value of Multi-Instance Resource must be in Json format!"); + } } + } else { + callback.onValidationError(toString(request), "Resource " + request.getVersionedId() + " is not configured in the device profile!"); } } if (downlink != null) { @@ -381,21 +384,10 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im } else { callback.onValidationError(toString(request), "Resource " + request.getVersionedId() + ". This operation can only be used for ObjectInstance or Multi-Instance Resource !"); } - } - else { - callback.onValidationError(toString(request), "Resource " + request.getVersionedId() + " is not configured in the device profile!"); - } } else { callback.onValidationError(toString(request), "Resource " + request.getVersionedId() + ". This operation can only be used for ObjectInstance or Resource (multiple)"); } - - - - - - - } catch (Exception e) { callback.onValidationError(toString(request), e.getMessage()); } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/DefaultLwM2MUplinkMsgHandler.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/DefaultLwM2MUplinkMsgHandler.java index 2c4f911db6..84ac0277a3 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/DefaultLwM2MUplinkMsgHandler.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/DefaultLwM2MUplinkMsgHandler.java @@ -418,8 +418,6 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl * #1 clientOnlyObserveAfterConnect == true * - Only Observe Request to the client marked as observe from the profile configuration. * #2. clientOnlyObserveAfterConnect == false - * После регистрации отправляю запрос на read всех ресурсов, которые после регистрации есть у клиента, - * а затем запрос на observe (edited) * - Read Request to the client after registration to read all resource values for all objects * - then Observe Request to the client marked as observe from the profile configuration. * diff --git a/common/transport/lwm2m/src/main/resources/credentials/shell/lwM2M_credentials.sh b/common/transport/lwm2m/src/main/resources/credentials/shell/lwM2M_credentials.sh index dcf38b4f10..f68ca30005 100644 --- a/common/transport/lwm2m/src/main/resources/credentials/shell/lwM2M_credentials.sh +++ b/common/transport/lwm2m/src/main/resources/credentials/shell/lwM2M_credentials.sh @@ -321,7 +321,6 @@ cert_end_point() { } if [ "$client_start" -lt "$client_finish" ]; then - echo "Файл содержит, как минимум, одно слово Bash." echo echo "==Start Client==" while [ "$CLIENT_NUMBER" -lt "$client_finish" ]; do diff --git a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java index bdc03d767c..dbe42cf9f4 100644 --- a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java +++ b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java @@ -899,7 +899,6 @@ public class DefaultTransportService implements TransportService { String resourceId = msg.getResourceKey(); transportResourceCache.update(tenantId, resourceType, resourceId); sessions.forEach((id, mdRez) -> { - log.warn("ResourceUpdate - [{}] [{}]", id, mdRez); transportCallbackExecutor.submit(() -> mdRez.getListener().onResourceUpdate(Optional.ofNullable(msg))); }); diff --git a/dao/pom.xml b/dao/pom.xml index 1ef95d8358..736ba64326 100644 --- a/dao/pom.xml +++ b/dao/pom.xml @@ -227,6 +227,10 @@ org.elasticsearch.client rest + + org.eclipse.leshan + leshan-server-cf + diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsServiceImpl.java index 3cce5e1506..9d0ff83491 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsServiceImpl.java @@ -15,9 +15,14 @@ */ package org.thingsboard.server.dao.device; +import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.ObjectNode; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.codec.DecoderException; +import org.apache.commons.codec.binary.Hex; +import org.eclipse.leshan.core.SecurityMode; +import org.eclipse.leshan.core.util.SecurityUtil; import org.hibernate.exception.ConstraintViolationException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cache.annotation.CacheEvict; @@ -30,6 +35,7 @@ import org.thingsboard.server.common.data.device.credentials.BasicMqttCredential import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MClientCredentials; import org.thingsboard.server.common.data.device.credentials.lwm2m.PSKClientCredentials; import org.thingsboard.server.common.data.device.credentials.lwm2m.X509ClientCredentials; +import org.thingsboard.server.common.data.device.profile.Lwm2mDeviceProfileTransportConfiguration; import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; @@ -39,10 +45,20 @@ import org.thingsboard.server.dao.entity.AbstractEntityService; import org.thingsboard.server.dao.exception.DataValidationException; import org.thingsboard.server.dao.service.DataValidator; +import java.io.IOException; +import java.security.GeneralSecurityException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.cert.Certificate; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + import static org.thingsboard.server.common.data.CacheConstants.DEVICE_CREDENTIALS_CACHE; import static org.thingsboard.server.dao.service.Validator.validateId; import static org.thingsboard.server.dao.service.Validator.validateString; + @Service @Slf4j public class DeviceCredentialsServiceImpl extends AbstractEntityService implements DeviceCredentialsService { @@ -92,6 +108,7 @@ public class DeviceCredentialsServiceImpl extends AbstractEntityService implemen break; case LWM2M_CREDENTIALS: formatSimpleLwm2mCredentials(deviceCredentials); + verifySecurityKeyDevice(deviceCredentials); break; } log.trace("Executing updateDeviceCredentials [{}]", deviceCredentials); @@ -237,4 +254,157 @@ public class DeviceCredentialsServiceImpl extends AbstractEntityService implemen } }; + + private void verifySecurityKeyDevice(DeviceCredentials deviceCredentials) { + try { +// LwM2MCredentialsValid credentials = JacksonUtil.fromString(deviceCredentials.getCredentialsValue(), LwM2MCredentialsValid.class); + JsonNode nodeCredentialsValue = JacksonUtil.toJsonNode(deviceCredentials.getCredentialsValue()); + String [] fields = {"client", "bootstrap", "bootstrap:bootstrapServer", "bootstrap:lwm2mServer"}; + String validateMsg = validateNodeCredentials (nodeCredentialsValue, fields); + if (validateMsg.isEmpty()) { + checkClientKey(nodeCredentialsValue.get("client")); + checkServerKey(nodeCredentialsValue.get("bootstrap").get("bootstrapServer"), "Client`s by bootstrapServer"); + checkServerKey(nodeCredentialsValue.get("bootstrap").get("lwm2mServer"), "Client`s by lwm2mServer"); + } + else { + throw new DataValidationException(validateMsg); + } + } catch (DataValidationException | DecoderException e) { + throw new DataValidationException(e.getMessage()); + } + } + + public void verifyLwm2mSecurityKeyDeviceProfile(Lwm2mDeviceProfileTransportConfiguration transportConfiguration) { + try { + Map serverBs = transportConfiguration.getBootstrap().getBootstrapServer(); + checkDeviceProfileServer (serverBs, "Servers: BootstrapServer`s"); + Map serverLwm2m = transportConfiguration.getBootstrap().getLwm2mServer(); + checkDeviceProfileServer (serverLwm2m, "Servers: Lwm2mServer`s"); + } catch (DataValidationException e) { + throw new DataValidationException(e.getMessage()); + + } + } + + private String validateNodeCredentials (JsonNode nodeCredentialsValue, String [] fields) { + Set msgSet = ConcurrentHashMap.newKeySet(); + String msg = ""; + for (String field : fields) { + if (field.contains(":")) { + String [] keys = field.split(":"); + if (!nodeCredentialsValue.hasNonNull(keys[0])) { + msgSet.add(keys[1]); + } + else { + if (!nodeCredentialsValue.get(keys[0]).hasNonNull(keys[1])) msgSet.add(keys[1]); + } + } + else { + if (!nodeCredentialsValue.hasNonNull(field)) msgSet.add(field); + } + } + if (msgSet.size() > 0) msg = "Device credentials are missing fields or mandatory value in this fields: " + String.join(", ", msgSet); + return msg; + } + + private void checkClientKey (JsonNode node) throws DataValidationException, DecoderException { + String modeName = node.get("securityConfigClientMode").asText(); + // checks security config + // HexDec Len = 32,64,128 + if (SecurityMode.PSK.name().equals(modeName)) { + String key = node.get("key").textValue(); + assertIf(key == null || key.isEmpty(), + "pre-shared-key mode, Client`s private key or id must be not null or empty."); + assertIf(!key.matches("-?[0-9a-fA-F]+"), + "pre-shared-key mode, Client`s private key or id must be HexDecimal format."); + assertIf(key.length()%32 != 0 , + "pre-shared-key mode, Client`s private key or id must be a multiple of 32."); + assertIf(key.length() > 128, + "pre-shared-key mode, Client`s private key or id must be not more than 128."); + String identity = node.get("identity").textValue(); + assertIf(identity == null || identity.isEmpty(), + "pre-shared-key mode, Client`s identity key must be not null or empty."); + } else if (SecurityMode.RPK.name().equals(modeName)) { + String value = node.get("key").textValue(); + assertIf(decodeRfc7250PublicKey(org.eclipse.leshan.core.util.Hex.decodeHex(((String) value).toCharArray())) == null, + "raw-public-key mode, Client`s public key or id must be RFC7250 encoded public key"); + } else if (SecurityMode.X509.name().equals(modeName)) { + String value = node.get("cert").textValue(); + if (value != null && !value.isEmpty()) { + assertIf(decodeCertificate(Hex.decodeHex(((String) value).toCharArray())) == null, + "x509 mode, Client`s public key must be DER encoded X.509 certificate"); + } + } + } + + private void checkServerKey (JsonNode node, String serverType) throws DataValidationException { + String modeName = node.get("securityMode").asText(); + // checks security config + if (SecurityMode.RPK.name().equals(modeName)) { + checkRPKServer(node, serverType); + } else if (SecurityMode.X509.name().equals(modeName)) { + checkX509Server(node, serverType); + } + } + + protected void checkRPKServer(JsonNode node, String serverType) throws DataValidationException { + String value = node.get("clientSecretKey").textValue(); + assertIf(decodeRfc5958PrivateKey(org.eclipse.leshan.core.util.Hex.decodeHex(value.toCharArray())) == null, + "raw-public-key mode, " + serverType + " secret key must be RFC5958 encoded private key"); + value = node.get("clientPublicKeyOrId").textValue(); + assertIf(decodeRfc7250PublicKey(org.eclipse.leshan.core.util.Hex.decodeHex(value.toCharArray())) == null, + "raw-public-key mode, " + serverType + " public key or id must be RFC7250 encoded public key"); + } + + protected void checkX509Server(JsonNode node, String serverType) throws DataValidationException { + String value = node.get("clientSecretKey").textValue(); + assertIf(decodeRfc5958PrivateKey(org.eclipse.leshan.core.util.Hex.decodeHex(value.toCharArray())) == null, + "x509 mode " + serverType + " secret key must be RFC5958 encoded private key"); + value = node.get("clientPublicKeyOrId").textValue(); + assertIf(decodeCertificate(org.eclipse.leshan.core.util.Hex.decodeHex(value.toCharArray())) == null, + "x509 mode " + serverType + " public key must be DER encoded X.509 certificate"); + + } + + protected void checkDeviceProfileServer (Map server, String serverType) throws DataValidationException { + // checks security config + String value = (String) server.get("serverPublicKey"); + if (SecurityMode.RPK.name().equals(server.get("securityMode"))) { + assertIf(decodeRfc7250PublicKey(org.eclipse.leshan.core.util.Hex.decodeHex(value.toCharArray())) == null, + "raw-public-key mode, " + serverType + " public key or id must be RFC7250 encoded public key"); + } else if (SecurityMode.X509.name().equals(server.get("securityMode"))) { + assertIf(decodeCertificate(org.eclipse.leshan.core.util.Hex.decodeHex(value.toCharArray())) == null, + "x509 mode, " + serverType + " public key must be DER encoded X.509 certificate"); + } + } + + protected PrivateKey decodeRfc5958PrivateKey(byte[] encodedKey) { + try { + return SecurityUtil.privateKey.decode(encodedKey); + } catch (IOException | GeneralSecurityException e) { + return null; + } + } + + protected PublicKey decodeRfc7250PublicKey(byte[] encodedKey) { + try { + return SecurityUtil.publicKey.decode(encodedKey); + } catch (IOException | GeneralSecurityException e) { + return null; + } + } + + protected Certificate decodeCertificate(byte[] encodedCert) { + try { + return SecurityUtil.certificate.decode(encodedCert); + } catch (IOException | GeneralSecurityException e) { + return null; + } + } + + protected static void assertIf(boolean condition, String message) throws DataValidationException { + if (condition) { + throw new DataValidationException(message); + } + } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java index 720d50ad69..aacaccc73b 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java @@ -54,6 +54,7 @@ import org.thingsboard.server.common.data.device.profile.DeviceProfileAlarm; import org.thingsboard.server.common.data.device.profile.DeviceProfileData; import org.thingsboard.server.common.data.device.profile.DeviceProfileTransportConfiguration; import org.thingsboard.server.common.data.device.profile.DisabledDeviceProfileProvisionConfiguration; +import org.thingsboard.server.common.data.device.profile.Lwm2mDeviceProfileTransportConfiguration; import org.thingsboard.server.common.data.device.profile.MqttDeviceProfileTransportConfiguration; import org.thingsboard.server.common.data.device.profile.ProtoTransportPayloadConfiguration; import org.thingsboard.server.common.data.device.profile.TransportPayloadTypeConfiguration; @@ -132,6 +133,9 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D @Autowired private DashboardService dashboardService; + @Autowired + private DeviceCredentialsService deviceCredentialsService; + private final Lock findOrCreateLock = new ReentrantLock(); @Cacheable(cacheNames = DEVICE_PROFILE_CACHE, key = "{#deviceProfileId.id}") @@ -409,6 +413,8 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D validateRpcRequestDynamicMessageFields(protoTransportPayloadConfiguration); } } + } else if (transportConfiguration instanceof Lwm2mDeviceProfileTransportConfiguration) { + deviceCredentialsService.verifyLwm2mSecurityKeyDeviceProfile((Lwm2mDeviceProfileTransportConfiguration) transportConfiguration); } List profileAlarms = deviceProfile.getProfileData().getAlarms(); diff --git a/transport/lwm2m/src/main/data/credentials/shell/lwM2M_credentials.sh b/transport/lwm2m/src/main/data/credentials/shell/lwM2M_credentials.sh index dcf38b4f10..d623bfad42 100755 --- a/transport/lwm2m/src/main/data/credentials/shell/lwM2M_credentials.sh +++ b/transport/lwm2m/src/main/data/credentials/shell/lwM2M_credentials.sh @@ -321,7 +321,7 @@ cert_end_point() { } if [ "$client_start" -lt "$client_finish" ]; then - echo "Файл содержит, как минимум, одно слово Bash." + echo echo "==Start Client==" while [ "$CLIENT_NUMBER" -lt "$client_finish" ]; do diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry.component.ts b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry.component.ts index 64a95d0513..47d7e5d35b 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry.component.ts @@ -185,13 +185,13 @@ export class Lwm2mObserveAttrTelemetryComponent implements ControlValueAccessor, * If the Object field “Mandatory” is “Mandatory” and the Object field “Instances” is “Single” then - * the number of Object Instance MUST be 1. * 1. == Multiple (true), == Optional (false) - - * Object Instance ID MIN_ID=0 MAX_ID=65535 (может ни одного не быть) + * Object Instance ID MIN_ID=0 MAX_ID=65535 (there may be none) * 2. == Multiple (true), == Mandatory (true) - - * Object Instance ID MIN_ID=0 MAX_ID=65535 (min один обязательный) + * Object Instance ID MIN_ID=0 MAX_ID=65535 (min one mandatory) * 3. == Single (false), == Optional (false) - - * Object Instance ID cnt_max = 1 cnt_min = 0 (может ни одного не быть) + * Object Instance ID cnt_max = 1 cnt_min = 0 (there may be none ) * 4. == Single (false), == Mandatory (true) - - * Object Instance ID cnt_max = cnt_min = 1 (всегда есть один) + * Object Instance ID cnt_max = cnt_min = 1 (there must always be one) */ addInstances = ($event: Event, control: AbstractControl): void => { From 6335f49c07c33ac0974927c67c09cf29f930fecf Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Wed, 8 Sep 2021 22:38:28 +0300 Subject: [PATCH 025/432] lwm2m: fix bug commit validate keys --- .../LwM2MServerSecurityInfoRepository.java | 196 ------------------ .../service/lwm2m/LwM2MServiceImpl.java | 71 +++++++ 2 files changed, 71 insertions(+), 196 deletions(-) delete mode 100644 application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MServerSecurityInfoRepository.java create mode 100644 application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MServiceImpl.java diff --git a/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MServerSecurityInfoRepository.java b/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MServerSecurityInfoRepository.java deleted file mode 100644 index 8750fa466c..0000000000 --- a/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MServerSecurityInfoRepository.java +++ /dev/null @@ -1,196 +0,0 @@ -/** - * Copyright © 2016-2021 The Thingsboard Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.thingsboard.server.service.lwm2m; - - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.JsonNode; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.eclipse.leshan.core.SecurityMode; -import org.eclipse.leshan.core.util.Hex; -import org.eclipse.leshan.core.util.SecurityUtil; -import org.eclipse.leshan.server.bootstrap.InvalidConfigurationException; -import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; -import org.springframework.stereotype.Service; -import org.thingsboard.server.common.data.DeviceProfile; -import org.thingsboard.server.common.data.device.profile.Lwm2mDeviceProfileTransportConfiguration; -import org.thingsboard.server.common.data.lwm2m.ServerSecurityConfig; -import org.thingsboard.server.common.data.security.DeviceCredentials; -import org.thingsboard.server.transport.lwm2m.config.LwM2MSecureServerConfig; -import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportBootstrapConfig; -import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; - -import java.io.IOException; -import java.security.GeneralSecurityException; -import java.security.KeyStore; -import java.security.PrivateKey; -import java.security.PublicKey; -import java.security.cert.Certificate; -import java.security.cert.X509Certificate; -import java.util.Map; - -@Slf4j -@Service -@RequiredArgsConstructor -@ConditionalOnExpression("('${service.type:null}'=='tb-transport' && '${transport.lwm2m.enabled:false}'=='true') || '${service.type:null}'=='monolith' || '${service.type:null}'=='tb-core'") -public class LwM2MServerSecurityInfoRepository { - - private final LwM2MTransportServerConfig serverConfig; - private final LwM2MTransportBootstrapConfig bootstrapConfig; - - public ServerSecurityConfig getServerSecurityInfo(boolean bootstrapServer) { - ServerSecurityConfig result = getServerSecurityConfig(bootstrapServer ? bootstrapConfig : serverConfig); - result.setBootstrapServerIs(bootstrapServer); - return result; - } - - private ServerSecurityConfig getServerSecurityConfig(LwM2MSecureServerConfig serverConfig) { - ServerSecurityConfig bsServ = new ServerSecurityConfig(); - bsServ.setServerId(serverConfig.getId()); - bsServ.setHost(serverConfig.getHost()); - bsServ.setPort(serverConfig.getPort()); - bsServ.setSecurityHost(serverConfig.getSecureHost()); - bsServ.setSecurityPort(serverConfig.getSecurePort()); - bsServ.setServerPublicKey(getPublicKey(serverConfig)); - return bsServ; - } - - private String getPublicKey(LwM2MSecureServerConfig config) { - try { - KeyStore keyStore = serverConfig.getKeyStoreValue(); - if (keyStore != null) { - X509Certificate serverCertificate = (X509Certificate) serverConfig.getKeyStoreValue().getCertificate(config.getCertificateAlias()); - return Hex.encodeHexString(serverCertificate.getPublicKey().getEncoded()); - } - } catch (Exception e) { - log.trace("Failed to fetch public key from key store!", e); - - } - return ""; - } - - public void verifySecurityKeyDevice(DeviceCredentials deviceCredentials) throws InvalidConfigurationException, JsonProcessingException { - JsonNode nodeCredentialsValue = deviceCredentials.getNodeCredentialsValue(); - checkClientKey (nodeCredentialsValue.get("client")); - checkServerKey (nodeCredentialsValue.get("bootstrap").get("bootstrapServer"), "Client`s by bootstrapServer"); - checkServerKey (nodeCredentialsValue.get("bootstrap").get("lwm2mServer"), "Client`s by lwm2mServer"); - } - - private void checkClientKey (JsonNode node) throws InvalidConfigurationException { - String modeName = node.get("securityConfigClientMode").asText(); - // checks security config - - if (SecurityMode.RPK.name().equals(modeName)) { - String value = node.get("key").textValue(); - assertIf(decodeRfc7250PublicKey(Hex.decodeHex(((String) value).toCharArray())) == null, - "raw-public-key mode, Client`s public key or id must be RFC7250 encoded public key"); - } else if (SecurityMode.X509.name().equals(modeName)) { - String value = node.get("cert").textValue(); - if (value != null && !value.isEmpty()) { - assertIf(decodeCertificate(Hex.decodeHex(((String) value).toCharArray())) == null, - "x509 mode, Client`s public key must be DER encoded X.509 certificate"); - } - } - - } - - private void checkServerKey (JsonNode node, String serverType) throws InvalidConfigurationException { - String modeName = node.get("securityMode").asText(); - // checks security config - if (SecurityMode.RPK.name().equals(modeName)) { - checkRPKServer(node, serverType); - } else if (SecurityMode.X509.name().equals(modeName)) { - checkX509Server(node, serverType); - } - } - - protected void checkRPKServer(JsonNode node, String serverType) throws InvalidConfigurationException { - String value = node.get("clientSecretKey").textValue(); - assertIf(decodeRfc5958PrivateKey(Hex.decodeHex(value.toCharArray())) == null, - "raw-public-key mode, " + serverType + " secret key must be RFC5958 encoded private key"); - value = node.get("clientPublicKeyOrId").textValue(); - assertIf(decodeRfc7250PublicKey(Hex.decodeHex(value.toCharArray())) == null, - "raw-public-key mode, " + serverType + " public key or id must be RFC7250 encoded public key"); - } - - protected void checkX509Server(JsonNode node, String serverType) throws InvalidConfigurationException { - String value = node.get("clientSecretKey").textValue(); - assertIf(decodeRfc5958PrivateKey(Hex.decodeHex(value.toCharArray())) == null, - "x509 mode " + serverType + " secret key must be RFC5958 encoded private key"); - value = node.get("clientPublicKeyOrId").textValue(); - assertIf(decodeCertificate(Hex.decodeHex(value.toCharArray())) == null, - "x509 mode " + serverType + " public key must be DER encoded X.509 certificate"); - - } - - public void verifySecurityKeyDeviceProfile(DeviceProfile deviceProfile) throws InvalidConfigurationException, JsonProcessingException { - Map serverBs = ((Lwm2mDeviceProfileTransportConfiguration)deviceProfile.getProfileData().getTransportConfiguration()).getBootstrap().getBootstrapServer(); - checkDeviceProfileServer (serverBs, "Servers: BootstrapServer`s"); - Map serverLwm2m = ((Lwm2mDeviceProfileTransportConfiguration)deviceProfile.getProfileData().getTransportConfiguration()).getBootstrap().getLwm2mServer(); - checkDeviceProfileServer (serverLwm2m, "Servers: Lwm2mServer`s"); - - } - - protected void checkDeviceProfileServer (Map server, String serverType) throws InvalidConfigurationException{ - // checks security config - String value = (String) server.get("serverPublicKey"); - if (SecurityMode.RPK.name().equals(server.get("securityMode"))) { - assertIf(decodeRfc7250PublicKey(Hex.decodeHex(value.toCharArray())) == null, - "raw-public-key mode, " + serverType + " public key or id must be RFC7250 encoded public key"); - } else if (SecurityMode.X509.name().equals(server.get("securityMode"))) { - assertIf(decodeCertificate(Hex.decodeHex(value.toCharArray())) == null, - "x509 mode, " + serverType + " public key must be DER encoded X.509 certificate"); - } - } - - protected PrivateKey decodeRfc5958PrivateKey(byte[] encodedKey) throws InvalidConfigurationException { - try { - return SecurityUtil.privateKey.decode(encodedKey); - } catch (IOException | GeneralSecurityException e) { - return null; - } - } - - protected PublicKey decodeRfc7250PublicKey(byte[] encodedKey) throws InvalidConfigurationException { - try { - return SecurityUtil.publicKey.decode(encodedKey); - } catch (IOException | GeneralSecurityException e) { - return null; - } - } - - protected Certificate decodeCertificate(byte[] encodedCert) throws InvalidConfigurationException { - try { - return SecurityUtil.certificate.decode(encodedCert); - } catch (IOException | GeneralSecurityException e) { - return null; - } - } - - protected static void assertIf(boolean condition, String message) throws InvalidConfigurationException { - if (condition) { - throw new InvalidConfigurationException(message); - } - } - - protected static boolean isEmpty(byte[] array) { - return array == null || array.length == 0; - } - - -} - diff --git a/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MServiceImpl.java b/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MServiceImpl.java new file mode 100644 index 0000000000..3a85a94f2d --- /dev/null +++ b/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MServiceImpl.java @@ -0,0 +1,71 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.service.lwm2m; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.eclipse.leshan.core.util.Hex; +import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; +import org.springframework.stereotype.Service; +import org.thingsboard.server.common.data.lwm2m.ServerSecurityConfig; +import org.thingsboard.server.transport.lwm2m.config.LwM2MSecureServerConfig; +import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportBootstrapConfig; +import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; +import java.security.KeyStore; +import java.security.cert.X509Certificate; + +@Slf4j +@Service +@RequiredArgsConstructor +@ConditionalOnExpression("('${service.type:null}'=='tb-transport' && '${transport.lwm2m.enabled:false}'=='true') || '${service.type:null}'=='monolith' || '${service.type:null}'=='tb-core'") +public class LwM2MServiceImpl implements LwM2MService { + + private final LwM2MTransportServerConfig serverConfig; + private final LwM2MTransportBootstrapConfig bootstrapConfig; + + @Override + public ServerSecurityConfig getServerSecurityInfo(boolean bootstrapServer) { + ServerSecurityConfig result = getServerSecurityConfig(bootstrapServer ? bootstrapConfig : serverConfig); + result.setBootstrapServerIs(bootstrapServer); + return result; + } + + private ServerSecurityConfig getServerSecurityConfig(LwM2MSecureServerConfig serverConfig) { + ServerSecurityConfig bsServ = new ServerSecurityConfig(); + bsServ.setServerId(serverConfig.getId()); + bsServ.setHost(serverConfig.getHost()); + bsServ.setPort(serverConfig.getPort()); + bsServ.setSecurityHost(serverConfig.getSecureHost()); + bsServ.setSecurityPort(serverConfig.getSecurePort()); + bsServ.setServerPublicKey(getPublicKey(serverConfig)); + return bsServ; + } + + private String getPublicKey(LwM2MSecureServerConfig config) { + try { + KeyStore keyStore = serverConfig.getKeyStoreValue(); + if (keyStore != null) { + X509Certificate serverCertificate = (X509Certificate) serverConfig.getKeyStoreValue().getCertificate(config.getCertificateAlias()); + return Hex.encodeHexString(serverCertificate.getPublicKey().getEncoded()); + } + } catch (Exception e) { + log.trace("Failed to fetch public key from key store!", e); + + } + return ""; + } +} + From 8dbacbd65f4cf182c2766e48cc154724907f3a3d Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Thu, 9 Sep 2021 07:46:35 +0300 Subject: [PATCH 026/432] lwm2m: add to JacksonUtil new method "validateFieldsToTree" --- .../thingsboard/common/util/JacksonUtil.java | 23 +++++++++++++++++ .../device/DeviceCredentialsServiceImpl.java | 25 ++----------------- 2 files changed, 25 insertions(+), 23 deletions(-) diff --git a/common/util/src/main/java/org/thingsboard/common/util/JacksonUtil.java b/common/util/src/main/java/org/thingsboard/common/util/JacksonUtil.java index 18b7abb67e..5ccfbd1461 100644 --- a/common/util/src/main/java/org/thingsboard/common/util/JacksonUtil.java +++ b/common/util/src/main/java/org/thingsboard/common/util/JacksonUtil.java @@ -23,6 +23,8 @@ import com.fasterxml.jackson.databind.node.ObjectNode; import java.io.IOException; import java.util.Arrays; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; /** * Created by Valerii Sosliuk on 5/12/2017. @@ -118,4 +120,25 @@ public class JacksonUtil { public static JsonNode valueToTree(T value) { return OBJECT_MAPPER.valueToTree(value); } + + public static String validateFieldsToTree(JsonNode nodeCredentialsValue, String[] fields, String delimiter) { + try { + Set msgSet = ConcurrentHashMap.newKeySet(); + for (String field : fields) { + String[] keys = field.split(delimiter); + JsonNode nodeVal = nodeCredentialsValue; + for (String key : keys) { + if (!nodeVal.hasNonNull(key)) { + msgSet.add(keys[keys.length - 1]); + break; + } else { + nodeVal = nodeVal.get(key); + } + } + } + return String.join(", ", msgSet); + } catch (Exception e) { + throw new IllegalArgumentException(e); + } + } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsServiceImpl.java index 9d0ff83491..1974f970cc 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsServiceImpl.java @@ -260,14 +260,14 @@ public class DeviceCredentialsServiceImpl extends AbstractEntityService implemen // LwM2MCredentialsValid credentials = JacksonUtil.fromString(deviceCredentials.getCredentialsValue(), LwM2MCredentialsValid.class); JsonNode nodeCredentialsValue = JacksonUtil.toJsonNode(deviceCredentials.getCredentialsValue()); String [] fields = {"client", "bootstrap", "bootstrap:bootstrapServer", "bootstrap:lwm2mServer"}; - String validateMsg = validateNodeCredentials (nodeCredentialsValue, fields); + String validateMsg = JacksonUtil.validateFieldsToTree(nodeCredentialsValue, fields, ":"); if (validateMsg.isEmpty()) { checkClientKey(nodeCredentialsValue.get("client")); checkServerKey(nodeCredentialsValue.get("bootstrap").get("bootstrapServer"), "Client`s by bootstrapServer"); checkServerKey(nodeCredentialsValue.get("bootstrap").get("lwm2mServer"), "Client`s by lwm2mServer"); } else { - throw new DataValidationException(validateMsg); + throw new DataValidationException("Device credentials are missing fields or mandatory value in this fields: " + validateMsg); } } catch (DataValidationException | DecoderException e) { throw new DataValidationException(e.getMessage()); @@ -286,27 +286,6 @@ public class DeviceCredentialsServiceImpl extends AbstractEntityService implemen } } - private String validateNodeCredentials (JsonNode nodeCredentialsValue, String [] fields) { - Set msgSet = ConcurrentHashMap.newKeySet(); - String msg = ""; - for (String field : fields) { - if (field.contains(":")) { - String [] keys = field.split(":"); - if (!nodeCredentialsValue.hasNonNull(keys[0])) { - msgSet.add(keys[1]); - } - else { - if (!nodeCredentialsValue.get(keys[0]).hasNonNull(keys[1])) msgSet.add(keys[1]); - } - } - else { - if (!nodeCredentialsValue.hasNonNull(field)) msgSet.add(field); - } - } - if (msgSet.size() > 0) msg = "Device credentials are missing fields or mandatory value in this fields: " + String.join(", ", msgSet); - return msg; - } - private void checkClientKey (JsonNode node) throws DataValidationException, DecoderException { String modeName = node.get("securityConfigClientMode").asText(); // checks security config From 9e6b0a01cd68a3c3363f6ebfbb890633a2b03a0d Mon Sep 17 00:00:00 2001 From: Swoq Date: Thu, 9 Sep 2021 15:22:19 +0300 Subject: [PATCH 027/432] Fix upgrade from version 3.2.2 --- .../service/install/update/DefaultDataUpdateService.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java b/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java index 11e0edfbe8..bac20b6ed9 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java @@ -156,12 +156,16 @@ public class DefaultDataUpdateService implements DataUpdateService { JsonNode createRules = node.get("createRules"); for (AlarmSeverity severity : AlarmSeverity.values()) { if (createRules.has(severity.name())) { - isUpdated = isUpdated || convertDeviceProfileAlarmRulesForVersion330(createRules.get(severity.name()).get("condition").get("spec")); + JsonNode spec = createRules.get(severity.name()).get("condition").get("spec"); + boolean convertResult = convertDeviceProfileAlarmRulesForVersion330(spec); + isUpdated = convertResult || isUpdated; } } } if (node.has("clearRule") && !node.get("clearRule").isNull()) { - isUpdated = isUpdated || convertDeviceProfileAlarmRulesForVersion330(node.get("clearRule").get("condition").get("spec")); + JsonNode spec = node.get("clearRule").get("condition").get("spec"); + boolean convertResult = convertDeviceProfileAlarmRulesForVersion330(spec); + isUpdated = convertResult || isUpdated; } } if (isUpdated) { From 24453861b5f4f04682a0d138a8696b2a6b0e81a8 Mon Sep 17 00:00:00 2001 From: Swoq Date: Mon, 13 Sep 2021 18:03:10 +0300 Subject: [PATCH 028/432] Refactoring Device Profile upgrade --- .../update/DefaultDataUpdateService.java | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java b/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java index bac20b6ed9..7077b61f77 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java @@ -150,22 +150,22 @@ public class DefaultDataUpdateService implements DataUpdateService { if (deviceProfile.getProfileData().has("alarms") && !deviceProfile.getProfileData().get("alarms").isNull()) { boolean isUpdated = false; - JsonNode array = deviceProfile.getProfileData().get("alarms"); - for (JsonNode node : array) { - if (node.has("createRules")) { - JsonNode createRules = node.get("createRules"); + JsonNode alarms = deviceProfile.getProfileData().get("alarms"); + for (JsonNode alarm : alarms) { + if (alarm.has("createRules")) { + JsonNode createRules = alarm.get("createRules"); for (AlarmSeverity severity : AlarmSeverity.values()) { if (createRules.has(severity.name())) { JsonNode spec = createRules.get(severity.name()).get("condition").get("spec"); - boolean convertResult = convertDeviceProfileAlarmRulesForVersion330(spec); - isUpdated = convertResult || isUpdated; + if (convertDeviceProfileAlarmRulesForVersion330(spec)) + isUpdated = true; } } } - if (node.has("clearRule") && !node.get("clearRule").isNull()) { - JsonNode spec = node.get("clearRule").get("condition").get("spec"); - boolean convertResult = convertDeviceProfileAlarmRulesForVersion330(spec); - isUpdated = convertResult || isUpdated; + if (alarm.has("clearRule") && !alarm.get("clearRule").isNull()) { + JsonNode spec = alarm.get("clearRule").get("condition").get("spec"); + if (convertDeviceProfileAlarmRulesForVersion330(spec)) + isUpdated = true; } } if (isUpdated) { From 9e9a8238db7c37bd2f3f7caac738202b80c92596 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Mon, 13 Sep 2021 19:01:04 +0300 Subject: [PATCH 029/432] Merge branch develop/3.3.2 into current --- .../AbstractLwM2MIntegrationTest.java | 2 +- .../dao/device/DeviceCredentialsService.java | 1 - .../dao/device/DeviceProfileServiceImpl.java | 2 +- transport/lwm2m/src/main/data/lwm2mserver.jks | Bin 3953 -> 3849 bytes 4 files changed, 2 insertions(+), 3 deletions(-) diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/AbstractLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/AbstractLwM2MIntegrationTest.java index eda896fa35..28d98693f1 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/AbstractLwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/AbstractLwM2MIntegrationTest.java @@ -177,7 +177,7 @@ public abstract class AbstractLwM2MIntegrationTest extends AbstractWebsocketTest protected static final String ENDPOINT = "deviceAEndpoint"; - protected CoapClient client; + protected LwM2MTestClient client; private final LwM2MBootstrapCredentials defaultBootstrapCredentials; diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsService.java index 599d08df3b..a57d39776f 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsService.java @@ -35,5 +35,4 @@ public interface DeviceCredentialsService { void deleteDeviceCredentials(TenantId tenantId, DeviceCredentials deviceCredentials); - void verifyLwm2mSecurityKeyDeviceProfile(Lwm2mDeviceProfileTransportConfiguration transportConfiguration) ; } diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java index aacaccc73b..adbaff5389 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java @@ -414,7 +414,7 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D } } } else if (transportConfiguration instanceof Lwm2mDeviceProfileTransportConfiguration) { - deviceCredentialsService.verifyLwm2mSecurityKeyDeviceProfile((Lwm2mDeviceProfileTransportConfiguration) transportConfiguration); +// deviceCredentialsService.verifyLwm2mSecurityKeyDeviceProfile((Lwm2mDeviceProfileTransportConfiguration) transportConfiguration); } List profileAlarms = deviceProfile.getProfileData().getAlarms(); diff --git a/transport/lwm2m/src/main/data/lwm2mserver.jks b/transport/lwm2m/src/main/data/lwm2mserver.jks index 9f6748f8fdab7179b895eccd71421fe1565d27db..5fab824aa1b19928fe711701cd27857472a9e739 100644 GIT binary patch delta 3653 zcmV-L4!ZI29*G_zFoF*S0s#Xsf)2h02`Yw2hW8Bt2LYgh4zC1)4y!PN4yTbKM1Ly* zom9BjJH$VcW(h0D2xIlY6r2JB0K-rOftaAyg&4(nOgQGgqZXKQNpgf$5vgZ}((Ysq z4>NDXm)2g@Mz`$C_E~pf2sbe$VNxNWg7CwD5uTlTd647vCxxS`5^~+i%3oo$<=Ut7 z96^zpSju@r$84gNVErKYNtV0q%r!bu0bINIX>{=o{Yo;qIe}jww@|a@ui(dgepJ8kd7lOaQD49BSZNR~ob$&O zk7x0cF9b%YM6(;R& z>c*G%1)}{X$%f_0t8V_&LNQU|0xkI3^#2v9Vh5%nhr zdsYmeWIv&B_#`cG{+tpJXY%zh<=zWf`~HA8b=FeEgQU!~(4G ztKp3!X7^z8TDs_-``@hRMC~tFi0__dxX*0}y=Ku+K_v3MQFss)6Mo3)N80o-GGc*W zqtL?nMDyA^8LxWo6s#(8BiGE*b(LJ80%S2I&;7tsS(Iud<2!Pq_7 z>J=D1|4`9nwAA=Bq*ee8T-oXYHqazGaBBxrAXf*xG306XETw{w1^@SbxoZrvB@7;< zIy#$$kn-oXcBOFb)gkUIjST)S6{Ak92W>iRfVl+>usEb%U`2m36mhpc(00T)sv9GL zZ$jfE=kcjZc;`J2HCB6CQ+Eo7vSpHPUfWuethbwDt_0oBbK8itz))(CMpr(R5B)?P zr~DX{n}1`D_WP?4W03usm03LnEe=atcZtA`B*4ji@MFI(hQ39`@cD~Jm?|Q>hp}MW zBP@1lTH|X@8(n|F3|tdOGU;dyMo*r%EEoj4(AO?W6L_WzK@B8a=dAk*lyd}Y<7RD8 zDR_+ERe&|!dTY>%hp9MP7c&=^FE3G%ga}k|^ApCxZyug=Q~wXW5j~F7WcH?x(18$d$?BpD-!$GC$eMt*93*}cRz@aC95vE zbo>Sjw~sSB?w+EcFhyjs5{!UFV^-YTX%vVAhx>n^P-^UJXp-RJAa8XB*qyRCj4cb- zRtI9BFx%wgz?Us z>oeetM}}cMV%1rd6J2x=wbRcLN|8R~st2r>ihqh38kECo?4fkJ)xNFJY}~=Z($G^E zA4-3tRMmld%nq7rkiC7%j-v#>2eMo|rUrNcT5$ea>7}Xj%0nMK0{lqoAh{EZWMFU2 z?!>~Mgb!SzeS4;xt}k}YQPqtxR@Yn-@Hk5Wx~hyDCk?gu)|OLkjL1s{>wRy@#2VmJ znoX1$=4b9mXv3K@I|f|Vd$T-lnF@i5Gpv7p{faHOI1{2$$;VcAM3>05@M7iAS`rs$ z*>pBhPp@>$(p>6^lmSApfZ%ati8_sF%z5n?;Gd^})wsAe;;qNqGJ5EEVj_h^rjoiWJAij^KT^KiemaQ*LCt~Vc3%5HuZn3TM|`;hAj3=a2h^{>eVrKIz$R}Fvl zJmCbxlRb|8U1EGj>#%#?-0qpbg5%1jjtN{&7vZS1JWUwzOU*9CNd2I*Bh-IfF^e%EmB7aaH-T0k*XL=`2^+C)>&jSZDe07V z|I4%HQH%Z1cDBB=vQ{6O*i<~L$P2-tsvZF+z6@(L<9ULG}>YN;%*B} zo&7)}<#)+(z{3{ma15xSj5$<%gE8F$A`EY_1d*@2ih?hm5)@&g{7Mb)ksyDSG8&tf zy48HrJ=34^yU*BnZ-6)`d`kR{RlA-@FbKSdbT#z*a`oMRyDQ}(Y!Qz!7PXIi?fNU+8JZJq?OJ9`gFo!Nn# zJCbbf)Pv82Lg$-wQ^T0FuBCqjsZnQZ_=7L}nJGtg^kAfH_h>wCtmB=X(v5|JM&@4J z*!#O;?Iq-XrN~m6R?p#9m)=}89sSH4jHKB;+L4A}Oi}=aCpZbb)W4d$ycoK`a@(&nXPD_7-8se;v2?#i@ z5|D*$W`hvY#F2L^dgS||;U-%m<8vK$+$eenj(YkZGz`+!`utjH=I*+sSFly$5KZK- zFSX4GPUe4~V!<7M_@B_sv@R4UoRo~)Ch$#3{30wRJ}2$##*6+N0F0Nv8NK-)mpX% z@4ostl_4ISiSl`rqt%-|_XE@aqA8<&YKiWy4$Z;oCpZ5nke+|c+~anTHd3P{mchxm ziE75=L4LzN-xtubZ8rc8A5+5}2#^ait_(WiB%^Z9ZWf=I=!O~HFS36eL^p6)v7Y5I zHz=sWEy^;s*M!^Fc)G|#SVGq}IHPJQOMBumSC^kVQ=~>gBr+a+Rq^?u{AGuFAQC@k zga)8!>>xqoC)nH6A<3~Y3s`@$#AV!Yr@k@`^o)oX>E1sT~Ag1wYDw5<6 zKV?q$Z-+AvG4p83!1rXSjAb!yr3$w4j0RBTz~66KXsds>x#XDMYi3=pj>usTFx|%e z2eODYW|KtQ`#XAByPJWfo?Pl>Y`FFf85H$>vVpi1+tlTD%@T}rSh`0Qj&hHNA4Y?| zOPd^d=-Zj_qh z)daLS3Q_pFP7FV!9CMWn*||txn|zMf8}{Jbz&sV9Q4sV%qUMzf@94TQ9jiR|;Qyr6 zb5g1e=SHGl^<8Y;LJ>?l!$^!hP=4 zWm$j!_x{)#<)ro~78OK;d#S{RBNWNJ;i?W`h9Q=9m(#`#uhmanl9}D7KVW!QHs`I- zt_jMk?j3^zaB9wh8rlvdeMQfNAe?3OXp#e_MLJ>nJ;)IVeyYZ8MSt`=*@GH-9sr@< zs-P+(o5bz0Fg`FLFbM_)D-Ht!8U+9Z6xYT>#LaQo(*VtnzN_qMP4M!Fhy)b<1nu-# X_d}DEK0Izji}dfgHE9+C0|ADhaZ(kz delta 3758 zcmV;f4pH%m9`PO`FoF+l0s#Xsf)6GJ2`Yw2hW8Bt2LYgh4;KW24-+tg4-b(dM1S-i z{srVqTGKEDaK2q&C*civrQ!ku0K-rOftY_W?dJLp*IR#Gc*!!xkpxE?wSF%W|6}_C zVqQ(g1?5uTlGag0&^c3`lU=^W>izj-T7{iDN&27>DOY+qHvUmtH2n3den$f;82fv2 zmBu!DS_FEdwT7F%f~R0@YJ42Rk2T5+bK`W-6?=o4(zV>6+8)fW5y+KjISE|QdhbFS ze3x#V^%TSREb9F`ENS$a>+MLW9--%x8UZ&CF*7nUHaIjmG&nLaf&n3sK_!1B5v#8o zUP=N1_%{{P>a~$lh=*DN0|3KN1c8{f3i>!()nXP2mOE4kkxSw!Hox+qA(3G2T$Sb* z*?Hl6f+<7&D3!y&QLoC~J2mf1y$-(Ls@OYsgBij&LNQU)RNo3>bAG$3Rz_n)NE)9t=eP2Ke*b)I2qPlt>Tk8!{cz5t1oikCNS1 zCcHPY|G_#|MCQm~`l1{{Zx@20KQjKfbxrTjr&KpZc4U$#j1pA5yKoOjLyA zAGBtRSisO-F9=!rwy#ko&xnl-^7-qYb87KZ08QTTwwa1vZ=ran1-van5_znwqoC6M zr_C=XqZT_9YnId8=>2QPgIhw0Z_PpLqxzzwDJKeZ&V1+De>Yx@AC_nJo}lUFEuBgd z3kRt=5Aj2$cm<%_CIq0Z> z@~)y&cPOg!<~6^O5N;Xm8w2PQxLX=oC1T9Fh`EyU<1O`?ar}Ql1j@^4g1bno6P@tj zC07JVoS2;6Z2b+$a2G7Eevy=zj$U zJlkqdCriZmaQG9|!W(0b%weA%o$s+tLF#L|y&8udAAb!zZw<#J!r_#_pEN-J0dy!r z++6QEOW$*1fsB7N3YQpmS#Syy7N}6qV!5O40tCr!t^JA)rDSOgOai|;p6zJwj_q( z06;bY`T19Pyl*YNYd33n3o34U!PwIQV0-^!M>FqQK<6@X^Iam(6aXxv2QP+L%qMZF zzpH)egz$gNNw%pMeekD5#0E_YOg!>6^`PucYmlo^$snKT zFJC%2E4(7)0f7i+VLc>_rQ6Ft(WUq}KxyLb+H8LttD*Se=H^xfV6VpEYq-u7aF83W zarF6tIoO5FKce|qn6w8a*wrN;)R11|pQ~l@@DsWwJ=Y7PVF$(mO-9cei-Gb{geXMt zKa*N3RZh=+!>UZKaLN(;#tHEf4#dC&@2&`W(Srf*bzv*_n^)hj&_b01>&;J`31l z(1}w7mP1uT7WxvERM16tE#*6U+yFF7Upa5L*B+B-NDZl_P~M}tDe&okQhg$V;ktiD zV^NUY^@4!~l31+g=jB#3*!F2SgwB5|)$T&b{h4w)Yavalvk~mbMmiIaRvx%vS!uuk zL1UvtC}lR+*`TkDHmt-Dfi$6@A$E&oV}!>S2b^jqfzmh`t=2gS`Ke%xZ}|1F_Jp%w zrIKuDOSf(tpg8Qa7p|jm?YX||zTxo~NTRCBSyD4t!t`)fWiD70COw=UPp*Hev!tQn z^44DgA}8B?Oqf$ECe>t;R=}%78o!yc$Jh_pc1fd~zx_W!mmG0?QunF9#es|?Zm^?Z zlLCct^SEnEMz_Xuyk0d2c~c3vEy9!~s>fZ-L5Kw2n9JS3_|>QiHg_pbj@sDp$7p`g z2w0I=0~MDJ9|KJhU;|-5w+Dax9-52ik*iW);Nr|+y@AylI_9;$tzeFS_}=|rg%9h} zogN`kY)D%rURD$Uf8oZg->{#4{k;MJM~X;)f`$gUw`V0t)>5nb--SpGUjMbq4Wbzm zy{oJx6~I{-OW@_ne8&IlLm**XS-V|rFnBBGSEeI2T;nCdV=@7ymfnATIB4XLeZD`` z(Tu~>sovCMYKTS>6gqe1!M?i-G6s-$2MuZLbh9NlzvSRW7jf6C;x2wy%}N*eC@AHB zPUU=Gj9#JOXR4dmpGsE?48meK^)Lgn^-yrAiEDaD*LuS+2~^#oQ)rLOIJ^&56W)FZ=A}u4m8##UC&C-G*nMTgm(38T&SR z?1(FWOY!Ypa2%}h=t5t)INw@L;qJ!68jqPhx)L z-E1PfXH?2kRYVinz&+Rp#VL z^1Lmcc2$0}=)9z)c3^`+tN1GaG{r#ZL&iNXZ{3Q%cJt0lKf1b|aCAd|tlqyTN+FV~8O%+Y4J0IDXKP)S znZRdG8euiXnVsX*2a~-g9QZYD=CkiH5?J>2ldTr0U_z5I=?EsbWlGkM$Ab-!Hjf#R zDJ-FbsuvSjx@0s#MgBmzZ_J*~JVz6`$OvLmQayj>)fIbeN+CgEMQ${Z5f)cOK@l{AyD=YZZsu>XwMF}_E|Lr$}-Vlv$aBN8+U zIXHjxcXZ+c#=okogeWoalI4N6r^i+CP&}`d2|5mmgB2AjiANzX1dEsS!CYj!p>C0< z20euq-Mob|^0$+Mgtk09EG)Y>qW+FtJ0(>!uNe>#E(e|PNO8qAxigumEjsQUy#4c^ z7_6iUE{bIsE3H}m>WUXAD^-LAOJ2pyGj4w_lfaz|QqF%Dx+T$)CTmyo(#6N3(RY1{ z0Wt(;QX*T8c>P!Npaas2QHN48Y$?A0G;kW$7?cW;jH3^rX6y~4nf}|L^lQFk_%(F9 zLhK}#H+IPKl5cmQGRu|HSt5(!+*Q)?4P^chb+LpjDpQb|%dkUO!p|<~&-!`bvUq=_ zVXoO)iogr>B&(<$=h1?Abc@rfUD}-3T#DH2jOu zXAl25fHe(E3pcvz=t$e|htX7_%QAn^Qtl&Ln>|s^4)5A@t*?G9w!0Jf5!&V=Q-}UN z Date: Tue, 14 Sep 2021 07:36:36 +0300 Subject: [PATCH 030/432] Lwm2m test fix bug device credential --- .../rpc/AbstractRpcLwM2MIntegrationTest.java | 13 +++++- .../sql/X509_NoTrustLwM2MIntegrationTest.java | 44 +++++++++++++++++++ ...va => X509_TrustLwM2MIntegrationTest.java} | 16 +------ 3 files changed, 56 insertions(+), 17 deletions(-) create mode 100644 application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/X509_NoTrustLwM2MIntegrationTest.java rename application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/{X509LwM2MIntegrationTest.java => X509_TrustLwM2MIntegrationTest.java} (69%) diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/AbstractRpcLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/AbstractRpcLwM2MIntegrationTest.java index 13bafd39d3..0e7c81b0be 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/AbstractRpcLwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/AbstractRpcLwM2MIntegrationTest.java @@ -30,8 +30,11 @@ import org.thingsboard.server.common.data.DeviceProfileType; import org.thingsboard.server.common.data.DeviceTransportType; import org.thingsboard.server.common.data.ResourceType; import org.thingsboard.server.common.data.TbResource; +import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MBootstrapCredentials; import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MClientCredentials; +import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MDeviceCredentials; import org.thingsboard.server.common.data.device.credentials.lwm2m.NoSecClientCredentials; +import org.thingsboard.server.common.data.device.credentials.lwm2m.NoSecServerCredentials; import org.thingsboard.server.common.data.device.profile.DefaultDeviceProfileConfiguration; import org.thingsboard.server.common.data.device.profile.DeviceProfileData; import org.thingsboard.server.common.data.device.profile.DisabledDeviceProfileProvisionConfiguration; @@ -267,9 +270,15 @@ public abstract class AbstractRpcLwM2MIntegrationTest extends AbstractWebsocketT doGet("/api/device/" + device.getId().getId().toString() + "/credentials", DeviceCredentials.class); Assert.assertEquals(device.getId(), deviceCredentials.getDeviceId()); deviceCredentials.setCredentialsType(DeviceCredentialsType.LWM2M_CREDENTIALS); - LwM2MCredentials credentials = new LwM2MCredentials(); + + LwM2MDeviceCredentials credentials = new LwM2MDeviceCredentials(); credentials.setClient(clientCredentials); - credentials.setBootstrap(createBootstrapConfig()); + LwM2MBootstrapCredentials defaultBootstrapCredentials = new LwM2MBootstrapCredentials(); + NoSecServerCredentials serverCredentials = new NoSecServerCredentials(); + defaultBootstrapCredentials.setBootstrapServer(serverCredentials); + defaultBootstrapCredentials.setLwm2mServer(serverCredentials); + + credentials.setBootstrap(defaultBootstrapCredentials); deviceCredentials.setCredentialsValue(JacksonUtil.toString(credentials)); doPost("/api/device/credentials", deviceCredentials).andExpect(status().isOk()); return device; diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/X509_NoTrustLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/X509_NoTrustLwM2MIntegrationTest.java new file mode 100644 index 0000000000..af721ab188 --- /dev/null +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/X509_NoTrustLwM2MIntegrationTest.java @@ -0,0 +1,44 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.transport.lwm2m.security.sql; + +import org.eclipse.leshan.client.object.Security; +import org.junit.Test; +import org.thingsboard.server.common.data.device.credentials.lwm2m.X509ClientCredentials; +import org.thingsboard.server.common.transport.util.SslUtil; +import org.thingsboard.server.transport.lwm2m.security.AbstractLwM2MIntegrationTest; + +import static org.eclipse.leshan.client.object.Security.x509; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SECURE_COAP_CONFIG; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SECURE_URI; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SHORT_SERVER_ID; + +public class X509_NoTrustLwM2MIntegrationTest extends AbstractLwM2MIntegrationTest { + + @Test + public void testConnectWithCertAndObserveTelemetry() throws Exception { + X509ClientCredentials credentials = new X509ClientCredentials(); + credentials.setEndpoint(ENDPOINT); + credentials.setCert(SslUtil.getCertificateString(clientX509CertNotTrusted)); + Security security = x509(SECURE_URI, + 123, + clientX509CertNotTrusted.getEncoded(), + clientPrivateKeyFromCert.getEncoded(), + serverX509Cert.getEncoded()); + super.basicTestConnectionObserveTelemetry(security, credentials, SECURE_COAP_CONFIG, ENDPOINT); + } + +} diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/X509LwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/X509_TrustLwM2MIntegrationTest.java similarity index 69% rename from application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/X509LwM2MIntegrationTest.java rename to application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/X509_TrustLwM2MIntegrationTest.java index cd172bda46..9870a2a527 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/X509LwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/X509_TrustLwM2MIntegrationTest.java @@ -25,7 +25,7 @@ import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SECURE_COAP import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SECURE_URI; import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SHORT_SERVER_ID; -public class X509LwM2MIntegrationTest extends AbstractLwM2MIntegrationTest { +public class X509_TrustLwM2MIntegrationTest extends AbstractLwM2MIntegrationTest { @Test public void testConnectAndObserveTelemetry() throws Exception { @@ -39,18 +39,4 @@ public class X509LwM2MIntegrationTest extends AbstractLwM2MIntegrationTest { super.basicTestConnectionObserveTelemetry(security, credentials, SECURE_COAP_CONFIG, ENDPOINT); } -// @Ignore //See LwM2mClientContextImpl.unregister -// @Test -// public void testConnectWithCertAndObserveTelemetry() throws Exception { -// X509ClientCredentials credentials = new X509ClientCredentials(); -// credentials.setEndpoint(ENDPOINT); -// credentials.setCert(SslUtil.getCertificateString(clientX509CertNotTrusted)); -// Security security = x509(SECURE_URI, -// 123, -// clientX509CertNotTrusted.getEncoded(), -// clientPrivateKeyFromCert.getEncoded(), -// serverX509Cert.getEncoded()); -// super.basicTestConnectionObserveTelemetry(security, credentials, SECURE_COAP_CONFIG, ENDPOINT); -// } - } From d808ba04bfbcd8ad0b9065f05e0ea9f8055fc687 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Tue, 14 Sep 2021 19:50:22 +0300 Subject: [PATCH 031/432] Lwm2m test OTA fix bug. Delete duplicate code. --- .../AbstractLwM2MIntegrationTest.java | 309 +++++------------- .../lwm2m/client/LwM2MTestClient.java | 2 +- .../ota/AbstractOtaLwM2MIntegrationTest.java | 76 +++++ .../sql/OtaLwM2MIntegrationTest.java | 106 +++--- .../rpc/AbstractRpcLwM2MIntegrationTest.java | 167 +--------- .../AbstractSecurityLwM2MIntegrationTest.java | 176 ++++++++++ .../sql/NoSecLwM2MIntegrationTest.java | 7 +- .../security/sql/PskLwm2mIntegrationTest.java | 6 +- .../security/sql/RpkLwM2MIntegrationTest.java | 4 +- .../sql/X509_NoTrustLwM2MIntegrationTest.java | 6 +- .../sql/X509_TrustLwM2MIntegrationTest.java | 4 +- .../DefaultLwM2MAttributesService.java | 7 +- .../ota/DefaultLwM2MOtaUpdateService.java | 6 + 13 files changed, 419 insertions(+), 457 deletions(-) rename application/src/test/java/org/thingsboard/server/transport/lwm2m/{security => }/AbstractLwM2MIntegrationTest.java (51%) create mode 100644 application/src/test/java/org/thingsboard/server/transport/lwm2m/ota/AbstractOtaLwM2MIntegrationTest.java rename application/src/test/java/org/thingsboard/server/transport/lwm2m/{security => ota}/sql/OtaLwM2MIntegrationTest.java (74%) create mode 100644 application/src/test/java/org/thingsboard/server/transport/lwm2m/security/AbstractSecurityLwM2MIntegrationTest.java diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/AbstractLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/AbstractLwM2MIntegrationTest.java similarity index 51% rename from application/src/test/java/org/thingsboard/server/transport/lwm2m/security/AbstractLwM2MIntegrationTest.java rename to application/src/test/java/org/thingsboard/server/transport/lwm2m/AbstractLwM2MIntegrationTest.java index 28d98693f1..225ae056e9 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/AbstractLwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/AbstractLwM2MIntegrationTest.java @@ -13,20 +13,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.transport.lwm2m.security; +package org.thingsboard.server.transport.lwm2m; import com.fasterxml.jackson.core.type.TypeReference; import org.apache.commons.io.IOUtils; -import org.eclipse.californium.core.CoapClient; import org.eclipse.californium.core.network.config.NetworkConfig; import org.eclipse.leshan.client.object.Security; -import org.eclipse.leshan.core.util.Hex; import org.junit.After; import org.junit.Assert; import org.junit.Before; -import org.springframework.mock.web.MockMultipartFile; -import org.springframework.test.web.servlet.request.MockMultipartHttpServletRequestBuilder; -import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; import org.springframework.util.SocketUtils; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.common.util.ThingsBoardThreadFactory; @@ -35,12 +30,12 @@ import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.DeviceProfileProvisionType; import org.thingsboard.server.common.data.DeviceProfileType; import org.thingsboard.server.common.data.DeviceTransportType; -import org.thingsboard.server.common.data.OtaPackageInfo; import org.thingsboard.server.common.data.ResourceType; import org.thingsboard.server.common.data.TbResource; import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MBootstrapCredentials; import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MClientCredentials; import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MDeviceCredentials; +import org.thingsboard.server.common.data.device.credentials.lwm2m.NoSecClientCredentials; import org.thingsboard.server.common.data.device.credentials.lwm2m.NoSecServerCredentials; import org.thingsboard.server.common.data.device.profile.DefaultDeviceProfileConfiguration; import org.thingsboard.server.common.data.device.profile.DeviceProfileData; @@ -62,41 +57,18 @@ import org.thingsboard.server.service.telemetry.cmd.v2.EntityDataCmd; import org.thingsboard.server.service.telemetry.cmd.v2.EntityDataUpdate; import org.thingsboard.server.service.telemetry.cmd.v2.LatestValueCmd; import org.thingsboard.server.transport.lwm2m.client.LwM2MTestClient; - -import java.io.IOException; -import java.io.InputStream; -import java.math.BigInteger; -import java.security.AlgorithmParameters; -import java.security.GeneralSecurityException; -import java.security.KeyFactory; -import java.security.KeyStore; -import java.security.PrivateKey; -import java.security.PublicKey; -import java.security.cert.Certificate; -import java.security.cert.X509Certificate; -import java.security.spec.ECGenParameterSpec; -import java.security.spec.ECParameterSpec; -import java.security.spec.ECPoint; -import java.security.spec.ECPrivateKeySpec; -import java.security.spec.ECPublicKeySpec; -import java.security.spec.KeySpec; import java.util.Base64; import java.util.Collections; import java.util.List; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; -import static org.eclipse.leshan.client.object.Security.noSec; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; -import static org.thingsboard.server.common.data.ota.OtaPackageType.FIRMWARE; -import static org.thingsboard.server.common.data.ota.OtaPackageType.SOFTWARE; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.COAP_CONFIG; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SECURITY; @DaoSqlTest public abstract class AbstractLwM2MIntegrationTest extends AbstractWebsocketTest { - protected final String TRANSPORT_CONFIGURATION = "{\n" + + protected String transportConfiguration = "{\n" + " \"type\": \"LWM2M\",\n" + " \"observeAttr\": {\n" + " \"keyName\": {\n" + @@ -148,135 +120,23 @@ public abstract class AbstractLwM2MIntegrationTest extends AbstractWebsocketTest protected DeviceProfile deviceProfile; protected ScheduledExecutorService executor; protected TbTestWebSocketClient wsClient; - - protected final PublicKey clientPublicKey; // client public key used for RPK - protected final PrivateKey clientPrivateKey; // client private key used for RPK - protected final PublicKey serverPublicKey; // server public key used for RPK - protected final PrivateKey serverPrivateKey; // server private key used for RPK - - // client private key used for X509 - protected final PrivateKey clientPrivateKeyFromCert; - // server private key used for X509 - protected final PrivateKey serverPrivateKeyFromCert; - // client certificate signed by rootCA with a good CN (CN start by leshan_integration_test) - protected final X509Certificate clientX509Cert; - // client certificate signed by rootCA but with bad CN (CN does not start by leshan_integration_test) - protected final X509Certificate clientX509CertWithBadCN; - // client certificate self-signed with a good CN (CN start by leshan_integration_test) - protected final X509Certificate clientX509CertSelfSigned; - // client certificate signed by another CA (not rootCA) with a good CN (CN start by leshan_integration_test) - protected final X509Certificate clientX509CertNotTrusted; - // server certificate signed by rootCA - protected final X509Certificate serverX509Cert; - // self-signed server certificate - protected final X509Certificate serverX509CertSelfSigned; - // rootCA used by the server - protected final X509Certificate rootCAX509Cert; - // certificates trustedby the server (should contain rootCA) - protected final Certificate[] trustedCertificates = new Certificate[1]; - - protected static final String ENDPOINT = "deviceAEndpoint"; - protected LwM2MTestClient client; - private final LwM2MBootstrapCredentials defaultBootstrapCredentials; + private String[] resources; + private String endpoint; public AbstractLwM2MIntegrationTest() { -// create client credentials - try { - // Get point values - byte[] publicX = Hex - .decodeHex("89c048261979208666f2bfb188be1968fc9021c416ce12828c06f4e314c167b5".toCharArray()); - byte[] publicY = Hex - .decodeHex("cbf1eb7587f08e01688d9ada4be859137ca49f79394bad9179326b3090967b68".toCharArray()); - byte[] privateS = Hex - .decodeHex("e67b68d2aaeb6550f19d98cade3ad62b39532e02e6b422e1f7ea189dabaea5d2".toCharArray()); - - // Get Elliptic Curve Parameter spec for secp256r1 - AlgorithmParameters algoParameters = AlgorithmParameters.getInstance("EC"); - algoParameters.init(new ECGenParameterSpec("secp256r1")); - ECParameterSpec parameterSpec = algoParameters.getParameterSpec(ECParameterSpec.class); - - // Create key specs - KeySpec publicKeySpec = new ECPublicKeySpec(new ECPoint(new BigInteger(publicX), new BigInteger(publicY)), - parameterSpec); - KeySpec privateKeySpec = new ECPrivateKeySpec(new BigInteger(privateS), parameterSpec); - - // Get keys - clientPublicKey = KeyFactory.getInstance("EC").generatePublic(publicKeySpec); - clientPrivateKey = KeyFactory.getInstance("EC").generatePrivate(privateKeySpec); - - // Get certificates from key store - char[] clientKeyStorePwd = "client".toCharArray(); - KeyStore clientKeyStore = KeyStore.getInstance(KeyStore.getDefaultType()); - try (InputStream clientKeyStoreFile = this.getClass().getClassLoader().getResourceAsStream("lwm2m/credentials/clientKeyStore.jks")) { - clientKeyStore.load(clientKeyStoreFile, clientKeyStorePwd); - } - - clientPrivateKeyFromCert = (PrivateKey) clientKeyStore.getKey("client", clientKeyStorePwd); - clientX509Cert = (X509Certificate) clientKeyStore.getCertificate("client"); - clientX509CertWithBadCN = (X509Certificate) clientKeyStore.getCertificate("client_bad_cn"); - clientX509CertSelfSigned = (X509Certificate) clientKeyStore.getCertificate("client_self_signed"); - clientX509CertNotTrusted = (X509Certificate) clientKeyStore.getCertificate("client_not_trusted"); - } catch (GeneralSecurityException | IOException e) { - throw new RuntimeException(e); - } - - // create server credentials - try { - // Get point values - byte[] publicX = Hex - .decodeHex("fcc28728c123b155be410fc1c0651da374fc6ebe7f96606e90d927d188894a73".toCharArray()); - byte[] publicY = Hex - .decodeHex("d2ffaa73957d76984633fc1cc54d0b763ca0559a9dff9706e9f4557dacc3f52a".toCharArray()); - byte[] privateS = Hex - .decodeHex("1dae121ba406802ef07c193c1ee4df91115aabd79c1ed7f4c0ef7ef6a5449400".toCharArray()); - - // Get Elliptic Curve Parameter spec for secp256r1 - AlgorithmParameters algoParameters = AlgorithmParameters.getInstance("EC"); - algoParameters.init(new ECGenParameterSpec("secp256r1")); - ECParameterSpec parameterSpec = algoParameters.getParameterSpec(ECParameterSpec.class); - - // Create key specs - KeySpec publicKeySpec = new ECPublicKeySpec(new ECPoint(new BigInteger(publicX), new BigInteger(publicY)), - parameterSpec); - KeySpec privateKeySpec = new ECPrivateKeySpec(new BigInteger(privateS), parameterSpec); - - // Get keys - serverPublicKey = KeyFactory.getInstance("EC").generatePublic(publicKeySpec); - serverPrivateKey = KeyFactory.getInstance("EC").generatePrivate(privateKeySpec); - - // Get certificates from key store - char[] serverKeyStorePwd = "server".toCharArray(); - KeyStore serverKeyStore = KeyStore.getInstance(KeyStore.getDefaultType()); - try (InputStream serverKeyStoreFile = this.getClass().getClassLoader().getResourceAsStream("lwm2m/credentials/serverKeyStore.jks")) { - serverKeyStore.load(serverKeyStoreFile, serverKeyStorePwd); - } - - serverPrivateKeyFromCert = (PrivateKey) serverKeyStore.getKey("server", serverKeyStorePwd); - rootCAX509Cert = (X509Certificate) serverKeyStore.getCertificate("rootCA"); - serverX509Cert = (X509Certificate) serverKeyStore.getCertificate("server"); - serverX509CertSelfSigned = (X509Certificate) serverKeyStore.getCertificate("server_self_signed"); - trustedCertificates[0] = rootCAX509Cert; - } catch (GeneralSecurityException | IOException e) { - throw new RuntimeException(e); - } - - defaultBootstrapCredentials = new LwM2MBootstrapCredentials(); - + this.defaultBootstrapCredentials = new LwM2MBootstrapCredentials(); NoSecServerCredentials serverCredentials = new NoSecServerCredentials(); - - defaultBootstrapCredentials.setBootstrapServer(serverCredentials); - defaultBootstrapCredentials.setLwm2mServer(serverCredentials); + this.defaultBootstrapCredentials.setBootstrapServer(serverCredentials); + this.defaultBootstrapCredentials.setLwm2mServer(serverCredentials); } - @Before - public void beforeTest() throws Exception { + public void init () throws Exception{ executor = Executors.newScheduledThreadPool(10, ThingsBoardThreadFactory.forName("test-lwm2m-scheduled")); loginTenantAdmin(); - String[] resources = new String[]{"1.xml", "2.xml", "3.xml", "5.xml", "9.xml"}; - for (String resourceName : resources) { + for (String resourceName : this.resources) { TbResource lwModel = new TbResource(); lwModel.setResourceType(ResourceType.LWM2M_MODEL); lwModel.setTitle(resourceName); @@ -291,9 +151,57 @@ public abstract class AbstractLwM2MIntegrationTest extends AbstractWebsocketTest wsClient = buildAndConnectWebSocketClient(); } + @Before + public void beforeTest() throws Exception { + this.init(); + } + + @After + public void after() { + executor.shutdownNow(); + wsClient.close(); + clientDestroy(); + } + + public void basicTestConnectionObserveTelemetry(Security security, + LwM2MClientCredentials credentials, + NetworkConfig coapConfig, + String endpoint) throws Exception { + createDeviceProfile(transportConfiguration); + Device device = createDevice(credentials); + + SingleEntityFilter sef = new SingleEntityFilter(); + sef.setSingleEntity(device.getId()); + LatestValueCmd latestCmd = new LatestValueCmd(); + latestCmd.setKeys(Collections.singletonList(new EntityKey(EntityKeyType.TIME_SERIES, "batteryLevel"))); + EntityDataQuery edq = new EntityDataQuery(sef, new EntityDataPageLink(1, 0, null, null), + Collections.emptyList(), Collections.emptyList(), Collections.emptyList()); + + EntityDataCmd cmd = new EntityDataCmd(1, edq, null, latestCmd, null); + TelemetryPluginCmdsWrapper wrapper = new TelemetryPluginCmdsWrapper(); + wrapper.setEntityDataCmds(Collections.singletonList(cmd)); + + wsClient.send(mapper.writeValueAsString(wrapper)); + wsClient.waitForReply(); + + wsClient.registerWaitForUpdate(); + this.endpoint = endpoint; + createNewClient (security, coapConfig); + String msg = wsClient.waitForUpdate(); + + EntityDataUpdate update = mapper.readValue(msg, EntityDataUpdate.class); + Assert.assertEquals(1, update.getCmdId()); + List eData = update.getUpdate(); + Assert.assertNotNull(eData); + Assert.assertEquals(1, eData.size()); + Assert.assertEquals(device.getId(), eData.get(0).getEntityId()); + Assert.assertNotNull(eData.get(0).getLatest().get(EntityKeyType.TIME_SERIES)); + var tsValue = eData.get(0).getLatest().get(EntityKeyType.TIME_SERIES).get("batteryLevel"); + Assert.assertEquals(42, Long.parseLong(tsValue.getValue())); + } + protected void createDeviceProfile(String transportConfiguration) throws Exception { deviceProfile = new DeviceProfile(); - deviceProfile.setName("LwM2M"); deviceProfile.setType(DeviceProfileType.DEFAULT); deviceProfile.setTenantId(tenantId); @@ -325,106 +233,39 @@ public abstract class AbstractLwM2MIntegrationTest extends AbstractWebsocketTest deviceCredentials.setCredentialsType(DeviceCredentialsType.LWM2M_CREDENTIALS); LwM2MDeviceCredentials credentials = new LwM2MDeviceCredentials(); - credentials.setClient(clientCredentials); credentials.setBootstrap(defaultBootstrapCredentials); deviceCredentials.setCredentialsValue(JacksonUtil.toString(credentials)); doPost("/api/device/credentials", deviceCredentials).andExpect(status().isOk()); + Thread.sleep(1000); return device; } - - protected OtaPackageInfo createFirmware() throws Exception { - String CHECKSUM = "4bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459a"; - - OtaPackageInfo firmwareInfo = new OtaPackageInfo(); - firmwareInfo.setDeviceProfileId(deviceProfile.getId()); - firmwareInfo.setType(FIRMWARE); - firmwareInfo.setTitle("My firmware"); - firmwareInfo.setVersion("v1.0"); - - OtaPackageInfo savedFirmwareInfo = doPost("/api/otaPackage", firmwareInfo, OtaPackageInfo.class); - - MockMultipartFile testData = new MockMultipartFile("file", "filename.txt", "text/plain", new byte[]{1}); - - return savaData("/api/otaPackage/" + savedFirmwareInfo.getId().getId().toString() + "?checksum={checksum}&checksumAlgorithm={checksumAlgorithm}", testData, CHECKSUM, "SHA256"); + public NoSecClientCredentials createNoSecClientCredentials(String endpoint) { + NoSecClientCredentials clientCredentials = new NoSecClientCredentials(); + clientCredentials.setEndpoint(endpoint); + return clientCredentials; } - protected OtaPackageInfo createSoftware() throws Exception { - String CHECKSUM = "4bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459a"; - - OtaPackageInfo swInfo = new OtaPackageInfo(); - swInfo.setDeviceProfileId(deviceProfile.getId()); - swInfo.setType(SOFTWARE); - swInfo.setTitle("My sw"); - swInfo.setVersion("v1.0"); - - OtaPackageInfo savedFirmwareInfo = doPost("/api/otaPackage", swInfo, OtaPackageInfo.class); - - MockMultipartFile testData = new MockMultipartFile("file", "filename.txt", "text/plain", new byte[]{1}); + public void setResources (String[] resources) { + this.resources = resources; + } - return savaData("/api/otaPackage/" + savedFirmwareInfo.getId().getId().toString() + "?checksum={checksum}&checksumAlgorithm={checksumAlgorithm}", testData, CHECKSUM, "SHA256"); + public void setEndpoint (String endpoint) { + this.endpoint = endpoint; } - protected OtaPackageInfo savaData(String urlTemplate, MockMultipartFile content, String... params) throws Exception { - MockMultipartHttpServletRequestBuilder postRequest = MockMvcRequestBuilders.multipart(urlTemplate, params); - postRequest.file(content); - setJwtToken(postRequest); - return readResponse(mockMvc.perform(postRequest).andExpect(status().isOk()), OtaPackageInfo.class); + public void createNewClient (Security security, NetworkConfig coapConfig) throws Exception { + clientDestroy(); + client = new LwM2MTestClient(this.executor, this.endpoint); + int clientPort = SocketUtils.findAvailableTcpPort(); + client.init(security, coapConfig, clientPort); } - @After - public void after() { - executor.shutdownNow(); - wsClient.close(); + private void clientDestroy() { if (client != null) { client.destroy(); } } - - public void basicTestConnectionObserveTelemetry(Security security, - LwM2MClientCredentials credentials, - NetworkConfig coapConfig, - String endpoint) throws Exception { - LwM2MTestClient client = null; - try { - createDeviceProfile(TRANSPORT_CONFIGURATION); - Device device = createDevice(credentials); - - SingleEntityFilter sef = new SingleEntityFilter(); - sef.setSingleEntity(device.getId()); - LatestValueCmd latestCmd = new LatestValueCmd(); - latestCmd.setKeys(Collections.singletonList(new EntityKey(EntityKeyType.TIME_SERIES, "batteryLevel"))); - EntityDataQuery edq = new EntityDataQuery(sef, new EntityDataPageLink(1, 0, null, null), - Collections.emptyList(), Collections.emptyList(), Collections.emptyList()); - - EntityDataCmd cmd = new EntityDataCmd(1, edq, null, latestCmd, null); - TelemetryPluginCmdsWrapper wrapper = new TelemetryPluginCmdsWrapper(); - wrapper.setEntityDataCmds(Collections.singletonList(cmd)); - - wsClient.send(mapper.writeValueAsString(wrapper)); - wsClient.waitForReply(); - - wsClient.registerWaitForUpdate(); - client = new LwM2MTestClient(executor, endpoint); - int clientPort = SocketUtils.findAvailableTcpPort(); - client.init(security, coapConfig, clientPort); - String msg = wsClient.waitForUpdate(); - - EntityDataUpdate update = mapper.readValue(msg, EntityDataUpdate.class); - Assert.assertEquals(1, update.getCmdId()); - List eData = update.getUpdate(); - Assert.assertNotNull(eData); - Assert.assertEquals(1, eData.size()); - Assert.assertEquals(device.getId(), eData.get(0).getEntityId()); - Assert.assertNotNull(eData.get(0).getLatest().get(EntityKeyType.TIME_SERIES)); - var tsValue = eData.get(0).getLatest().get(EntityKeyType.TIME_SERIES).get("batteryLevel"); - Assert.assertEquals(42, Long.parseLong(tsValue.getValue())); - } finally { - if (client != null) { - client.destroy(); - } - } - } } diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2MTestClient.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2MTestClient.java index 5c36f9820f..3fc83625ba 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2MTestClient.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2MTestClient.java @@ -61,12 +61,12 @@ import static org.eclipse.leshan.core.LwM2mId.LOCATION; import static org.eclipse.leshan.core.LwM2mId.SECURITY; import static org.eclipse.leshan.core.LwM2mId.SERVER; import static org.eclipse.leshan.core.LwM2mId.SOFTWARE_MANAGEMENT; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resources; import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.BINARY_APP_DATA_CONTAINER; import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.TEMPERATURE_SENSOR; import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.objectInstanceId_0; import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.objectInstanceId_1; import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.objectInstanceId_12; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resources; @Slf4j diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/ota/AbstractOtaLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/ota/AbstractOtaLwM2MIntegrationTest.java new file mode 100644 index 0000000000..e78d74bdcd --- /dev/null +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/ota/AbstractOtaLwM2MIntegrationTest.java @@ -0,0 +1,76 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.transport.lwm2m.ota; + +import org.springframework.mock.web.MockMultipartFile; +import org.springframework.test.web.servlet.request.MockMultipartHttpServletRequestBuilder; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; +import org.thingsboard.server.common.data.OtaPackageInfo; +import org.thingsboard.server.dao.service.DaoSqlTest; +import org.thingsboard.server.transport.lwm2m.AbstractLwM2MIntegrationTest; + +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static org.thingsboard.server.common.data.ota.OtaPackageType.FIRMWARE; +import static org.thingsboard.server.common.data.ota.OtaPackageType.SOFTWARE; + +@DaoSqlTest +public abstract class AbstractOtaLwM2MIntegrationTest extends AbstractLwM2MIntegrationTest { + + private final String[] resources = new String[]{"3.xml", "5.xml", "9.xml"}; + + public AbstractOtaLwM2MIntegrationTest() { + setResources(this.resources); + } + + protected OtaPackageInfo createFirmware() throws Exception { + String CHECKSUM = "4bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459a"; + + OtaPackageInfo firmwareInfo = new OtaPackageInfo(); + firmwareInfo.setDeviceProfileId(deviceProfile.getId()); + firmwareInfo.setType(FIRMWARE); + firmwareInfo.setTitle("My firmware"); + firmwareInfo.setVersion("v1.0"); + + OtaPackageInfo savedFirmwareInfo = doPost("/api/otaPackage", firmwareInfo, OtaPackageInfo.class); + + MockMultipartFile testData = new MockMultipartFile("file", "filename.txt", "text/plain", new byte[]{1}); + + return savaData("/api/otaPackage/" + savedFirmwareInfo.getId().getId().toString() + "?checksum={checksum}&checksumAlgorithm={checksumAlgorithm}", testData, CHECKSUM, "SHA256"); + } + + protected OtaPackageInfo createSoftware() throws Exception { + String CHECKSUM = "4bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459a"; + + OtaPackageInfo swInfo = new OtaPackageInfo(); + swInfo.setDeviceProfileId(deviceProfile.getId()); + swInfo.setType(SOFTWARE); + swInfo.setTitle("My sw"); + swInfo.setVersion("v1.0"); + + OtaPackageInfo savedFirmwareInfo = doPost("/api/otaPackage", swInfo, OtaPackageInfo.class); + + MockMultipartFile testData = new MockMultipartFile("file", "filename.txt", "text/plain", new byte[]{1}); + + return savaData("/api/otaPackage/" + savedFirmwareInfo.getId().getId().toString() + "?checksum={checksum}&checksumAlgorithm={checksumAlgorithm}", testData, CHECKSUM, "SHA256"); + } + + protected OtaPackageInfo savaData(String urlTemplate, MockMultipartFile content, String... params) throws Exception { + MockMultipartHttpServletRequestBuilder postRequest = MockMvcRequestBuilders.multipart(urlTemplate, params); + postRequest.file(content); + setJwtToken(postRequest); + return readResponse(mockMvc.perform(postRequest).andExpect(status().isOk()), OtaPackageInfo.class); + } +} diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/OtaLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/ota/sql/OtaLwM2MIntegrationTest.java similarity index 74% rename from application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/OtaLwM2MIntegrationTest.java rename to application/src/test/java/org/thingsboard/server/transport/lwm2m/ota/sql/OtaLwM2MIntegrationTest.java index 96006cbe67..de7c432564 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/OtaLwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/ota/sql/OtaLwM2MIntegrationTest.java @@ -13,21 +13,18 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.transport.lwm2m.security.sql; +package org.thingsboard.server.transport.lwm2m.ota.sql; import com.fasterxml.jackson.core.type.TypeReference; import lombok.extern.slf4j.Slf4j; import org.junit.Assert; import org.junit.Test; -import org.springframework.util.SocketUtils; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.device.credentials.lwm2m.NoSecClientCredentials; import org.thingsboard.server.common.data.kv.KvEntry; import org.thingsboard.server.common.data.kv.TsKvEntry; -import org.thingsboard.server.common.data.ota.OtaPackageType; import org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus; -import org.thingsboard.server.transport.lwm2m.client.LwM2MTestClient; -import org.thingsboard.server.transport.lwm2m.security.AbstractLwM2MIntegrationTest; +import org.thingsboard.server.transport.lwm2m.ota.AbstractOtaLwM2MIntegrationTest; import java.util.Arrays; import java.util.Collections; @@ -41,9 +38,6 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.awaitility.Awaitility.await; import static org.hamcrest.Matchers.hasSize; import static org.thingsboard.rest.client.utils.RestJsonConverter.toTimeseries; -import static org.thingsboard.server.common.data.ota.OtaPackageKey.CHECKSUM; -import static org.thingsboard.server.common.data.ota.OtaPackageKey.CHECKSUM_ALGORITHM; -import static org.thingsboard.server.common.data.ota.OtaPackageKey.SIZE; import static org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus.DOWNLOADED; import static org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus.DOWNLOADING; import static org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus.FAILED; @@ -56,7 +50,7 @@ import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.COAP_CONFIG import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SECURITY; @Slf4j -public class OtaLwM2MIntegrationTest extends AbstractLwM2MIntegrationTest { +public class OtaLwM2MIntegrationTest extends AbstractOtaLwM2MIntegrationTest { public static final int TIMEOUT = 30; private final String OTA_TRANSPORT_CONFIGURATION = "{\n" + @@ -139,56 +133,60 @@ public class OtaLwM2MIntegrationTest extends AbstractLwM2MIntegrationTest { @Test public void testFirmwareUpdateWithClientWithoutFirmwareOtaInfoFromProfile() throws Exception { String endpoint = "WithoutFirmwareInfoDevice"; - createDeviceProfile(TRANSPORT_CONFIGURATION); - NoSecClientCredentials clientCredentials = new NoSecClientCredentials(); - clientCredentials.setEndpoint(endpoint); - Device device = createDevice(clientCredentials); - client = new LwM2MTestClient(executor, endpoint); - int clientPort = SocketUtils.findAvailableTcpPort(); - client.init(SECURITY, COAP_CONFIG, clientPort); + setEndpoint(endpoint); + createDeviceProfile(transportConfiguration); + NoSecClientCredentials credentials = createNoSecClientCredentials(endpoint); + final Device device = createDevice(credentials); + createNewClient(SECURITY, COAP_CONFIG); - Thread.sleep(1000); - - device.setFirmwareId(createFirmware().getId()); - device = doPost("/api/device", device, Device.class); + Thread.sleep(1000); - Thread.sleep(5000); + device.setFirmwareId(createFirmware().getId()); + final Device savedDevice = doPost("/api/device", device, Device.class); - List ts = toTimeseries(doGetAsyncTyped("/api/plugins/telemetry/DEVICE/" + device.getId().getId() + "/values/timeseries?keys=fw_state", new TypeReference<>() { - })); + Thread.sleep(1000); - List statuses = ts.stream().map(KvEntry::getValueAsString).map(OtaPackageUpdateStatus::valueOf).collect(Collectors.toList()); + assertThat(savedDevice).as("saved device").isNotNull(); + assertThat(getDeviceFromAPI(device.getId().getId())).as("fetched device").isEqualTo(savedDevice); - List expectedStatuses = Collections.singletonList(FAILED); + List ts = toTimeseries(doGetAsyncTyped("/api/plugins/telemetry/DEVICE/" + + savedDevice.getId().getId() + "/values/timeseries?keys=fw_state", new TypeReference<>() {})); + List statuses = ts.stream().map(KvEntry::getValueAsString).map(OtaPackageUpdateStatus::valueOf).collect(Collectors.toList()); + List expectedStatuses = Collections.singletonList(FAILED); - Assert.assertEquals(expectedStatuses, statuses); + Assert.assertEquals(expectedStatuses, statuses); } @Test public void testFirmwareUpdateByObject5() throws Exception { String endpoint = "Ota5_Device"; - List expectedStatuses = Arrays.asList(QUEUED, INITIATED, DOWNLOADING, DOWNLOADED, UPDATING, UPDATED); + setEndpoint(endpoint); createDeviceProfile(OTA_TRANSPORT_CONFIGURATION); - NoSecClientCredentials clientCredentials = new NoSecClientCredentials(); - clientCredentials.setEndpoint(endpoint); - Device device = createDevice(clientCredentials); + NoSecClientCredentials credentials = createNoSecClientCredentials(endpoint); + final Device device = createDevice(credentials); + createNewClient(SECURITY, COAP_CONFIG); + + Thread.sleep(1000); device.setFirmwareId(createFirmware().getId()); - Device saveDevice = doPost("/api/device", device, Device.class); + final Device savedDevice = doPost("/api/device", device, Device.class); + Thread.sleep(1000); - client = new LwM2MTestClient(executor, endpoint); - int clientPort = SocketUtils.findAvailableTcpPort(); - client.init(SECURITY, COAP_CONFIG, clientPort); + assertThat(savedDevice).as("saved device").isNotNull(); + assertThat(getDeviceFromAPI(device.getId().getId())).as("fetched device").isEqualTo(savedDevice); + final List expectedStatuses = Arrays.asList(QUEUED, INITIATED, DOWNLOADING, DOWNLOADED, UPDATING, UPDATED); List ts = await("await on timeseries") .atMost(30, TimeUnit.SECONDS) - .until(() -> toTimeseries(doGetAsyncTyped("/api/plugins/telemetry/DEVICE/" + saveDevice.getId().getId() + "/values/timeseries?orderBy=ASC&keys=fw_state&startTs=0&endTs=" + System.currentTimeMillis(), new TypeReference<>() { + .until(() -> toTimeseries(doGetAsyncTyped("/api/plugins/telemetry/DEVICE/" + + savedDevice.getId().getId() + "/values/timeseries?orderBy=ASC&keys=fw_state&startTs=0&endTs=" + + System.currentTimeMillis(), new TypeReference<>() { })), hasSize(expectedStatuses.size())); - - - List statuses = ts.stream().sorted(Comparator.comparingLong(TsKvEntry::getTs)).map(KvEntry::getValueAsString).map(OtaPackageUpdateStatus::valueOf).collect(Collectors.toList()); - + List statuses = ts.stream().sorted(Comparator + .comparingLong(TsKvEntry::getTs)).map(KvEntry::getValueAsString) + .map(OtaPackageUpdateStatus::valueOf) + .collect(Collectors.toList()); Assert.assertEquals(expectedStatuses, statuses); } @@ -200,28 +198,25 @@ public class OtaLwM2MIntegrationTest extends AbstractLwM2MIntegrationTest { * */ @Test public void testSoftwareUpdateByObject9() throws Exception { - //given - final List expectedStatuses = List.of( - QUEUED, INITIATED, DOWNLOADING, DOWNLOADING, DOWNLOADING, DOWNLOADED, VERIFIED, UPDATED); String endpoint = "Ota9_Device"; + setEndpoint(endpoint); createDeviceProfile(OTA_TRANSPORT_CONFIGURATION); - NoSecClientCredentials clientCredentials = new NoSecClientCredentials(); - clientCredentials.setEndpoint(endpoint); - final Device device = createDevice(clientCredentials); - device.setSoftwareId(createSoftware().getId()); + NoSecClientCredentials credentials = createNoSecClientCredentials(endpoint); + final Device device = createDevice(credentials); + createNewClient(SECURITY, COAP_CONFIG); + + Thread.sleep(1000); + device.setSoftwareId(createSoftware().getId()); final Device savedDevice = doPost("/api/device", device, Device.class); //sync call + Thread.sleep(1000); assertThat(savedDevice).as("saved device").isNotNull(); assertThat(getDeviceFromAPI(device.getId().getId())).as("fetched device").isEqualTo(savedDevice); - //when - log.warn("Init the client..."); - client = new LwM2MTestClient(executor, endpoint); - int clientPort = SocketUtils.findAvailableTcpPort(); - client.init(SECURITY, COAP_CONFIG, clientPort); - + final List expectedStatuses = List.of( + QUEUED, INITIATED, DOWNLOADING, DOWNLOADING, DOWNLOADING, DOWNLOADED, VERIFIED, UPDATED); log.warn("AWAIT atMost {} SECONDS on timeseries List by API with list size {}...", TIMEOUT, expectedStatuses.size()); List ts = await("await on timeseries") .atMost(30, TimeUnit.SECONDS) @@ -230,9 +225,10 @@ public class OtaLwM2MIntegrationTest extends AbstractLwM2MIntegrationTest { ts.sort(Comparator.comparingLong(TsKvEntry::getTs)); log.warn("Ts ordered: {}", ts); - ts.forEach((x) -> log.warn("ts: {} ", x)); - - List statuses = ts.stream().map(KvEntry::getValueAsString).map(OtaPackageUpdateStatus::valueOf).collect(Collectors.toList()); + ts.forEach((x) -> log.warn("ts: { Thread.sleep(1000);} ", x)); + List statuses = ts.stream().map(KvEntry::getValueAsString) + .map(OtaPackageUpdateStatus::valueOf) + .collect(Collectors.toList()); log.warn("Converted ts to statuses: {}", statuses); assertThat(statuses).isEqualTo(expectedStatuses); diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/AbstractRpcLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/AbstractRpcLwM2MIntegrationTest.java index 0e7c81b0be..83bb46e934 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/AbstractRpcLwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/AbstractRpcLwM2MIntegrationTest.java @@ -15,46 +15,14 @@ */ package org.thingsboard.server.transport.lwm2m.rpc; -import com.fasterxml.jackson.core.type.TypeReference; -import org.apache.commons.io.IOUtils; -import org.junit.After; -import org.junit.Assert; import org.junit.Before; -import org.springframework.util.SocketUtils; -import org.thingsboard.common.util.JacksonUtil; -import org.thingsboard.common.util.ThingsBoardThreadFactory; import org.thingsboard.server.common.data.Device; -import org.thingsboard.server.common.data.DeviceProfile; -import org.thingsboard.server.common.data.DeviceProfileProvisionType; -import org.thingsboard.server.common.data.DeviceProfileType; -import org.thingsboard.server.common.data.DeviceTransportType; -import org.thingsboard.server.common.data.ResourceType; -import org.thingsboard.server.common.data.TbResource; -import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MBootstrapCredentials; -import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MClientCredentials; -import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MDeviceCredentials; import org.thingsboard.server.common.data.device.credentials.lwm2m.NoSecClientCredentials; -import org.thingsboard.server.common.data.device.credentials.lwm2m.NoSecServerCredentials; -import org.thingsboard.server.common.data.device.profile.DefaultDeviceProfileConfiguration; -import org.thingsboard.server.common.data.device.profile.DeviceProfileData; -import org.thingsboard.server.common.data.device.profile.DisabledDeviceProfileProvisionConfiguration; -import org.thingsboard.server.common.data.device.profile.Lwm2mDeviceProfileTransportConfiguration; -import org.thingsboard.server.common.data.security.DeviceCredentials; -import org.thingsboard.server.common.data.security.DeviceCredentialsType; -import org.thingsboard.server.controller.AbstractWebsocketTest; import org.thingsboard.server.controller.TbTestWebSocketClient; import org.thingsboard.server.dao.service.DaoSqlTest; -import org.thingsboard.server.transport.lwm2m.bootstrap.secure.LwM2MBootstrapConfig; -import org.thingsboard.server.transport.lwm2m.bootstrap.secure.LwM2MBootstrapServers; -import org.thingsboard.server.transport.lwm2m.bootstrap.secure.LwM2MServerBootstrap; -import org.thingsboard.server.transport.lwm2m.client.LwM2MTestClient; -import org.thingsboard.server.transport.lwm2m.secure.credentials.LwM2MCredentials; -import org.thingsboard.server.transport.lwm2m.security.AbstractLwM2MIntegrationTest; - -import java.util.Base64; +import org.thingsboard.server.transport.lwm2m.AbstractLwM2MIntegrationTest; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.function.Predicate; @@ -63,18 +31,9 @@ import static org.eclipse.leshan.core.LwM2mId.DEVICE; import static org.eclipse.leshan.core.LwM2mId.FIRMWARE; import static org.eclipse.leshan.core.LwM2mId.SERVER; import static org.eclipse.leshan.core.LwM2mId.SOFTWARE_MANAGEMENT; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.BINARY_APP_DATA_CONTAINER; import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.COAP_CONFIG; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.HOST; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.HOST_BS; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.PORT; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.PORT_BS; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SECURE_PORT; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SECURE_PORT_BS; import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SECURITY; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SHORT_SERVER_ID; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SHORT_SERVER_ID_BS; import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.TEMPERATURE_SENSOR; import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.objectId_0; import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.objectInstanceId_0; @@ -89,7 +48,7 @@ import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_ import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resources; @DaoSqlTest -public abstract class AbstractRpcLwM2MIntegrationTest extends AbstractWebsocketTest { +public abstract class AbstractRpcLwM2MIntegrationTest extends AbstractLwM2MIntegrationTest { protected final String RPC_TRANSPORT_CONFIGURATION = "{\n" + " \"type\": \"LWM2M\",\n" + @@ -152,10 +111,6 @@ public abstract class AbstractRpcLwM2MIntegrationTest extends AbstractWebsocketT protected static final String ENDPOINT_RPC = "deviceEndpointRpc"; protected ScheduledExecutorService executor; protected TbTestWebSocketClient wsClient; - protected DeviceProfile deviceProfile; - - protected NoSecClientCredentials clientCredentials; - protected LwM2MTestClient client; protected String deviceId; public Set expectedObjects; public Set expectedObjectIdVers; @@ -174,34 +129,25 @@ public abstract class AbstractRpcLwM2MIntegrationTest extends AbstractWebsocketT protected String objectIdVer_50 = "/50"; protected String objectIdVer_3303; - public AbstractRpcLwM2MIntegrationTest(){ } + public AbstractRpcLwM2MIntegrationTest(){ + setResources(resources); + setEndpoint(ENDPOINT_RPC); + } @Before public void beforeTest() throws Exception { - executor = Executors.newScheduledThreadPool(10, ThingsBoardThreadFactory.forName("test-lwm2m-rpc-scheduled")); - loginTenantAdmin(); - wsClient = buildAndConnectWebSocketClient(); + init(); createDeviceProfile(RPC_TRANSPORT_CONFIGURATION); - clientCredentials = new NoSecClientCredentials(); - clientCredentials.setEndpoint(ENDPOINT_RPC); - Device device = createDevice(clientCredentials); + + Thread.sleep(1000); + + NoSecClientCredentials credentials = createNoSecClientCredentials(ENDPOINT_RPC); + final Device device = createDevice(credentials); deviceId = device.getId().getId().toString(); - client = new LwM2MTestClient(executor, ENDPOINT_RPC); - int clientPort = SocketUtils.findAvailableTcpPort(); - client.init(SECURITY, COAP_CONFIG, clientPort); - for (String resourceName : resources) { - TbResource lwModel = new TbResource(); - lwModel.setResourceType(ResourceType.LWM2M_MODEL); - lwModel.setTitle(resourceName); - lwModel.setFileName(resourceName); - lwModel.setTenantId(tenantId); - byte[] bytes = IOUtils.toByteArray(AbstractLwM2MIntegrationTest.class.getClassLoader().getResourceAsStream("lwm2m/" + resourceName)); - lwModel.setData(Base64.getEncoder().encodeToString(bytes)); - lwModel = doPostWithTypedResponse("/api/resource", lwModel, new TypeReference<>() { - }); - Assert.assertNotNull(lwModel); - } - wsClient = buildAndConnectWebSocketClient(); + createNewClient (SECURITY, COAP_CONFIG); + + Thread.sleep(1000); + expectedObjects = ConcurrentHashMap.newKeySet(); expectedObjectIdVers = ConcurrentHashMap.newKeySet(); expectedInstances = ConcurrentHashMap.newKeySet(); @@ -238,76 +184,6 @@ public abstract class AbstractRpcLwM2MIntegrationTest extends AbstractWebsocketT objectInstanceIdVer_9 = (String) expectedObjectIdVerInstances.stream().filter(path -> ((String) path).contains("/" + SOFTWARE_MANAGEMENT)).findFirst().get(); } - protected void createDeviceProfile(String transportConfiguration) throws Exception { - deviceProfile = new DeviceProfile(); - - deviceProfile.setName("LwM2M_RPC"); - deviceProfile.setType(DeviceProfileType.DEFAULT); - deviceProfile.setTenantId(tenantId); - deviceProfile.setTransportType(DeviceTransportType.LWM2M); - deviceProfile.setProvisionType(DeviceProfileProvisionType.DISABLED); - deviceProfile.setDescription(deviceProfile.getName()); - - DeviceProfileData deviceProfileData = new DeviceProfileData(); - deviceProfileData.setConfiguration(new DefaultDeviceProfileConfiguration()); - deviceProfileData.setProvisionConfiguration(new DisabledDeviceProfileProvisionConfiguration(null)); - deviceProfileData.setTransportConfiguration(JacksonUtil.fromString(transportConfiguration, Lwm2mDeviceProfileTransportConfiguration.class)); - deviceProfile.setProfileData(deviceProfileData); - - deviceProfile = doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class); - Assert.assertNotNull(deviceProfile); - } - - - protected Device createDevice(LwM2MClientCredentials clientCredentials) throws Exception { - Device device = new Device(); - device.setName("Device A"); - device.setDeviceProfileId(deviceProfile.getId()); - device.setTenantId(tenantId); - device = doPost("/api/device", device, Device.class); - Assert.assertNotNull(device); - DeviceCredentials deviceCredentials = - doGet("/api/device/" + device.getId().getId().toString() + "/credentials", DeviceCredentials.class); - Assert.assertEquals(device.getId(), deviceCredentials.getDeviceId()); - deviceCredentials.setCredentialsType(DeviceCredentialsType.LWM2M_CREDENTIALS); - - LwM2MDeviceCredentials credentials = new LwM2MDeviceCredentials(); - credentials.setClient(clientCredentials); - LwM2MBootstrapCredentials defaultBootstrapCredentials = new LwM2MBootstrapCredentials(); - NoSecServerCredentials serverCredentials = new NoSecServerCredentials(); - defaultBootstrapCredentials.setBootstrapServer(serverCredentials); - defaultBootstrapCredentials.setLwm2mServer(serverCredentials); - - credentials.setBootstrap(defaultBootstrapCredentials); - deviceCredentials.setCredentialsValue(JacksonUtil.toString(credentials)); - doPost("/api/device/credentials", deviceCredentials).andExpect(status().isOk()); - return device; - } - - protected LwM2MBootstrapConfig createBootstrapConfig() { - LwM2MBootstrapConfig bootstrap = new LwM2MBootstrapConfig(); - LwM2MBootstrapServers servers = new LwM2MBootstrapServers(); - servers.setShortId(SHORT_SERVER_ID); - bootstrap.setServers(servers); - LwM2MServerBootstrap server = new LwM2MServerBootstrap(); - server.setHost(HOST); - server.setPort(PORT); - server.setSecurityHost(HOST); - server.setSecurityPort(SECURE_PORT); - server.setServerId(servers.getShortId()); - server.setBootstrapServerIs(false); - bootstrap.setLwm2mServer(server); - LwM2MServerBootstrap serverBS = new LwM2MServerBootstrap(); - serverBS.setHost(HOST_BS); - serverBS.setPort(PORT_BS); - serverBS.setSecurityHost(HOST_BS); - serverBS.setSecurityPort(SECURE_PORT_BS); - serverBS.setServerId(SHORT_SERVER_ID_BS); - serverBS.setBootstrapServerIs(true); - bootstrap.setBootstrapServer(serverBS); - return bootstrap; - } - protected String pathIdVerToObjectId(String pathIdVer) { if (pathIdVer.contains("_")){ String [] objVer = pathIdVer.split("/"); @@ -316,15 +192,4 @@ public abstract class AbstractRpcLwM2MIntegrationTest extends AbstractWebsocketT } return pathIdVer; } - - @After - public void after() { - if (client != null) { - client.destroy(); - } - executor.shutdownNow(); - if (wsClient != null) { - wsClient.close(); - } - } } diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/AbstractSecurityLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/AbstractSecurityLwM2MIntegrationTest.java new file mode 100644 index 0000000000..491c39a9f9 --- /dev/null +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/AbstractSecurityLwM2MIntegrationTest.java @@ -0,0 +1,176 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.transport.lwm2m.security; + +import org.eclipse.leshan.core.util.Hex; +import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MBootstrapCredentials; +import org.thingsboard.server.common.data.device.credentials.lwm2m.NoSecServerCredentials; +import org.thingsboard.server.dao.service.DaoSqlTest; +import org.thingsboard.server.transport.lwm2m.AbstractLwM2MIntegrationTest; +import org.thingsboard.server.transport.lwm2m.client.LwM2MTestClient; + +import java.io.IOException; +import java.io.InputStream; +import java.math.BigInteger; +import java.security.AlgorithmParameters; +import java.security.GeneralSecurityException; +import java.security.KeyFactory; +import java.security.KeyStore; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.cert.Certificate; +import java.security.cert.X509Certificate; +import java.security.spec.ECGenParameterSpec; +import java.security.spec.ECParameterSpec; +import java.security.spec.ECPoint; +import java.security.spec.ECPrivateKeySpec; +import java.security.spec.ECPublicKeySpec; +import java.security.spec.KeySpec; + +@DaoSqlTest +public abstract class AbstractSecurityLwM2MIntegrationTest extends AbstractLwM2MIntegrationTest { + + protected final String pskIdentity; // client public key or id used for PSK + protected final String pskKey; // client private/secret key used for PSK + protected final PublicKey clientPublicKey; // client public key used for RPK + protected final PrivateKey clientPrivateKey; // client private key used for RPK + protected final PublicKey serverPublicKey; // server public key used for RPK + protected final PrivateKey serverPrivateKey; // server private key used for RPK + + // client private key used for X509 + protected final PrivateKey clientPrivateKeyFromCert; + // server private key used for X509 + protected final PrivateKey serverPrivateKeyFromCert; + // client certificate signed by rootCA with a good CN (CN start by leshan_integration_test) + protected final X509Certificate clientX509Cert; + // client certificate signed by rootCA but with bad CN (CN does not start by leshan_integration_test) + protected final X509Certificate clientX509CertWithBadCN; + // client certificate self-signed with a good CN (CN start by leshan_integration_test) + protected final X509Certificate clientX509CertSelfSigned; + // client certificate signed by another CA (not rootCA) with a good CN (CN start by leshan_integration_test) + protected final X509Certificate clientX509CertNotTrusted; + // server certificate signed by rootCA + protected final X509Certificate serverX509Cert; + // self-signed server certificate + protected final X509Certificate serverX509CertSelfSigned; + // rootCA used by the server + protected final X509Certificate rootCAX509Cert; + // certificates trustedby the server (should contain rootCA) + protected final Certificate[] trustedCertificates = new Certificate[1]; + + protected static final String ENDPOINT = "deviceAEndpoint"; + + protected LwM2MTestClient client; + + private final LwM2MBootstrapCredentials defaultBootstrapCredentials; + + private final String[] resources = new String[]{"1.xml", "2.xml", "3.xml", "5.xml", "9.xml"}; + + public AbstractSecurityLwM2MIntegrationTest() { + // create client credentials + setResources(this.resources); + setEndpoint(ENDPOINT); + try { + // Get keys PSK + this.pskIdentity = "SOME_PSK_ID"; + this.pskKey = "73656372657450534b73656372657450"; + + // Get point values + byte[] publicX = Hex + .decodeHex("89c048261979208666f2bfb188be1968fc9021c416ce12828c06f4e314c167b5".toCharArray()); + byte[] publicY = Hex + .decodeHex("cbf1eb7587f08e01688d9ada4be859137ca49f79394bad9179326b3090967b68".toCharArray()); + byte[] privateS = Hex + .decodeHex("e67b68d2aaeb6550f19d98cade3ad62b39532e02e6b422e1f7ea189dabaea5d2".toCharArray()); + + // Get Elliptic Curve Parameter spec for secp256r1 + AlgorithmParameters algoParameters = AlgorithmParameters.getInstance("EC"); + algoParameters.init(new ECGenParameterSpec("secp256r1")); + ECParameterSpec parameterSpec = algoParameters.getParameterSpec(ECParameterSpec.class); + + // Create key specs + KeySpec publicKeySpec = new ECPublicKeySpec(new ECPoint(new BigInteger(publicX), new BigInteger(publicY)), + parameterSpec); + KeySpec privateKeySpec = new ECPrivateKeySpec(new BigInteger(privateS), parameterSpec); + + // Get keys RPK + clientPublicKey = KeyFactory.getInstance("EC").generatePublic(publicKeySpec); + clientPrivateKey = KeyFactory.getInstance("EC").generatePrivate(privateKeySpec); + + // Get certificates from key store + char[] clientKeyStorePwd = "client".toCharArray(); + KeyStore clientKeyStore = KeyStore.getInstance(KeyStore.getDefaultType()); + try (InputStream clientKeyStoreFile = this.getClass().getClassLoader().getResourceAsStream("lwm2m/credentials/clientKeyStore.jks")) { + clientKeyStore.load(clientKeyStoreFile, clientKeyStorePwd); + } + + clientPrivateKeyFromCert = (PrivateKey) clientKeyStore.getKey("client", clientKeyStorePwd); + clientX509Cert = (X509Certificate) clientKeyStore.getCertificate("client"); + clientX509CertWithBadCN = (X509Certificate) clientKeyStore.getCertificate("client_bad_cn"); + clientX509CertSelfSigned = (X509Certificate) clientKeyStore.getCertificate("client_self_signed"); + clientX509CertNotTrusted = (X509Certificate) clientKeyStore.getCertificate("client_not_trusted"); + } catch (GeneralSecurityException | IOException e) { + throw new RuntimeException(e); + } + + // create server credentials + try { + // Get point values + byte[] publicX = Hex + .decodeHex("fcc28728c123b155be410fc1c0651da374fc6ebe7f96606e90d927d188894a73".toCharArray()); + byte[] publicY = Hex + .decodeHex("d2ffaa73957d76984633fc1cc54d0b763ca0559a9dff9706e9f4557dacc3f52a".toCharArray()); + byte[] privateS = Hex + .decodeHex("1dae121ba406802ef07c193c1ee4df91115aabd79c1ed7f4c0ef7ef6a5449400".toCharArray()); + + // Get Elliptic Curve Parameter spec for secp256r1 + AlgorithmParameters algoParameters = AlgorithmParameters.getInstance("EC"); + algoParameters.init(new ECGenParameterSpec("secp256r1")); + ECParameterSpec parameterSpec = algoParameters.getParameterSpec(ECParameterSpec.class); + + // Create key specs + KeySpec publicKeySpec = new ECPublicKeySpec(new ECPoint(new BigInteger(publicX), new BigInteger(publicY)), + parameterSpec); + KeySpec privateKeySpec = new ECPrivateKeySpec(new BigInteger(privateS), parameterSpec); + + // Get keys + serverPublicKey = KeyFactory.getInstance("EC").generatePublic(publicKeySpec); + serverPrivateKey = KeyFactory.getInstance("EC").generatePrivate(privateKeySpec); + + // Get certificates from key store + char[] serverKeyStorePwd = "server".toCharArray(); + KeyStore serverKeyStore = KeyStore.getInstance(KeyStore.getDefaultType()); + try (InputStream serverKeyStoreFile = this.getClass().getClassLoader().getResourceAsStream("lwm2m/credentials/serverKeyStore.jks")) { + serverKeyStore.load(serverKeyStoreFile, serverKeyStorePwd); + } + + serverPrivateKeyFromCert = (PrivateKey) serverKeyStore.getKey("server", serverKeyStorePwd); + rootCAX509Cert = (X509Certificate) serverKeyStore.getCertificate("rootCA"); + serverX509Cert = (X509Certificate) serverKeyStore.getCertificate("server"); + serverX509CertSelfSigned = (X509Certificate) serverKeyStore.getCertificate("server_self_signed"); + trustedCertificates[0] = rootCAX509Cert; + } catch (GeneralSecurityException | IOException e) { + throw new RuntimeException(e); + } + + defaultBootstrapCredentials = new LwM2MBootstrapCredentials(); + + NoSecServerCredentials serverCredentials = new NoSecServerCredentials(); + + defaultBootstrapCredentials.setBootstrapServer(serverCredentials); + defaultBootstrapCredentials.setLwm2mServer(serverCredentials); + } +} diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/NoSecLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/NoSecLwM2MIntegrationTest.java index af13dd62c4..1d278354b5 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/NoSecLwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/NoSecLwM2MIntegrationTest.java @@ -18,18 +18,17 @@ package org.thingsboard.server.transport.lwm2m.security.sql; import lombok.extern.slf4j.Slf4j; import org.junit.Test; import org.thingsboard.server.common.data.device.credentials.lwm2m.NoSecClientCredentials; -import org.thingsboard.server.transport.lwm2m.security.AbstractLwM2MIntegrationTest; +import org.thingsboard.server.transport.lwm2m.security.AbstractSecurityLwM2MIntegrationTest; import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.COAP_CONFIG; import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SECURITY; @Slf4j -public class NoSecLwM2MIntegrationTest extends AbstractLwM2MIntegrationTest { +public class NoSecLwM2MIntegrationTest extends AbstractSecurityLwM2MIntegrationTest { @Test public void testConnectAndObserveTelemetry() throws Exception { - NoSecClientCredentials clientCredentials = new NoSecClientCredentials(); - clientCredentials.setEndpoint(ENDPOINT); + NoSecClientCredentials clientCredentials = createNoSecClientCredentials(ENDPOINT); super.basicTestConnectionObserveTelemetry(SECURITY, clientCredentials, COAP_CONFIG, ENDPOINT); } diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/PskLwm2mIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/PskLwm2mIntegrationTest.java index cd30ff52e8..23b60482f0 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/PskLwm2mIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/PskLwm2mIntegrationTest.java @@ -19,7 +19,7 @@ import org.eclipse.leshan.client.object.Security; import org.eclipse.leshan.core.util.Hex; import org.junit.Test; import org.thingsboard.server.common.data.device.credentials.lwm2m.PSKClientCredentials; -import org.thingsboard.server.transport.lwm2m.security.AbstractLwM2MIntegrationTest; +import org.thingsboard.server.transport.lwm2m.security.AbstractSecurityLwM2MIntegrationTest; import java.nio.charset.StandardCharsets; @@ -28,12 +28,10 @@ import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SECURE_COAP import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SECURE_URI; import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SHORT_SERVER_ID; -public class PskLwm2mIntegrationTest extends AbstractLwM2MIntegrationTest { +public class PskLwm2mIntegrationTest extends AbstractSecurityLwM2MIntegrationTest { @Test public void testConnectWithPSKAndObserveTelemetry() throws Exception { - String pskIdentity = "SOME_PSK_ID"; - String pskKey = "73656372657450534b73656372657450"; PSKClientCredentials clientCredentials = new PSKClientCredentials(); clientCredentials.setEndpoint(ENDPOINT); clientCredentials.setKey(pskKey); diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/RpkLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/RpkLwM2MIntegrationTest.java index 02d57d6782..fdfa56957c 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/RpkLwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/RpkLwM2MIntegrationTest.java @@ -19,14 +19,14 @@ import org.eclipse.leshan.client.object.Security; import org.eclipse.leshan.core.util.Hex; import org.junit.Test; import org.thingsboard.server.common.data.device.credentials.lwm2m.RPKClientCredentials; -import org.thingsboard.server.transport.lwm2m.security.AbstractLwM2MIntegrationTest; +import org.thingsboard.server.transport.lwm2m.security.AbstractSecurityLwM2MIntegrationTest; import static org.eclipse.leshan.client.object.Security.rpk; import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SECURE_COAP_CONFIG; import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SECURE_URI; import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SHORT_SERVER_ID; -public class RpkLwM2MIntegrationTest extends AbstractLwM2MIntegrationTest { +public class RpkLwM2MIntegrationTest extends AbstractSecurityLwM2MIntegrationTest { @Test public void testConnectWithRPKAndObserveTelemetry() throws Exception { diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/X509_NoTrustLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/X509_NoTrustLwM2MIntegrationTest.java index af721ab188..f6e08f0e3d 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/X509_NoTrustLwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/X509_NoTrustLwM2MIntegrationTest.java @@ -19,14 +19,14 @@ import org.eclipse.leshan.client.object.Security; import org.junit.Test; import org.thingsboard.server.common.data.device.credentials.lwm2m.X509ClientCredentials; import org.thingsboard.server.common.transport.util.SslUtil; -import org.thingsboard.server.transport.lwm2m.security.AbstractLwM2MIntegrationTest; +import org.thingsboard.server.transport.lwm2m.security.AbstractSecurityLwM2MIntegrationTest; import static org.eclipse.leshan.client.object.Security.x509; import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SECURE_COAP_CONFIG; import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SECURE_URI; import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SHORT_SERVER_ID; -public class X509_NoTrustLwM2MIntegrationTest extends AbstractLwM2MIntegrationTest { +public class X509_NoTrustLwM2MIntegrationTest extends AbstractSecurityLwM2MIntegrationTest { @Test public void testConnectWithCertAndObserveTelemetry() throws Exception { @@ -34,7 +34,7 @@ public class X509_NoTrustLwM2MIntegrationTest extends AbstractLwM2MIntegrationTe credentials.setEndpoint(ENDPOINT); credentials.setCert(SslUtil.getCertificateString(clientX509CertNotTrusted)); Security security = x509(SECURE_URI, - 123, + SHORT_SERVER_ID, clientX509CertNotTrusted.getEncoded(), clientPrivateKeyFromCert.getEncoded(), serverX509Cert.getEncoded()); diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/X509_TrustLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/X509_TrustLwM2MIntegrationTest.java index 9870a2a527..28289b32bf 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/X509_TrustLwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/X509_TrustLwM2MIntegrationTest.java @@ -18,14 +18,14 @@ package org.thingsboard.server.transport.lwm2m.security.sql; import org.eclipse.leshan.client.object.Security; import org.junit.Test; import org.thingsboard.server.common.data.device.credentials.lwm2m.X509ClientCredentials; -import org.thingsboard.server.transport.lwm2m.security.AbstractLwM2MIntegrationTest; +import org.thingsboard.server.transport.lwm2m.security.AbstractSecurityLwM2MIntegrationTest; import static org.eclipse.leshan.client.object.Security.x509; import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SECURE_COAP_CONFIG; import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SECURE_URI; import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SHORT_SERVER_ID; -public class X509_TrustLwM2MIntegrationTest extends AbstractLwM2MIntegrationTest { +public class X509_TrustLwM2MIntegrationTest extends AbstractSecurityLwM2MIntegrationTest { @Test public void testConnectAndObserveTelemetry() throws Exception { diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/attributes/DefaultLwM2MAttributesService.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/attributes/DefaultLwM2MAttributesService.java index 38b4790216..2df47e3bfa 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/attributes/DefaultLwM2MAttributesService.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/attributes/DefaultLwM2MAttributesService.java @@ -153,7 +153,12 @@ public class DefaultLwM2MAttributesService implements LwM2MAttributesService { newSoftwareTag = getStrValue(tsKvProto); } else if (DefaultLwM2MOtaUpdateService.SOFTWARE_URL.equals(attrName)) { newSoftwareUrl = getStrValue(tsKvProto); - } else { + } else if (!DefaultLwM2MOtaUpdateService.FIRMWARE_SIZE.equals(attrName) && + !DefaultLwM2MOtaUpdateService.FIRMWARE_CHECKSUM.equals(attrName) && + !DefaultLwM2MOtaUpdateService.FIRMWARE_CHECKSUM_ALGORITHM.equals(attrName) && + !DefaultLwM2MOtaUpdateService.SOFTWARE_SIZE.equals(attrName) && + !DefaultLwM2MOtaUpdateService.SOFTWARE_CHECKSUM.equals(attrName) && + !DefaultLwM2MOtaUpdateService.SOFTWARE_CHECKSUM_ALGORITHM.equals(attrName)){ otherAttributes.add(tsKvProto); } } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/DefaultLwM2MOtaUpdateService.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/DefaultLwM2MOtaUpdateService.java index 8335057caa..f25f826c30 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/DefaultLwM2MOtaUpdateService.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/DefaultLwM2MOtaUpdateService.java @@ -87,10 +87,16 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl public static final String FIRMWARE_TITLE = getAttributeKey(OtaPackageType.FIRMWARE, OtaPackageKey.TITLE); public static final String FIRMWARE_TAG = getAttributeKey(OtaPackageType.FIRMWARE, OtaPackageKey.TAG); public static final String FIRMWARE_URL = getAttributeKey(OtaPackageType.FIRMWARE, OtaPackageKey.URL); + public static final String FIRMWARE_SIZE = getAttributeKey(OtaPackageType.FIRMWARE, OtaPackageKey.SIZE); + public static final String FIRMWARE_CHECKSUM_ALGORITHM = getAttributeKey(OtaPackageType.FIRMWARE, OtaPackageKey.CHECKSUM_ALGORITHM); + public static final String FIRMWARE_CHECKSUM = getAttributeKey(OtaPackageType.FIRMWARE, OtaPackageKey.CHECKSUM); public static final String SOFTWARE_VERSION = getAttributeKey(OtaPackageType.SOFTWARE, OtaPackageKey.VERSION); public static final String SOFTWARE_TITLE = getAttributeKey(OtaPackageType.SOFTWARE, OtaPackageKey.TITLE); public static final String SOFTWARE_TAG = getAttributeKey(OtaPackageType.SOFTWARE, OtaPackageKey.TAG); public static final String SOFTWARE_URL = getAttributeKey(OtaPackageType.SOFTWARE, OtaPackageKey.URL); + public static final String SOFTWARE_SIZE = getAttributeKey(OtaPackageType.SOFTWARE, OtaPackageKey.SIZE); + public static final String SOFTWARE_CHECKSUM_ALGORITHM = getAttributeKey(OtaPackageType.SOFTWARE, OtaPackageKey.CHECKSUM_ALGORITHM); + public static final String SOFTWARE_CHECKSUM = getAttributeKey(OtaPackageType.SOFTWARE, OtaPackageKey.CHECKSUM); public static final String FIRMWARE_UPDATE_COAP_RESOURCE = "tbfw"; public static final String SOFTWARE_UPDATE_COAP_RESOURCE = "tbsw"; From 604b7e380f11b8c8cdebfa7cee87fe68493fdfd8 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Tue, 14 Sep 2021 23:06:39 +0300 Subject: [PATCH 032/432] Lwm2m test OTA fix bug. Object9. --- .../DefaultLwM2MAttributesService.java | 42 +++++++++---------- 1 file changed, 20 insertions(+), 22 deletions(-) diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/attributes/DefaultLwM2MAttributesService.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/attributes/DefaultLwM2MAttributesService.java index 2df47e3bfa..c1c995e687 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/attributes/DefaultLwM2MAttributesService.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/attributes/DefaultLwM2MAttributesService.java @@ -26,6 +26,7 @@ import org.eclipse.leshan.core.node.LwM2mPath; import org.eclipse.leshan.core.node.LwM2mResource; import org.eclipse.leshan.core.node.LwM2mResourceInstance; import org.springframework.stereotype.Service; +import org.thingsboard.server.common.data.ota.OtaPackageType; import org.thingsboard.server.common.transport.TransportService; import org.thingsboard.server.common.transport.TransportServiceCallback; import org.thingsboard.server.gen.transport.TransportProtos; @@ -137,28 +138,25 @@ public class DefaultLwM2MAttributesService implements LwM2MAttributesService { List otherAttributes = new ArrayList<>(); for (TransportProtos.TsKvProto tsKvProto : msg.getSharedUpdatedList()) { String attrName = tsKvProto.getKv().getKey(); - if (DefaultLwM2MOtaUpdateService.FIRMWARE_TITLE.equals(attrName)) { - newFirmwareTitle = getStrValue(tsKvProto); - } else if (DefaultLwM2MOtaUpdateService.FIRMWARE_VERSION.equals(attrName)) { - newFirmwareVersion = getStrValue(tsKvProto); - } else if (DefaultLwM2MOtaUpdateService.FIRMWARE_TAG.equals(attrName)) { - newFirmwareTag = getStrValue(tsKvProto); - } else if (DefaultLwM2MOtaUpdateService.FIRMWARE_URL.equals(attrName)) { - newFirmwareUrl = getStrValue(tsKvProto); - } else if (DefaultLwM2MOtaUpdateService.SOFTWARE_TITLE.equals(attrName)) { - newSoftwareTitle = getStrValue(tsKvProto); - } else if (DefaultLwM2MOtaUpdateService.SOFTWARE_VERSION.equals(attrName)) { - newSoftwareVersion = getStrValue(tsKvProto); - } else if (DefaultLwM2MOtaUpdateService.SOFTWARE_TAG.equals(attrName)) { - newSoftwareTag = getStrValue(tsKvProto); - } else if (DefaultLwM2MOtaUpdateService.SOFTWARE_URL.equals(attrName)) { - newSoftwareUrl = getStrValue(tsKvProto); - } else if (!DefaultLwM2MOtaUpdateService.FIRMWARE_SIZE.equals(attrName) && - !DefaultLwM2MOtaUpdateService.FIRMWARE_CHECKSUM.equals(attrName) && - !DefaultLwM2MOtaUpdateService.FIRMWARE_CHECKSUM_ALGORITHM.equals(attrName) && - !DefaultLwM2MOtaUpdateService.SOFTWARE_SIZE.equals(attrName) && - !DefaultLwM2MOtaUpdateService.SOFTWARE_CHECKSUM.equals(attrName) && - !DefaultLwM2MOtaUpdateService.SOFTWARE_CHECKSUM_ALGORITHM.equals(attrName)){ + if (attrName.contains(OtaPackageType.FIRMWARE.getKeyPrefix()) || attrName.contains(OtaPackageType.SOFTWARE.getKeyPrefix())) { + if (DefaultLwM2MOtaUpdateService.FIRMWARE_TITLE.equals(attrName)) { + newFirmwareTitle = getStrValue(tsKvProto); + } else if (DefaultLwM2MOtaUpdateService.FIRMWARE_VERSION.equals(attrName)) { + newFirmwareVersion = getStrValue(tsKvProto); + } else if (DefaultLwM2MOtaUpdateService.FIRMWARE_TAG.equals(attrName)) { + newFirmwareTag = getStrValue(tsKvProto); + } else if (DefaultLwM2MOtaUpdateService.FIRMWARE_URL.equals(attrName)) { + newFirmwareUrl = getStrValue(tsKvProto); + } else if (DefaultLwM2MOtaUpdateService.SOFTWARE_TITLE.equals(attrName)) { + newSoftwareTitle = getStrValue(tsKvProto); + } else if (DefaultLwM2MOtaUpdateService.SOFTWARE_VERSION.equals(attrName)) { + newSoftwareVersion = getStrValue(tsKvProto); + } else if (DefaultLwM2MOtaUpdateService.SOFTWARE_TAG.equals(attrName)) { + newSoftwareTag = getStrValue(tsKvProto); + } else if (DefaultLwM2MOtaUpdateService.SOFTWARE_URL.equals(attrName)) { + newSoftwareUrl = getStrValue(tsKvProto); + } + } else { otherAttributes.add(tsKvProto); } } From 8df2e83eddad6fdf31ff16243483086773297332 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Wed, 15 Sep 2021 10:55:07 +0300 Subject: [PATCH 033/432] Lwm2m test OTA fix bug. Object 9, 5 --- .../transport/TransportSqlTestSuite.java | 16 ++++---- .../LwM2mTransportServerHelperTest.java | 2 +- .../secure/LwM2MBootstrapSecurityStore.java | 8 ++-- .../LwM2mDefaultBootstrapSessionManager.java | 2 +- .../lwm2m/server/LwM2mServerListener.java | 2 +- .../DefaultLwM2MAttributesService.java | 38 +++++++++++-------- .../lwm2m/server/client/LwM2mClient.java | 12 +++--- .../server/client/LwM2mClientContextImpl.java | 6 +-- .../AbstractTbLwM2MRequestCallback.java | 2 +- .../DefaultLwM2mDownlinkMsgHandler.java | 10 ++--- .../lwm2m/server/downlink/HasVersionedId.java | 2 +- .../server/downlink/HasVersionedIds.java | 2 +- .../TbLwM2MCancelAllObserveCallback.java | 2 +- .../TbLwM2MCancelObserveCallback.java | 2 +- .../downlink/TbLwM2MTargetedCallback.java | 2 +- .../log/DefaultLwM2MTelemetryLogService.java | 2 +- .../ota/DefaultLwM2MOtaUpdateService.java | 10 +---- .../rpc/DefaultLwM2MRpcRequestHandler.java | 9 +---- .../server/rpc/RpcReadResponseCallback.java | 2 +- .../RpcReadResponseCompositeCallback.java | 2 +- .../uplink/DefaultLwM2MUplinkMsgHandler.java | 14 +++---- .../{server => utils}/LwM2mTransportUtil.java | 24 +++++++++--- 22 files changed, 90 insertions(+), 81 deletions(-) rename common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/{server => utils}/LwM2mTransportUtil.java (96%) diff --git a/application/src/test/java/org/thingsboard/server/transport/TransportSqlTestSuite.java b/application/src/test/java/org/thingsboard/server/transport/TransportSqlTestSuite.java index 095321c184..5c26a65978 100644 --- a/application/src/test/java/org/thingsboard/server/transport/TransportSqlTestSuite.java +++ b/application/src/test/java/org/thingsboard/server/transport/TransportSqlTestSuite.java @@ -26,14 +26,14 @@ import java.util.Arrays; @RunWith(ClasspathSuite.class) @ClasspathSuite.ClassnameFilters({ - "org.thingsboard.server.transport.*.rpc.sql.*Test", - "org.thingsboard.server.transport.*.telemetry.timeseries.sql.*Test", - "org.thingsboard.server.transport.*.telemetry.attributes.sql.*Test", - "org.thingsboard.server.transport.*.attributes.updates.sql.*Test", - "org.thingsboard.server.transport.*.attributes.request.sql.*Test", - "org.thingsboard.server.transport.*.claim.sql.*Test", - "org.thingsboard.server.transport.*.provision.sql.*Test", - "org.thingsboard.server.transport.lwm2m.*.sql.*Test" +// "org.thingsboard.server.transport.*.rpc.sql.*Test", +// "org.thingsboard.server.transport.*.telemetry.timeseries.sql.*Test", +// "org.thingsboard.server.transport.*.telemetry.attributes.sql.*Test", +// "org.thingsboard.server.transport.*.attributes.updates.sql.*Test", +// "org.thingsboard.server.transport.*.attributes.request.sql.*Test", +// "org.thingsboard.server.transport.*.claim.sql.*Test", +// "org.thingsboard.server.transport.*.provision.sql.*Test", + "org.thingsboard.server.transport.lwm2m.ota.sql.*Test" }) public class TransportSqlTestSuite { diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportServerHelperTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportServerHelperTest.java index 15af28284e..fdccc2e933 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportServerHelperTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportServerHelperTest.java @@ -37,7 +37,7 @@ import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LWM2M_TELEMETRY; +import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.LOG_LWM2M_TELEMETRY; class LwM2mTransportServerHelperTest { diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapSecurityStore.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapSecurityStore.java index fb6149a796..a83f006543 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapSecurityStore.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapSecurityStore.java @@ -43,10 +43,10 @@ import java.util.Map; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LWM2M_ERROR; -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LWM2M_INFO; -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LWM2M_TELEMETRY; -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.getBootstrapParametersFromThingsboard; +import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.LOG_LWM2M_ERROR; +import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.LOG_LWM2M_INFO; +import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.LOG_LWM2M_TELEMETRY; +import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.getBootstrapParametersFromThingsboard; import static org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mTypeServer.BOOTSTRAP; @Slf4j diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2mDefaultBootstrapSessionManager.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2mDefaultBootstrapSessionManager.java index 2e41d17635..7c6e157f83 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2mDefaultBootstrapSessionManager.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2mDefaultBootstrapSessionManager.java @@ -39,7 +39,7 @@ import java.util.ArrayList; import java.util.Iterator; import java.util.List; -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LWM2M_INFO; +import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.LOG_LWM2M_INFO; @Slf4j public class LwM2mDefaultBootstrapSessionManager extends DefaultBootstrapSessionManager { diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mServerListener.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mServerListener.java index edc408a78d..8c8624fcf3 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mServerListener.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mServerListener.java @@ -27,7 +27,7 @@ import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandle import java.util.Collection; -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertObjectIdToVersionedId; +import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.convertObjectIdToVersionedId; @Slf4j public class LwM2mServerListener { diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/attributes/DefaultLwM2MAttributesService.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/attributes/DefaultLwM2MAttributesService.java index c1c995e687..dfe5146017 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/attributes/DefaultLwM2MAttributesService.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/attributes/DefaultLwM2MAttributesService.java @@ -26,7 +26,6 @@ import org.eclipse.leshan.core.node.LwM2mPath; import org.eclipse.leshan.core.node.LwM2mResource; import org.eclipse.leshan.core.node.LwM2mResourceInstance; import org.springframework.stereotype.Service; -import org.thingsboard.server.common.data.ota.OtaPackageType; import org.thingsboard.server.common.transport.TransportService; import org.thingsboard.server.common.transport.TransportServiceCallback; import org.thingsboard.server.gen.transport.TransportProtos; @@ -34,7 +33,7 @@ import org.thingsboard.server.gen.transport.TransportProtos.GetAttributeResponse import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportServerHelper; -import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil; +import org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil; import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientContext; import org.thingsboard.server.transport.lwm2m.server.downlink.LwM2mDownlinkMsgHandler; @@ -57,10 +56,19 @@ import java.util.concurrent.atomic.AtomicInteger; import static org.eclipse.leshan.core.model.ResourceModel.Type.OPAQUE; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportServerHelper.getValueFromKvProto; -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LWM2M_ERROR; -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LWM2M_WARN; -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertMultiResourceValuesFromJson; -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.fromVersionedIdToObjectId; +import static org.thingsboard.server.transport.lwm2m.server.ota.DefaultLwM2MOtaUpdateService.FIRMWARE_TAG; +import static org.thingsboard.server.transport.lwm2m.server.ota.DefaultLwM2MOtaUpdateService.FIRMWARE_TITLE; +import static org.thingsboard.server.transport.lwm2m.server.ota.DefaultLwM2MOtaUpdateService.FIRMWARE_URL; +import static org.thingsboard.server.transport.lwm2m.server.ota.DefaultLwM2MOtaUpdateService.FIRMWARE_VERSION; +import static org.thingsboard.server.transport.lwm2m.server.ota.DefaultLwM2MOtaUpdateService.SOFTWARE_TAG; +import static org.thingsboard.server.transport.lwm2m.server.ota.DefaultLwM2MOtaUpdateService.SOFTWARE_TITLE; +import static org.thingsboard.server.transport.lwm2m.server.ota.DefaultLwM2MOtaUpdateService.SOFTWARE_URL; +import static org.thingsboard.server.transport.lwm2m.server.ota.DefaultLwM2MOtaUpdateService.SOFTWARE_VERSION; +import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.LOG_LWM2M_ERROR; +import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.LOG_LWM2M_WARN; +import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.compareAttNameKeyOta; +import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.convertMultiResourceValuesFromJson; +import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.fromVersionedIdToObjectId; @Slf4j @Service @@ -138,22 +146,22 @@ public class DefaultLwM2MAttributesService implements LwM2MAttributesService { List otherAttributes = new ArrayList<>(); for (TransportProtos.TsKvProto tsKvProto : msg.getSharedUpdatedList()) { String attrName = tsKvProto.getKv().getKey(); - if (attrName.contains(OtaPackageType.FIRMWARE.getKeyPrefix()) || attrName.contains(OtaPackageType.SOFTWARE.getKeyPrefix())) { - if (DefaultLwM2MOtaUpdateService.FIRMWARE_TITLE.equals(attrName)) { + if (compareAttNameKeyOta(attrName)) { + if (FIRMWARE_TITLE.equals(attrName)) { newFirmwareTitle = getStrValue(tsKvProto); - } else if (DefaultLwM2MOtaUpdateService.FIRMWARE_VERSION.equals(attrName)) { + } else if (FIRMWARE_VERSION.equals(attrName)) { newFirmwareVersion = getStrValue(tsKvProto); - } else if (DefaultLwM2MOtaUpdateService.FIRMWARE_TAG.equals(attrName)) { + } else if (FIRMWARE_TAG.equals(attrName)) { newFirmwareTag = getStrValue(tsKvProto); - } else if (DefaultLwM2MOtaUpdateService.FIRMWARE_URL.equals(attrName)) { + } else if (FIRMWARE_URL.equals(attrName)) { newFirmwareUrl = getStrValue(tsKvProto); - } else if (DefaultLwM2MOtaUpdateService.SOFTWARE_TITLE.equals(attrName)) { + } else if (SOFTWARE_TITLE.equals(attrName)) { newSoftwareTitle = getStrValue(tsKvProto); - } else if (DefaultLwM2MOtaUpdateService.SOFTWARE_VERSION.equals(attrName)) { + } else if (SOFTWARE_VERSION.equals(attrName)) { newSoftwareVersion = getStrValue(tsKvProto); - } else if (DefaultLwM2MOtaUpdateService.SOFTWARE_TAG.equals(attrName)) { + } else if (SOFTWARE_TAG.equals(attrName)) { newSoftwareTag = getStrValue(tsKvProto); - } else if (DefaultLwM2MOtaUpdateService.SOFTWARE_URL.equals(attrName)) { + } else if (SOFTWARE_URL.equals(attrName)) { newSoftwareUrl = getStrValue(tsKvProto); } } else { diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java index 8106871aee..048bc046aa 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java @@ -62,12 +62,12 @@ import java.util.stream.Collectors; import java.util.stream.Stream; import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPARATOR_PATH; -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LWM2M_OBJECT_VERSION_DEFAULT; -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertMultiResourceValuesFromRpcBody; -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertObjectIdToVersionedId; -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.equalsResourceTypeGetSimpleName; -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.fromVersionedIdToObjectId; -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.getVerFromPathIdVerOrId; +import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.LWM2M_OBJECT_VERSION_DEFAULT; +import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.convertMultiResourceValuesFromRpcBody; +import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.convertObjectIdToVersionedId; +import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.equalsResourceTypeGetSimpleName; +import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.fromVersionedIdToObjectId; +import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.getVerFromPathIdVerOrId; @Slf4j @EqualsAndHashCode(of = {"endpoint"}) diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java index ebf9c11155..71f4a0058a 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java @@ -38,7 +38,7 @@ import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; import org.thingsboard.server.transport.lwm2m.secure.TbLwM2MSecurityInfo; import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportContext; -import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil; +import org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil; import org.thingsboard.server.transport.lwm2m.server.ota.LwM2MOtaUpdateService; import org.thingsboard.server.transport.lwm2m.server.session.LwM2MSessionManager; import org.thingsboard.server.transport.lwm2m.server.store.TbLwM2MClientStore; @@ -57,8 +57,8 @@ import java.util.concurrent.TimeUnit; import java.util.function.Predicate; import static org.eclipse.leshan.core.SecurityMode.NO_SEC; -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertObjectIdToVersionedId; -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.getMsgException; +import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.convertObjectIdToVersionedId; +import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.getMsgException; @Slf4j @Service diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/AbstractTbLwM2MRequestCallback.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/AbstractTbLwM2MRequestCallback.java index 561b103277..c99a5ea2a1 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/AbstractTbLwM2MRequestCallback.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/AbstractTbLwM2MRequestCallback.java @@ -19,7 +19,7 @@ import lombok.extern.slf4j.Slf4j; import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService; -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LWM2M_WARN; +import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.LOG_LWM2M_WARN; @Slf4j public abstract class AbstractTbLwM2MRequestCallback implements DownlinkRequestCallback { diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2mDownlinkMsgHandler.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2mDownlinkMsgHandler.java index 0fdfb6c908..ddf6984eb8 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2mDownlinkMsgHandler.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2mDownlinkMsgHandler.java @@ -95,11 +95,11 @@ import static org.eclipse.leshan.core.attributes.Attribute.MINIMUM_PERIOD; import static org.eclipse.leshan.core.attributes.Attribute.STEP; import static org.eclipse.leshan.core.model.ResourceModel.Type.OBJLNK; import static org.eclipse.leshan.core.model.ResourceModel.Type.OPAQUE; -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertMultiResourceValuesFromRpcBody; -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.createModelsDefault; -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.fromVersionedIdToObjectId; -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.getVerFromPathIdVerOrId; -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.validateVersionedId; +import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.convertMultiResourceValuesFromRpcBody; +import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.createModelsDefault; +import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.fromVersionedIdToObjectId; +import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.getVerFromPathIdVerOrId; +import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.validateVersionedId; @Slf4j @Service diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/HasVersionedId.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/HasVersionedId.java index fcbb195935..5e427fcb31 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/HasVersionedId.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/HasVersionedId.java @@ -15,7 +15,7 @@ */ package org.thingsboard.server.transport.lwm2m.server.downlink; -import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil; +import org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil; public interface HasVersionedId { diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/HasVersionedIds.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/HasVersionedIds.java index 5ccef5ecea..a24789a410 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/HasVersionedIds.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/HasVersionedIds.java @@ -15,7 +15,7 @@ */ package org.thingsboard.server.transport.lwm2m.server.downlink; -import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil; +import org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MCancelAllObserveCallback.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MCancelAllObserveCallback.java index f90e0f8b97..d59ab9f16d 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MCancelAllObserveCallback.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MCancelAllObserveCallback.java @@ -19,7 +19,7 @@ import lombok.extern.slf4j.Slf4j; import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService; -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LWM2M_INFO; +import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.LOG_LWM2M_INFO; @Slf4j public class TbLwM2MCancelAllObserveCallback extends AbstractTbLwM2MRequestCallback { diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MCancelObserveCallback.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MCancelObserveCallback.java index b663215078..85accc5166 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MCancelObserveCallback.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MCancelObserveCallback.java @@ -19,7 +19,7 @@ import lombok.extern.slf4j.Slf4j; import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService; -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LWM2M_INFO; +import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.LOG_LWM2M_INFO; @Slf4j public class TbLwM2MCancelObserveCallback extends AbstractTbLwM2MRequestCallback { diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MTargetedCallback.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MTargetedCallback.java index 92992d299c..52053093f0 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MTargetedCallback.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MTargetedCallback.java @@ -24,7 +24,7 @@ import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogServic import java.util.Arrays; -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LWM2M_INFO; +import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.LOG_LWM2M_INFO; @Slf4j public abstract class TbLwM2MTargetedCallback extends AbstractTbLwM2MRequestCallback { diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/log/DefaultLwM2MTelemetryLogService.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/log/DefaultLwM2MTelemetryLogService.java index 4e59eb5b44..ceaa163b63 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/log/DefaultLwM2MTelemetryLogService.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/log/DefaultLwM2MTelemetryLogService.java @@ -22,7 +22,7 @@ import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportServerHelper; import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LWM2M_TELEMETRY; +import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.LOG_LWM2M_TELEMETRY; @Slf4j @Service diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/DefaultLwM2MOtaUpdateService.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/DefaultLwM2MOtaUpdateService.java index f25f826c30..6a9fc54971 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/DefaultLwM2MOtaUpdateService.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/DefaultLwM2MOtaUpdateService.java @@ -74,8 +74,8 @@ import static org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus.UPDA import static org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus.UPDATING; import static org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus.VERIFIED; import static org.thingsboard.server.common.data.ota.OtaPackageUtil.getAttributeKey; -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LWM2M_TELEMETRY; -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertObjectIdToVersionedId; +import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.LOG_LWM2M_TELEMETRY; +import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.convertObjectIdToVersionedId; @Slf4j @Service @@ -87,16 +87,10 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl public static final String FIRMWARE_TITLE = getAttributeKey(OtaPackageType.FIRMWARE, OtaPackageKey.TITLE); public static final String FIRMWARE_TAG = getAttributeKey(OtaPackageType.FIRMWARE, OtaPackageKey.TAG); public static final String FIRMWARE_URL = getAttributeKey(OtaPackageType.FIRMWARE, OtaPackageKey.URL); - public static final String FIRMWARE_SIZE = getAttributeKey(OtaPackageType.FIRMWARE, OtaPackageKey.SIZE); - public static final String FIRMWARE_CHECKSUM_ALGORITHM = getAttributeKey(OtaPackageType.FIRMWARE, OtaPackageKey.CHECKSUM_ALGORITHM); - public static final String FIRMWARE_CHECKSUM = getAttributeKey(OtaPackageType.FIRMWARE, OtaPackageKey.CHECKSUM); public static final String SOFTWARE_VERSION = getAttributeKey(OtaPackageType.SOFTWARE, OtaPackageKey.VERSION); public static final String SOFTWARE_TITLE = getAttributeKey(OtaPackageType.SOFTWARE, OtaPackageKey.TITLE); public static final String SOFTWARE_TAG = getAttributeKey(OtaPackageType.SOFTWARE, OtaPackageKey.TAG); public static final String SOFTWARE_URL = getAttributeKey(OtaPackageType.SOFTWARE, OtaPackageKey.URL); - public static final String SOFTWARE_SIZE = getAttributeKey(OtaPackageType.SOFTWARE, OtaPackageKey.SIZE); - public static final String SOFTWARE_CHECKSUM_ALGORITHM = getAttributeKey(OtaPackageType.SOFTWARE, OtaPackageKey.CHECKSUM_ALGORITHM); - public static final String SOFTWARE_CHECKSUM = getAttributeKey(OtaPackageType.SOFTWARE, OtaPackageKey.CHECKSUM); public static final String FIRMWARE_UPDATE_COAP_RESOURCE = "tbfw"; public static final String SOFTWARE_UPDATE_COAP_RESOURCE = "tbsw"; diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/DefaultLwM2MRpcRequestHandler.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/DefaultLwM2MRpcRequestHandler.java index 57217290b5..3d032081ee 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/DefaultLwM2MRpcRequestHandler.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/DefaultLwM2MRpcRequestHandler.java @@ -21,14 +21,10 @@ import org.eclipse.leshan.core.ResponseCode; import org.eclipse.leshan.core.model.ResourceModel; import org.eclipse.leshan.core.node.LwM2mPath; import org.eclipse.leshan.core.request.ContentFormat; -import org.eclipse.leshan.core.request.ReadCompositeRequest; -import org.eclipse.leshan.core.response.ReadCompositeResponse; import org.springframework.stereotype.Service; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.StringUtils; -import org.thingsboard.server.common.data.rpc.RpcStatus; import org.thingsboard.server.common.transport.TransportService; -import org.thingsboard.server.common.transport.TransportServiceCallback; import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; @@ -68,15 +64,14 @@ import org.thingsboard.server.transport.lwm2m.server.rpc.composite.RpcReadRespon import org.thingsboard.server.transport.lwm2m.server.rpc.composite.RpcWriteCompositeRequest; import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler; -import java.util.HashSet; import java.util.LinkedHashMap; import java.util.Map; import java.util.Set; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertMultiResourceValuesFromRpcBody; -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.fromVersionedIdToObjectId; +import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.convertMultiResourceValuesFromRpcBody; +import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.fromVersionedIdToObjectId; @Slf4j @Service diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcReadResponseCallback.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcReadResponseCallback.java index 0a5fa70b5b..de033548fb 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcReadResponseCallback.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcReadResponseCallback.java @@ -24,7 +24,7 @@ import org.thingsboard.server.transport.lwm2m.server.downlink.DownlinkRequestCal import java.util.Optional; -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.contentToString; +import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.contentToString; public class RpcReadResponseCallback, T extends ReadResponse> extends RpcLwM2MDownlinkCallback { diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/composite/RpcReadResponseCompositeCallback.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/composite/RpcReadResponseCompositeCallback.java index 11f6849410..ea10ca90ca 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/composite/RpcReadResponseCompositeCallback.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/composite/RpcReadResponseCompositeCallback.java @@ -25,7 +25,7 @@ import org.thingsboard.server.transport.lwm2m.server.rpc.RpcLwM2MDownlinkCallbac import java.util.Optional; -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.contentToString; +import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.contentToString; public class RpcReadResponseCompositeCallback, T extends ReadCompositeResponse> extends RpcLwM2MDownlinkCallback { diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/DefaultLwM2MUplinkMsgHandler.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/DefaultLwM2MUplinkMsgHandler.java index 84ac0277a3..bb8a74aaef 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/DefaultLwM2MUplinkMsgHandler.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/DefaultLwM2MUplinkMsgHandler.java @@ -61,7 +61,7 @@ import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; import org.thingsboard.server.transport.lwm2m.server.LwM2mOtaConvert; import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportContext; import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportServerHelper; -import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil; +import org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil; import org.thingsboard.server.transport.lwm2m.server.attributes.LwM2MAttributesService; import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClientState; import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClientStateException; @@ -106,12 +106,12 @@ import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPARATOR_PATH; -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LWM2M_ERROR; -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LWM2M_INFO; -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LWM2M_WARN; -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertObjectIdToVersionedId; -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertOtaUpdateValueToString; -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.fromVersionedIdToObjectId; +import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.LOG_LWM2M_ERROR; +import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.LOG_LWM2M_INFO; +import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.LOG_LWM2M_WARN; +import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.convertObjectIdToVersionedId; +import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.convertOtaUpdateValueToString; +import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.fromVersionedIdToObjectId; import static org.thingsboard.server.transport.lwm2m.server.ota.DefaultLwM2MOtaUpdateService.FW_3_VER_ID; import static org.thingsboard.server.transport.lwm2m.server.ota.DefaultLwM2MOtaUpdateService.FW_DELIVERY_METHOD; import static org.thingsboard.server.transport.lwm2m.server.ota.DefaultLwM2MOtaUpdateService.FW_NAME_ID; diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportUtil.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2mTransportUtil.java similarity index 96% rename from common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportUtil.java rename to common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2mTransportUtil.java index 9648edc20f..69cee060ab 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportUtil.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2mTransportUtil.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.transport.lwm2m.server; +package org.thingsboard.server.transport.lwm2m.utils; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; @@ -45,7 +45,10 @@ import org.thingsboard.server.common.data.DeviceTransportType; import org.thingsboard.server.common.data.device.data.lwm2m.BootstrapConfiguration; import org.thingsboard.server.common.data.device.profile.DeviceProfileTransportConfiguration; import org.thingsboard.server.common.data.device.profile.Lwm2mDeviceProfileTransportConfiguration; +import org.thingsboard.server.common.data.ota.OtaPackageKey; +import org.thingsboard.server.common.data.ota.OtaPackageType; import org.thingsboard.server.transport.lwm2m.config.LwM2mVersion; +import org.thingsboard.server.transport.lwm2m.server.LwM2mOtaConvert; import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; import org.thingsboard.server.transport.lwm2m.server.client.ResourceValue; import org.thingsboard.server.transport.lwm2m.server.downlink.HasVersionedId; @@ -83,6 +86,7 @@ import static org.eclipse.leshan.core.model.ResourceModel.Type.STRING; import static org.eclipse.leshan.core.model.ResourceModel.Type.TIME; import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPARATOR_KEY; import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPARATOR_PATH; +import static org.thingsboard.server.common.data.ota.OtaPackageUtil.getAttributeKey; import static org.thingsboard.server.transport.lwm2m.server.ota.DefaultLwM2MOtaUpdateService.FW_RESULT_ID; import static org.thingsboard.server.transport.lwm2m.server.ota.DefaultLwM2MOtaUpdateService.FW_STATE_ID; import static org.thingsboard.server.transport.lwm2m.server.ota.DefaultLwM2MOtaUpdateService.SW_RESULT_ID; @@ -300,7 +304,8 @@ public class LwM2mTransportUtil { private static Attribute[] createWriteAttributes(Object params, DefaultLwM2MUplinkMsgHandler serviceImpl, String target) { List attributeLists = new ArrayList<>(); - Map map = JacksonUtil.convertValue(params, new TypeReference<>() {}); + Map map = JacksonUtil.convertValue(params, new TypeReference<>() { + }); map.forEach((k, v) -> { if (StringUtils.trimToNull(v.toString()) != null) { Object attrValue = convertWriteAttributes(k, v, serviceImpl, target); @@ -316,9 +321,9 @@ public class LwM2mTransportUtil { } /** - * "UNSIGNED_INTEGER": // Number -> Integer Example: - * Alarm Timestamp [32-bit unsigned integer] - * Short Server ID, Object ID, Object Instance ID, Resource ID, Resource Instance ID + * "UNSIGNED_INTEGER": // Number -> Integer Example: + * Alarm Timestamp [32-bit unsigned integer] + * Short Server ID, Object ID, Object Instance ID, Resource ID, Resource Instance ID * "CORELINK": // String used in Attribute */ public static ResourceModel.Type equalsResourceTypeGetSimpleName(Object value) { @@ -349,7 +354,7 @@ public class LwM2mTransportUtil { } else { msgExceptionStr = client.isValidObjectVersion(request.getVersionedId()); } - if (!msgExceptionStr.isEmpty() ) { + if (!msgExceptionStr.isEmpty()) { throw new IllegalArgumentException(msgExceptionStr); } } @@ -531,4 +536,11 @@ public class LwM2mTransportUtil { return new StaticModel(ObjectLoader.loadDefault()); } + public static boolean compareAttNameKeyOta(String attrName) { + for (OtaPackageKey value : OtaPackageKey.values()) { + if (getAttributeKey(OtaPackageType.FIRMWARE, value).equals(attrName)) return true; + if (getAttributeKey(OtaPackageType.SOFTWARE, value).equals(attrName)) return true; + } + return false; + } } From 565cc29cbbb4c6a39d43d79f99f293add14461d6 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Wed, 15 Sep 2021 14:25:00 +0300 Subject: [PATCH 034/432] Lwm2m Fix bug Write, Read - if Not_Found --- .../transport/TransportSqlTestSuite.java | 16 ++--- .../DefaultLwM2mDownlinkMsgHandler.java | 1 + .../downlink/TbLwM2MTargetedCallback.java | 18 +++++- .../TbLwM2MWriteResponseCallback.java | 4 +- ...TbLwM2MWriteResponseCompositeCallback.java | 2 +- .../uplink/DefaultLwM2MUplinkMsgHandler.java | 60 ++++++++++--------- .../server/uplink/LwM2mUplinkMsgHandler.java | 4 +- 7 files changed, 63 insertions(+), 42 deletions(-) diff --git a/application/src/test/java/org/thingsboard/server/transport/TransportSqlTestSuite.java b/application/src/test/java/org/thingsboard/server/transport/TransportSqlTestSuite.java index 5c26a65978..095321c184 100644 --- a/application/src/test/java/org/thingsboard/server/transport/TransportSqlTestSuite.java +++ b/application/src/test/java/org/thingsboard/server/transport/TransportSqlTestSuite.java @@ -26,14 +26,14 @@ import java.util.Arrays; @RunWith(ClasspathSuite.class) @ClasspathSuite.ClassnameFilters({ -// "org.thingsboard.server.transport.*.rpc.sql.*Test", -// "org.thingsboard.server.transport.*.telemetry.timeseries.sql.*Test", -// "org.thingsboard.server.transport.*.telemetry.attributes.sql.*Test", -// "org.thingsboard.server.transport.*.attributes.updates.sql.*Test", -// "org.thingsboard.server.transport.*.attributes.request.sql.*Test", -// "org.thingsboard.server.transport.*.claim.sql.*Test", -// "org.thingsboard.server.transport.*.provision.sql.*Test", - "org.thingsboard.server.transport.lwm2m.ota.sql.*Test" + "org.thingsboard.server.transport.*.rpc.sql.*Test", + "org.thingsboard.server.transport.*.telemetry.timeseries.sql.*Test", + "org.thingsboard.server.transport.*.telemetry.attributes.sql.*Test", + "org.thingsboard.server.transport.*.attributes.updates.sql.*Test", + "org.thingsboard.server.transport.*.attributes.request.sql.*Test", + "org.thingsboard.server.transport.*.claim.sql.*Test", + "org.thingsboard.server.transport.*.provision.sql.*Test", + "org.thingsboard.server.transport.lwm2m.*.sql.*Test" }) public class TransportSqlTestSuite { diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2mDownlinkMsgHandler.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2mDownlinkMsgHandler.java index ddf6984eb8..309d456663 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2mDownlinkMsgHandler.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2mDownlinkMsgHandler.java @@ -19,6 +19,7 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.eclipse.leshan.core.Link; import org.eclipse.leshan.core.LwM2m; +import org.eclipse.leshan.core.ResponseCode; import org.eclipse.leshan.core.attributes.Attribute; import org.eclipse.leshan.core.attributes.AttributeSet; import org.eclipse.leshan.core.model.LwM2mModel; diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MTargetedCallback.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MTargetedCallback.java index 52053093f0..c14527e3b1 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MTargetedCallback.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MTargetedCallback.java @@ -16,7 +16,9 @@ package org.thingsboard.server.transport.lwm2m.server.downlink; import lombok.extern.slf4j.Slf4j; +import org.eclipse.leshan.core.ResponseCode; import org.eclipse.leshan.core.node.LwM2mSingleResource; +import org.eclipse.leshan.core.response.LwM2mResponse; import org.eclipse.leshan.core.response.ReadResponse; import org.eclipse.leshan.core.util.Hex; import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; @@ -24,6 +26,7 @@ import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogServic import java.util.Arrays; +import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.LOG_LWM2M_ERROR; import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.LOG_LWM2M_INFO; @Slf4j @@ -49,11 +52,22 @@ public abstract class TbLwM2MTargetedCallback extends AbstractTbLwM2MReque //TODO convert camelCase to "camel case" using .split("(?= ResponseCode.BAD_REQUEST.getCode()) { + log.error("[{}] [{}] [{}] failed to process successful response [{}] ", client.getEndpoint(), requestName, versionedId != null ? versionedId : Arrays.toString(versionedIds), responseStr); + logService.log(client, String.format("[%s]: %s [%s] failed to process successful. Result: %s", LOG_LWM2M_ERROR, requestName, versionedId != null ? versionedId : Arrays.toString(versionedIds), responseStr)); + } + else { + log.trace("[{}] {} [{}] successful: {}", client.getEndpoint(), requestName, versionedId != null ? versionedId : versionedIds, responseStr); + logService.log(client, String.format("[%s]: %s [%s] successful. Result: %s", LOG_LWM2M_INFO, requestName, versionedId != null ? versionedId : Arrays.toString(versionedIds), responseStr)); } - log.trace("[{}] {} [{}] successful: {}", client.getEndpoint(), requestName, versionedId != null ? versionedId : versionedIds, responseStr); - logService.log(client, String.format("[%s]: %s [%s] successful. Result: [%s]", LOG_LWM2M_INFO, requestName, versionedId != null ? versionedId : Arrays.toString(versionedIds), responseStr)); } private String responseToString (ReadResponse response) { diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MWriteResponseCallback.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MWriteResponseCallback.java index 4746077f19..a452c3b187 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MWriteResponseCallback.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MWriteResponseCallback.java @@ -15,12 +15,14 @@ */ package org.thingsboard.server.transport.lwm2m.server.downlink; +import lombok.extern.slf4j.Slf4j; import org.eclipse.leshan.core.request.WriteRequest; import org.eclipse.leshan.core.response.WriteResponse; import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService; import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler; +@Slf4j public class TbLwM2MWriteResponseCallback extends TbLwM2MUplinkTargetedCallback { public TbLwM2MWriteResponseCallback(LwM2mUplinkMsgHandler handler, LwM2MTelemetryLogService logService, LwM2mClient client, String targetId) { @@ -30,7 +32,7 @@ public class TbLwM2MWriteResponseCallback extends TbLwM2MUplinkTargetedCallback< @Override public void onSuccess(WriteRequest request, WriteResponse response) { super.onSuccess(request, response); - handler.onWriteResponseOk(client, versionedId, request); + handler.onWriteResponseOk(client, versionedId, request, response.getCode().getCode()); } } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/composite/TbLwM2MWriteResponseCompositeCallback.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/composite/TbLwM2MWriteResponseCompositeCallback.java index 9dccc98185..6d5de06e90 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/composite/TbLwM2MWriteResponseCompositeCallback.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/composite/TbLwM2MWriteResponseCompositeCallback.java @@ -31,7 +31,7 @@ public class TbLwM2MWriteResponseCompositeCallback extends TbLwM2MUplinkTargeted @Override public void onSuccess(WriteCompositeRequest request, WriteCompositeResponse response) { super.onSuccess(request, response); - handler.onWriteCompositeResponseOk(client, request); + handler.onWriteCompositeResponseOk(client, request, response.getCode().getCode()); } } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/DefaultLwM2MUplinkMsgHandler.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/DefaultLwM2MUplinkMsgHandler.java index bb8a74aaef..b6f8095b60 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/DefaultLwM2MUplinkMsgHandler.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/DefaultLwM2MUplinkMsgHandler.java @@ -21,6 +21,7 @@ import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.reflect.TypeToken; import lombok.extern.slf4j.Slf4j; +import org.eclipse.leshan.core.ResponseCode; import org.eclipse.leshan.core.model.ObjectModel; import org.eclipse.leshan.core.model.ResourceModel; import org.eclipse.leshan.core.node.LwM2mMultipleResource; @@ -61,7 +62,6 @@ import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; import org.thingsboard.server.transport.lwm2m.server.LwM2mOtaConvert; import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportContext; import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportServerHelper; -import org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil; import org.thingsboard.server.transport.lwm2m.server.attributes.LwM2MAttributesService; import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClientState; import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClientStateException; @@ -86,6 +86,7 @@ import org.thingsboard.server.transport.lwm2m.server.ota.LwM2MOtaUpdateService; import org.thingsboard.server.transport.lwm2m.server.rpc.LwM2MRpcRequestHandler; import org.thingsboard.server.transport.lwm2m.server.session.LwM2MSessionManager; import org.thingsboard.server.transport.lwm2m.server.store.TbLwM2MDtlsSessionStore; +import org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil; import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl; import javax.annotation.PostConstruct; @@ -106,12 +107,6 @@ import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPARATOR_PATH; -import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.LOG_LWM2M_ERROR; -import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.LOG_LWM2M_INFO; -import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.LOG_LWM2M_WARN; -import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.convertObjectIdToVersionedId; -import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.convertOtaUpdateValueToString; -import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.fromVersionedIdToObjectId; import static org.thingsboard.server.transport.lwm2m.server.ota.DefaultLwM2MOtaUpdateService.FW_3_VER_ID; import static org.thingsboard.server.transport.lwm2m.server.ota.DefaultLwM2MOtaUpdateService.FW_DELIVERY_METHOD; import static org.thingsboard.server.transport.lwm2m.server.ota.DefaultLwM2MOtaUpdateService.FW_NAME_ID; @@ -123,6 +118,12 @@ import static org.thingsboard.server.transport.lwm2m.server.ota.DefaultLwM2MOtaU import static org.thingsboard.server.transport.lwm2m.server.ota.DefaultLwM2MOtaUpdateService.SW_RESULT_ID; import static org.thingsboard.server.transport.lwm2m.server.ota.DefaultLwM2MOtaUpdateService.SW_STATE_ID; import static org.thingsboard.server.transport.lwm2m.server.ota.DefaultLwM2MOtaUpdateService.SW_VER_ID; +import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.LOG_LWM2M_ERROR; +import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.LOG_LWM2M_INFO; +import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.LOG_LWM2M_WARN; +import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.convertObjectIdToVersionedId; +import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.convertOtaUpdateValueToString; +import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.fromVersionedIdToObjectId; @Slf4j @@ -316,13 +317,13 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl if (objectModelVersion != null) { if (response.getContent() instanceof LwM2mObject) { LwM2mObject lwM2mObject = (LwM2mObject) response.getContent(); - this.updateObjectResourceValue(lwM2MClient, lwM2mObject, path); + this.updateObjectResourceValue(lwM2MClient, lwM2mObject, path, response.getCode().getCode()); } else if (response.getContent() instanceof LwM2mObjectInstance) { LwM2mObjectInstance lwM2mObjectInstance = (LwM2mObjectInstance) response.getContent(); - this.updateObjectInstanceResourceValue(lwM2MClient, lwM2mObjectInstance, path); + this.updateObjectInstanceResourceValue(lwM2MClient, lwM2mObjectInstance, path, response.getCode().getCode()); } else if (response.getContent() instanceof LwM2mResource) { LwM2mResource lwM2mResource = (LwM2mResource) response.getContent(); - this.updateResourcesValue(lwM2MClient, lwM2mResource, path, Mode.UPDATE); + this.updateResourcesValue(lwM2MClient, lwM2mResource, path, Mode.UPDATE, response.getCode().getCode()); } } if (clientContext.awake(lwM2MClient)) { @@ -341,11 +342,11 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl response.getContent().forEach((k, v) -> { if (v != null) { if (v instanceof LwM2mObject) { - this.updateObjectResourceValue(lwM2MClient, (LwM2mObject) v, k.toString()); + this.updateObjectResourceValue(lwM2MClient, (LwM2mObject) v, k.toString(), response.getCode().getCode()); } else if (v instanceof LwM2mObjectInstance) { - this.updateObjectInstanceResourceValue(lwM2MClient, (LwM2mObjectInstance) v, k.toString()); + this.updateObjectInstanceResourceValue(lwM2MClient, (LwM2mObjectInstance) v, k.toString(), response.getCode().getCode()); } else if (v instanceof LwM2mResource) { - this.updateResourcesValue(lwM2MClient, (LwM2mResource) v, k.toString(), Mode.UPDATE); + this.updateResourcesValue(lwM2MClient, (LwM2mResource) v, k.toString(), Mode.UPDATE, response.getCode().getCode()); } } }); @@ -511,19 +512,19 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl defaultLwM2MDownlinkMsgHandler.sendCancelObserveRequest(client, request, new TbLwM2MCancelObserveCallback(logService, client, versionedId)); } - private void updateObjectResourceValue(LwM2mClient client, LwM2mObject lwM2mObject, String pathIdVer) { + private void updateObjectResourceValue(LwM2mClient client, LwM2mObject lwM2mObject, String pathIdVer, int code) { LwM2mPath pathIds = new LwM2mPath(fromVersionedIdToObjectId(pathIdVer)); lwM2mObject.getInstances().forEach((instanceId, instance) -> { String pathInstance = pathIds.toString() + "/" + instanceId; - this.updateObjectInstanceResourceValue(client, instance, pathInstance); + this.updateObjectInstanceResourceValue(client, instance, pathInstance, code); }); } - private void updateObjectInstanceResourceValue(LwM2mClient client, LwM2mObjectInstance lwM2mObjectInstance, String pathIdVer) { + private void updateObjectInstanceResourceValue(LwM2mClient client, LwM2mObjectInstance lwM2mObjectInstance, String pathIdVer, int code) { LwM2mPath pathIds = new LwM2mPath(fromVersionedIdToObjectId(pathIdVer)); lwM2mObjectInstance.getResources().forEach((resourceId, resource) -> { String pathRez = pathIds.toString() + "/" + resourceId; - this.updateResourcesValue(client, resource, pathRez, Mode.UPDATE); + this.updateResourcesValue(client, resource, pathRez, Mode.UPDATE, code); }); } @@ -538,7 +539,7 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl * @param path - resource * @param mode - Replace, Update */ - private void updateResourcesValue(LwM2mClient lwM2MClient, LwM2mResource lwM2mResource, String path, Mode mode) { + private void updateResourcesValue(LwM2mClient lwM2MClient, LwM2mResource lwM2mResource, String path, Mode mode, int code) { Registration registration = lwM2MClient.getRegistration(); if (lwM2MClient.saveResourceValue(path, lwM2mResource, this.config.getModelProvider(), mode)) { if (path.equals(convertObjectIdToVersionedId(FW_NAME_ID, registration))) { @@ -564,7 +565,9 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl } else if (path.equals(convertObjectIdToVersionedId(SW_RESULT_ID, registration))) { otaService.onCurrentSoftwareResultUpdate(lwM2MClient, (Long) lwM2mResource.getValue()); } - this.updateAttrTelemetry(registration, Collections.singleton(path)); + if (ResponseCode.BAD_REQUEST.getCode() > code) { + this.updateAttrTelemetry(registration, Collections.singleton(path)); + } } else { log.error("Fail update path [{}] Resource [{}]", path, lwM2mResource); } @@ -708,38 +711,39 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl } @Override - public void onWriteResponseOk(LwM2mClient client, String path, WriteRequest request) { + public void onWriteResponseOk(LwM2mClient client, String path, WriteRequest request, int code) { if (request.getNode() instanceof LwM2mResource) { - this.updateResourcesValue(client, ((LwM2mResource) request.getNode()), path, request.isReplaceRequest() ? Mode.REPLACE : Mode.UPDATE); - clientContext.update(client); + this.updateResourcesValue(client, ((LwM2mResource) request.getNode()), path, request.isReplaceRequest() ? Mode.REPLACE : Mode.UPDATE, code); } else if (request.getNode() instanceof LwM2mObjectInstance) { ((LwM2mObjectInstance) request.getNode()).getResources().forEach((resId, resource) -> { - this.updateResourcesValue(client, resource, path + "/" + resId, request.isReplaceRequest() ? Mode.REPLACE : Mode.UPDATE); + this.updateResourcesValue(client, resource, path + "/" + resId, request.isReplaceRequest() ? Mode.REPLACE : Mode.UPDATE, code); }); + } + if (request.getNode() instanceof LwM2mResource || request.getNode() instanceof LwM2mObjectInstance) { clientContext.update(client); } } + @Override public void onCreateResponseOk(LwM2mClient client, String path, CreateRequest request) { if (request.getObjectInstances() != null && request.getObjectInstances().size() > 0) { - request.getObjectInstances().forEach( instance -> + request.getObjectInstances().forEach(instance -> instance.getResources() ); -// this.updateResourcesValue(client, ((LwM2mResource) request.getNode()), path, request.isReplaceRequest() ? Mode.REPLACE : Mode.UPDATE); clientContext.update(client); } } @Override - public void onWriteCompositeResponseOk(LwM2mClient client, WriteCompositeRequest request) { + public void onWriteCompositeResponseOk(LwM2mClient client, WriteCompositeRequest request, int code) { log.trace("ReadCompositeResponse: [{}]", request.getNodes()); request.getNodes().forEach((k, v) -> { if (v instanceof LwM2mSingleResource) { - this.updateResourcesValue(client, (LwM2mResource) v, k.toString(), Mode.REPLACE); + this.updateResourcesValue(client, (LwM2mResource) v, k.toString(), Mode.REPLACE, code); } else { LwM2mResourceInstance resourceInstance = (LwM2mResourceInstance) v; LwM2mMultipleResource multipleResource = new LwM2mMultipleResource(v.getId(), resourceInstance.getType(), resourceInstance); - this.updateResourcesValue(client, multipleResource, k.toString(), Mode.REPLACE); + this.updateResourcesValue(client, multipleResource, k.toString(), Mode.REPLACE, code); } }); } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/LwM2mUplinkMsgHandler.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/LwM2mUplinkMsgHandler.java index 0749ab34f6..af0d349687 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/LwM2mUplinkMsgHandler.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/LwM2mUplinkMsgHandler.java @@ -55,11 +55,11 @@ public interface LwM2mUplinkMsgHandler { void onAwakeDev(Registration registration); - void onWriteResponseOk(LwM2mClient client, String path, WriteRequest request); + void onWriteResponseOk(LwM2mClient client, String path, WriteRequest request, int code); void onCreateResponseOk(LwM2mClient client, String path, CreateRequest request); - void onWriteCompositeResponseOk(LwM2mClient client, WriteCompositeRequest request); + void onWriteCompositeResponseOk(LwM2mClient client, WriteCompositeRequest request, int code); void onToTransportUpdateCredentials(TransportProtos.SessionInfoProto sessionInfo, TransportProtos.ToTransportUpdateCredentialsProto updateCredentials); From e2b3f0f742a7918f4ed232189c888cf1a9305007 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Wed, 15 Sep 2021 19:49:30 +0300 Subject: [PATCH 035/432] Lwm2m Fix bug Bootstrap Security URI --- .../bootstrap/secure/LwM2MBootstrapSecurityStore.java | 8 ++++++++ .../secure/LwM2mDefaultBootstrapSessionManager.java | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapSecurityStore.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapSecurityStore.java index a83f006543..c59f7467a9 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapSecurityStore.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapSecurityStore.java @@ -160,7 +160,15 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore { BootstrapConfiguration bootstrapObject = getBootstrapParametersFromThingsboard(store.getDeviceProfile()); lwM2MBootstrapConfig.servers = JacksonUtil.fromString(JacksonUtil.toString(bootstrapObject.getServers()), LwM2MBootstrapServers.class); LwM2MServerBootstrap profileServerBootstrap = JacksonUtil.fromString(JacksonUtil.toString(bootstrapObject.getBootstrapServer()), LwM2MServerBootstrap.class); + if (SecurityMode.NO_SEC != profileServerBootstrap.getSecurityMode() && profileServerBootstrap != null) { + profileServerBootstrap.setSecurityHost( profileServerBootstrap.getHost()); + profileServerBootstrap.setSecurityPort( profileServerBootstrap.getPort()); + } LwM2MServerBootstrap profileLwm2mServer = JacksonUtil.fromString(JacksonUtil.toString(bootstrapObject.getLwm2mServer()), LwM2MServerBootstrap.class); + if (SecurityMode.NO_SEC != profileLwm2mServer.getSecurityMode() && profileLwm2mServer != null) { + profileLwm2mServer.setSecurityHost(profileLwm2mServer.getHost()); + profileLwm2mServer.setSecurityPort(profileLwm2mServer.getPort()); + } UUID sessionUUiD = UUID.randomUUID(); TransportProtos.SessionInfoProto sessionInfo = helper.getValidateSessionInfo(store.getMsg(), sessionUUiD.getMostSignificantBits(), sessionUUiD.getLeastSignificantBits()); bsSessions.put(store.getEndpoint(), sessionInfo); diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2mDefaultBootstrapSessionManager.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2mDefaultBootstrapSessionManager.java index 7c6e157f83..da5e8db695 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2mDefaultBootstrapSessionManager.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2mDefaultBootstrapSessionManager.java @@ -218,7 +218,7 @@ public class LwM2mDefaultBootstrapSessionManager extends DefaultBootstrapSession } private void sendLogs (String endpointName, String logMsg) { - log.trace(logMsg); + log.info(logMsg); transportService.log(((LwM2MBootstrapSecurityStore) bsSecurityStore).getSessionByEndpoint(endpointName), logMsg); } } From b297ab231cd20dfe31a6b49b30f6f1dfff67207d Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Thu, 16 Sep 2021 08:43:28 +0300 Subject: [PATCH 036/432] Lwm2m Fix bug create new Device with X509 Trust / update credential to X509 trust --- .../org/thingsboard/server/common/data/StringUtils.java | 8 ++++++++ .../server/dao/device/DeviceCredentialsServiceImpl.java | 4 ++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/StringUtils.java b/common/data/src/main/java/org/thingsboard/server/common/data/StringUtils.java index cbe7094715..6e96893c22 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/StringUtils.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/StringUtils.java @@ -21,7 +21,15 @@ public class StringUtils { return source == null || source.isEmpty(); } + public static boolean isBlank(String source) { + return source == null || source.isEmpty() || source.trim().isEmpty(); + } + public static boolean isNotEmpty(String source) { return source != null && !source.isEmpty(); } + + public static boolean isNotBlank(String source) { + return source != null && !source.isEmpty() && !source.trim().isEmpty(); + } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsServiceImpl.java index f62d25dcec..969745ae31 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsServiceImpl.java @@ -183,7 +183,7 @@ public class DeviceCredentialsServiceImpl extends AbstractEntityService implemen break; case X509: X509ClientCredentials x509Config = (X509ClientCredentials) clientCredentials; - if (x509Config.getCert() != null) { + if ((StringUtils.isNotBlank(x509Config.getCert()))) { String cert = EncryptionUtil.trimNewLines(x509Config.getCert()); String sha3Hash = EncryptionUtil.getSha3Hash(cert); x509Config.setCert(cert); @@ -272,7 +272,7 @@ public class DeviceCredentialsServiceImpl extends AbstractEntityService implemen break; case X509: X509ClientCredentials x509CCredentials = (X509ClientCredentials) clientCredentials; - if (x509CCredentials.getCert() != null) { + if (StringUtils.isNotBlank(x509CCredentials.getCert())) { try { SecurityUtil.certificate.decode(Base64.decodeBase64(x509CCredentials.getCert())); } catch (Exception e) { From 55394f6367a877c118156d7d53864fb1e32d4552 Mon Sep 17 00:00:00 2001 From: vparomskiy Date: Fri, 17 Sep 2021 13:11:51 +0300 Subject: [PATCH 037/432] add REST API for fetching TB application version --- .../controller/SystemInfoController.java | 67 +++++++++++++++++++ pom.xml | 1 + 2 files changed, 68 insertions(+) create mode 100644 application/src/main/java/org/thingsboard/server/controller/SystemInfoController.java diff --git a/application/src/main/java/org/thingsboard/server/controller/SystemInfoController.java b/application/src/main/java/org/thingsboard/server/controller/SystemInfoController.java new file mode 100644 index 0000000000..1fd3819880 --- /dev/null +++ b/application/src/main/java/org/thingsboard/server/controller/SystemInfoController.java @@ -0,0 +1,67 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.controller; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.info.BuildProperties; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.RestController; +import org.thingsboard.server.queue.util.TbCoreComponent; + +import javax.annotation.PostConstruct; + +@RestController +@TbCoreComponent +@RequestMapping("/api") +@Slf4j +public class SystemInfoController { + + @Autowired + private BuildProperties buildProperties; + + @PostConstruct + public void init() { + JsonNode info = buildInfoObject(); + log.info("System build info: {}", info); + } + + @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") + @RequestMapping(value = "/system/info", method = RequestMethod.GET) + @ResponseBody + public JsonNode getSystemVersionInfo() { + return buildInfoObject(); + } + + private JsonNode buildInfoObject() { + ObjectMapper objectMapper = new ObjectMapper(); + ObjectNode infoObject = objectMapper.createObjectNode(); + if (buildProperties != null) { + infoObject.put("version", buildProperties.getVersion()); + infoObject.put("artifact", buildProperties.getArtifact()); + infoObject.put("name", buildProperties.getName()); + } else { + infoObject.put("version", "unknown"); + } + return infoObject; + } +} diff --git a/pom.xml b/pom.xml index fa33548a56..b638ea55ff 100755 --- a/pom.xml +++ b/pom.xml @@ -497,6 +497,7 @@ repackage + build-info From 19d08428ffd8ca07c98881295b8f0fd4d88301bc Mon Sep 17 00:00:00 2001 From: vparomskiy Date: Fri, 17 Sep 2021 13:12:50 +0300 Subject: [PATCH 038/432] add support for multi-root relation queries --- .../data/query/RelationsQueryFilter.java | 3 + .../server/dao/entity/BaseEntityService.java | 12 ++ .../query/DefaultEntityQueryRepository.java | 30 ++- .../dao/sql/query/EntityKeyMapping.java | 4 +- .../dao/service/BaseEntityServiceTest.java | 180 ++++++++++++++++++ 5 files changed, 221 insertions(+), 8 deletions(-) diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/query/RelationsQueryFilter.java b/common/data/src/main/java/org/thingsboard/server/common/data/query/RelationsQueryFilter.java index 9c113eb793..4409ebdab6 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/query/RelationsQueryFilter.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/query/RelationsQueryFilter.java @@ -21,6 +21,7 @@ import org.thingsboard.server.common.data.relation.EntitySearchDirection; import org.thingsboard.server.common.data.relation.RelationEntityTypeFilter; import java.util.List; +import java.util.Set; @Data public class RelationsQueryFilter implements EntityFilter { @@ -31,6 +32,8 @@ public class RelationsQueryFilter implements EntityFilter { } private EntityId rootEntity; + private boolean isMultiRoot; + private Set multiRootEntities; private EntitySearchDirection direction; private List filters; private int maxLevel; diff --git a/dao/src/main/java/org/thingsboard/server/dao/entity/BaseEntityService.java b/dao/src/main/java/org/thingsboard/server/dao/entity/BaseEntityService.java index 7686d9ec21..6c3fe1fd24 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/entity/BaseEntityService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/entity/BaseEntityService.java @@ -42,6 +42,8 @@ import org.thingsboard.server.common.data.query.EntityCountQuery; import org.thingsboard.server.common.data.query.EntityData; import org.thingsboard.server.common.data.query.EntityDataPageLink; import org.thingsboard.server.common.data.query.EntityDataQuery; +import org.thingsboard.server.common.data.query.EntityFilterType; +import org.thingsboard.server.common.data.query.RelationsQueryFilter; import org.thingsboard.server.dao.alarm.AlarmService; import org.thingsboard.server.dao.asset.AssetService; import org.thingsboard.server.dao.customer.CustomerService; @@ -228,6 +230,8 @@ public class BaseEntityService extends AbstractEntityService implements EntitySe throw new IncorrectParameterException("Query entity filter must be specified."); } else if (query.getEntityFilter().getType() == null) { throw new IncorrectParameterException("Query entity filter type must be specified."); + } else if (query.getEntityFilter().getType().equals(EntityFilterType.RELATIONS_QUERY)) { + validateRelationQuery((RelationsQueryFilter) query.getEntityFilter()); } } @@ -246,4 +250,12 @@ public class BaseEntityService extends AbstractEntityService implements EntitySe } } + private static void validateRelationQuery(RelationsQueryFilter queryFilter) { + if(queryFilter.isMultiRoot() && queryFilter.getMultiRootEntities().isEmpty()) { + throw new IncorrectParameterException("Multi-root relation query filter should contain root entities"); + } + if(!queryFilter.isMultiRoot() && queryFilter.getRootEntity() == null) { + throw new IncorrectParameterException("Relation query filter root entity should not be blank"); + } + } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/query/DefaultEntityQueryRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/query/DefaultEntityQueryRepository.java index 7b3ea36cfa..6a4212df6f 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/query/DefaultEntityQueryRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/query/DefaultEntityQueryRepository.java @@ -220,6 +220,8 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository { " THEN (select additional_info from edge where id = entity_id)" + " END as additional_info"; + private static final String SELECT_RELATED_PARENT_ID = "entity.parentId AS parentId"; + private static final String SELECT_API_USAGE_STATE = "(select aus.id, aus.created_time, aus.tenant_id, aus.entity_id, " + "coalesce((select title from tenant where id = aus.entity_id), (select title from customer where id = aus.entity_id)) as name " + "from api_usage_state as aus)"; @@ -242,16 +244,16 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository { private static final String HIERARCHICAL_QUERY_TEMPLATE = " FROM (WITH RECURSIVE related_entities(from_id, from_type, to_id, to_type, relation_type, lvl) AS (" + " SELECT from_id, from_type, to_id, to_type, relation_type, 1 as lvl" + " FROM relation" + - " WHERE $in_id = :relation_root_id and $in_type = :relation_root_type and relation_type_group = 'COMMON'" + + " WHERE $in_id $rootIdCondition and $in_type = :relation_root_type and relation_type_group = 'COMMON'" + " UNION ALL" + " SELECT r.from_id, r.from_type, r.to_id, r.to_type, r.relation_type, lvl + 1" + " FROM relation r" + " INNER JOIN related_entities re ON" + " r.$in_id = re.$out_id and r.$in_type = re.$out_type and" + " relation_type_group = 'COMMON' %s)" + - " SELECT re.$out_id entity_id, re.$out_type entity_type, max(re.lvl) lvl" + + " SELECT re.$out_id entity_id, re.$out_type entity_type, re.$in_id parentId, max(re.lvl) lvl" + " from related_entities re" + - " %s GROUP BY entity_id, entity_type) entity"; + " %s GROUP BY entity_id, entity_type, parentId) entity"; private static final String HIERARCHICAL_TO_QUERY_TEMPLATE = HIERARCHICAL_QUERY_TEMPLATE.replace("$in", "to").replace("$out", "from"); private static final String HIERARCHICAL_FROM_QUERY_TEMPLATE = HIERARCHICAL_QUERY_TEMPLATE.replace("$in", "from").replace("$out", "to"); @@ -562,6 +564,7 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository { + (entityType.equals(EntityType.ENTITY_VIEW) ? "" : ", label ") + "FROM " + entityType.name() + " WHERE id in ( SELECT entity_id"; String from = getQueryTemplate(entityFilter.getDirection()); + from = from.replace("$rootIdCondition", "= :relation_root_id"); String whereFilter = " WHERE"; if (!StringUtils.isEmpty(entityFilter.getRelationType())) { ctx.addStringParameter("where_relation_type", entityFilter.getRelationType()); @@ -604,11 +607,20 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository { + SELECT_TYPE + ", " + SELECT_NAME + ", " + SELECT_LABEL + ", " + SELECT_FIRST_NAME + ", " + SELECT_LAST_NAME + ", " + SELECT_EMAIL + ", " + SELECT_REGION + ", " + SELECT_TITLE + ", " + SELECT_COUNTRY + ", " + SELECT_STATE + ", " + SELECT_CITY + ", " + - SELECT_ADDRESS + ", " + SELECT_ADDRESS_2 + ", " + SELECT_ZIP + ", " + SELECT_PHONE + ", " + SELECT_ADDITIONAL_INFO + + SELECT_ADDRESS + ", " + SELECT_ADDRESS_2 + ", " + SELECT_ZIP + ", " + SELECT_PHONE + ", " + + SELECT_ADDITIONAL_INFO + ", " + SELECT_RELATED_PARENT_ID + ", entity.entity_type as entity_type"; String from = getQueryTemplate(entityFilter.getDirection()); - ctx.addUuidParameter("relation_root_id", rootId.getId()); - ctx.addStringParameter("relation_root_type", rootId.getEntityType().name()); + + if(entityFilter.isMultiRoot()) { + ctx.addUuidListParameter("relation_root_ids", entityFilter.getMultiRootEntities().stream().map(EntityId::getId).collect(Collectors.toList())); + ctx.addStringParameter("relation_root_type", entityFilter.getMultiRootEntities().stream().map(EntityId::getEntityType).findFirst().get().name()); + from = from.replace("$rootIdCondition", "in (:relation_root_ids)"); + } else { + ctx.addUuidParameter("relation_root_id", rootId.getId()); + ctx.addStringParameter("relation_root_type", rootId.getEntityType().name()); + from = from.replace("$rootIdCondition", "= :relation_root_id"); + } StringBuilder whereFilter = new StringBuilder(); @@ -790,7 +802,11 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository { case EDGE_SEARCH_QUERY: return EntityType.EDGE; case RELATIONS_QUERY: - return ((RelationsQueryFilter) entityFilter).getRootEntity().getEntityType(); + RelationsQueryFilter rgf = (RelationsQueryFilter) entityFilter; + if(rgf.isMultiRoot()) { + return rgf.getMultiRootEntities().iterator().next().getEntityType(); + } + return rgf.getRootEntity().getEntityType(); case API_USAGE_STATE: return EntityType.API_USAGE_STATE; default: diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/query/EntityKeyMapping.java b/dao/src/main/java/org/thingsboard/server/dao/sql/query/EntityKeyMapping.java index caed48758a..3aab5ee63e 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/query/EntityKeyMapping.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/query/EntityKeyMapping.java @@ -72,6 +72,7 @@ public class EntityKeyMapping { public static final String ZIP = "zip"; public static final String PHONE = "phone"; public static final String ADDITIONAL_INFO = "additionalInfo"; + public static final String RELATED_PARENT_ID = "parentId"; public static final List typedEntityFields = Arrays.asList(CREATED_TIME, ENTITY_TYPE, NAME, TYPE, ADDITIONAL_INFO); public static final List widgetEntityFields = Arrays.asList(CREATED_TIME, ENTITY_TYPE, NAME); @@ -82,7 +83,7 @@ public class EntityKeyMapping { public static final Set apiUsageStateEntityFields = new HashSet<>(Arrays.asList(CREATED_TIME, ENTITY_TYPE, NAME)); public static final Set commonEntityFieldsSet = new HashSet<>(commonEntityFields); - public static final Set relationQueryEntityFieldsSet = new HashSet<>(Arrays.asList(CREATED_TIME, ENTITY_TYPE, NAME, TYPE, LABEL, FIRST_NAME, LAST_NAME, EMAIL, REGION, TITLE, COUNTRY, STATE, CITY, ADDRESS, ADDRESS_2, ZIP, PHONE, ADDITIONAL_INFO)); + public static final Set relationQueryEntityFieldsSet = new HashSet<>(Arrays.asList(CREATED_TIME, ENTITY_TYPE, NAME, TYPE, LABEL, FIRST_NAME, LAST_NAME, EMAIL, REGION, TITLE, COUNTRY, STATE, CITY, ADDRESS, ADDRESS_2, ZIP, PHONE, ADDITIONAL_INFO, RELATED_PARENT_ID)); static { allowedEntityFieldMap.put(EntityType.DEVICE, new HashSet<>(labeledEntityFields)); @@ -120,6 +121,7 @@ public class EntityKeyMapping { entityFieldColumnMap.put(ZIP, ModelConstants.ZIP_PROPERTY); entityFieldColumnMap.put(PHONE, ModelConstants.PHONE_PROPERTY); entityFieldColumnMap.put(ADDITIONAL_INFO, ModelConstants.ADDITIONAL_INFO_PROPERTY); + entityFieldColumnMap.put(RELATED_PARENT_ID, RELATED_PARENT_ID); Map contactBasedAliases = new HashMap<>(); contactBasedAliases.put(NAME, TITLE); diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseEntityServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseEntityServiceTest.java index 831d92965b..ab8d8233e1 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseEntityServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseEntityServiceTest.java @@ -15,10 +15,12 @@ */ package org.thingsboard.server.dao.service; +import com.google.common.collect.Lists; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import org.apache.commons.lang3.RandomStringUtils; import org.apache.commons.lang3.RandomUtils; +import org.apache.commons.lang3.StringUtils; import org.junit.After; import org.junit.Assert; import org.junit.Before; @@ -35,6 +37,7 @@ import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.id.IdBased; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.kv.AttributeKvEntry; import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry; @@ -75,8 +78,11 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Random; +import java.util.UUID; import java.util.concurrent.ExecutionException; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -373,6 +379,108 @@ public abstract class BaseEntityServiceTest extends AbstractServiceTest { deviceService.deleteDevicesByTenantId(tenantId); } + @Test + public void testCountHierarchicalEntitiesByMultiRootQuery() throws InterruptedException { + List buildings = new ArrayList<>(); + List apartments = new ArrayList<>(); + Map> entityNameByTypeMap = new HashMap<>(); + Map childParentRelationMap = new HashMap<>(); + createMultiRootHierarchy(buildings, apartments, entityNameByTypeMap, childParentRelationMap); + + RelationsQueryFilter filter = new RelationsQueryFilter(); + filter.setMultiRoot(true); + filter.setMultiRootEntities(buildings.stream().map(IdBased::getId).collect(Collectors.toSet())); + filter.setDirection(EntitySearchDirection.FROM); + + EntityCountQuery countQuery = new EntityCountQuery(filter); + + long count = entityService.countEntitiesByQuery(tenantId, new CustomerId(CustomerId.NULL_UUID), countQuery); + Assert.assertEquals(63, count); + + filter.setFilters(Collections.singletonList(new RelationEntityTypeFilter("AptToHeat", Collections.singletonList(EntityType.DEVICE)))); + count = entityService.countEntitiesByQuery(tenantId, new CustomerId(CustomerId.NULL_UUID), countQuery); + Assert.assertEquals(27, count); + + filter.setMultiRootEntities(apartments.stream().map(IdBased::getId).collect(Collectors.toSet())); + filter.setDirection(EntitySearchDirection.TO); + filter.setFilters(Lists.newArrayList( + new RelationEntityTypeFilter("buildingToApt", Collections.singletonList(EntityType.ASSET)), + new RelationEntityTypeFilter("AptToEnergy", Collections.singletonList(EntityType.DEVICE)))); + + count = entityService.countEntitiesByQuery(tenantId, new CustomerId(CustomerId.NULL_UUID), countQuery); + Assert.assertEquals(9, count); + + deviceService.deleteDevicesByTenantId(tenantId); + assetService.deleteAssetsByTenantId(tenantId); + + } + + @Test + public void testMultiRootHierarchicalFindEntityDataWithAttributesByQuery() throws ExecutionException, InterruptedException { + List buildings = new ArrayList<>(); + List apartments = new ArrayList<>(); + Map> entityNameByTypeMap = new HashMap<>(); + Map childParentRelationMap = new HashMap<>(); + createMultiRootHierarchy(buildings, apartments, entityNameByTypeMap, childParentRelationMap); + + RelationsQueryFilter filter = new RelationsQueryFilter(); + filter.setMultiRoot(true); + filter.setMultiRootEntities(buildings.stream().map(IdBased::getId).collect(Collectors.toSet())); + filter.setDirection(EntitySearchDirection.FROM); + + EntityDataSortOrder sortOrder = new EntityDataSortOrder( + new EntityKey(EntityKeyType.ENTITY_FIELD, "createdTime"), EntityDataSortOrder.Direction.ASC + ); + EntityDataPageLink pageLink = new EntityDataPageLink(10, 0, null, sortOrder); + List entityFields = Lists.newArrayList( + new EntityKey(EntityKeyType.ENTITY_FIELD, "name"), + new EntityKey(EntityKeyType.ENTITY_FIELD, "parentId"), + new EntityKey(EntityKeyType.ENTITY_FIELD, "type") + ); + List latestValues = Collections.singletonList(new EntityKey(EntityKeyType.ATTRIBUTE, "status")); + + KeyFilter onlineStatusFilter = new KeyFilter(); + onlineStatusFilter.setKey(new EntityKey(EntityKeyType.ENTITY_FIELD, "name")); + StringFilterPredicate predicate = new StringFilterPredicate(); + predicate.setOperation(StringOperation.ENDS_WITH); + predicate.setValue(FilterPredicateValue.fromString("_1")); + onlineStatusFilter.setPredicate(predicate); + List keyFilters = Collections.singletonList(onlineStatusFilter); + + EntityDataQuery query = new EntityDataQuery(filter, pageLink, entityFields, latestValues, keyFilters); + PageData data = entityService.findEntityDataByQuery(tenantId, new CustomerId(CustomerId.NULL_UUID), query); + List loadedEntities = new ArrayList<>(data.getData()); + while (data.hasNext()) { + query = query.next(); + data = entityService.findEntityDataByQuery(tenantId, new CustomerId(CustomerId.NULL_UUID), query); + loadedEntities.addAll(data.getData()); + } + + long expectedEntitiesCnt = entityNameByTypeMap.entrySet() + .stream() + .filter(e -> !e.getKey().equals("building")) + .flatMap(e -> e.getValue().entrySet().stream()) + .map(Map.Entry::getValue) + .filter(e -> StringUtils.endsWith(e, "_1")) + .count(); + Assert.assertEquals(expectedEntitiesCnt, loadedEntities.size()); + + Map actualRelations = new HashMap<>(); + loadedEntities.forEach(ed -> { + UUID parentId = UUID.fromString(ed.getLatest().get(EntityKeyType.ENTITY_FIELD).get("parentId").getValue()); + UUID entityId = ed.getEntityId().getId(); + Assert.assertEquals(childParentRelationMap.get(entityId), parentId); + actualRelations.put(entityId, parentId); + + String entityType = ed.getLatest().get(EntityKeyType.ENTITY_FIELD).get("type").getValue(); + String actualEntityName = ed.getLatest().get(EntityKeyType.ENTITY_FIELD).get("name").getValue(); + String expectedEntityName = entityNameByTypeMap.get(entityType).get(entityId); + Assert.assertEquals(expectedEntityName, actualEntityName); + }); + + deviceService.deleteDevicesByTenantId(tenantId); + assetService.deleteAssetsByTenantId(tenantId); + } @Test public void testHierarchicalFindDevicesWithAttributesByQuery() throws ExecutionException, InterruptedException { @@ -1534,4 +1642,76 @@ public abstract class BaseEntityServiceTest extends AbstractServiceTest { BasicTsKvEntry timeseries = new BasicTsKvEntry(42L, telemetryValue); return timeseriesService.save(SYSTEM_TENANT_ID, entityId, timeseries); } + + private void createMultiRootHierarchy(List buildings, List apartments, + Map> entityNameByTypeMap, + Map childParentRelationMap) throws InterruptedException { + for (int k = 0; k < 3; k++) { + Asset building = new Asset(); + building.setTenantId(tenantId); + building.setName("Building _" + k); + building.setType("building"); + building.setLabel("building label" + k); + building = assetService.saveAsset(building); + buildings.add(building); + entityNameByTypeMap.computeIfAbsent(building.getType(), n -> new HashMap<>()).put(building.getId().getId(), building.getName()); + + for (int i = 0; i < 3; i++) { + Asset asset = new Asset(); + asset.setTenantId(tenantId); + asset.setName("Apt " + k + "_" + i); + asset.setType("apartment"); + asset.setLabel("apartment " + i); + asset = assetService.saveAsset(asset); + //TO make sure devices have different created time + Thread.sleep(1); + entityNameByTypeMap.computeIfAbsent(asset.getType(), n -> new HashMap<>()).put(asset.getId().getId(), asset.getName()); + apartments.add(asset); + EntityRelation er = new EntityRelation(); + er.setFrom(building.getId()); + er.setTo(asset.getId()); + er.setType("buildingToApt"); + er.setTypeGroup(RelationTypeGroup.COMMON); + relationService.saveRelation(tenantId, er); + childParentRelationMap.put(asset.getUuidId(), building.getUuidId()); + for (int j = 0; j < 3; j++) { + Device device = new Device(); + device.setTenantId(tenantId); + device.setName("Heat" + k + "_" + i + "_" + j); + device.setType("heatmeter"); + device.setLabel("heatmeter" + (int) (Math.random() * 1000)); + device = deviceService.saveDevice(device); + //TO make sure devices have different created time + Thread.sleep(1); + entityNameByTypeMap.computeIfAbsent(device.getType(), n -> new HashMap<>()).put(device.getId().getId(), device.getName()); + er = new EntityRelation(); + er.setFrom(asset.getId()); + er.setTo(device.getId()); + er.setType("AptToHeat"); + er.setTypeGroup(RelationTypeGroup.COMMON); + relationService.saveRelation(tenantId, er); + childParentRelationMap.put(device.getUuidId(), asset.getUuidId()); + } + + for (int j = 0; j < 3; j++) { + Device device = new Device(); + device.setTenantId(tenantId); + device.setName("Energy" + k + "_" + i + "_" + j); + device.setType("energymeter"); + device.setLabel("energymeter" + (int) (Math.random() * 1000)); + device = deviceService.saveDevice(device); + //TO make sure devices have different created time + Thread.sleep(1); + entityNameByTypeMap.computeIfAbsent(device.getType(), n -> new HashMap<>()).put(device.getId().getId(), device.getName()); + er = new EntityRelation(); + er.setFrom(asset.getId()); + er.setTo(device.getId()); + er.setType("AptToEnergy"); + er.setTypeGroup(RelationTypeGroup.COMMON); + relationService.saveRelation(tenantId, er); + childParentRelationMap.put(device.getUuidId(), asset.getUuidId()); + } + } + } + } } From f86a30a8ed40f0600c90c5ac3bfa6ecc7a51e7a5 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Fri, 17 Sep 2021 14:56:07 +0300 Subject: [PATCH 039/432] Lwm2m Fix bug review 1-10 --- .../server/controller/BaseController.java | 4 --- .../server/controller/Lwm2mController.java | 5 +++ .../src/main/resources/thingsboard.yml | 2 ++ .../transport/lwm2m/client/FwLwM2MDevice.java | 2 +- .../transport/lwm2m/client/SwLwM2MDevice.java | 2 +- .../data/security/DeviceCredentials.java | 3 -- .../secure/LwM2MBootstrapConfig.java | 14 +++++++-- .../secure/LwM2MBootstrapSecurityStore.java | 31 +++++++++---------- .../LwM2mDefaultBootstrapSessionManager.java | 11 +++---- .../lwm2m/server/LwM2mOperationType.java | 17 +++++----- .../lwm2m/server/LwM2mServerListener.java | 4 ++- .../server/LwM2mTransportServerHelper.java | 8 +++-- .../DefaultLwM2MAttributesService.java | 7 ++--- .../lwm2m/server/client/LwM2mClient.java | 22 +++++++------ .../AbstractTbLwM2MRequestCallback.java | 6 ++-- .../DefaultLwM2mDownlinkMsgHandler.java | 20 ++++++------ .../rpc/DefaultLwM2MRpcRequestHandler.java | 13 +++++--- .../lwm2m/utils/LwM2mTransportUtil.java | 15 +++------ .../common/transport/util/JsonUtils.java | 9 ++++++ .../src/main/resources/tb-lwm2m-transport.yml | 2 +- 20 files changed, 107 insertions(+), 90 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/BaseController.java b/application/src/main/java/org/thingsboard/server/controller/BaseController.java index 64100363e4..7e8e3800f7 100644 --- a/application/src/main/java/org/thingsboard/server/controller/BaseController.java +++ b/application/src/main/java/org/thingsboard/server/controller/BaseController.java @@ -126,7 +126,6 @@ import org.thingsboard.server.service.component.ComponentDiscoveryService; import org.thingsboard.server.service.edge.EdgeLicenseService; import org.thingsboard.server.service.edge.EdgeNotificationService; import org.thingsboard.server.service.edge.rpc.EdgeRpcService; -import org.thingsboard.server.service.lwm2m.LwM2MServiceImpl; import org.thingsboard.server.service.ota.OtaPackageStateService; import org.thingsboard.server.service.profile.TbDeviceProfileCache; import org.thingsboard.server.service.resource.TbResourceService; @@ -185,9 +184,6 @@ public abstract class BaseController { @Autowired protected DeviceProfileService deviceProfileService; - @Autowired - protected LwM2MServiceImpl lwM2MService; - @Autowired protected AssetService assetService; diff --git a/application/src/main/java/org/thingsboard/server/controller/Lwm2mController.java b/application/src/main/java/org/thingsboard/server/controller/Lwm2mController.java index fb71d4ea91..12cc60c4e2 100644 --- a/application/src/main/java/org/thingsboard/server/controller/Lwm2mController.java +++ b/application/src/main/java/org/thingsboard/server/controller/Lwm2mController.java @@ -17,6 +17,7 @@ package org.thingsboard.server.controller; import com.fasterxml.jackson.databind.ObjectMapper; import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestBody; @@ -31,6 +32,7 @@ import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.lwm2m.ServerSecurityConfig; import org.thingsboard.server.common.data.security.DeviceCredentials; import org.thingsboard.server.queue.util.TbCoreComponent; +import org.thingsboard.server.service.lwm2m.LwM2MServiceImpl; import org.thingsboard.server.service.security.permission.Resource; import java.util.Map; @@ -41,6 +43,9 @@ import java.util.Map; @RequestMapping("/api") public class Lwm2mController extends BaseController { + @Autowired + protected LwM2MServiceImpl lwM2MService; + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/lwm2m/deviceProfile/bootstrap/{isBootstrapServer}", method = RequestMethod.GET) @ResponseBody diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index 95ba839792..61df401a94 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -693,6 +693,8 @@ transport: ota_pool_size: "${LWM2M_OTA_POOL_SIZE:10}" clean_period_in_sec: "${LWM2M_CLEAN_PERIOD_IN_SEC:2}" log_max_length: "${LWM2M_LOG_MAX_LENGTH:1024}" + psm_activity_timer: "${LWM2M_PSM_ACTIVITY_TIMER:10000}" + paging_transmission_window: "${LWM2M_PAGING_TRANSMISSION_WINDOW:10000}" # Use redis for Security and Registration stores redis.enabled: "${LWM2M_REDIS_ENABLED:false}" snmp: diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/FwLwM2MDevice.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/FwLwM2MDevice.java index e95f3d4841..cc097c869d 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/FwLwM2MDevice.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/FwLwM2MDevice.java @@ -83,7 +83,7 @@ public class FwLwM2MDevice extends BaseInstanceEnabler implements Destroyable { @Override public WriteResponse write(ServerIdentity identity, boolean replace, int resourceId, LwM2mResource value) { - log.warn("Write on Device resource /{}/{}/{}", getModel().id, getId(), resourceId); + log.info("Write on Device resource /{}/{}/{}", getModel().id, getId(), resourceId); switch (resourceId) { case 0: diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/SwLwM2MDevice.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/SwLwM2MDevice.java index dc6ad348a3..4b1e02a68d 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/SwLwM2MDevice.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/SwLwM2MDevice.java @@ -83,7 +83,7 @@ public class SwLwM2MDevice extends BaseInstanceEnabler implements Destroyable { @Override public WriteResponse write(ServerIdentity identity, boolean replace, int resourceId, LwM2mResource value) { - log.warn("Write on Device resource /{}/{}/{}", getModel().id, getId(), resourceId); + log.info("Write on Device resource /{}/{}/{}", getModel().id, getId(), resourceId); switch (resourceId) { case 2: diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/security/DeviceCredentials.java b/common/data/src/main/java/org/thingsboard/server/common/data/security/DeviceCredentials.java index 4ccf07f2b0..74adcdd06a 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/security/DeviceCredentials.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/security/DeviceCredentials.java @@ -15,9 +15,6 @@ */ package org.thingsboard.server.common.data.security; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; import lombok.EqualsAndHashCode; import org.thingsboard.server.common.data.BaseData; import org.thingsboard.server.common.data.id.DeviceCredentialsId; diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapConfig.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapConfig.java index ab96228600..f2ba39dcfa 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapConfig.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapConfig.java @@ -17,6 +17,8 @@ package org.thingsboard.server.transport.lwm2m.bootstrap.secure; import com.fasterxml.jackson.annotation.JsonIgnore; import lombok.Data; +import lombok.Getter; +import lombok.Setter; import org.eclipse.leshan.core.SecurityMode; import org.eclipse.leshan.core.request.BindingMode; import org.eclipse.leshan.core.util.Hex; @@ -41,7 +43,9 @@ public class LwM2MBootstrapConfig implements Serializable { * notifIfDisabled: boolean, * binding: string * */ - LwM2MBootstrapServers servers; + @Getter + @Setter + private LwM2MBootstrapServers servers; /** -bootstrapServer, lwm2mServer * interface ServerSecurityConfig @@ -56,9 +60,13 @@ public class LwM2MBootstrapConfig implements Serializable { * serverId?: number, * bootstrapServerAccountTimeout: number * */ - LwM2MServerBootstrap bootstrapServer; + @Getter + @Setter + private LwM2MServerBootstrap bootstrapServer; - LwM2MServerBootstrap lwm2mServer; + @Getter + @Setter + private LwM2MServerBootstrap lwm2mServer; @JsonIgnore public BootstrapConfig getLwM2MBootstrapConfig() { diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapSecurityStore.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapSecurityStore.java index c59f7467a9..bf5f40f055 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapSecurityStore.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapSecurityStore.java @@ -43,11 +43,11 @@ import java.util.Map; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; +import static org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mTypeServer.BOOTSTRAP; import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.LOG_LWM2M_ERROR; import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.LOG_LWM2M_INFO; import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.LOG_LWM2M_TELEMETRY; import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.getBootstrapParametersFromThingsboard; -import static org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mTypeServer.BOOTSTRAP; @Slf4j @Service("LwM2MBootstrapSecurityStore") @@ -86,10 +86,10 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore { bootstrapConfigStore.add(endPoint, bsConfigNew); } catch (InvalidConfigurationException e) { if (e.getMessage().contains("Psk identity") && e.getMessage().contains("already used for this bootstrap server")) { - log.trace("", e); + log.trace("Invalid Bootstrap Configuration", e); } else { - log.error("", e); + log.error("Invalid Bootstrap Configuration", e); } } return store.getSecurityInfo() == null ? null : Collections.singletonList(store.getSecurityInfo()).iterator(); @@ -109,7 +109,7 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore { try { bootstrapConfigStore.add(store.getEndpoint(), bsConfig); } catch (InvalidConfigurationException e) { - log.error("", e); + log.error("Invalid Bootstrap Configuration", e); } return store.getSecurityInfo(); } @@ -158,11 +158,11 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore { LwM2MBootstrapConfig lwM2MBootstrapConfig = store.getBootstrapCredentialConfig(); if (lwM2MBootstrapConfig != null) { BootstrapConfiguration bootstrapObject = getBootstrapParametersFromThingsboard(store.getDeviceProfile()); - lwM2MBootstrapConfig.servers = JacksonUtil.fromString(JacksonUtil.toString(bootstrapObject.getServers()), LwM2MBootstrapServers.class); - LwM2MServerBootstrap profileServerBootstrap = JacksonUtil.fromString(JacksonUtil.toString(bootstrapObject.getBootstrapServer()), LwM2MServerBootstrap.class); - if (SecurityMode.NO_SEC != profileServerBootstrap.getSecurityMode() && profileServerBootstrap != null) { - profileServerBootstrap.setSecurityHost( profileServerBootstrap.getHost()); - profileServerBootstrap.setSecurityPort( profileServerBootstrap.getPort()); + lwM2MBootstrapConfig.setServers(JacksonUtil.fromString(JacksonUtil.toString(bootstrapObject.getServers()), LwM2MBootstrapServers.class)); + LwM2MServerBootstrap bootstrapServerProfile = JacksonUtil.fromString(JacksonUtil.toString(bootstrapObject.getBootstrapServer()), LwM2MServerBootstrap.class); + if (SecurityMode.NO_SEC != bootstrapServerProfile.getSecurityMode() && bootstrapServerProfile != null) { + bootstrapServerProfile.setSecurityHost( bootstrapServerProfile.getHost()); + bootstrapServerProfile.setSecurityPort( bootstrapServerProfile.getPort()); } LwM2MServerBootstrap profileLwm2mServer = JacksonUtil.fromString(JacksonUtil.toString(bootstrapObject.getLwm2mServer()), LwM2MServerBootstrap.class); if (SecurityMode.NO_SEC != profileLwm2mServer.getSecurityMode() && profileLwm2mServer != null) { @@ -173,9 +173,9 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore { TransportProtos.SessionInfoProto sessionInfo = helper.getValidateSessionInfo(store.getMsg(), sessionUUiD.getMostSignificantBits(), sessionUUiD.getLeastSignificantBits()); bsSessions.put(store.getEndpoint(), sessionInfo); context.getTransportService().registerAsyncSession(sessionInfo, new LwM2mSessionMsgListener(null, null, null, sessionInfo, context.getTransportService())); - if (this.getValidatedSecurityMode(lwM2MBootstrapConfig.bootstrapServer, profileServerBootstrap, lwM2MBootstrapConfig.lwm2mServer, profileLwm2mServer)) { - lwM2MBootstrapConfig.bootstrapServer = new LwM2MServerBootstrap(lwM2MBootstrapConfig.bootstrapServer, profileServerBootstrap); - lwM2MBootstrapConfig.lwm2mServer = new LwM2MServerBootstrap(lwM2MBootstrapConfig.lwm2mServer, profileLwm2mServer); + if (this.getValidatedSecurityMode(lwM2MBootstrapConfig.getBootstrapServer(), bootstrapServerProfile, lwM2MBootstrapConfig.getLwm2mServer(), profileLwm2mServer)) { + lwM2MBootstrapConfig.setBootstrapServer(new LwM2MServerBootstrap(lwM2MBootstrapConfig.getBootstrapServer(), bootstrapServerProfile)); + lwM2MBootstrapConfig.setLwm2mServer(new LwM2MServerBootstrap(lwM2MBootstrapConfig.getLwm2mServer(), profileLwm2mServer)); String logMsg = String.format("%s: getParametersBootstrap: %s Access connect client with bootstrap server.", LOG_LWM2M_INFO, store.getEndpoint()); helper.sendParametersOnThingsboardTelemetry(helper.getKvStringtoThingsboard(LOG_LWM2M_TELEMETRY, logMsg), sessionInfo); return lwM2MBootstrapConfig; @@ -187,7 +187,6 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore { return null; } } - log.error("Unable to decode Json or Certificate for [{}]", store.getEndpoint()); return null; } @@ -197,13 +196,13 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore { * and (lwm2mServer in credential and lwm2mServer in profile * * @param bootstrapFromCredential - Bootstrap -> Security of bootstrapServer in credential - * @param profileServerBootstrap - Bootstrap -> Security of bootstrapServer in profile + * @param bootstrapServerProfile - Bootstrap -> Security of bootstrapServer in profile * @param lwm2mFromCredential - Bootstrap -> Security of lwm2mServer in credential * @param profileLwm2mServer - Bootstrap -> Security of lwm2mServer in profile * @return false if not sync between SecurityMode of Bootstrap credential and profile */ - private boolean getValidatedSecurityMode(LwM2MServerBootstrap bootstrapFromCredential, LwM2MServerBootstrap profileServerBootstrap, LwM2MServerBootstrap lwm2mFromCredential, LwM2MServerBootstrap profileLwm2mServer) { - return (bootstrapFromCredential.getSecurityMode().equals(profileServerBootstrap.getSecurityMode()) && + private boolean getValidatedSecurityMode(LwM2MServerBootstrap bootstrapFromCredential, LwM2MServerBootstrap bootstrapServerProfile, LwM2MServerBootstrap lwm2mFromCredential, LwM2MServerBootstrap profileLwm2mServer) { + return (bootstrapFromCredential.getSecurityMode().equals(bootstrapServerProfile.getSecurityMode()) && lwm2mFromCredential.getSecurityMode().equals(profileLwm2mServer.getSecurityMode())); } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2mDefaultBootstrapSessionManager.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2mDefaultBootstrapSessionManager.java index da5e8db695..4ad8a95108 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2mDefaultBootstrapSessionManager.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2mDefaultBootstrapSessionManager.java @@ -200,21 +200,20 @@ public class LwM2mDefaultBootstrapSessionManager extends DefaultBootstrapSession public BootstrapPolicy onRequestFailure(BootstrapSession bsSession, BootstrapDownlinkRequest request, Throwable cause) { this.sendLogs (bsSession.getEndpoint(), - String.format("%s: %s %s failed because of %s for %s : %s", LOG_LWM2M_INFO, - request.getClass().getSimpleName(), request.getPath().toString(), cause.toString(), bsSession.toString(), request.toString())); + String.format("%s: %s %s failed because of %s for %s : %s", LOG_LWM2M_INFO, request.getClass().getSimpleName(), + request.getPath().toString(), cause.toString(), bsSession.toString(), request.toString())); return BootstrapPolicy.failed(); } @Override public void end(BootstrapSession bsSession) { - this.sendLogs (bsSession.getEndpoint(), - String.format("%s: Bootstrap session finished : %s", LOG_LWM2M_INFO, bsSession.toString())); + this.sendLogs (bsSession.getEndpoint(), String.format("%s: Bootstrap session finished : %s", LOG_LWM2M_INFO, bsSession.toString())); } @Override public void failed(BootstrapSession bsSession, BootstrapFailureCause cause) { - this.sendLogs (bsSession.getEndpoint(), - String.format("%s: Bootstrap session failed by %s: %s", LOG_LWM2M_INFO, cause.toString(), bsSession.toString())); + this.sendLogs (bsSession.getEndpoint(), String.format("%s: Bootstrap session failed by %s: %s", LOG_LWM2M_INFO, + cause.toString(), bsSession.toString())); } private void sendLogs (String endpointName, String logMsg) { diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mOperationType.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mOperationType.java index 7ac959605a..ff0e431649 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mOperationType.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mOperationType.java @@ -50,16 +50,13 @@ public enum LwM2mOperationType { WRITE_COMPOSITE(14, "WriteComposite", false, true), WRITE_ATTRIBUTES(15, "WriteAttributes", true), DELETE(16, "Delete", true), - - // only for RPC - FW_UPDATE(17, "FirmwareUpdate", false), - // FW_READ_INFO(18, "FirmwareReadInfo", false), - SW_UPDATE(19, "SoftwareUpdate", false), - // SW_READ_INFO(20, "SoftwareReadInfo", false), - SW_UNINSTALL(21, "SoftwareUninstall", false), - CREATE(11, "Create", true); - - + CREATE(17, "Create", true); + // only for RPC - future +// FW_UPDATE(18, "FirmwareUpdate", false), +// FW_READ_INFO(19, "FirmwareReadInfo", false), +// SW_UPDATE(20, "SoftwareUpdate", false), +// SW_READ_INFO(21, "SoftwareReadInfo", false), +// SW_UNINSTALL(22, "SoftwareUninstall", false); @Getter diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mServerListener.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mServerListener.java index 8c8624fcf3..3ffc41c8ca 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mServerListener.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mServerListener.java @@ -98,7 +98,9 @@ public class LwM2mServerListener { @Override public void onError(Observation observation, Registration registration, Exception error) { - log.error("Unable to handle notification of [{}:{}] [{}]", observation.getRegistrationId(), observation.getPath(), error.getMessage()); + if (error != null) { + log.debug("Unable to handle notification of [{}:{}] [{}]", observation.getRegistrationId(), observation.getPath(), error.getMessage()); + } } @Override diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportServerHelper.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportServerHelper.java index 81278824e6..136f95dd35 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportServerHelper.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportServerHelper.java @@ -51,7 +51,7 @@ import static org.thingsboard.server.gen.transport.TransportProtos.KeyValueType. public class LwM2mTransportServerHelper { private final LwM2mTransportContext context; - private final static JsonParser JSON_PARSER = new JsonParser();; + private final static JsonParser JSON_PARSER = new JsonParser(); public void sendParametersOnThingsboardAttribute(List result, SessionInfoProto sessionInfo) { PostAttributeMsg.Builder request = PostAttributeMsg.newBuilder(); @@ -231,7 +231,11 @@ public class LwM2mTransportServerHelper { case STRING_V: return kv.getStringV(); case JSON_V: - return JSON_PARSER.parse(kv.getJsonV()); + try { + return JSON_PARSER.parse(kv.getJsonV()); + } catch (Exception e) { + return null; + } } return null; } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/attributes/DefaultLwM2MAttributesService.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/attributes/DefaultLwM2MAttributesService.java index dfe5146017..f7df2ee658 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/attributes/DefaultLwM2MAttributesService.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/attributes/DefaultLwM2MAttributesService.java @@ -40,7 +40,6 @@ import org.thingsboard.server.transport.lwm2m.server.downlink.LwM2mDownlinkMsgHa import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MWriteReplaceRequest; import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MWriteResponseCallback; import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService; -import org.thingsboard.server.transport.lwm2m.server.ota.DefaultLwM2MOtaUpdateService; import org.thingsboard.server.transport.lwm2m.server.ota.LwM2MOtaUpdateService; import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler; import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl; @@ -225,7 +224,7 @@ public class DefaultLwM2MAttributesService implements LwM2MAttributesService { this.pushUpdateToClientIfNeeded(lwM2MClient, oldResourceValue, newValProto, pathIdVer, logFailedUpdateOfNonChangedValue, resourceModel.type); } else { pushUpdateMultiToClientIfNeeded(lwM2MClient, resourceModel, (JsonElement) newValProto, - (Map) oldResourceValue, pathIdVer); + (Map) oldResourceValue, pathIdVer, logFailedUpdateOfNonChangedValue); } }); } @@ -251,7 +250,7 @@ public class DefaultLwM2MAttributesService implements LwM2MAttributesService { } private void pushUpdateMultiToClientIfNeeded(LwM2mClient client, ResourceModel resourceModel, JsonElement newValProto, - Map valueOld, String versionedId) { + Map valueOld, String versionedId, boolean logFailedUpdateOfNonChangedValue) { Map newValues = convertMultiResourceValuesFromJson((JsonObject) newValProto, resourceModel.type, versionedId); if (newValues.size() > 0 && valueOld != null && valueOld.size() > 0) { valueOld.values().stream().forEach((v) -> { @@ -272,7 +271,7 @@ public class DefaultLwM2MAttributesService implements LwM2MAttributesService { if (newValues.size() > 0) { TbLwM2MWriteReplaceRequest request = TbLwM2MWriteReplaceRequest.builder().versionedId(versionedId).value(newValues).timeout(this.config.getTimeout()).build(); downlinkHandler.sendWriteReplaceRequest(client, request, new TbLwM2MWriteResponseCallback(uplinkHandler, logService, client, versionedId)); - } else { + } else if (logFailedUpdateOfNonChangedValue) { log.warn("Didn't update resource [{}] [{}]", versionedId, newValProto); String logMsg = String.format("%s: Didn't update resource versionedId - %s value - %s. Value is not changed", LOG_LWM2M_WARN, versionedId, newValProto); diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java index 048bc046aa..33b1972fa9 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java @@ -46,7 +46,6 @@ import java.io.Serializable; import java.util.Arrays; import java.util.Collection; import java.util.HashSet; -import java.util.LinkedHashMap; import java.util.Map; import java.util.Optional; import java.util.Set; @@ -106,7 +105,6 @@ public class LwM2mClient implements Serializable { @Getter private Long pagingTransmissionWindow; @Getter - @Setter private Long edrxCycle; @Getter private Registration registration; @@ -122,9 +120,9 @@ public class LwM2mClient implements Serializable { private boolean firstEdrxDownlink = true; @Getter - Set clientSupportContentFormats; + private Set clientSupportContentFormats; @Getter - ContentFormat defaultContentFormat; + private ContentFormat defaultContentFormat; @Getter private final AtomicInteger retryAttempts; @@ -327,15 +325,18 @@ public class LwM2mClient implements Serializable { Collection resources = ConcurrentHashMap.newKeySet(); Map resourceModels = modelProvider.getObjectModel(registration) .getObjectModel(pathIds.getObjectId()).resources; - if (params != null) { + if (params != null && params instanceof Map && ((Map) params).size() > 0) { resourceModels.forEach((resourceId, resourceModel) -> { if (((Map) params).containsKey(String.valueOf(resourceId))) { Object value = ((Map) params).get((String.valueOf(resourceId))); - LwM2mResource resource = null; + LwM2mResource resource; if (resourceModel.multiple) { - if (value instanceof LinkedHashMap) { - Map values = convertMultiResourceValuesFromRpcBody((LinkedHashMap) value, resourceModel.type, pathRezIdVer); + try { + Map values = convertMultiResourceValuesFromRpcBody(value, resourceModel.type, pathRezIdVer); resource = LwM2mMultipleResource.newResource(resourceId, (Map) values, resourceModel.type); + } catch (Exception e) { + throw new IllegalArgumentException("Resource id=" + resourceId + ", value = " + value + ", class = " + + value.getClass().getSimpleName() + "is bad. Value of Multi-Instance Resource must be in Json format!"); } } else { Object valueRez = value.getClass().getSimpleName().equals("Integer") ? ((Integer) value).longValue() : value; @@ -353,9 +354,12 @@ public class LwM2mClient implements Serializable { } }); } - else { + else if (params == null) { throw new IllegalArgumentException("The value of this resource must not be null."); } + else { + throw new IllegalArgumentException("The value of this resource must be in Map format and size > 0"); + } return resources; } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/AbstractTbLwM2MRequestCallback.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/AbstractTbLwM2MRequestCallback.java index c99a5ea2a1..830b7ee4ca 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/AbstractTbLwM2MRequestCallback.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/AbstractTbLwM2MRequestCallback.java @@ -19,7 +19,7 @@ import lombok.extern.slf4j.Slf4j; import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService; -import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.LOG_LWM2M_WARN; +import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.LOG_LWM2M_ERROR; @Slf4j public abstract class AbstractTbLwM2MRequestCallback implements DownlinkRequestCallback { @@ -35,12 +35,12 @@ public abstract class AbstractTbLwM2MRequestCallback implements DownlinkRe @Override public void onValidationError(String params, String msg) { log.trace("[{}] Request [{}] validation failed. Reason: {}", client.getEndpoint(), params, msg); - logService.log(client, String.format("[%s]: Request [%s] validation failed. Reason: %s", LOG_LWM2M_WARN, params, msg)); + logService.log(client, String.format("[%s]: Request [%s] validation failed. Reason: %s", LOG_LWM2M_ERROR, params, msg)); } @Override public void onError(String params, Exception e) { log.trace("[{}] Request [{}] processing failed", client.getEndpoint(), params, e); - logService.log(client, String.format("[%s]: Request [%s] processing failed. Reason: %s", LOG_LWM2M_WARN, params, e)); + logService.log(client, String.format("[%s]: Request [%s] processing failed. Reason: %s", LOG_LWM2M_ERROR, params, e)); } } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2mDownlinkMsgHandler.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2mDownlinkMsgHandler.java index 309d456663..bf475a6fb4 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2mDownlinkMsgHandler.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2mDownlinkMsgHandler.java @@ -19,7 +19,6 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.eclipse.leshan.core.Link; import org.eclipse.leshan.core.LwM2m; -import org.eclipse.leshan.core.ResponseCode; import org.eclipse.leshan.core.attributes.Attribute; import org.eclipse.leshan.core.attributes.AttributeSet; import org.eclipse.leshan.core.model.LwM2mModel; @@ -79,7 +78,6 @@ import javax.annotation.PreDestroy; import java.util.Arrays; import java.util.Collection; import java.util.Date; -import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; @@ -302,11 +300,13 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im try { WriteRequest downlink = null; if (resourceModelWrite.multiple) { - if (request.getValue() instanceof Map && ((Map) request.getValue()).size() > 0) { + try { + Map value = convertMultiResourceValuesFromRpcBody(request.getValue(), resourceModelWrite.type, request.getObjectId()); downlink = new WriteRequest(contentFormat, resultIds.getObjectId(), resultIds.getObjectInstanceId(), resultIds.getResourceId(), - (Map) request.getValue(), resourceModelWrite.type); - } else { - callback.onValidationError(toString(request), "Resource value is: " + request.getValue().getClass().getSimpleName() + ". Value of Multi-Instance Resource must be in Json format!"); + value, resourceModelWrite.type); + } catch (Exception e) { + callback.onValidationError(toString(request), "Resource id=" + resultIds.toString() + ", value = " + request.getValue() + + ", class = " + request.getValue().getClass().getSimpleName() + "is bad. Value of Multi-Instance Resource must be in Json format!"); } } else { downlink = this.getWriteRequestSingleResource(resourceModelWrite.type, contentFormat, @@ -368,12 +368,12 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im ResourceModel resourceModelWrite = client.getResourceModel(request.getVersionedId(), this.config.getModelProvider()); if (resourceModelWrite != null) { if (resourceModelWrite.multiple) { - if (request.getValue() instanceof Map && ((Map) request.getValue()).size() > 0) { - Map value = convertMultiResourceValuesFromRpcBody((LinkedHashMap) request.getValue(), resourceModelWrite.type, request.getObjectId()); + try { + Map value = convertMultiResourceValuesFromRpcBody(request.getValue(), resourceModelWrite.type, request.getObjectId()); downlink = new WriteRequest(WriteRequest.Mode.UPDATE, contentFormat, resultIds.getObjectId(), resultIds.getObjectInstanceId(), resultIds.getResourceId(), value, resourceModelWrite.type); - } else { - callback.onValidationError(toString(request), "Resource value is bad. Format: " + request.getValue().getClass().getSimpleName() + ". Value of Multi-Instance Resource must be in Json format!"); + } catch (Exception e1) { + callback.onValidationError(toString(request), "Resource id=" + resultIds.toString() + ", value = " + request.getValue() + ", class = " + request.getValue().getClass().getSimpleName() + "is bad. Value of Multi-Instance Resource must be in Json format!"); } } } else { diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/DefaultLwM2MRpcRequestHandler.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/DefaultLwM2MRpcRequestHandler.java index 3d032081ee..12ee3581ac 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/DefaultLwM2MRpcRequestHandler.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/DefaultLwM2MRpcRequestHandler.java @@ -169,8 +169,6 @@ public class DefaultLwM2MRpcRequestHandler implements LwM2MRpcRequestHandler { case DISCOVER_ALL: sendDiscoverAllRequest(client, rpcRequest); break; - case FW_UPDATE: - //TODO: implement and add break statement default: throw new IllegalArgumentException("Unsupported operation: " + operationType.name()); } @@ -257,11 +255,16 @@ public class DefaultLwM2MRpcRequestHandler implements LwM2MRpcRequestHandler { private void sendWriteReplaceRequest(LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, String versionedId) { RpcWriteReplaceRequest requestBody = JacksonUtil.fromString(requestMsg.getParams(), RpcWriteReplaceRequest.class); LwM2mPath path = new LwM2mPath(fromVersionedIdToObjectId(versionedId)); - if (path.isResource() && requestBody.getValue() instanceof LinkedHashMap) { + if (path.isResource()) { ResourceModel resourceModel = client.getResourceModel(versionedId, this.config.getModelProvider()); if (resourceModel != null && resourceModel.multiple) { - Map value = convertMultiResourceValuesFromRpcBody((LinkedHashMap) requestBody.getValue(), resourceModel.type, versionedId); - requestBody.setValue(value); + try { + Map value = convertMultiResourceValuesFromRpcBody(requestBody.getValue(), resourceModel.type, versionedId); + requestBody.setValue(value); + } catch (Exception e) { + throw new IllegalArgumentException("Resource id=" + versionedId + ", value = " + requestBody.getValue() + ", class = " + + requestBody.getValue().getClass().getSimpleName() + "is bad. Value of Multi-Instance Resource must be in Json format!"); + } } } TbLwM2MWriteReplaceRequest request = TbLwM2MWriteReplaceRequest.builder().versionedId(versionedId) diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2mTransportUtil.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2mTransportUtil.java index 69cee060ab..76e5ce4d91 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2mTransportUtil.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2mTransportUtil.java @@ -16,10 +16,7 @@ package org.thingsboard.server.transport.lwm2m.utils; import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.google.gson.Gson; import com.google.gson.JsonObject; -import com.google.gson.JsonParser; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.eclipse.leshan.core.attributes.Attribute; @@ -47,6 +44,7 @@ import org.thingsboard.server.common.data.device.profile.DeviceProfileTransportC import org.thingsboard.server.common.data.device.profile.Lwm2mDeviceProfileTransportConfiguration; import org.thingsboard.server.common.data.ota.OtaPackageKey; import org.thingsboard.server.common.data.ota.OtaPackageType; +import org.thingsboard.server.common.transport.util.JsonUtils; import org.thingsboard.server.transport.lwm2m.config.LwM2mVersion; import org.thingsboard.server.transport.lwm2m.server.LwM2mOtaConvert; import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; @@ -57,18 +55,15 @@ import org.thingsboard.server.transport.lwm2m.server.ota.firmware.FirmwareUpdate import org.thingsboard.server.transport.lwm2m.server.ota.software.SoftwareUpdateResult; import org.thingsboard.server.transport.lwm2m.server.ota.software.SoftwareUpdateState; import org.thingsboard.server.transport.lwm2m.server.uplink.DefaultLwM2MUplinkMsgHandler; -import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl; import java.util.ArrayList; import java.util.Arrays; import java.util.Date; import java.util.HashMap; -import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; import static org.eclipse.leshan.core.attributes.Attribute.DIMENSION; import static org.eclipse.leshan.core.attributes.Attribute.GREATER_THAN; @@ -367,11 +362,9 @@ public class LwM2mTransportUtil { return String.format("%s %s", keyName, String.join(",", msgException)).trim(); } - public static Map convertMultiResourceValuesFromRpcBody(LinkedHashMap value, ResourceModel.Type type, String versionedId) { - Gson gson = new Gson(); - JsonParser JSON_PARSER = new JsonParser(); - String json = gson.toJson(value, LinkedHashMap.class); - return convertMultiResourceValuesFromJson((JsonObject) JSON_PARSER.parse(json), type, versionedId); + public static Map convertMultiResourceValuesFromRpcBody(Object value, ResourceModel.Type type, String versionedId) throws Exception { + String valueJsonStr = JsonUtils.riteValueAsString(value); + return convertMultiResourceValuesFromJson((JsonObject) JsonUtils.parse(valueJsonStr), type, versionedId); } public static Map convertMultiResourceValuesFromJson(JsonObject newValProto, ResourceModel.Type type, String versionedId) { diff --git a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/util/JsonUtils.java b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/util/JsonUtils.java index 29817ad350..82f7c2cf3a 100644 --- a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/util/JsonUtils.java +++ b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/util/JsonUtils.java @@ -15,15 +15,19 @@ */ package org.thingsboard.server.common.transport.util; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParser; import org.thingsboard.server.gen.transport.TransportProtos.KeyValueProto; + import java.util.List; public class JsonUtils { private static final JsonParser jsonParser = new JsonParser(); + private static final ObjectMapper json = new ObjectMapper(); public static JsonObject getJsonObject(List tsKv) { JsonObject json = new JsonObject(); @@ -52,4 +56,9 @@ public class JsonUtils { public static JsonElement parse(String params) { return jsonParser.parse(params); } + + public static String riteValueAsString (Object value) throws JsonProcessingException { + return json.writeValueAsString(value); + + } } diff --git a/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml b/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml index d398b676dd..3398d82234 100644 --- a/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml +++ b/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml @@ -97,10 +97,10 @@ transport: timeout: "${CLIENT_SIDE_RPC_TIMEOUT:60000}" # Enable/disable http/mqtt/coap transport protocols (has higher priority than certain protocol's 'enabled' property) api_enabled: "${TB_TRANSPORT_API_ENABLED:true}" - # Local LwM2M transport parameters log: enabled: "${TB_TRANSPORT_LOG_ENABLED:true}" max_length: "${TB_TRANSPORT_LOG_MAX_LENGTH:1024}" + # Local LwM2M transport parameters lwm2m: # Enable/disable lvm2m transport protocol. enabled: "${LWM2M_ENABLED:true}" From 16a520cd80f03a31e6092663333daeed315f14da Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Fri, 17 Sep 2021 19:20:05 +0300 Subject: [PATCH 040/432] Lwm2m Fix bug review last --- .../DefaultLwM2MAttributesService.java | 2 +- .../lwm2m/server/client/LwM2mClient.java | 36 ++++++------- .../server/client/LwM2mClientContext.java | 5 +- .../server/client/LwM2mClientContextImpl.java | 24 ++++----- .../DefaultLwM2mDownlinkMsgHandler.java | 50 +++++++++---------- .../server/downlink/TbLwM2MCreateRequest.java | 5 +- .../server/downlink/TbLwM2MReadCallback.java | 20 ++++++++ .../downlink/TbLwM2MTargetedCallback.java | 47 +++++------------ .../rpc/DefaultLwM2MRpcRequestHandler.java | 39 +++++++++++---- .../lwm2m/utils/LwM2mTransportUtil.java | 11 +--- .../thingsboard/common/util/JacksonUtil.java | 21 ++++++-- .../dao/device/DeviceProfileServiceImpl.java | 3 -- 12 files changed, 130 insertions(+), 133 deletions(-) diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/attributes/DefaultLwM2MAttributesService.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/attributes/DefaultLwM2MAttributesService.java index f7df2ee658..e54277060a 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/attributes/DefaultLwM2MAttributesService.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/attributes/DefaultLwM2MAttributesService.java @@ -194,7 +194,7 @@ public class DefaultLwM2MAttributesService implements LwM2MAttributesService { Map attributesUpdate = new ConcurrentHashMap<>(); tsKvProtos.forEach(tsKvProto -> { try { - String pathIdVer = clientContext.getObjectIdByKeyNameFromProfile(lwM2MClient, tsKvProto.getKv().getKey(), false); + String pathIdVer = clientContext.getObjectIdByKeyNameFromProfile(lwM2MClient, tsKvProto.getKv().getKey()); if (pathIdVer != null) { // #1.1 if (lwM2MClient.getSharedAttributes().containsKey(pathIdVer)) { diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java index 33b1972fa9..2cc69f2c58 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java @@ -61,7 +61,6 @@ import java.util.stream.Collectors; import java.util.stream.Stream; import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPARATOR_PATH; -import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.LWM2M_OBJECT_VERSION_DEFAULT; import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.convertMultiResourceValuesFromRpcBody; import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.convertObjectIdToVersionedId; import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.equalsResourceTypeGetSimpleName; @@ -277,7 +276,7 @@ public class LwM2mClient implements Serializable { LwM2mPath pathIds = new LwM2mPath(fromVersionedIdToObjectId(pathIdVer)); String verSupportedObject = registration.getSupportedObject().get(pathIds.getObjectId()); String verRez = getVerFromPathIdVerOrId(pathIdVer); - return verRez == null || verRez.equals(verSupportedObject) ? modelProvider.getObjectModel(registration) + return verRez != null && verRez.equals(verSupportedObject) ? modelProvider.getObjectModel(registration) .getResourceModel(pathIds.getObjectId(), pathIds.getResourceId()) : null; } @@ -294,7 +293,7 @@ public class LwM2mClient implements Serializable { LwM2mPath pathIds = new LwM2mPath(fromVersionedIdToObjectId(pathIdVer)); String verSupportedObject = registration.getSupportedObject().get(pathIds.getObjectId()); String verRez = getVerFromPathIdVerOrId(pathIdVer); - return verRez == null || verRez.equals(verSupportedObject) ? modelProvider.getObjectModel(registration) + return verRez != null && verRez.equals(verSupportedObject) ? modelProvider.getObjectModel(registration) .getObjectModel(pathIds.getObjectId()) : null; } @@ -339,7 +338,7 @@ public class LwM2mClient implements Serializable { value.getClass().getSimpleName() + "is bad. Value of Multi-Instance Resource must be in Json format!"); } } else { - Object valueRez = value.getClass().getSimpleName().equals("Integer") ? ((Integer) value).longValue() : value; + Object valueRez = value instanceof Integer ? ((Integer) value).longValue() : value; resource = LwM2mSingleResource.newResource(resourceId, converter.convertValue(valueRez, equalsResourceTypeGetSimpleName(value), resourceModel.type, pathIds), resourceModel.type); } @@ -370,8 +369,7 @@ public class LwM2mClient implements Serializable { return String.format("Specified object id %s absent in the list supported objects of the client or is security object!", pathIds.getObjectId()); } else { String verRez = getVerFromPathIdVerOrId(path); - if ((verRez != null && !verRez.equals(verSupportedObject)) || - (verRez == null && !LWM2M_OBJECT_VERSION_DEFAULT.equals(verSupportedObject))) { + if (verRez == null || !verRez.equals(verSupportedObject)) { return String.format("Specified resource id %s is not valid version! Must be version: %s", path, verSupportedObject); } } @@ -425,23 +423,17 @@ public class LwM2mClient implements Serializable { } } - private Set clientSupportContentFormat(Registration registration) { + static private Set clientSupportContentFormat(Registration registration) { Set contentFormats = new HashSet<>(); - if (registration == null) { - contentFormats.add(ContentFormat.DEFAULT); - } else { - String code = Arrays.stream(registration.getObjectLinks()).filter(link -> link.getUrl().equals("/")). - findFirst().get().getAttributes().get("ct"); - if (code != null) { - Set codes = Stream.of(code.replaceAll("\"", "").split(" ", -1)) - .map(String::trim) - .map(Integer::parseInt) - .map(ContentFormat::fromCode) - .collect(Collectors.toSet()); - contentFormats.addAll(codes); - } else { - contentFormats.add(ContentFormat.DEFAULT); - } + contentFormats.add(ContentFormat.DEFAULT); + String code = Arrays.stream(registration.getObjectLinks()).filter(link -> link.getUrl().equals("/")).findFirst().get().getAttributes().get("ct"); + if (code != null) { + Set codes = Stream.of(code.replaceAll("\"", "").split(" ", -1)) + .map(String::trim) + .map(Integer::parseInt) + .map(ContentFormat::fromCode) + .collect(Collectors.toSet()); + contentFormats.addAll(codes); } return contentFormats; } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContext.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContext.java index 5b720a8b66..8d97e775c6 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContext.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContext.java @@ -15,7 +15,6 @@ */ package org.thingsboard.server.transport.lwm2m.server.client; -import org.eclipse.leshan.core.request.ContentFormat; import org.eclipse.leshan.server.registration.Registration; import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.device.profile.Lwm2mDeviceProfileTransportConfiguration; @@ -52,7 +51,7 @@ public interface LwM2mClientContext { LwM2mClient getClientByDeviceId(UUID deviceId); - String getObjectIdByKeyNameFromProfile(LwM2mClient lwM2mClient, String keyName, boolean isCompositeOperation); + String getObjectIdByKeyNameFromProfile(LwM2mClient lwM2mClient, String keyName); void registerClient(Registration registration, ValidateDeviceCredentialsResponse credentials); @@ -62,8 +61,6 @@ public interface LwM2mClientContext { void sendMsgsAfterSleeping(LwM2mClient lwM2MClient); - ContentFormat getContentFormatComposite(LwM2mClient client); - void onUplink(LwM2mClient client); Long getRequestTimeout(LwM2mClient client); diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java index 71f4a0058a..413629ebc1 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java @@ -19,7 +19,6 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.eclipse.leshan.core.SecurityMode; import org.eclipse.leshan.core.node.LwM2mPath; -import org.eclipse.leshan.core.request.ContentFormat; import org.eclipse.leshan.server.registration.Registration; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Lazy; @@ -58,7 +57,6 @@ import java.util.function.Predicate; import static org.eclipse.leshan.core.SecurityMode.NO_SEC; import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.convertObjectIdToVersionedId; -import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.getMsgException; @Slf4j @Service @@ -289,14 +287,16 @@ public class LwM2mClientContextImpl implements LwM2mClientContext { } @Override - public String getObjectIdByKeyNameFromProfile(LwM2mClient client, String keyName, boolean isCompositeOperation) { + public String getObjectIdByKeyNameFromProfile(LwM2mClient client, String keyName) { Lwm2mDeviceProfileTransportConfiguration profile = getProfile(client.getProfileId()); - Set msgException = ConcurrentHashMap.newKeySet(); - msgException.add(""); - return profile.getObserveAttr().getKeyName().entrySet().stream() - .filter(e -> e.getValue().equals(keyName) && (isCompositeOperation || !msgException.add(client.isValidObjectVersion(e.getKey())))).findFirst().orElseThrow( - () -> new IllegalArgumentException(getMsgException (keyName, msgException)) - ).getKey(); + for (Map.Entry entry : profile.getObserveAttr().getKeyName().entrySet()) { + String k = entry.getKey(); + String v = entry.getValue(); + if (v.equals(keyName) && client.isValidObjectVersion(k).isEmpty()) { + return k; + } + } + throw new IllegalArgumentException(keyName + " is not configured in the device profile!"); } public Registration getRegistration(String registrationId) { @@ -410,12 +410,6 @@ public class LwM2mClientContextImpl implements LwM2mClientContext { return lwM2mClientsByRegistrationId.values().stream().filter(e -> deviceId.equals(e.getDeviceId())).findFirst().orElse(null); } - @Override - public ContentFormat getContentFormatComposite(LwM2mClient client) { - return client.getClientSupportContentFormats().contains(ContentFormat.SENML_JSON) ? ContentFormat.SENML_JSON : - client.getClientSupportContentFormats().contains(ContentFormat.SENML_CBOR) ? ContentFormat.SENML_CBOR : null; - } - @Override public boolean isDownlinkAllowed(LwM2mClient client) { PowerMode powerMode = client.getPowerMode(); diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2mDownlinkMsgHandler.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2mDownlinkMsgHandler.java index bf475a6fb4..71a27def66 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2mDownlinkMsgHandler.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2mDownlinkMsgHandler.java @@ -147,9 +147,9 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im @Override public void sendReadCompositeRequest(LwM2mClient client, TbLwM2MReadCompositeRequest request, - DownlinkRequestCallback callback, ContentFormat contentFormatComposite) { + DownlinkRequestCallback callback, ContentFormat compositeContentFormat) { try { - ReadCompositeRequest downlink = new ReadCompositeRequest(contentFormatComposite, contentFormatComposite, request.getObjectIds()); + ReadCompositeRequest downlink = new ReadCompositeRequest(compositeContentFormat, compositeContentFormat, request.getObjectIds()); sendCompositeRequest(client, downlink, this.config.getTimeout(), callback); } catch (InvalidRequestException e) { callback.onValidationError(request.toString(), e.getMessage()); @@ -207,13 +207,15 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im } } if (resourceModelExecute == null) { - callback.onValidationError(request.toString(), "ResourceModel with " + request.getVersionedId() + " is absent in system. Need ddd Lwm2m Model with id=" + - pathIds.getObjectId() + " ver=" + getVerFromPathIdVerOrId(request.getVersionedId()) + " to profile."); + callback.onValidationError(request.toString(), "ResourceModel with " + request.getVersionedId() + + " is absent in system. Need ddd Lwm2m Model with id=" + pathIds.getObjectId() + " ver=" + + getVerFromPathIdVerOrId(request.getVersionedId()) + " to profile."); } else if (resourceModelExecute.operations.isExecutable()) { ExecuteRequest downlink; if (request.getParams() != null && !resourceModelExecute.multiple) { - downlink = new ExecuteRequest(request.getObjectId(), (String) this.converter.convertValue(request.getParams(), resourceModelExecute.type, ResourceModel.Type.STRING, new LwM2mPath(request.getObjectId()))); + downlink = new ExecuteRequest(request.getObjectId(), (String) this.converter.convertValue(request.getParams(), + resourceModelExecute.type, ResourceModel.Type.STRING, new LwM2mPath(request.getObjectId()))); } else { downlink = new ExecuteRequest(request.getObjectId()); } @@ -357,9 +359,11 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im * int rscId = resultIds.getObjectInstanceId(); * contentFormat – Format of the payload (TLV or JSON). */ - Collection resources = client.getNewResourcesForInstance(request.getVersionedId(), request.getValue(), this.config.getModelProvider(), this.converter); + Collection resources = client.getNewResourcesForInstance(request.getVersionedId(), + request.getValue(), this.config.getModelProvider(), this.converter); if (resources.size() > 0) { - downlink = new WriteRequest(WriteRequest.Mode.UPDATE, contentFormat, resultIds.getObjectId(), resultIds.getObjectInstanceId(), resources); + downlink = new WriteRequest(WriteRequest.Mode.UPDATE, contentFormat, resultIds.getObjectId(), + resultIds.getObjectInstanceId(), resources); } else { callback.onValidationError(toString(request), "No resources to update!"); } @@ -370,24 +374,30 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im if (resourceModelWrite.multiple) { try { Map value = convertMultiResourceValuesFromRpcBody(request.getValue(), resourceModelWrite.type, request.getObjectId()); - downlink = new WriteRequest(WriteRequest.Mode.UPDATE, contentFormat, resultIds.getObjectId(), resultIds.getObjectInstanceId(), resultIds.getResourceId(), + downlink = new WriteRequest(WriteRequest.Mode.UPDATE, contentFormat, resultIds.getObjectId(), + resultIds.getObjectInstanceId(), resultIds.getResourceId(), value, resourceModelWrite.type); } catch (Exception e1) { - callback.onValidationError(toString(request), "Resource id=" + resultIds.toString() + ", value = " + request.getValue() + ", class = " + request.getValue().getClass().getSimpleName() + "is bad. Value of Multi-Instance Resource must be in Json format!"); + callback.onValidationError(toString(request), "Resource id=" + resultIds.toString() + ", value = " + + request.getValue() + ", class = " + request.getValue().getClass().getSimpleName() + + "is bad. Value of Multi-Instance Resource must be in Json format!"); } } } else { - callback.onValidationError(toString(request), "Resource " + request.getVersionedId() + " is not configured in the device profile!"); + callback.onValidationError(toString(request), "Resource " + request.getVersionedId() + + " is not configured in the device profile!"); } } if (downlink != null) { sendSimpleRequest(client, downlink, request.getTimeout(), callback); } else { - callback.onValidationError(toString(request), "Resource " + request.getVersionedId() + ". This operation can only be used for ObjectInstance or Multi-Instance Resource !"); + callback.onValidationError(toString(request), "Resource " + request.getVersionedId() + + ". This operation can only be used for ObjectInstance or Multi-Instance Resource !"); } } else { - callback.onValidationError(toString(request), "Resource " + request.getVersionedId() + ". This operation can only be used for ObjectInstance or Resource (multiple)"); + callback.onValidationError(toString(request), "Resource " + request.getVersionedId() + + ". This operation can only be used for ObjectInstance or Resource (multiple)"); } } catch (Exception e) { callback.onValidationError(toString(request), e.getMessage()); @@ -406,7 +416,6 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im if (resultIds.isObject() || resultIds.isObjectInstance()) { Collection resources; if (resultIds.isObject()) { -// contentFormat = ContentFormat.TLV; if (request.getValue() != null) { resources = client.getNewResourcesForInstance(request.getVersionedId(), request.getValue(), this.config.getModelProvider(), this.converter); downlink = new CreateRequest(contentFormat, resultIds.getObjectId(), resources); @@ -584,18 +593,9 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im private static ContentFormat getRequestContentFormat(LwM2mClient client, String versionedId, LwM2mModelProvider modelProvider) { LwM2mPath pathIds = new LwM2mPath(fromVersionedIdToObjectId(versionedId)); - if (pathIds.isResourceInstance()) { + if (pathIds.isResource() || pathIds.isResourceInstance()) { ResourceModel resourceModel = client.getResourceModel(versionedId, modelProvider); - if (OBJLNK.equals(resourceModel.type)) { - return ContentFormat.LINK; - } else if (OPAQUE.equals(resourceModel.type)) { - return ContentFormat.OPAQUE; - } else { - return findFirst(client.getClientSupportContentFormats(), client.getDefaultContentFormat(), ContentFormat.CBOR, ContentFormat.SENML_CBOR, ContentFormat.SENML_JSON); - } - } else if (pathIds.isResource()) { - ResourceModel resourceModel = client.getResourceModel(versionedId, modelProvider); - if (resourceModel!= null && !resourceModel.multiple) { + if (resourceModel!= null && (pathIds.isResourceInstance() || (pathIds.isResource() && !resourceModel.multiple))) { if (OBJLNK.equals(resourceModel.type)) { return ContentFormat.LINK; } else if (OPAQUE.equals(resourceModel.type)) { @@ -639,7 +639,7 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im try { return request != null ? request.toString() : ""; } catch (Exception e) { - log.trace("Failed to convert request to string", e); + log.debug("Failed to convert request to string", e); return request.getClass().getSimpleName(); } } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MCreateRequest.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MCreateRequest.java index 9eed9381a8..76e7ca845a 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MCreateRequest.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MCreateRequest.java @@ -30,7 +30,7 @@ public class TbLwM2MCreateRequest extends AbstractTbLwM2MTargetedDownlinkRequest @Getter private final ContentFormat objectContentFormat; @Getter - private final Map nodes;; + private final Map nodes; @Builder private TbLwM2MCreateRequest(String versionedId, long timeout, Object value, ContentFormat objectContentFormat, Map nodes) { @@ -44,7 +44,4 @@ public class TbLwM2MCreateRequest extends AbstractTbLwM2MTargetedDownlinkRequest public LwM2mOperationType getType() { return LwM2mOperationType.CREATE; } - - - } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MReadCallback.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MReadCallback.java index 59247b103b..0ae17ea449 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MReadCallback.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MReadCallback.java @@ -16,8 +16,10 @@ package org.thingsboard.server.transport.lwm2m.server.downlink; import lombok.extern.slf4j.Slf4j; +import org.eclipse.leshan.core.node.LwM2mSingleResource; import org.eclipse.leshan.core.request.ReadRequest; import org.eclipse.leshan.core.response.ReadResponse; +import org.eclipse.leshan.core.util.Hex; import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService; import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler; @@ -31,8 +33,26 @@ public class TbLwM2MReadCallback extends TbLwM2MUplinkTargetedCallback 0) { + int len = ((byte[])((LwM2mSingleResource) response.getContent()).getValue()).length; + String valueReplace = len + "Bytes"; + String valueStr = Hex.encodeHexString((byte[]) (((LwM2mSingleResource) response.getContent()).getValue())); + return response.toString().replace(valueReplace, valueStr); + } + } + return response.toString(); + } + else { + return response.toString(); + } + } + } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MTargetedCallback.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MTargetedCallback.java index c14527e3b1..8f7015a6fa 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MTargetedCallback.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MTargetedCallback.java @@ -17,10 +17,7 @@ package org.thingsboard.server.transport.lwm2m.server.downlink; import lombok.extern.slf4j.Slf4j; import org.eclipse.leshan.core.ResponseCode; -import org.eclipse.leshan.core.node.LwM2mSingleResource; import org.eclipse.leshan.core.response.LwM2mResponse; -import org.eclipse.leshan.core.response.ReadResponse; -import org.eclipse.leshan.core.util.Hex; import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService; @@ -50,40 +47,22 @@ public abstract class TbLwM2MTargetedCallback extends AbstractTbLwM2MReque @Override public void onSuccess(R request, T response) { //TODO convert camelCase to "camel case" using .split("(?= ResponseCode.BAD_REQUEST.getCode()) { - log.error("[{}] [{}] [{}] failed to process successful response [{}] ", client.getEndpoint(), requestName, versionedId != null ? versionedId : Arrays.toString(versionedIds), responseStr); - logService.log(client, String.format("[%s]: %s [%s] failed to process successful. Result: %s", LOG_LWM2M_ERROR, requestName, versionedId != null ? versionedId : Arrays.toString(versionedIds), responseStr)); - } - else { - log.trace("[{}] {} [{}] successful: {}", client.getEndpoint(), requestName, versionedId != null ? versionedId : versionedIds, responseStr); - logService.log(client, String.format("[%s]: %s [%s] successful. Result: %s", LOG_LWM2M_INFO, requestName, versionedId != null ? versionedId : Arrays.toString(versionedIds), responseStr)); + if (response instanceof LwM2mResponse) { + logForBadResponse(((LwM2mResponse) response).getCode().getCode(), response.toString(), request.getClass().getSimpleName()); } } - private String responseToString (ReadResponse response) { - if (response.getContent() instanceof LwM2mSingleResource) { - if (((LwM2mSingleResource) response.getContent()).getType().name().equals("OPAQUE")) { - if (((byte[])((LwM2mSingleResource) response.getContent()).getValue()).length > 0) { - int len = ((byte[])((LwM2mSingleResource) response.getContent()).getValue()).length; - String valueReplace = len + "Bytes"; - String valueStr = Hex.encodeHexString((byte[]) (((LwM2mSingleResource) response.getContent()).getValue())); - return response.toString().replace(valueReplace, valueStr); - } - } - return response.toString(); - } - else { - return response.toString(); + public void logForBadResponse(int code, String responseStr, String requestName) { + if (code > ResponseCode.CONTENT_CODE) { + log.error("[{}] [{}] [{}] failed to process successful response [{}] ", client.getEndpoint(), requestName, + versionedId != null ? versionedId : Arrays.toString(versionedIds), responseStr); + logService.log(client, String.format("[%s]: %s [%s] failed to process successful. Result: %s", LOG_LWM2M_ERROR, + requestName, versionedId != null ? versionedId : Arrays.toString(versionedIds), responseStr)); + } else { + log.trace("[{}] {} [{}] successful: {}", client.getEndpoint(), requestName, versionedId != null ? + versionedId : versionedIds, responseStr); + logService.log(client, String.format("[%s]: %s [%s] successful. Result: %s", LOG_LWM2M_INFO, requestName, + versionedId != null ? versionedId : Arrays.toString(versionedIds), responseStr)); } } } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/DefaultLwM2MRpcRequestHandler.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/DefaultLwM2MRpcRequestHandler.java index 12ee3581ac..a881047f91 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/DefaultLwM2MRpcRequestHandler.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/DefaultLwM2MRpcRequestHandler.java @@ -15,6 +15,7 @@ */ package org.thingsboard.server.transport.lwm2m.server.rpc; +import com.google.gson.JsonSyntaxException; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.eclipse.leshan.core.ResponseCode; @@ -25,6 +26,7 @@ import org.springframework.stereotype.Service; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.transport.TransportService; +import org.thingsboard.server.common.transport.util.JsonUtils; import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; @@ -103,10 +105,6 @@ public class DefaultLwM2MRpcRequestHandler implements LwM2MRpcRequestHandler { if (operationType.isHasObjectId()) { LwM2MRpcRequestHeader header = JacksonUtil.fromString(rpcRequest.getParams(), LwM2MRpcRequestHeader.class); String objectId = getIdFromParameters(client, header); - ContentFormat contentFormat = null; - if (StringUtils.isNotEmpty(header.getContentFormat())) { - contentFormat = ContentFormat.fromName(header.getContentFormat()); - } switch (operationType) { case READ: sendReadRequest(client, rpcRequest, objectId); @@ -142,7 +140,7 @@ public class DefaultLwM2MRpcRequestHandler implements LwM2MRpcRequestHandler { throw new IllegalArgumentException("Unsupported operation: " + operationType.name()); } } else if (operationType.isComposite()) { - ContentFormat contentFormatComposite = clientContext.getContentFormatComposite(client); + ContentFormat contentFormatComposite = this.getContentFormatComposite(client); if (contentFormatComposite != null) { switch (operationType) { case READ_COMPOSITE: @@ -305,14 +303,21 @@ public class DefaultLwM2MRpcRequestHandler implements LwM2MRpcRequestHandler { new LwM2mPath(fromVersionedIdToObjectId(key.toString())); versionedId = key.toString(); } catch (Exception e) { - versionedId = clientContext.getObjectIdByKeyNameFromProfile(client, key.toString(), true); + versionedId = clientContext.getObjectIdByKeyNameFromProfile(client, key.toString()); } // validate value. Must be only primitive, not Json - if (value instanceof LinkedHashMap) { + try { + JsonUtils.parse(value.toString()); throw new IllegalArgumentException(String.format("nodes: %s is not validate value. " + "The WriteComposite operation is only used for SingleResources or/and ResourceInstance.", nodes.toString())); - } else { - newNodes.put(fromVersionedIdToObjectId(versionedId), value); + } catch (JsonSyntaxException jse) { +// if (value instanceof LinkedHashMap) { +// throw new IllegalArgumentException(String.format("nodes: %s is not validate value. " + +// "The WriteComposite operation is only used for SingleResources or/and ResourceInstance.", nodes.toString())); +// } + if (versionedId != null) { + newNodes.put(fromVersionedIdToObjectId(versionedId), value); + } } }); return newNodes; @@ -342,7 +347,7 @@ public class DefaultLwM2MRpcRequestHandler implements LwM2MRpcRequestHandler { private String getIdFromParameters(LwM2mClient client, LwM2MRpcRequestHeader header) { String targetId; if (StringUtils.isNotEmpty(header.getKey())) { - targetId = clientContext.getObjectIdByKeyNameFromProfile(client, header.getKey(), false); + targetId = clientContext.getObjectIdByKeyNameFromProfile(client, header.getKey()); } else if (StringUtils.isNotEmpty(header.getId())) { targetId = header.getId(); } else { @@ -356,7 +361,7 @@ public class DefaultLwM2MRpcRequestHandler implements LwM2MRpcRequestHandler { if (requestParams.getKeys() != null && requestParams.getKeys().length > 0) { Set targetIds = ConcurrentHashMap.newKeySet(); for (String key : requestParams.getKeys()) { - String targetId = clientContext.getObjectIdByKeyNameFromProfile(client, key, true); + String targetId = clientContext.getObjectIdByKeyNameFromProfile(client, key); if (targetId != null) { targetIds.add(targetId); } @@ -384,4 +389,16 @@ public class DefaultLwM2MRpcRequestHandler implements LwM2MRpcRequestHandler { public void onToServerRpcResponse(TransportProtos.ToServerRpcResponseMsg toServerResponse) { log.info("[{}] toServerRpcResponse", toServerResponse); } + + private ContentFormat getContentFormatComposite(LwM2mClient client) { + if (client.getClientSupportContentFormats().contains(ContentFormat.SENML_JSON)) { + return ContentFormat.SENML_JSON; + } + else if (client.getClientSupportContentFormats().contains(ContentFormat.SENML_CBOR)) { + return ContentFormat.SENML_CBOR; + } + else { + return null; + } + } } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2mTransportUtil.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2mTransportUtil.java index 76e5ce4d91..b04868c501 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2mTransportUtil.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2mTransportUtil.java @@ -63,7 +63,6 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; -import java.util.Set; import static org.eclipse.leshan.core.attributes.Attribute.DIMENSION; import static org.eclipse.leshan.core.attributes.Attribute.GREATER_THAN; @@ -220,7 +219,7 @@ public class LwM2mTransportUtil { } catch (Exception e) { return null; } - return null; + return LWM2M_OBJECT_VERSION_DEFAULT; } public static String validPathIdVer(String pathIdVer, Registration registration) throws @@ -354,14 +353,6 @@ public class LwM2mTransportUtil { } } - public static String getMsgException(String keyName, Set msgException) { - if (msgException.size() == 1) { - msgException.add(" is not configured in the device profile!"); - } - msgException.remove(""); - return String.format("%s %s", keyName, String.join(",", msgException)).trim(); - } - public static Map convertMultiResourceValuesFromRpcBody(Object value, ResourceModel.Type type, String versionedId) throws Exception { String valueJsonStr = JsonUtils.riteValueAsString(value); return convertMultiResourceValuesFromJson((JsonObject) JsonUtils.parse(valueJsonStr), type, versionedId); diff --git a/common/util/src/main/java/org/thingsboard/common/util/JacksonUtil.java b/common/util/src/main/java/org/thingsboard/common/util/JacksonUtil.java index a71be5fe5f..ddd074fc6c 100644 --- a/common/util/src/main/java/org/thingsboard/common/util/JacksonUtil.java +++ b/common/util/src/main/java/org/thingsboard/common/util/JacksonUtil.java @@ -23,8 +23,8 @@ import com.fasterxml.jackson.databind.node.ObjectNode; import java.io.IOException; import java.util.Arrays; +import java.util.HashSet; import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; /** * Created by Valerii Sosliuk on 5/12/2017. @@ -126,22 +126,35 @@ public class JacksonUtil { } + /** + * + * @param {bootstrap:client:host, client, client:port, client:endpoint} + * @param ":" + * @return + * - "bootstrap:client:host" + * -- if in nodeCredentialsValue is absent: + * --- "bootstrap" or "bootstrap:client" or "bootstrap:client:host" -> return "host" + * -- if in nodeCredentialsValue is absent: + * --- "client:port" -> return "port" + * -- if the nodeCredentialsValue contains: + * --- "client" and "client:port" -> "port" not add to Set + */ public static String validateFieldsToTree(JsonNode nodeCredentialsValue, String[] fields, String delimiter) { try { - Set msgSet = ConcurrentHashMap.newKeySet(); + StringBuilder msgSet = new StringBuilder(); for (String field : fields) { String[] keys = field.split(delimiter); JsonNode nodeVal = nodeCredentialsValue; for (String key : keys) { if (!nodeVal.hasNonNull(key)) { - msgSet.add(keys[keys.length - 1]); + msgSet.append(" " + keys[keys.length - 1]); break; } else { nodeVal = nodeVal.get(key); } } } - return String.join(", ", msgSet); + return msgSet.toString().trim(); } catch (Exception e) { throw new IllegalArgumentException(e); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java index adbaff5389..913ee19d1c 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java @@ -133,9 +133,6 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D @Autowired private DashboardService dashboardService; - @Autowired - private DeviceCredentialsService deviceCredentialsService; - private final Lock findOrCreateLock = new ReentrantLock(); @Cacheable(cacheNames = DEVICE_PROFILE_CACHE, key = "{#deviceProfileId.id}") From 0a9553b83cdc8473b1362a2a8fed68fb3ee4094c Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Sun, 19 Sep 2021 19:03:14 +0300 Subject: [PATCH 041/432] Lwm2m Fix bug review edit tests --- .../lwm2m/AbstractLwM2MIntegrationTest.java | 1 + .../lwm2m/client/LwM2MTestClient.java | 8 +- .../rpc/AbstractRpcLwM2MIntegrationTest.java | 137 +++++++++--------- .../rpc/sql/RpcLwm2mIntegrationWriteTest.java | 2 +- .../DefaultLwM2MAttributesService.java | 17 ++- .../lwm2m/server/client/LwM2mClient.java | 4 +- .../DefaultLwM2mDownlinkMsgHandler.java | 70 +++++---- .../rpc/DefaultLwM2MRpcRequestHandler.java | 36 +++-- .../lwm2m/utils/LwM2mTransportUtil.java | 11 +- 9 files changed, 160 insertions(+), 126 deletions(-) diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/AbstractLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/AbstractLwM2MIntegrationTest.java index 225ae056e9..e2b70a4490 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/AbstractLwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/AbstractLwM2MIntegrationTest.java @@ -261,6 +261,7 @@ public abstract class AbstractLwM2MIntegrationTest extends AbstractWebsocketTest client = new LwM2MTestClient(this.executor, this.endpoint); int clientPort = SocketUtils.findAvailableTcpPort(); client.init(security, coapConfig, clientPort); + client.start(); } private void clientDestroy() { diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2MTestClient.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2MTestClient.java index 3fc83625ba..f4ef1463d5 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2MTestClient.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2MTestClient.java @@ -250,8 +250,6 @@ public class LwM2MTestClient { } }; this.client.addObserver(observer); - - client.start(); } public void destroy() { @@ -278,4 +276,10 @@ public class LwM2MTestClient { } } + public void start() { + if (client != null) { + client.start(); + } + } + } diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/AbstractRpcLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/AbstractRpcLwM2MIntegrationTest.java index 83bb46e934..56668bbe56 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/AbstractRpcLwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/AbstractRpcLwM2MIntegrationTest.java @@ -50,63 +50,7 @@ import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resources; @DaoSqlTest public abstract class AbstractRpcLwM2MIntegrationTest extends AbstractLwM2MIntegrationTest { - protected final String RPC_TRANSPORT_CONFIGURATION = "{\n" + - " \"type\": \"LWM2M\",\n" + - " \"observeAttr\": {\n" + - " \"keyName\": {\n" + - " \"" + "/" + DEVICE + "/" + objectInstanceId_0 + "/" + resourceId_9 + "\": \"" + resourceIdName_3_9 + "\",\n" + - " \"" + "/" + DEVICE + "/" + objectInstanceId_0 + "/" + resourceId_14 + "\": \"" + resourceIdName_3_14 + "\",\n" + - " \"" + "/" + BINARY_APP_DATA_CONTAINER + "/" + objectInstanceId_0 + "/" + resourceId_0 + "\": \"" + resourceIdName_19_0_0 + "\",\n" + - " \"" + "/" + BINARY_APP_DATA_CONTAINER + "/" + objectInstanceId_1 + "/" + resourceId_0 + "\": \"" + resourceIdName_19_1_0 + "\"\n" + - " },\n" + - " \"observe\": [\n" + - " \"" + "/" + DEVICE + "/" + objectInstanceId_0 + "/" + resourceId_9 + "\",\n" + - " \"" + "/" + BINARY_APP_DATA_CONTAINER + "/" + objectInstanceId_0 + "/" + resourceId_0 + "\"\n" + - " ],\n" + - " \"attribute\": [\n" + - " ],\n" + - " \"telemetry\": [\n" + - " \"" + "/" + DEVICE + "/" + objectInstanceId_0 + "/" + resourceId_9 + "\",\n" + - " \"" + "/" + DEVICE + "/" + objectInstanceId_0 + "/" + resourceId_14 + "\",\n" + - " \"" + "/" + BINARY_APP_DATA_CONTAINER + "/" + objectInstanceId_0 + "/" + resourceId_0 + "\",\n" + - " \"" + "/" + BINARY_APP_DATA_CONTAINER + "/" + objectInstanceId_1 + "/" + resourceId_0 + "\"\n" + - " ],\n" + - " \"attributeLwm2m\": {}\n" + - " },\n" + - " \"bootstrap\": {\n" + - " \"servers\": {\n" + - " \"binding\": \"U\",\n" + - " \"shortId\": 123,\n" + - " \"lifetime\": 300,\n" + - " \"notifIfDisabled\": true,\n" + - " \"defaultMinPeriod\": 1\n" + - " },\n" + - " \"lwm2mServer\": {\n" + - " \"host\": \"localhost\",\n" + - " \"port\": 5686,\n" + - " \"serverId\": 123,\n" + - " \"serverPublicKey\": \"\",\n" + - " \"bootstrapServerIs\": false,\n" + - " \"clientHoldOffTime\": 1,\n" + - " \"bootstrapServerAccountTimeout\": 0\n" + - " },\n" + - " \"bootstrapServer\": {\n" + - " \"host\": \"localhost\",\n" + - " \"port\": 5687,\n" + - " \"serverId\": 111,\n" + - " \"securityMode\": \"NO_SEC\",\n" + - " \"serverPublicKey\": \"\",\n" + - " \"bootstrapServerIs\": true,\n" + - " \"clientHoldOffTime\": 1,\n" + - " \"bootstrapServerAccountTimeout\": 0\n" + - " }\n" + - " },\n" + - " \"clientLwM2mSettings\": {\n" + - " \"clientOnlyObserveAfterConnect\": 1,\n" + - " \"fwUpdateStrategy\": 1,\n" + - " \"swUpdateStrategy\": 1\n" + - " }\n" + - "}"; + protected String RPC_TRANSPORT_CONFIGURATION; protected static final String ENDPOINT_RPC = "deviceEndpointRpc"; protected ScheduledExecutorService executor; @@ -137,13 +81,6 @@ public abstract class AbstractRpcLwM2MIntegrationTest extends AbstractLwM2MInteg @Before public void beforeTest() throws Exception { init(); - createDeviceProfile(RPC_TRANSPORT_CONFIGURATION); - - Thread.sleep(1000); - - NoSecClientCredentials credentials = createNoSecClientCredentials(ENDPOINT_RPC); - final Device device = createDevice(credentials); - deviceId = device.getId().getId().toString(); createNewClient (SECURITY, COAP_CONFIG); Thread.sleep(1000); @@ -182,7 +119,76 @@ public abstract class AbstractRpcLwM2MIntegrationTest extends AbstractLwM2MInteg objectInstanceIdVer_3 = (String) expectedObjectIdVerInstances.stream().filter(predicate_3).findFirst().get(); objectInstanceIdVer_5 = (String) expectedObjectIdVerInstances.stream().filter(path -> ((String) path).contains("/" + FIRMWARE)).findFirst().get(); objectInstanceIdVer_9 = (String) expectedObjectIdVerInstances.stream().filter(path -> ((String) path).contains("/" + SOFTWARE_MANAGEMENT)).findFirst().get(); - } + + RPC_TRANSPORT_CONFIGURATION = "{\n" + + " \"type\": \"LWM2M\",\n" + + " \"observeAttr\": {\n" + + " \"keyName\": {\n" + + " \"" + objectIdVer_3 + "/" + objectInstanceId_0 + "/" + resourceId_9 + "\": \"" + resourceIdName_3_9 + "\",\n" + + " \"" + objectIdVer_3 + "/" + objectInstanceId_0 + "/" + resourceId_14 + "\": \"" + resourceIdName_3_14 + "\",\n" + + " \"" + objectIdVer_19 + "/" + objectInstanceId_0 + "/" + resourceId_0 + "\": \"" + resourceIdName_19_0_0 + "\",\n" + + " \"" + objectIdVer_19 + "/" + objectInstanceId_1 + "/" + resourceId_0 + "\": \"" + resourceIdName_19_1_0 + "\"\n" + + " },\n" + + " \"observe\": [\n" + + " \"" + objectIdVer_3 + "/" + objectInstanceId_0 + "/" + resourceId_9 + "\",\n" + + " \"" + objectIdVer_19 + "/" + objectInstanceId_0 + "/" + resourceId_0 + "\"\n" + + " ],\n" + + " \"attribute\": [\n" + + " ],\n" + + " \"telemetry\": [\n" + + " \"" + objectIdVer_3 + "/" + objectInstanceId_0 + "/" + resourceId_9 + "\",\n" + + " \"" + objectIdVer_3 + "/" + objectInstanceId_0 + "/" + resourceId_14 + "\",\n" + + " \"" + objectIdVer_19 + "/" + objectInstanceId_0 + "/" + resourceId_0 + "\",\n" + + " \"" + objectIdVer_19 + "/" + objectInstanceId_1 + "/" + resourceId_0 + "\"\n" + + " ],\n" + + " \"attributeLwm2m\": {}\n" + + " },\n" + + " \"bootstrap\": {\n" + + " \"servers\": {\n" + + " \"binding\": \"U\",\n" + + " \"shortId\": 123,\n" + + " \"lifetime\": 300,\n" + + " \"notifIfDisabled\": true,\n" + + " \"defaultMinPeriod\": 1\n" + + " },\n" + + " \"lwm2mServer\": {\n" + + " \"host\": \"localhost\",\n" + + " \"port\": 5686,\n" + + " \"serverId\": 123,\n" + + " \"serverPublicKey\": \"\",\n" + + " \"bootstrapServerIs\": false,\n" + + " \"clientHoldOffTime\": 1,\n" + + " \"bootstrapServerAccountTimeout\": 0\n" + + " },\n" + + " \"bootstrapServer\": {\n" + + " \"host\": \"localhost\",\n" + + " \"port\": 5687,\n" + + " \"serverId\": 111,\n" + + " \"securityMode\": \"NO_SEC\",\n" + + " \"serverPublicKey\": \"\",\n" + + " \"bootstrapServerIs\": true,\n" + + " \"clientHoldOffTime\": 1,\n" + + " \"bootstrapServerAccountTimeout\": 0\n" + + " }\n" + + " },\n" + + " \"clientLwM2mSettings\": {\n" + + " \"clientOnlyObserveAfterConnect\": 1,\n" + + " \"fwUpdateStrategy\": 1,\n" + + " \"swUpdateStrategy\": 1\n" + + " }\n" + + "}"; + createDeviceProfile(RPC_TRANSPORT_CONFIGURATION); + + Thread.sleep(1000); + + NoSecClientCredentials credentials = createNoSecClientCredentials(ENDPOINT_RPC); + final Device device = createDevice(credentials); + deviceId = device.getId().getId().toString(); + + Thread.sleep(1000); + + client.start(); + } protected String pathIdVerToObjectId(String pathIdVer) { if (pathIdVer.contains("_")){ @@ -192,4 +198,5 @@ public abstract class AbstractRpcLwM2MIntegrationTest extends AbstractLwM2MInteg } return pathIdVer; } + } diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationWriteTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationWriteTest.java index 3bc9c075f1..de0a22756d 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationWriteTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationWriteTest.java @@ -121,7 +121,7 @@ public class RpcLwm2mIntegrationWriteTest extends AbstractRpcLwM2MIntegrationTes ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); assertEquals(ResponseCode.BAD_REQUEST.getName(), rpcActualResult.get("result").asText()); String actualValues = rpcActualResult.get("error").asText(); - String expected = "Resource value is: String. Value of Multi-Instance Resource must be in Json format!"; + String expected = "is bad. Value of Multi-Instance Resource must be in Json format!"; assertTrue(actualValues.contains(expected)); } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/attributes/DefaultLwM2MAttributesService.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/attributes/DefaultLwM2MAttributesService.java index e54277060a..cfbc21e57c 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/attributes/DefaultLwM2MAttributesService.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/attributes/DefaultLwM2MAttributesService.java @@ -18,7 +18,6 @@ package org.thingsboard.server.transport.lwm2m.server.attributes; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.SettableFuture; import com.google.gson.JsonElement; -import com.google.gson.JsonObject; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.eclipse.leshan.core.model.ResourceModel; @@ -223,8 +222,15 @@ public class DefaultLwM2MAttributesService implements LwM2MAttributesService { if (!resourceModel.multiple || !(newValProto instanceof JsonElement)) { this.pushUpdateToClientIfNeeded(lwM2MClient, oldResourceValue, newValProto, pathIdVer, logFailedUpdateOfNonChangedValue, resourceModel.type); } else { - pushUpdateMultiToClientIfNeeded(lwM2MClient, resourceModel, (JsonElement) newValProto, - (Map) oldResourceValue, pathIdVer, logFailedUpdateOfNonChangedValue); + try { + pushUpdateMultiToClientIfNeeded(lwM2MClient, resourceModel, (JsonElement) newValProto, + (Map) oldResourceValue, pathIdVer, logFailedUpdateOfNonChangedValue); + } catch (Exception e){ + log.error("Failed update resource ["+lwM2MClient.getEndpoint()+"] onAttributesUpdate:", e); + String logMsg = String.format("%s: Failed update resource onAttributesUpdate %s.", + LOG_LWM2M_ERROR, e.getMessage()); + logService.log(lwM2MClient, logMsg); + } } }); } @@ -250,8 +256,9 @@ public class DefaultLwM2MAttributesService implements LwM2MAttributesService { } private void pushUpdateMultiToClientIfNeeded(LwM2mClient client, ResourceModel resourceModel, JsonElement newValProto, - Map valueOld, String versionedId, boolean logFailedUpdateOfNonChangedValue) { - Map newValues = convertMultiResourceValuesFromJson((JsonObject) newValProto, resourceModel.type, versionedId); + Map valueOld, String versionedId, + boolean logFailedUpdateOfNonChangedValue) throws Exception { + Map newValues = convertMultiResourceValuesFromJson(newValProto, resourceModel.type, versionedId); if (newValues.size() > 0 && valueOld != null && valueOld.size() > 0) { valueOld.values().stream().forEach((v) -> { if (newValues.containsKey(v.getId())) { diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java index 2cc69f2c58..b5db43e66e 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java @@ -334,8 +334,8 @@ public class LwM2mClient implements Serializable { Map values = convertMultiResourceValuesFromRpcBody(value, resourceModel.type, pathRezIdVer); resource = LwM2mMultipleResource.newResource(resourceId, (Map) values, resourceModel.type); } catch (Exception e) { - throw new IllegalArgumentException("Resource id=" + resourceId + ", value = " + value + ", class = " + - value.getClass().getSimpleName() + "is bad. Value of Multi-Instance Resource must be in Json format!"); + throw new IllegalArgumentException("Resource id=" + resourceId + ", class = " + + value.getClass().getSimpleName() + ", value = " + value + " is bad. Value of Multi-Instance Resource must be in Json format!"); } } else { Object valueRez = value instanceof Integer ? ((Integer) value).longValue() : value; diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2mDownlinkMsgHandler.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2mDownlinkMsgHandler.java index 71a27def66..c980fde4ad 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2mDownlinkMsgHandler.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2mDownlinkMsgHandler.java @@ -378,9 +378,10 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im resultIds.getObjectInstanceId(), resultIds.getResourceId(), value, resourceModelWrite.type); } catch (Exception e1) { - callback.onValidationError(toString(request), "Resource id=" + resultIds.toString() + ", value = " + - request.getValue() + ", class = " + request.getValue().getClass().getSimpleName() + - "is bad. Value of Multi-Instance Resource must be in Json format!"); + callback.onValidationError(toString(request), "Resource id=" + resultIds.toString() + + ", class = " + request.getValue().getClass().getSimpleName() + + ", value = " + request.getValue() + " is bad. " + + "Value of Multi-Instance Resource must be in Json format!"); } } } else { @@ -408,43 +409,48 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im validateVersionedId(client, request); CreateRequest downlink = null; LwM2mPath resultIds = new LwM2mPath(request.getObjectId()); - ObjectModel objectModel = client.getObjectModel(request.getObjectId(), this.config.getModelProvider()); + ObjectModel objectModel = client.getObjectModel(request.getVersionedId(), this.config.getModelProvider()); // POST /{Object ID}/{Object Instance ID} && Resources is Mandatory - if (objectModel.multiple) { - // LwM2M CBOR, SenML CBOR, SenML JSON, or TLV (see [LwM2M-CORE]) - ContentFormat contentFormat = getWriteRequestContentFormat(client, request, this.config.getModelProvider()); - if (resultIds.isObject() || resultIds.isObjectInstance()) { - Collection resources; - if (resultIds.isObject()) { - if (request.getValue() != null) { + if (objectModel != null) { + if (objectModel.multiple) { + + // LwM2M CBOR, SenML CBOR, SenML JSON, or TLV (see [LwM2M-CORE]) + ContentFormat contentFormat = getWriteRequestContentFormat(client, request, this.config.getModelProvider()); + if (resultIds.isObject() || resultIds.isObjectInstance()) { + Collection resources; + if (resultIds.isObject()) { + if (request.getValue() != null) { + resources = client.getNewResourcesForInstance(request.getVersionedId(), request.getValue(), this.config.getModelProvider(), this.converter); + downlink = new CreateRequest(contentFormat, resultIds.getObjectId(), resources); + } else if (request.getNodes() != null && request.getNodes().size() > 0) { + Set instances = ConcurrentHashMap.newKeySet(); + request.getNodes().forEach((key, value) -> { + Collection resourcesForInstance = client.getNewResourcesForInstance(request.getVersionedId(), value, this.config.getModelProvider(), this.converter); + LwM2mObjectInstance instance = new LwM2mObjectInstance(Integer.parseInt(key), resourcesForInstance); + instances.add(instance); + }); + LwM2mObjectInstance[] instanceArrays = instances.toArray(new LwM2mObjectInstance[instances.size()]); + downlink = new CreateRequest(contentFormat, resultIds.getObjectId(), instanceArrays); + } + + } else { resources = client.getNewResourcesForInstance(request.getVersionedId(), request.getValue(), this.config.getModelProvider(), this.converter); - downlink = new CreateRequest(contentFormat, resultIds.getObjectId(), resources); - } else if (request.getNodes() != null && request.getNodes().size() > 0) { - Set instances = ConcurrentHashMap.newKeySet(); - request.getNodes().forEach((key, value) -> { - Collection resourcesForInstance = client.getNewResourcesForInstance(request.getVersionedId(), value, this.config.getModelProvider(), this.converter); - LwM2mObjectInstance instance = new LwM2mObjectInstance(Integer.parseInt(key), resourcesForInstance); - instances.add(instance); - }); - LwM2mObjectInstance[] instanceArrays = instances.toArray(new LwM2mObjectInstance[instances.size()]); - downlink = new CreateRequest(contentFormat, resultIds.getObjectId(), instanceArrays); + LwM2mObjectInstance instance = new LwM2mObjectInstance(resultIds.getObjectInstanceId(), resources); + downlink = new CreateRequest(contentFormat, resultIds.getObjectId(), instance); } - + } + if (downlink != null) { + sendSimpleRequest(client, downlink, request.getTimeout(), callback); } else { - resources = client.getNewResourcesForInstance(request.getVersionedId(), request.getValue(), this.config.getModelProvider(), this.converter); - LwM2mObjectInstance instance = new LwM2mObjectInstance(resultIds.getObjectInstanceId(), resources); - downlink = new CreateRequest(contentFormat, resultIds.getObjectId(), instance); + callback.onValidationError(toString(request), "Path " + request.getVersionedId() + + ". Object must be Multiple !"); } - } - if (downlink != null) { - sendSimpleRequest(client, downlink, request.getTimeout(), callback); } else { - callback.onValidationError(toString(request), "Path " + request.getVersionedId() + - ". This operation can only be used for created new ObjectInstance !"); + throw new IllegalArgumentException("Path " + request.getVersionedId() + ". Object must be Multiple !"); } } else { - throw new IllegalArgumentException("Path " + request.getVersionedId() + - ". Object must be Multiple !"); + callback.onValidationError(toString(request), "Resource " + request.getVersionedId() + + " is not configured in the device profile!"); } } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/DefaultLwM2MRpcRequestHandler.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/DefaultLwM2MRpcRequestHandler.java index a881047f91..6501d443a2 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/DefaultLwM2MRpcRequestHandler.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/DefaultLwM2MRpcRequestHandler.java @@ -15,6 +15,7 @@ */ package org.thingsboard.server.transport.lwm2m.server.rpc; +import com.google.gson.JsonElement; import com.google.gson.JsonSyntaxException; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -260,8 +261,8 @@ public class DefaultLwM2MRpcRequestHandler implements LwM2MRpcRequestHandler { Map value = convertMultiResourceValuesFromRpcBody(requestBody.getValue(), resourceModel.type, versionedId); requestBody.setValue(value); } catch (Exception e) { - throw new IllegalArgumentException("Resource id=" + versionedId + ", value = " + requestBody.getValue() + ", class = " + - requestBody.getValue().getClass().getSimpleName() + "is bad. Value of Multi-Instance Resource must be in Json format!"); + throw new IllegalArgumentException("Resource id=" + versionedId + ", class = " + + requestBody.getValue().getClass().getSimpleName() + ", value = " + requestBody.getValue() + " is bad. Value of Multi-Instance Resource must be in Json format!"); } } } @@ -300,21 +301,28 @@ public class DefaultLwM2MRpcRequestHandler implements LwM2MRpcRequestHandler { String versionedId; try { // validate key.toString() - new LwM2mPath(fromVersionedIdToObjectId(key.toString())); - versionedId = key.toString(); + LwM2mPath path = new LwM2mPath(fromVersionedIdToObjectId(key.toString())); + if (path.isResource() || path.isResourceInstance()) { + versionedId = key.toString(); + } + else { + throw new IllegalArgumentException(String.format("nodes: %s is not validate value. " + + "The WriteComposite operation is only used for SingleResources or/and ResourceInstance.", nodes.toString())); + } } catch (Exception e) { versionedId = clientContext.getObjectIdByKeyNameFromProfile(client, key.toString()); } - // validate value. Must be only primitive, not Json + // validate value. Must be only primitive, not JsonObject or JsonArray try { - JsonUtils.parse(value.toString()); - throw new IllegalArgumentException(String.format("nodes: %s is not validate value. " + - "The WriteComposite operation is only used for SingleResources or/and ResourceInstance.", nodes.toString())); + JsonElement element = JsonUtils.parse(value.toString()); + if (!element.isJsonNull() && !element.isJsonPrimitive()) { + throw new IllegalArgumentException(String.format("nodes: %s is not validate value. " + + "The WriteComposite operation is only used for SingleResources or/and ResourceInstance.", nodes.toString())); + } + else if (versionedId != null) { + newNodes.put(fromVersionedIdToObjectId(versionedId), value); + } } catch (JsonSyntaxException jse) { -// if (value instanceof LinkedHashMap) { -// throw new IllegalArgumentException(String.format("nodes: %s is not validate value. " + -// "The WriteComposite operation is only used for SingleResources or/and ResourceInstance.", nodes.toString())); -// } if (versionedId != null) { newNodes.put(fromVersionedIdToObjectId(versionedId), value); } @@ -356,8 +364,8 @@ public class DefaultLwM2MRpcRequestHandler implements LwM2MRpcRequestHandler { return targetId; } - private String[] getIdsFromParameters(LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg rpcRequst) { - RpcReadCompositeRequest requestParams = JacksonUtil.fromString(rpcRequst.getParams(), RpcReadCompositeRequest.class); + private String[] getIdsFromParameters(LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg rpcRequest) { + RpcReadCompositeRequest requestParams = JacksonUtil.fromString(rpcRequest.getParams(), RpcReadCompositeRequest.class); if (requestParams.getKeys() != null && requestParams.getKeys().length > 0) { Set targetIds = ConcurrentHashMap.newKeySet(); for (String key : requestParams.getKeys()) { diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2mTransportUtil.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2mTransportUtil.java index b04868c501..23ee5a0a57 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2mTransportUtil.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2mTransportUtil.java @@ -16,7 +16,7 @@ package org.thingsboard.server.transport.lwm2m.utils; import com.fasterxml.jackson.core.type.TypeReference; -import com.google.gson.JsonObject; +import com.google.gson.JsonElement; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.eclipse.leshan.core.attributes.Attribute; @@ -214,12 +214,12 @@ public class LwM2mTransportUtil { String[] keyArray = path.split(LWM2M_SEPARATOR_PATH); if (keyArray.length > 1) { String[] keyArrayVer = keyArray[1].split(LWM2M_SEPARATOR_KEY); - return keyArrayVer.length == 2 ? keyArrayVer[1] : null; + return keyArrayVer.length == 2 ? keyArrayVer[1] : LWM2M_OBJECT_VERSION_DEFAULT; } } catch (Exception e) { return null; } - return LWM2M_OBJECT_VERSION_DEFAULT; + return null; } public static String validPathIdVer(String pathIdVer, Registration registration) throws @@ -355,10 +355,11 @@ public class LwM2mTransportUtil { public static Map convertMultiResourceValuesFromRpcBody(Object value, ResourceModel.Type type, String versionedId) throws Exception { String valueJsonStr = JsonUtils.riteValueAsString(value); - return convertMultiResourceValuesFromJson((JsonObject) JsonUtils.parse(valueJsonStr), type, versionedId); + JsonElement element = JsonUtils.parse(valueJsonStr); + return convertMultiResourceValuesFromJson(element, type, versionedId); } - public static Map convertMultiResourceValuesFromJson(JsonObject newValProto, ResourceModel.Type type, String versionedId) { + public static Map convertMultiResourceValuesFromJson(JsonElement newValProto, ResourceModel.Type type, String versionedId) throws Exception{ Map newValues = equalsMultiResourceValuesResourceType(type); newValProto.getAsJsonObject().entrySet().forEach((obj) -> { newValues.put(Integer.valueOf(obj.getKey()), LwM2mValueConverterImpl.getInstance().convertValue(obj.getValue().getAsString(), From 45921f89f47823b4e713060755fc85b245ae24c7 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Sun, 19 Sep 2021 21:25:33 +0300 Subject: [PATCH 042/432] Lwm2m Fix bug review edit tests security --- .../transport/lwm2m/AbstractLwM2MIntegrationTest.java | 7 +++---- .../server/transport/lwm2m/client/LwM2MTestClient.java | 6 ++++-- .../transport/lwm2m/ota/sql/OtaLwM2MIntegrationTest.java | 6 +++--- .../lwm2m/rpc/AbstractRpcLwM2MIntegrationTest.java | 2 +- 4 files changed, 11 insertions(+), 10 deletions(-) diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/AbstractLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/AbstractLwM2MIntegrationTest.java index e2b70a4490..0bdc221b1b 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/AbstractLwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/AbstractLwM2MIntegrationTest.java @@ -186,7 +186,7 @@ public abstract class AbstractLwM2MIntegrationTest extends AbstractWebsocketTest wsClient.registerWaitForUpdate(); this.endpoint = endpoint; - createNewClient (security, coapConfig); + createNewClient (security, coapConfig, false); String msg = wsClient.waitForUpdate(); EntityDataUpdate update = mapper.readValue(msg, EntityDataUpdate.class); @@ -256,12 +256,11 @@ public abstract class AbstractLwM2MIntegrationTest extends AbstractWebsocketTest this.endpoint = endpoint; } - public void createNewClient (Security security, NetworkConfig coapConfig) throws Exception { + public void createNewClient (Security security, NetworkConfig coapConfig, boolean isRpc) throws Exception { clientDestroy(); client = new LwM2MTestClient(this.executor, this.endpoint); int clientPort = SocketUtils.findAvailableTcpPort(); - client.init(security, coapConfig, clientPort); - client.start(); + client.init(security, coapConfig, clientPort, isRpc); } private void clientDestroy() { diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2MTestClient.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2MTestClient.java index f4ef1463d5..1c62b2b79d 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2MTestClient.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2MTestClient.java @@ -46,7 +46,6 @@ import org.eclipse.leshan.core.request.RegisterRequest; import org.eclipse.leshan.core.request.UpdateRequest; import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl; import org.junit.Assert; -import org.junit.Assert; import java.io.IOException; import java.net.InetSocketAddress; @@ -85,7 +84,7 @@ public class LwM2MTestClient { private LwM2MLocationParams locationParams; private LwM2mTemperatureSensor lwM2MTemperatureSensor; - public void init(Security security, NetworkConfig coapConfig, int port) throws InvalidDDFFileException, IOException { + public void init(Security security, NetworkConfig coapConfig, int port, boolean isRpc) throws InvalidDDFFileException, IOException { Assert.assertNull("client already initialized", client); List models = new ArrayList<>(); for (String resourceName : resources) { @@ -250,6 +249,9 @@ public class LwM2MTestClient { } }; this.client.addObserver(observer); + if (!isRpc) { + client.start(); + } } public void destroy() { diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/ota/sql/OtaLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/ota/sql/OtaLwM2MIntegrationTest.java index de7c432564..68f8c98d6f 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/ota/sql/OtaLwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/ota/sql/OtaLwM2MIntegrationTest.java @@ -137,7 +137,7 @@ public class OtaLwM2MIntegrationTest extends AbstractOtaLwM2MIntegrationTest { createDeviceProfile(transportConfiguration); NoSecClientCredentials credentials = createNoSecClientCredentials(endpoint); final Device device = createDevice(credentials); - createNewClient(SECURITY, COAP_CONFIG); + createNewClient(SECURITY, COAP_CONFIG, false); Thread.sleep(1000); @@ -164,7 +164,7 @@ public class OtaLwM2MIntegrationTest extends AbstractOtaLwM2MIntegrationTest { createDeviceProfile(OTA_TRANSPORT_CONFIGURATION); NoSecClientCredentials credentials = createNoSecClientCredentials(endpoint); final Device device = createDevice(credentials); - createNewClient(SECURITY, COAP_CONFIG); + createNewClient(SECURITY, COAP_CONFIG, false); Thread.sleep(1000); @@ -203,7 +203,7 @@ public class OtaLwM2MIntegrationTest extends AbstractOtaLwM2MIntegrationTest { createDeviceProfile(OTA_TRANSPORT_CONFIGURATION); NoSecClientCredentials credentials = createNoSecClientCredentials(endpoint); final Device device = createDevice(credentials); - createNewClient(SECURITY, COAP_CONFIG); + createNewClient(SECURITY, COAP_CONFIG, false); Thread.sleep(1000); diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/AbstractRpcLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/AbstractRpcLwM2MIntegrationTest.java index 56668bbe56..ab08379389 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/AbstractRpcLwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/AbstractRpcLwM2MIntegrationTest.java @@ -81,7 +81,7 @@ public abstract class AbstractRpcLwM2MIntegrationTest extends AbstractLwM2MInteg @Before public void beforeTest() throws Exception { init(); - createNewClient (SECURITY, COAP_CONFIG); + createNewClient (SECURITY, COAP_CONFIG, true); Thread.sleep(1000); From 7f681a993fc42810d8047ffdcbaa92169bc1241f Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Tue, 21 Sep 2021 16:36:03 +0300 Subject: [PATCH 043/432] Lwm2m Fix bug review edit formatting & Lwm2m to LwM2M --- .../server/controller/Lwm2mController.java | 3 +- ....java => LwM2MBinaryAppDataContainer.java} | 6 +- ...{LwM2mLocation.java => LwM2MLocation.java} | 8 +- ...ensor.java => LwM2MTemperatureSensor.java} | 6 +- .../lwm2m/client/LwM2MTestClient.java | 16 +- ...ava => RpcLwM2MIntegrationCreateTest.java} | 2 +- ...ava => RpcLwM2MIntegrationDeleteTest.java} | 2 +- ...a => RpcLwM2MIntegrationDiscoverTest.java} | 2 +- ...va => RpcLwM2MIntegrationExecuteTest.java} | 2 +- ...va => RpcLwM2MIntegrationObserveTest.java} | 2 +- ....java => RpcLwM2MIntegrationReadTest.java} | 2 +- ...cLwM2MIntegrationWriteAttributesTest.java} | 2 +- ...java => RpcLwM2MIntegrationWriteTest.java} | 2 +- ...Test.java => PskLwM2MIntegrationTest.java} | 2 +- .../LwM2mTransportServerHelperTest.java | 10 +- .../LwM2MTransportBootstrapService.java | 6 +- .../secure/LwM2MBootstrapSecurityStore.java | 32 ++-- .../LwM2mDefaultBootstrapSessionManager.java | 10 +- ...wM2MCredentialsSecurityInfoValidator.java} | 14 +- ...dentials.java => LwM2MRPkCredentials.java} | 4 +- .../lwm2m/secure/TbLwM2MAuthorizer.java | 4 +- .../TbLwM2MDtlsCertificateVerifier.java | 4 +- ...va => AbstractLwM2MTransportResource.java} | 4 +- ...java => DefaultLwM2MTransportService.java} | 22 +-- ...orkConfig.java => LwM2MNetworkConfig.java} | 2 +- ...ationType.java => LwM2MOperationType.java} | 10 +- ...2mOtaConvert.java => LwM2MOtaConvert.java} | 2 +- ...edRequest.java => LwM2MQueuedRequest.java} | 2 +- ...Listener.java => LwM2MServerListener.java} | 10 +- ...ener.java => LwM2MSessionMsgListener.java} | 6 +- ...e.java => LwM2MTransportCoapResource.java} | 4 +- ...ontext.java => LwM2MTransportContext.java} | 2 +- ...r.java => LwM2MTransportServerHelper.java} | 4 +- ....java => LwM2MVersionedModelProvider.java} | 10 +- .../DefaultLwM2MAttributesService.java | 50 +++--- .../attributes/LwM2MAttributesService.java | 6 +- .../{LwM2mClient.java => LwM2MClient.java} | 19 +- ...ntContext.java => LwM2MClientContext.java} | 34 ++-- ...tImpl.java => LwM2MClientContextImpl.java} | 68 +++---- .../AbstractTbLwM2MRequestCallback.java | 8 +- ...va => DefaultLwM2MDownlinkMsgHandler.java} | 170 +++++++++--------- .../lwm2m/server/downlink/HasVersionedId.java | 4 +- .../server/downlink/HasVersionedIds.java | 4 +- ...dler.java => LwM2MDownlinkMsgHandler.java} | 34 ++-- .../TbLwM2MCancelAllObserveCallback.java | 6 +- .../downlink/TbLwM2MCancelAllRequest.java | 6 +- .../TbLwM2MCancelObserveCallback.java | 6 +- .../downlink/TbLwM2MCancelObserveRequest.java | 6 +- .../server/downlink/TbLwM2MCreateRequest.java | 6 +- .../TbLwM2MCreateResponseCallback.java | 6 +- .../downlink/TbLwM2MDeleteCallback.java | 4 +- .../server/downlink/TbLwM2MDeleteRequest.java | 6 +- .../downlink/TbLwM2MDiscoverAllRequest.java | 6 +- .../downlink/TbLwM2MDiscoverCallback.java | 4 +- .../downlink/TbLwM2MDiscoverRequest.java | 6 +- .../downlink/TbLwM2MDownlinkRequest.java | 4 +- .../downlink/TbLwM2MExecuteCallback.java | 4 +- .../downlink/TbLwM2MExecuteRequest.java | 6 +- .../downlink/TbLwM2MObserveAllRequest.java | 6 +- .../downlink/TbLwM2MObserveCallback.java | 6 +- .../downlink/TbLwM2MObserveRequest.java | 6 +- .../server/downlink/TbLwM2MReadCallback.java | 6 +- .../server/downlink/TbLwM2MReadRequest.java | 6 +- .../downlink/TbLwM2MTargetedCallback.java | 10 +- .../TbLwM2MUplinkTargetedCallback.java | 10 +- .../TbLwM2MWriteAttributesCallback.java | 4 +- .../TbLwM2MWriteAttributesRequest.java | 6 +- .../downlink/TbLwM2MWriteReplaceRequest.java | 6 +- .../TbLwM2MWriteResponseCallback.java | 6 +- .../downlink/TbLwM2MWriteUpdateRequest.java | 6 +- .../TbLwM2MReadCompositeCallback.java | 6 +- .../TbLwM2MReadCompositeRequest.java | 6 +- .../TbLwM2MWriteCompositeRequest.java | 6 +- ...TbLwM2MWriteResponseCompositeCallback.java | 6 +- .../log/DefaultLwM2MTelemetryLogService.java | 10 +- .../server/log/LwM2MTelemetryLogService.java | 4 +- .../ota/DefaultLwM2MOtaUpdateService.java | 84 ++++----- .../server/ota/LwM2MOtaUpdateService.java | 36 ++-- .../rpc/DefaultLwM2MRpcRequestHandler.java | 64 +++---- .../rpc/RpcCancelAllObserveCallback.java | 4 +- .../server/rpc/RpcCancelObserveCallback.java | 4 +- .../server/rpc/RpcCreateResponseCallback.java | 4 +- .../lwm2m/server/rpc/RpcDiscoverCallback.java | 4 +- .../rpc/RpcDownlinkRequestCallbackProxy.java | 6 +- .../server/rpc/RpcEmptyResponseCallback.java | 4 +- .../lwm2m/server/rpc/RpcLinkSetCallback.java | 4 +- .../server/rpc/RpcLwM2MDownlinkCallback.java | 4 +- .../server/rpc/RpcReadResponseCallback.java | 6 +- .../RpcReadResponseCompositeCallback.java | 6 +- .../session/DefaultLwM2MSessionManager.java | 10 +- .../server/store/TbDummyLwM2MClientStore.java | 8 +- .../server/store/TbLwM2MClientStore.java | 8 +- .../server/store/TbLwM2mSecurityStore.java | 8 +- .../server/store/TbLwM2mStoreFactory.java | 4 +- .../server/store/TbRedisLwM2MClientStore.java | 14 +- .../uplink/DefaultLwM2MUplinkMsgHandler.java | 114 ++++++------ ...2mTypeServer.java => LwM2MTypeServer.java} | 8 +- ...andler.java => LwM2MUplinkMsgHandler.java} | 10 +- ...sportUtil.java => LwM2MTransportUtil.java} | 21 +-- ...Impl.java => LwM2MValueConverterImpl.java} | 6 +- 100 files changed, 624 insertions(+), 625 deletions(-) rename application/src/test/java/org/thingsboard/server/transport/lwm2m/client/{LwM2mBinaryAppDataContainer.java => LwM2MBinaryAppDataContainer.java} (97%) rename application/src/test/java/org/thingsboard/server/transport/lwm2m/client/{LwM2mLocation.java => LwM2MLocation.java} (95%) rename application/src/test/java/org/thingsboard/server/transport/lwm2m/client/{LwM2mTemperatureSensor.java => LwM2MTemperatureSensor.java} (96%) rename application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/{RpcLwm2mIntegrationCreateTest.java => RpcLwM2MIntegrationCreateTest.java} (99%) rename application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/{RpcLwm2mIntegrationDeleteTest.java => RpcLwM2MIntegrationDeleteTest.java} (98%) rename application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/{RpcLwm2mIntegrationDiscoverTest.java => RpcLwM2MIntegrationDiscoverTest.java} (99%) rename application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/{RpcLwm2mIntegrationExecuteTest.java => RpcLwM2MIntegrationExecuteTest.java} (99%) rename application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/{RpcLwm2mIntegrationObserveTest.java => RpcLwM2MIntegrationObserveTest.java} (99%) rename application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/{RpcLwm2mIntegrationReadTest.java => RpcLwM2MIntegrationReadTest.java} (99%) rename application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/{RpcLwm2mIntegrationWriteAttributesTest.java => RpcLwM2MIntegrationWriteAttributesTest.java} (97%) rename application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/{RpcLwm2mIntegrationWriteTest.java => RpcLwM2MIntegrationWriteTest.java} (99%) rename application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/{PskLwm2mIntegrationTest.java => PskLwM2MIntegrationTest.java} (96%) rename common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/{LwM2mCredentialsSecurityInfoValidator.java => LwM2MCredentialsSecurityInfoValidator.java} (96%) rename common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/{LwM2mRPkCredentials.java => LwM2MRPkCredentials.java} (97%) rename common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/{AbstractLwM2mTransportResource.java => AbstractLwM2MTransportResource.java} (91%) rename common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/{DefaultLwM2mTransportService.java => DefaultLwM2MTransportService.java} (93%) rename common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/{LwM2mNetworkConfig.java => LwM2MNetworkConfig.java} (99%) rename common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/{LwM2mOperationType.java => LwM2MOperationType.java} (91%) rename common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/{LwM2mOtaConvert.java => LwM2MOtaConvert.java} (96%) rename common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/{LwM2mQueuedRequest.java => LwM2MQueuedRequest.java} (94%) rename common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/{LwM2mServerListener.java => LwM2MServerListener.java} (94%) rename common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/{LwM2mSessionMsgListener.java => LwM2MSessionMsgListener.java} (97%) rename common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/{LwM2mTransportCoapResource.java => LwM2MTransportCoapResource.java} (97%) rename common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/{LwM2mTransportContext.java => LwM2MTransportContext.java} (94%) rename common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/{LwM2mTransportServerHelper.java => LwM2MTransportServerHelper.java} (99%) rename common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/{LwM2mVersionedModelProvider.java => LwM2MVersionedModelProvider.java} (95%) rename common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/{LwM2mClient.java => LwM2MClient.java} (97%) rename common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/{LwM2mClientContext.java => LwM2MClientContext.java} (67%) rename common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/{LwM2mClientContextImpl.java => LwM2MClientContextImpl.java} (91%) rename common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/{DefaultLwM2mDownlinkMsgHandler.java => DefaultLwM2MDownlinkMsgHandler.java} (84%) rename common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/{LwM2mDownlinkMsgHandler.java => LwM2MDownlinkMsgHandler.java} (78%) rename common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/{LwM2mTypeServer.java => LwM2MTypeServer.java} (83%) rename common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/{LwM2mUplinkMsgHandler.java => LwM2MUplinkMsgHandler.java} (91%) rename common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/{LwM2mTransportUtil.java => LwM2MTransportUtil.java} (97%) rename common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/{LwM2mValueConverterImpl.java => LwM2MValueConverterImpl.java} (97%) diff --git a/application/src/main/java/org/thingsboard/server/controller/Lwm2mController.java b/application/src/main/java/org/thingsboard/server/controller/Lwm2mController.java index 12cc60c4e2..6c1a7f315d 100644 --- a/application/src/main/java/org/thingsboard/server/controller/Lwm2mController.java +++ b/application/src/main/java/org/thingsboard/server/controller/Lwm2mController.java @@ -32,6 +32,7 @@ import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.lwm2m.ServerSecurityConfig; import org.thingsboard.server.common.data.security.DeviceCredentials; import org.thingsboard.server.queue.util.TbCoreComponent; +import org.thingsboard.server.service.lwm2m.LwM2MService; import org.thingsboard.server.service.lwm2m.LwM2MServiceImpl; import org.thingsboard.server.service.security.permission.Resource; @@ -44,7 +45,7 @@ import java.util.Map; public class Lwm2mController extends BaseController { @Autowired - protected LwM2MServiceImpl lwM2MService; + protected LwM2MService lwM2MService; @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/lwm2m/deviceProfile/bootstrap/{isBootstrapServer}", method = RequestMethod.GET) diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2mBinaryAppDataContainer.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2MBinaryAppDataContainer.java similarity index 97% rename from application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2mBinaryAppDataContainer.java rename to application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2MBinaryAppDataContainer.java index b7ac889649..e8d028cf73 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2mBinaryAppDataContainer.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2MBinaryAppDataContainer.java @@ -37,7 +37,7 @@ import java.util.concurrent.TimeUnit; @Slf4j -public class LwM2mBinaryAppDataContainer extends BaseInstanceEnabler implements Destroyable { +public class LwM2MBinaryAppDataContainer extends BaseInstanceEnabler implements Destroyable { /** * id = 0 @@ -76,10 +76,10 @@ public class LwM2mBinaryAppDataContainer extends BaseInstanceEnabler implements private Integer appID = -1; private static final List supportedResources = Arrays.asList(0, 1, 2, 3, 4, 5); - public LwM2mBinaryAppDataContainer() { + public LwM2MBinaryAppDataContainer() { } - public LwM2mBinaryAppDataContainer(ScheduledExecutorService executorService, Integer id) { + public LwM2MBinaryAppDataContainer(ScheduledExecutorService executorService, Integer id) { try { if (id != null) this.setId(id); executorService.scheduleWithFixedDelay(() -> diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2mLocation.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2MLocation.java similarity index 95% rename from application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2mLocation.java rename to application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2MLocation.java index 079cd9fdac..6ee267d466 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2mLocation.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2MLocation.java @@ -30,7 +30,7 @@ import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; @Slf4j -public class LwM2mLocation extends BaseInstanceEnabler implements Destroyable { +public class LwM2MLocation extends BaseInstanceEnabler implements Destroyable { private float latitude; private float longitude; @@ -39,11 +39,11 @@ public class LwM2mLocation extends BaseInstanceEnabler implements Destroyable { protected static final Random RANDOM = new Random(); private static final List supportedResources = Arrays.asList(0, 1, 5); - public LwM2mLocation() { + public LwM2MLocation() { this(null, null, 1.0f); } - public LwM2mLocation(Float latitude, Float longitude, float scaleFactor) { + public LwM2MLocation(Float latitude, Float longitude, float scaleFactor) { if (latitude != null) { this.latitude = latitude + 90f; @@ -59,7 +59,7 @@ public class LwM2mLocation extends BaseInstanceEnabler implements Destroyable { timestamp = new Date(); } - public LwM2mLocation(Float latitude, Float longitude, float scaleFactor, ScheduledExecutorService executorService, Integer id) { + public LwM2MLocation(Float latitude, Float longitude, float scaleFactor, ScheduledExecutorService executorService, Integer id) { try { if (id != null) this.setId(id); if (latitude != null) { diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2mTemperatureSensor.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2MTemperatureSensor.java similarity index 96% rename from application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2mTemperatureSensor.java rename to application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2MTemperatureSensor.java index 2e52cfc812..6b592bdeaa 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2mTemperatureSensor.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2MTemperatureSensor.java @@ -32,7 +32,7 @@ import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; @Slf4j -public class LwM2mTemperatureSensor extends BaseInstanceEnabler implements Destroyable { +public class LwM2MTemperatureSensor extends BaseInstanceEnabler implements Destroyable { private static final String UNIT_CELSIUS = "cel"; private double currentTemp = 20d; @@ -41,11 +41,11 @@ public class LwM2mTemperatureSensor extends BaseInstanceEnabler implements Destr protected static final Random RANDOM = new Random(); private static final List supportedResources = Arrays.asList(5601, 5602, 5700, 5701); - public LwM2mTemperatureSensor() { + public LwM2MTemperatureSensor() { } - public LwM2mTemperatureSensor(ScheduledExecutorService executorService, Integer id) { + public LwM2MTemperatureSensor(ScheduledExecutorService executorService, Integer id) { try { if (id != null) this.setId(id); executorService.scheduleWithFixedDelay(this::adjustTemperature, 2000, 2000, TimeUnit.MILLISECONDS); diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2MTestClient.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2MTestClient.java index 1c62b2b79d..33f5382ca8 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2MTestClient.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2MTestClient.java @@ -44,7 +44,7 @@ import org.eclipse.leshan.core.request.BootstrapRequest; import org.eclipse.leshan.core.request.DeregisterRequest; import org.eclipse.leshan.core.request.RegisterRequest; import org.eclipse.leshan.core.request.UpdateRequest; -import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl; +import org.thingsboard.server.transport.lwm2m.utils.LwM2MValueConverterImpl; import org.junit.Assert; import java.io.IOException; @@ -80,9 +80,9 @@ public class LwM2MTestClient { private SimpleLwM2MDevice lwM2MDevice; private FwLwM2MDevice fwLwM2MDevice; private SwLwM2MDevice swLwM2MDevice; - private LwM2mBinaryAppDataContainer lwM2MBinaryAppDataContainer; + private LwM2MBinaryAppDataContainer lwM2MBinaryAppDataContainer; private LwM2MLocationParams locationParams; - private LwM2mTemperatureSensor lwM2MTemperatureSensor; + private LwM2MTemperatureSensor lwM2MTemperatureSensor; public void init(Security security, NetworkConfig coapConfig, int port, boolean isRpc) throws InvalidDDFFileException, IOException { Assert.assertNull("client already initialized", client); @@ -99,12 +99,12 @@ public class LwM2MTestClient { initializer.setInstancesForObject(FIRMWARE, fwLwM2MDevice = new FwLwM2MDevice()); initializer.setInstancesForObject(SOFTWARE_MANAGEMENT, swLwM2MDevice = new SwLwM2MDevice()); initializer.setClassForObject(ACCESS_CONTROL, DummyInstanceEnabler.class); - initializer.setInstancesForObject(BINARY_APP_DATA_CONTAINER, lwM2MBinaryAppDataContainer = new LwM2mBinaryAppDataContainer(executor, objectInstanceId_0), - new LwM2mBinaryAppDataContainer(executor, objectInstanceId_1)); + initializer.setInstancesForObject(BINARY_APP_DATA_CONTAINER, lwM2MBinaryAppDataContainer = new LwM2MBinaryAppDataContainer(executor, objectInstanceId_0), + new LwM2MBinaryAppDataContainer(executor, objectInstanceId_1)); locationParams = new LwM2MLocationParams(); locationParams.getPos(); - initializer.setInstancesForObject(LOCATION, new LwM2mLocation(locationParams.getLatitude(), locationParams.getLongitude(), locationParams.getScaleFactor(), executor, objectInstanceId_0)); - initializer.setInstancesForObject(TEMPERATURE_SENSOR, lwM2MTemperatureSensor = new LwM2mTemperatureSensor(executor, objectInstanceId_0), new LwM2mTemperatureSensor(executor, objectInstanceId_12)); + initializer.setInstancesForObject(LOCATION, new LwM2MLocation(locationParams.getLatitude(), locationParams.getLongitude(), locationParams.getScaleFactor(), executor, objectInstanceId_0)); + initializer.setInstancesForObject(TEMPERATURE_SENSOR, lwM2MTemperatureSensor = new LwM2MTemperatureSensor(executor, objectInstanceId_0), new LwM2MTemperatureSensor(executor, objectInstanceId_12)); DtlsConnectorConfig.Builder dtlsConfig = new DtlsConnectorConfig.Builder(); dtlsConfig.setRecommendedCipherSuitesOnly(true); @@ -157,7 +157,7 @@ public class LwM2MTestClient { builder.setSharedExecutor(executor); builder.setDecoder(new DefaultLwM2mDecoder(false)); - builder.setEncoder(new DefaultLwM2mEncoder(new LwM2mValueConverterImpl(), false)); + builder.setEncoder(new DefaultLwM2mEncoder(new LwM2MValueConverterImpl(), false)); client = builder.build(); LwM2mClientObserver observer = new LwM2mClientObserver() { diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationCreateTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwM2MIntegrationCreateTest.java similarity index 99% rename from application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationCreateTest.java rename to application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwM2MIntegrationCreateTest.java index 4ab0d68794..3c8c9efda2 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationCreateTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwM2MIntegrationCreateTest.java @@ -31,7 +31,7 @@ import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.objectInsta import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_0; -public class RpcLwm2mIntegrationCreateTest extends AbstractRpcLwM2MIntegrationTest { +public class RpcLwM2MIntegrationCreateTest extends AbstractRpcLwM2MIntegrationTest { /** * Create {"id":"/19_1.1","value":{"0":{"0":"00AC"}, "1":1}} diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationDeleteTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwM2MIntegrationDeleteTest.java similarity index 98% rename from application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationDeleteTest.java rename to application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwM2MIntegrationDeleteTest.java index 6f24d7176c..a974bb4aaa 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationDeleteTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwM2MIntegrationDeleteTest.java @@ -29,7 +29,7 @@ import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.objectInsta import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_9; -public class RpcLwm2mIntegrationDeleteTest extends AbstractRpcLwM2MIntegrationTest { +public class RpcLwM2MIntegrationDeleteTest extends AbstractRpcLwM2MIntegrationTest { /** * if there is such an instance diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationDiscoverTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwM2MIntegrationDiscoverTest.java similarity index 99% rename from application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationDiscoverTest.java rename to application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwM2MIntegrationDiscoverTest.java index b8ca7be61f..39b7ffda08 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationDiscoverTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwM2MIntegrationDiscoverTest.java @@ -35,7 +35,7 @@ import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.objectInsta import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_2; -public class RpcLwm2mIntegrationDiscoverTest extends AbstractRpcLwM2MIntegrationTest { +public class RpcLwM2MIntegrationDiscoverTest extends AbstractRpcLwM2MIntegrationTest { /** * DiscoverAll diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationExecuteTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwM2MIntegrationExecuteTest.java similarity index 99% rename from application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationExecuteTest.java rename to application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwM2MIntegrationExecuteTest.java index 73ea0fb74c..0ea38d56a2 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationExecuteTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwM2MIntegrationExecuteTest.java @@ -33,7 +33,7 @@ import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_ import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_9; -public class RpcLwm2mIntegrationExecuteTest extends AbstractRpcLwM2MIntegrationTest { +public class RpcLwM2MIntegrationExecuteTest extends AbstractRpcLwM2MIntegrationTest { /** diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationObserveTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwM2MIntegrationObserveTest.java similarity index 99% rename from application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationObserveTest.java rename to application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwM2MIntegrationObserveTest.java index 848a9563ed..a31e01c59e 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationObserveTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwM2MIntegrationObserveTest.java @@ -32,7 +32,7 @@ import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_ import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_3; import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_9; -public class RpcLwm2mIntegrationObserveTest extends AbstractRpcLwM2MIntegrationTest { +public class RpcLwM2MIntegrationObserveTest extends AbstractRpcLwM2MIntegrationTest { /** * ObserveReadAll diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationReadTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwM2MIntegrationReadTest.java similarity index 99% rename from application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationReadTest.java rename to application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwM2MIntegrationReadTest.java index 9116659bc3..d78498a364 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationReadTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwM2MIntegrationReadTest.java @@ -41,7 +41,7 @@ import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_ import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_9; -public class RpcLwm2mIntegrationReadTest extends AbstractRpcLwM2MIntegrationTest { +public class RpcLwM2MIntegrationReadTest extends AbstractRpcLwM2MIntegrationTest { /** * Read {"id":"/3"} diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationWriteAttributesTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwM2MIntegrationWriteAttributesTest.java similarity index 97% rename from application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationWriteAttributesTest.java rename to application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwM2MIntegrationWriteAttributesTest.java index ea23ab48b9..49bc79f1c0 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationWriteAttributesTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwM2MIntegrationWriteAttributesTest.java @@ -34,7 +34,7 @@ import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_ import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_9; -public class RpcLwm2mIntegrationWriteAttributesTest extends AbstractRpcLwM2MIntegrationTest { +public class RpcLwM2MIntegrationWriteAttributesTest extends AbstractRpcLwM2MIntegrationTest { /** * WriteAttributes {"id":"/3/0/14","attributes":{"pmax":100, "pmin":10}} diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationWriteTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwM2MIntegrationWriteTest.java similarity index 99% rename from application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationWriteTest.java rename to application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwM2MIntegrationWriteTest.java index de0a22756d..cbea43b418 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationWriteTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwM2MIntegrationWriteTest.java @@ -36,7 +36,7 @@ import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_ import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_9; import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceInstanceId_2; -public class RpcLwm2mIntegrationWriteTest extends AbstractRpcLwM2MIntegrationTest { +public class RpcLwM2MIntegrationWriteTest extends AbstractRpcLwM2MIntegrationTest { /** diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/PskLwm2mIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/PskLwM2MIntegrationTest.java similarity index 96% rename from application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/PskLwm2mIntegrationTest.java rename to application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/PskLwM2MIntegrationTest.java index 23b60482f0..7e49dacca7 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/PskLwm2mIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/PskLwM2MIntegrationTest.java @@ -28,7 +28,7 @@ import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SECURE_COAP import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SECURE_URI; import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SHORT_SERVER_ID; -public class PskLwm2mIntegrationTest extends AbstractSecurityLwM2MIntegrationTest { +public class PskLwM2MIntegrationTest extends AbstractSecurityLwM2MIntegrationTest { @Test public void testConnectWithPSKAndObserveTelemetry() throws Exception { diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportServerHelperTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportServerHelperTest.java index fdccc2e933..71fb4e8a91 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportServerHelperTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportServerHelperTest.java @@ -37,7 +37,7 @@ import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; -import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.LOG_LWM2M_TELEMETRY; +import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.LOG_LWM2M_TELEMETRY; class LwM2mTransportServerHelperTest { @@ -47,15 +47,15 @@ class LwM2mTransportServerHelperTest { long now; List kvList; ConcurrentMap keyTsLatestMap; - LwM2mTransportServerHelper helper; - LwM2mTransportContext context; + LwM2MTransportServerHelper helper; + LwM2MTransportContext context; @BeforeEach void setUp() { now = System.currentTimeMillis(); - context = mock(LwM2mTransportContext.class); - helper = spy(new LwM2mTransportServerHelper(context)); + context = mock(LwM2MTransportContext.class); + helper = spy(new LwM2MTransportServerHelper(context)); willReturn(now).given(helper).getCurrentTimeMillis(); kvList = List.of( TransportProtos.KeyValueProto.newBuilder().setKey(KEY_SW_STATE).setStringV(DOWNLOADING).build(), diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportBootstrapService.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportBootstrapService.java index 0026392ece..4284512687 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportBootstrapService.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportBootstrapService.java @@ -30,7 +30,7 @@ import org.thingsboard.server.transport.lwm2m.bootstrap.secure.LwM2MInMemoryBoot import org.thingsboard.server.transport.lwm2m.bootstrap.secure.LwM2mDefaultBootstrapSessionManager; import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportBootstrapConfig; import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; -import org.thingsboard.server.transport.lwm2m.server.DefaultLwM2mTransportService; +import org.thingsboard.server.transport.lwm2m.server.DefaultLwM2MTransportService; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; @@ -40,7 +40,7 @@ import java.security.PrivateKey; import java.security.PublicKey; import java.security.cert.X509Certificate; -import static org.thingsboard.server.transport.lwm2m.server.LwM2mNetworkConfig.getCoapConfig; +import static org.thingsboard.server.transport.lwm2m.server.LwM2MNetworkConfig.getCoapConfig; @Slf4j @Component @@ -93,7 +93,7 @@ public class LwM2MTransportBootstrapService { DtlsConnectorConfig.Builder dtlsConfig = new DtlsConnectorConfig.Builder(); dtlsConfig.setRecommendedSupportedGroupsOnly(serverConfig.isRecommendedSupportedGroups()); dtlsConfig.setRecommendedCipherSuitesOnly(serverConfig.isRecommendedCiphers()); - dtlsConfig.setSupportedCipherSuites(this.pskMode ? DefaultLwM2mTransportService.PSK_CIPHER_SUITES : DefaultLwM2mTransportService.RPK_OR_X509_CIPHER_SUITES); + dtlsConfig.setSupportedCipherSuites(this.pskMode ? DefaultLwM2MTransportService.PSK_CIPHER_SUITES : DefaultLwM2MTransportService.RPK_OR_X509_CIPHER_SUITES); /* Set DTLS Config */ builder.setDtlsConfig(dtlsConfig); diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapSecurityStore.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapSecurityStore.java index bf5f40f055..ebaefc10b0 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapSecurityStore.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapSecurityStore.java @@ -29,11 +29,11 @@ import org.springframework.stereotype.Service; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.device.data.lwm2m.BootstrapConfiguration; import org.thingsboard.server.gen.transport.TransportProtos; -import org.thingsboard.server.transport.lwm2m.secure.LwM2mCredentialsSecurityInfoValidator; +import org.thingsboard.server.transport.lwm2m.secure.LwM2MCredentialsSecurityInfoValidator; import org.thingsboard.server.transport.lwm2m.secure.TbLwM2MSecurityInfo; -import org.thingsboard.server.transport.lwm2m.server.LwM2mSessionMsgListener; -import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportContext; -import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportServerHelper; +import org.thingsboard.server.transport.lwm2m.server.LwM2MSessionMsgListener; +import org.thingsboard.server.transport.lwm2m.server.LwM2MTransportContext; +import org.thingsboard.server.transport.lwm2m.server.LwM2MTransportServerHelper; import java.io.IOException; import java.security.GeneralSecurityException; @@ -43,11 +43,11 @@ import java.util.Map; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; -import static org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mTypeServer.BOOTSTRAP; -import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.LOG_LWM2M_ERROR; -import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.LOG_LWM2M_INFO; -import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.LOG_LWM2M_TELEMETRY; -import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.getBootstrapParametersFromThingsboard; +import static org.thingsboard.server.transport.lwm2m.server.uplink.LwM2MTypeServer.BOOTSTRAP; +import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.LOG_LWM2M_ERROR; +import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.LOG_LWM2M_INFO; +import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.LOG_LWM2M_TELEMETRY; +import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.getBootstrapParametersFromThingsboard; @Slf4j @Service("LwM2MBootstrapSecurityStore") @@ -56,13 +56,13 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore { private final EditableBootstrapConfigStore bootstrapConfigStore; - private final LwM2mCredentialsSecurityInfoValidator lwM2MCredentialsSecurityInfoValidator; + private final LwM2MCredentialsSecurityInfoValidator lwM2MCredentialsSecurityInfoValidator; - private final LwM2mTransportContext context; - private final LwM2mTransportServerHelper helper; + private final LwM2MTransportContext context; + private final LwM2MTransportServerHelper helper; private final Map bsSessions = new ConcurrentHashMap<>(); - public LwM2MBootstrapSecurityStore(EditableBootstrapConfigStore bootstrapConfigStore, LwM2mCredentialsSecurityInfoValidator lwM2MCredentialsSecurityInfoValidator, LwM2mTransportContext context, LwM2mTransportServerHelper helper) { + public LwM2MBootstrapSecurityStore(EditableBootstrapConfigStore bootstrapConfigStore, LwM2MCredentialsSecurityInfoValidator lwM2MCredentialsSecurityInfoValidator, LwM2MTransportContext context, LwM2MTransportServerHelper helper) { this.bootstrapConfigStore = bootstrapConfigStore; this.lwM2MCredentialsSecurityInfoValidator = lwM2MCredentialsSecurityInfoValidator; this.context = context; @@ -161,8 +161,8 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore { lwM2MBootstrapConfig.setServers(JacksonUtil.fromString(JacksonUtil.toString(bootstrapObject.getServers()), LwM2MBootstrapServers.class)); LwM2MServerBootstrap bootstrapServerProfile = JacksonUtil.fromString(JacksonUtil.toString(bootstrapObject.getBootstrapServer()), LwM2MServerBootstrap.class); if (SecurityMode.NO_SEC != bootstrapServerProfile.getSecurityMode() && bootstrapServerProfile != null) { - bootstrapServerProfile.setSecurityHost( bootstrapServerProfile.getHost()); - bootstrapServerProfile.setSecurityPort( bootstrapServerProfile.getPort()); + bootstrapServerProfile.setSecurityHost(bootstrapServerProfile.getHost()); + bootstrapServerProfile.setSecurityPort(bootstrapServerProfile.getPort()); } LwM2MServerBootstrap profileLwm2mServer = JacksonUtil.fromString(JacksonUtil.toString(bootstrapObject.getLwm2mServer()), LwM2MServerBootstrap.class); if (SecurityMode.NO_SEC != profileLwm2mServer.getSecurityMode() && profileLwm2mServer != null) { @@ -172,7 +172,7 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore { UUID sessionUUiD = UUID.randomUUID(); TransportProtos.SessionInfoProto sessionInfo = helper.getValidateSessionInfo(store.getMsg(), sessionUUiD.getMostSignificantBits(), sessionUUiD.getLeastSignificantBits()); bsSessions.put(store.getEndpoint(), sessionInfo); - context.getTransportService().registerAsyncSession(sessionInfo, new LwM2mSessionMsgListener(null, null, null, sessionInfo, context.getTransportService())); + context.getTransportService().registerAsyncSession(sessionInfo, new LwM2MSessionMsgListener(null, null, null, sessionInfo, context.getTransportService())); if (this.getValidatedSecurityMode(lwM2MBootstrapConfig.getBootstrapServer(), bootstrapServerProfile, lwM2MBootstrapConfig.getLwm2mServer(), profileLwm2mServer)) { lwM2MBootstrapConfig.setBootstrapServer(new LwM2MServerBootstrap(lwM2MBootstrapConfig.getBootstrapServer(), bootstrapServerProfile)); lwM2MBootstrapConfig.setLwm2mServer(new LwM2MServerBootstrap(lwM2MBootstrapConfig.getLwm2mServer(), profileLwm2mServer)); diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2mDefaultBootstrapSessionManager.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2mDefaultBootstrapSessionManager.java index 4ad8a95108..0e6d2933e4 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2mDefaultBootstrapSessionManager.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2mDefaultBootstrapSessionManager.java @@ -39,7 +39,7 @@ import java.util.ArrayList; import java.util.Iterator; import java.util.List; -import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.LOG_LWM2M_INFO; +import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.LOG_LWM2M_INFO; @Slf4j public class LwM2mDefaultBootstrapSessionManager extends DefaultBootstrapSessionManager { @@ -199,7 +199,7 @@ public class LwM2mDefaultBootstrapSessionManager extends DefaultBootstrapSession @Override public BootstrapPolicy onRequestFailure(BootstrapSession bsSession, BootstrapDownlinkRequest request, Throwable cause) { - this.sendLogs (bsSession.getEndpoint(), + this.sendLogs(bsSession.getEndpoint(), String.format("%s: %s %s failed because of %s for %s : %s", LOG_LWM2M_INFO, request.getClass().getSimpleName(), request.getPath().toString(), cause.toString(), bsSession.toString(), request.toString())); return BootstrapPolicy.failed(); @@ -207,16 +207,16 @@ public class LwM2mDefaultBootstrapSessionManager extends DefaultBootstrapSession @Override public void end(BootstrapSession bsSession) { - this.sendLogs (bsSession.getEndpoint(), String.format("%s: Bootstrap session finished : %s", LOG_LWM2M_INFO, bsSession.toString())); + this.sendLogs(bsSession.getEndpoint(), String.format("%s: Bootstrap session finished : %s", LOG_LWM2M_INFO, bsSession.toString())); } @Override public void failed(BootstrapSession bsSession, BootstrapFailureCause cause) { - this.sendLogs (bsSession.getEndpoint(), String.format("%s: Bootstrap session failed by %s: %s", LOG_LWM2M_INFO, + this.sendLogs(bsSession.getEndpoint(), String.format("%s: Bootstrap session failed by %s: %s", LOG_LWM2M_INFO, cause.toString(), bsSession.toString())); } - private void sendLogs (String endpointName, String logMsg) { + private void sendLogs(String endpointName, String logMsg) { log.info(logMsg); transportService.log(((LwM2MBootstrapSecurityStore) bsSecurityStore).getSessionByEndpoint(endpointName), logMsg); } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LwM2mCredentialsSecurityInfoValidator.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LwM2MCredentialsSecurityInfoValidator.java similarity index 96% rename from common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LwM2mCredentialsSecurityInfoValidator.java rename to common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LwM2MCredentialsSecurityInfoValidator.java index bf30723ce0..ccbd30b11b 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LwM2mCredentialsSecurityInfoValidator.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LwM2MCredentialsSecurityInfoValidator.java @@ -32,9 +32,9 @@ import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceLwM2MC import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; import org.thingsboard.server.transport.lwm2m.secure.credentials.LwM2MCredentials; -import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportContext; +import org.thingsboard.server.transport.lwm2m.server.LwM2MTransportContext; import org.thingsboard.server.transport.lwm2m.server.client.LwM2MAuthException; -import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mTypeServer; +import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2MTypeServer; import java.io.IOException; import java.security.GeneralSecurityException; @@ -46,18 +46,18 @@ import static org.eclipse.leshan.core.SecurityMode.NO_SEC; import static org.eclipse.leshan.core.SecurityMode.PSK; import static org.eclipse.leshan.core.SecurityMode.RPK; import static org.eclipse.leshan.core.SecurityMode.X509; -import static org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mTypeServer.BOOTSTRAP; +import static org.thingsboard.server.transport.lwm2m.server.uplink.LwM2MTypeServer.BOOTSTRAP; @Slf4j @Component @TbLwM2mTransportComponent @RequiredArgsConstructor -public class LwM2mCredentialsSecurityInfoValidator { +public class LwM2MCredentialsSecurityInfoValidator { - private final LwM2mTransportContext context; + private final LwM2MTransportContext context; private final LwM2MTransportServerConfig config; - public TbLwM2MSecurityInfo getEndpointSecurityInfoByCredentialsId(String credentialsId, LwM2mTypeServer keyValue) { + public TbLwM2MSecurityInfo getEndpointSecurityInfoByCredentialsId(String credentialsId, LwM2MTypeServer keyValue) { CountDownLatch latch = new CountDownLatch(1); final TbLwM2MSecurityInfo[] resultSecurityStore = new TbLwM2MSecurityInfo[1]; log.trace("Validating credentials [{}]", credentialsId); @@ -102,7 +102,7 @@ public class LwM2mCredentialsSecurityInfoValidator { * @param keyValue - * @return SecurityInfo */ - private TbLwM2MSecurityInfo createSecurityInfo(String endpoint, String jsonStr, LwM2mTypeServer keyValue) { + private TbLwM2MSecurityInfo createSecurityInfo(String endpoint, String jsonStr, LwM2MTypeServer keyValue) { TbLwM2MSecurityInfo result = new TbLwM2MSecurityInfo(); LwM2MCredentials credentials = JacksonUtil.fromString(jsonStr, LwM2MCredentials.class); if (credentials != null) { diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LwM2mRPkCredentials.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LwM2MRPkCredentials.java similarity index 97% rename from common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LwM2mRPkCredentials.java rename to common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LwM2MRPkCredentials.java index 47fa2f8090..445a0c18c3 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LwM2mRPkCredentials.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LwM2MRPkCredentials.java @@ -37,7 +37,7 @@ import java.util.List; @Slf4j @Data -public class LwM2mRPkCredentials { +public class LwM2MRPkCredentials { private PublicKey serverPublicKey; private PrivateKey serverPrivateKey; private X509Certificate certificate; @@ -49,7 +49,7 @@ public class LwM2mRPkCredentials { * @param publY * @param privS */ - public LwM2mRPkCredentials(String publX, String publY, String privS) { + public LwM2MRPkCredentials(String publX, String publY, String privS) { generatePublicKeyRPK(publX, publY, privS); } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MAuthorizer.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MAuthorizer.java index 04c6a2b160..ee5dd0112b 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MAuthorizer.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MAuthorizer.java @@ -26,7 +26,7 @@ import org.eclipse.leshan.server.security.SecurityInfo; import org.springframework.stereotype.Component; import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; import org.thingsboard.server.transport.lwm2m.server.client.LwM2MAuthException; -import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientContext; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClientContext; import org.thingsboard.server.transport.lwm2m.server.store.TbLwM2MDtlsSessionStore; import org.thingsboard.server.transport.lwm2m.server.store.TbSecurityStore; @@ -39,7 +39,7 @@ public class TbLwM2MAuthorizer implements Authorizer { private final TbLwM2MDtlsSessionStore sessionStorage; private final TbSecurityStore securityStore; private final SecurityChecker securityChecker = new SecurityChecker(); - private final LwM2mClientContext clientContext; + private final LwM2MClientContext clientContext; @Override public Registration isAuthorized(UplinkRequest request, Registration registration, Identity senderIdentity) { diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MDtlsCertificateVerifier.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MDtlsCertificateVerifier.java index fe04410c17..8f0358b0c9 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MDtlsCertificateVerifier.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MDtlsCertificateVerifier.java @@ -57,7 +57,7 @@ import java.security.cert.X509Certificate; import java.util.Arrays; import java.util.List; -import static org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mTypeServer.CLIENT; +import static org.thingsboard.server.transport.lwm2m.server.uplink.LwM2MTypeServer.CLIENT; @Slf4j @Component @@ -67,7 +67,7 @@ public class TbLwM2MDtlsCertificateVerifier implements NewAdvancedCertificateVer private final TbLwM2MDtlsSessionStore sessionStorage; private final LwM2MTransportServerConfig config; - private final LwM2mCredentialsSecurityInfoValidator securityInfoValidator; + private final LwM2MCredentialsSecurityInfoValidator securityInfoValidator; private final TbMainSecurityStore securityStore; @SuppressWarnings("deprecation") diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/AbstractLwM2mTransportResource.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/AbstractLwM2MTransportResource.java similarity index 91% rename from common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/AbstractLwM2mTransportResource.java rename to common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/AbstractLwM2MTransportResource.java index 5aed494934..2d8aa2c1a7 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/AbstractLwM2mTransportResource.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/AbstractLwM2MTransportResource.java @@ -20,9 +20,9 @@ import org.eclipse.californium.core.server.resources.CoapExchange; import org.eclipse.leshan.core.californium.LwM2mCoapResource; @Slf4j -public abstract class AbstractLwM2mTransportResource extends LwM2mCoapResource { +public abstract class AbstractLwM2MTransportResource extends LwM2mCoapResource { - public AbstractLwM2mTransportResource(String name) { + public AbstractLwM2MTransportResource(String name) { super(name); } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2mTransportService.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2MTransportService.java similarity index 93% rename from common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2mTransportService.java rename to common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2MTransportService.java index c099d7ad17..c1b91dd451 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2mTransportService.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2MTransportService.java @@ -33,10 +33,10 @@ import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; import org.thingsboard.server.transport.lwm2m.secure.TbLwM2MAuthorizer; import org.thingsboard.server.transport.lwm2m.secure.TbLwM2MDtlsCertificateVerifier; -import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientContext; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClientContext; import org.thingsboard.server.transport.lwm2m.server.store.TbSecurityStore; import org.thingsboard.server.transport.lwm2m.server.uplink.DefaultLwM2MUplinkMsgHandler; -import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl; +import org.thingsboard.server.transport.lwm2m.utils.LwM2MValueConverterImpl; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; @@ -48,26 +48,26 @@ import static org.eclipse.californium.scandium.dtls.cipher.CipherSuite.TLS_ECDHE import static org.eclipse.californium.scandium.dtls.cipher.CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8; import static org.eclipse.californium.scandium.dtls.cipher.CipherSuite.TLS_PSK_WITH_AES_128_CBC_SHA256; import static org.eclipse.californium.scandium.dtls.cipher.CipherSuite.TLS_PSK_WITH_AES_128_CCM_8; -import static org.thingsboard.server.transport.lwm2m.server.LwM2mNetworkConfig.getCoapConfig; +import static org.thingsboard.server.transport.lwm2m.server.LwM2MNetworkConfig.getCoapConfig; import static org.thingsboard.server.transport.lwm2m.server.ota.DefaultLwM2MOtaUpdateService.FIRMWARE_UPDATE_COAP_RESOURCE; @Slf4j @Component @TbLwM2mTransportComponent @RequiredArgsConstructor -public class DefaultLwM2mTransportService implements LwM2MTransportService { +public class DefaultLwM2MTransportService implements LwM2MTransportService { public static final CipherSuite[] RPK_OR_X509_CIPHER_SUITES = {TLS_PSK_WITH_AES_128_CCM_8, TLS_PSK_WITH_AES_128_CBC_SHA256, TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256}; public static final CipherSuite[] PSK_CIPHER_SUITES = {TLS_PSK_WITH_AES_128_CCM_8, TLS_PSK_WITH_AES_128_CBC_SHA256}; - private final LwM2mTransportContext context; + private final LwM2MTransportContext context; private final LwM2MTransportServerConfig config; - private final LwM2mTransportServerHelper helper; + private final LwM2MTransportServerHelper helper; private final OtaPackageDataCache otaPackageDataCache; private final DefaultLwM2MUplinkMsgHandler handler; private final CaliforniumRegistrationStore registrationStore; private final TbSecurityStore securityStore; - private final LwM2mClientContext lwM2mClientContext; + private final LwM2MClientContext lwM2mClientContext; private final TbLwM2MDtlsCertificateVerifier certificateVerifier; private final TbLwM2MAuthorizer authorizer; @@ -83,7 +83,7 @@ public class DefaultLwM2mTransportService implements LwM2MTransportService { * nameFile = "BC68JAR01A09_TO_BC68JAR01A10.bin" * "coap://host:port/{path}/{token}/{nameFile}" */ - LwM2mTransportCoapResource otaCoapResource = new LwM2mTransportCoapResource(otaPackageDataCache, FIRMWARE_UPDATE_COAP_RESOURCE); + LwM2MTransportCoapResource otaCoapResource = new LwM2MTransportCoapResource(otaPackageDataCache, FIRMWARE_UPDATE_COAP_RESOURCE); this.server.coap().getServer().add(otaCoapResource); this.startLhServer(); this.context.setServer(server); @@ -92,7 +92,7 @@ public class DefaultLwM2mTransportService implements LwM2MTransportService { private void startLhServer() { log.info("Starting LwM2M transport server..."); this.server.start(); - LwM2mServerListener lhServerCertListener = new LwM2mServerListener(handler); + LwM2MServerListener lhServerCertListener = new LwM2MServerListener(handler); this.server.getRegistrationService().addListener(lhServerCertListener.registrationListener); this.server.getPresenceService().addListener(lhServerCertListener.presenceListener); this.server.getObservationService().addListener(lhServerCertListener.observationListener); @@ -112,13 +112,13 @@ public class DefaultLwM2mTransportService implements LwM2MTransportService { builder.setLocalSecureAddress(config.getSecureHost(), config.getSecurePort()); builder.setDecoder(new DefaultLwM2mDecoder()); /* Use a magic converter to support bad type send by the UI. */ - builder.setEncoder(new DefaultLwM2mEncoder(LwM2mValueConverterImpl.getInstance())); + builder.setEncoder(new DefaultLwM2mEncoder(LwM2MValueConverterImpl.getInstance())); /* Create CoAP Config */ builder.setCoapConfig(getCoapConfig(config.getPort(), config.getSecurePort(), config)); /* Define model provider (Create Models )*/ - LwM2mModelProvider modelProvider = new LwM2mVersionedModelProvider(this.lwM2mClientContext, this.helper, this.context); + LwM2mModelProvider modelProvider = new LwM2MVersionedModelProvider(this.lwM2mClientContext, this.helper, this.context); config.setModelProvider(modelProvider); builder.setObjectModelProvider(modelProvider); diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mNetworkConfig.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MNetworkConfig.java similarity index 99% rename from common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mNetworkConfig.java rename to common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MNetworkConfig.java index 4fc60aecfc..cab959b2ed 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mNetworkConfig.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MNetworkConfig.java @@ -21,7 +21,7 @@ import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; import static org.eclipse.californium.core.network.config.NetworkConfigDefaults.DEFAULT_BLOCKWISE_STATUS_LIFETIME; -public class LwM2mNetworkConfig { +public class LwM2MNetworkConfig { public static NetworkConfig getCoapConfig(Integer serverPortNoSec, Integer serverSecurePort, LwM2MTransportServerConfig config) { NetworkConfig coapConfig = new NetworkConfig(); diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mOperationType.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MOperationType.java similarity index 91% rename from common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mOperationType.java rename to common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MOperationType.java index ff0e431649..48eb300c8b 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mOperationType.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MOperationType.java @@ -20,7 +20,7 @@ import lombok.Getter; /** * Define the behavior of a write request. */ -public enum LwM2mOperationType { +public enum LwM2MOperationType { READ(0, "Read", true), READ_COMPOSITE(1, "ReadComposite", false, true), @@ -69,11 +69,11 @@ public enum LwM2mOperationType { @Getter private final boolean composite; - LwM2mOperationType(int code, String type, boolean hasObjectId) { + LwM2MOperationType(int code, String type, boolean hasObjectId) { this(code, type, hasObjectId, false); } - LwM2mOperationType(int code, String type, boolean hasObjectId, boolean composite) { + LwM2MOperationType(int code, String type, boolean hasObjectId, boolean composite) { this.code = code; this.type = type; this.hasObjectId = hasObjectId; @@ -83,8 +83,8 @@ public enum LwM2mOperationType { } } - public static LwM2mOperationType fromType(String type) { - for (LwM2mOperationType to : LwM2mOperationType.values()) { + public static LwM2MOperationType fromType(String type) { + for (LwM2MOperationType to : LwM2MOperationType.values()) { if (to.type.equals(type)) { return to; } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mOtaConvert.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MOtaConvert.java similarity index 96% rename from common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mOtaConvert.java rename to common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MOtaConvert.java index 7b7c56adb3..07534a1be4 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mOtaConvert.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MOtaConvert.java @@ -19,7 +19,7 @@ import lombok.Data; import org.eclipse.leshan.core.model.ResourceModel; @Data -public class LwM2mOtaConvert { +public class LwM2MOtaConvert { private ResourceModel.Type currentType; private Object value; } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mQueuedRequest.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MQueuedRequest.java similarity index 94% rename from common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mQueuedRequest.java rename to common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MQueuedRequest.java index dfc88a3331..2e6951ebe4 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mQueuedRequest.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MQueuedRequest.java @@ -15,6 +15,6 @@ */ package org.thingsboard.server.transport.lwm2m.server; -public interface LwM2mQueuedRequest { +public interface LwM2MQueuedRequest { void send(); } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mServerListener.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MServerListener.java similarity index 94% rename from common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mServerListener.java rename to common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MServerListener.java index 3ffc41c8ca..1e66bc2924 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mServerListener.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MServerListener.java @@ -23,18 +23,18 @@ import org.eclipse.leshan.server.queue.PresenceListener; import org.eclipse.leshan.server.registration.Registration; import org.eclipse.leshan.server.registration.RegistrationListener; import org.eclipse.leshan.server.registration.RegistrationUpdate; -import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler; +import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2MUplinkMsgHandler; import java.util.Collection; -import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.convertObjectIdToVersionedId; +import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.convertObjectIdToVersionedId; @Slf4j -public class LwM2mServerListener { +public class LwM2MServerListener { - private final LwM2mUplinkMsgHandler service; + private final LwM2MUplinkMsgHandler service; - public LwM2mServerListener(LwM2mUplinkMsgHandler service) { + public LwM2MServerListener(LwM2MUplinkMsgHandler service) { this.service = service; } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mSessionMsgListener.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MSessionMsgListener.java similarity index 97% rename from common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mSessionMsgListener.java rename to common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MSessionMsgListener.java index 463823e583..704a29ee9b 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mSessionMsgListener.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MSessionMsgListener.java @@ -34,15 +34,15 @@ import org.thingsboard.server.gen.transport.TransportProtos.ToServerRpcResponseM import org.thingsboard.server.gen.transport.TransportProtos.ToTransportUpdateCredentialsProto; import org.thingsboard.server.transport.lwm2m.server.attributes.LwM2MAttributesService; import org.thingsboard.server.transport.lwm2m.server.rpc.LwM2MRpcRequestHandler; -import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler; +import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2MUplinkMsgHandler; import java.util.Optional; import java.util.UUID; @Slf4j @RequiredArgsConstructor -public class LwM2mSessionMsgListener implements GenericFutureListener>, SessionMsgListener { - private final LwM2mUplinkMsgHandler handler; +public class LwM2MSessionMsgListener implements GenericFutureListener>, SessionMsgListener { + private final LwM2MUplinkMsgHandler handler; private final LwM2MAttributesService attributesService; private final LwM2MRpcRequestHandler rpcHandler; private final TransportProtos.SessionInfoProto sessionInfo; diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportCoapResource.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportCoapResource.java similarity index 97% rename from common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportCoapResource.java rename to common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportCoapResource.java index bde1725807..17a1f61856 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportCoapResource.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportCoapResource.java @@ -36,12 +36,12 @@ import static org.thingsboard.server.transport.lwm2m.server.ota.DefaultLwM2MOtaU import static org.thingsboard.server.transport.lwm2m.server.ota.DefaultLwM2MOtaUpdateService.SOFTWARE_UPDATE_COAP_RESOURCE; @Slf4j -public class LwM2mTransportCoapResource extends AbstractLwM2mTransportResource { +public class LwM2MTransportCoapResource extends AbstractLwM2MTransportResource { private final ConcurrentMap tokenToObserveRelationMap = new ConcurrentHashMap<>(); private final ConcurrentMap tokenToObserveNotificationSeqMap = new ConcurrentHashMap<>(); private final OtaPackageDataCache otaPackageDataCache; - public LwM2mTransportCoapResource(OtaPackageDataCache otaPackageDataCache, String name) { + public LwM2MTransportCoapResource(OtaPackageDataCache otaPackageDataCache, String name) { super(name); this.otaPackageDataCache = otaPackageDataCache; this.setObservable(true); // enable observing diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportContext.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportContext.java similarity index 94% rename from common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportContext.java rename to common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportContext.java index 6ae204affc..370743394e 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportContext.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportContext.java @@ -24,7 +24,7 @@ import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; @Component @TbLwM2mTransportComponent -public class LwM2mTransportContext extends TransportContext { +public class LwM2MTransportContext extends TransportContext { @Getter @Setter private LeshanServer server; diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportServerHelper.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportServerHelper.java similarity index 99% rename from common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportServerHelper.java rename to common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportServerHelper.java index 136f95dd35..0a02dee97e 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportServerHelper.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportServerHelper.java @@ -48,9 +48,9 @@ import static org.thingsboard.server.gen.transport.TransportProtos.KeyValueType. @Component @TbLwM2mTransportComponent @RequiredArgsConstructor -public class LwM2mTransportServerHelper { +public class LwM2MTransportServerHelper { - private final LwM2mTransportContext context; + private final LwM2MTransportContext context; private final static JsonParser JSON_PARSER = new JsonParser(); public void sendParametersOnThingsboardAttribute(List result, SessionInfoProto sessionInfo) { diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mVersionedModelProvider.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MVersionedModelProvider.java similarity index 95% rename from common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mVersionedModelProvider.java rename to common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MVersionedModelProvider.java index 650726604f..1107731a01 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mVersionedModelProvider.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MVersionedModelProvider.java @@ -25,7 +25,7 @@ import org.eclipse.leshan.server.model.LwM2mModelProvider; import org.eclipse.leshan.server.registration.Registration; import org.thingsboard.server.common.data.TbResource; import org.thingsboard.server.common.data.id.TenantId; -import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientContext; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClientContext; import java.util.ArrayList; import java.util.Base64; @@ -38,7 +38,7 @@ import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPA @Slf4j @RequiredArgsConstructor -public class LwM2mVersionedModelProvider implements LwM2mModelProvider { +public class LwM2MVersionedModelProvider implements LwM2mModelProvider { /** * int objectId @@ -46,9 +46,9 @@ public class LwM2mVersionedModelProvider implements LwM2mModelProvider { * Key = objectId + "##" + version * Value = TenantId */ - private final LwM2mClientContext lwM2mClientContext; - private final LwM2mTransportServerHelper helper; - private final LwM2mTransportContext context; + private final LwM2MClientContext lwM2mClientContext; + private final LwM2MTransportServerHelper helper; + private final LwM2MTransportContext context; private String getKeyIdVer(Integer objectId, String version) { return objectId != null ? objectId + LWM2M_SEPARATOR_KEY + ((version == null || version.isEmpty()) ? ObjectModel.DEFAULT_VERSION : version) : null; diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/attributes/DefaultLwM2MAttributesService.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/attributes/DefaultLwM2MAttributesService.java index cfbc21e57c..00e4fee3f9 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/attributes/DefaultLwM2MAttributesService.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/attributes/DefaultLwM2MAttributesService.java @@ -31,17 +31,17 @@ import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.gen.transport.TransportProtos.GetAttributeResponseMsg; import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; -import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportServerHelper; -import org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil; -import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; -import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientContext; -import org.thingsboard.server.transport.lwm2m.server.downlink.LwM2mDownlinkMsgHandler; +import org.thingsboard.server.transport.lwm2m.server.LwM2MTransportServerHelper; +import org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClient; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClientContext; +import org.thingsboard.server.transport.lwm2m.server.downlink.LwM2MDownlinkMsgHandler; import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MWriteReplaceRequest; import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MWriteResponseCallback; import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService; import org.thingsboard.server.transport.lwm2m.server.ota.LwM2MOtaUpdateService; -import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler; -import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl; +import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2MUplinkMsgHandler; +import org.thingsboard.server.transport.lwm2m.utils.LwM2MValueConverterImpl; import java.util.ArrayList; import java.util.Arrays; @@ -53,7 +53,7 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicInteger; import static org.eclipse.leshan.core.model.ResourceModel.Type.OPAQUE; -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportServerHelper.getValueFromKvProto; +import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportServerHelper.getValueFromKvProto; import static org.thingsboard.server.transport.lwm2m.server.ota.DefaultLwM2MOtaUpdateService.FIRMWARE_TAG; import static org.thingsboard.server.transport.lwm2m.server.ota.DefaultLwM2MOtaUpdateService.FIRMWARE_TITLE; import static org.thingsboard.server.transport.lwm2m.server.ota.DefaultLwM2MOtaUpdateService.FIRMWARE_URL; @@ -62,11 +62,11 @@ import static org.thingsboard.server.transport.lwm2m.server.ota.DefaultLwM2MOtaU import static org.thingsboard.server.transport.lwm2m.server.ota.DefaultLwM2MOtaUpdateService.SOFTWARE_TITLE; import static org.thingsboard.server.transport.lwm2m.server.ota.DefaultLwM2MOtaUpdateService.SOFTWARE_URL; import static org.thingsboard.server.transport.lwm2m.server.ota.DefaultLwM2MOtaUpdateService.SOFTWARE_VERSION; -import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.LOG_LWM2M_ERROR; -import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.LOG_LWM2M_WARN; -import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.compareAttNameKeyOta; -import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.convertMultiResourceValuesFromJson; -import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.fromVersionedIdToObjectId; +import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.LOG_LWM2M_ERROR; +import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.LOG_LWM2M_WARN; +import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.compareAttNameKeyOta; +import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.convertMultiResourceValuesFromJson; +import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.fromVersionedIdToObjectId; @Slf4j @Service @@ -79,16 +79,16 @@ public class DefaultLwM2MAttributesService implements LwM2MAttributesService { private final Map>> futures; private final TransportService transportService; - private final LwM2mTransportServerHelper helper; - private final LwM2mClientContext clientContext; + private final LwM2MTransportServerHelper helper; + private final LwM2MClientContext clientContext; private final LwM2MTransportServerConfig config; - private final LwM2mUplinkMsgHandler uplinkHandler; - private final LwM2mDownlinkMsgHandler downlinkHandler; + private final LwM2MUplinkMsgHandler uplinkHandler; + private final LwM2MDownlinkMsgHandler downlinkHandler; private final LwM2MTelemetryLogService logService; private final LwM2MOtaUpdateService otaUpdateService; @Override - public ListenableFuture> getSharedAttributes(LwM2mClient client, Collection keys) { + public ListenableFuture> getSharedAttributes(LwM2MClient client, Collection keys) { SettableFuture> future = SettableFuture.create(); int requestId = reqIdSeq.incrementAndGet(); futures.put(requestId, future); @@ -131,7 +131,7 @@ public class DefaultLwM2MAttributesService implements LwM2MAttributesService { */ @Override public void onAttributesUpdate(TransportProtos.AttributeUpdateNotificationMsg msg, TransportProtos.SessionInfoProto sessionInfo) { - LwM2mClient lwM2MClient = clientContext.getClientBySessionInfo(sessionInfo); + LwM2MClient lwM2MClient = clientContext.getClientBySessionInfo(sessionInfo); if (msg.getSharedUpdatedCount() > 0 && lwM2MClient != null) { String newFirmwareTitle = null; String newFirmwareVersion = null; @@ -188,7 +188,7 @@ public class DefaultLwM2MAttributesService implements LwM2MAttributesService { * #2.1 if there is not a difference in values between the current resource values and the shared attribute values */ @Override - public void onAttributesUpdate(LwM2mClient lwM2MClient, List tsKvProtos, boolean logFailedUpdateOfNonChangedValue) { + public void onAttributesUpdate(LwM2MClient lwM2MClient, List tsKvProtos, boolean logFailedUpdateOfNonChangedValue) { log.trace("[{}] onAttributesUpdate [{}]", lwM2MClient.getEndpoint(), tsKvProtos); Map attributesUpdate = new ConcurrentHashMap<>(); tsKvProtos.forEach(tsKvProto -> { @@ -235,7 +235,7 @@ public class DefaultLwM2MAttributesService implements LwM2MAttributesService { }); } - private void pushUpdateToClientIfNeeded(LwM2mClient lwM2MClient, Object valueOld, Object newValue, + private void pushUpdateToClientIfNeeded(LwM2MClient lwM2MClient, Object valueOld, Object newValue, String versionedId, boolean logFailedUpdateOfNonChangedValue, ResourceModel.Type type) { if (newValue == null) { String logMsg = String.format("%s: Failed update resource versionedId - %s value - %s. New value is bad", @@ -255,7 +255,7 @@ public class DefaultLwM2MAttributesService implements LwM2MAttributesService { } } - private void pushUpdateMultiToClientIfNeeded(LwM2mClient client, ResourceModel resourceModel, JsonElement newValProto, + private void pushUpdateMultiToClientIfNeeded(LwM2MClient client, ResourceModel resourceModel, JsonElement newValProto, Map valueOld, String versionedId, boolean logFailedUpdateOfNonChangedValue) throws Exception { Map newValues = convertMultiResourceValuesFromJson(newValProto, resourceModel.type, versionedId); @@ -290,13 +290,13 @@ public class DefaultLwM2MAttributesService implements LwM2MAttributesService { * @param pathIdVer - path resource * @return - value of Resource into format KvProto or null */ - private Object getResourceValueFormatKv(LwM2mClient lwM2MClient, String pathIdVer) { - LwM2mResource resourceValue = LwM2mTransportUtil.getResourceValueFromLwM2MClient(lwM2MClient, pathIdVer); + private Object getResourceValueFormatKv(LwM2MClient lwM2MClient, String pathIdVer) { + LwM2mResource resourceValue = LwM2MTransportUtil.getResourceValueFromLwM2MClient(lwM2MClient, pathIdVer); if (resourceValue != null) { ResourceModel.Type currentType = resourceValue.getType(); ResourceModel.Type expectedType = helper.getResourceModelTypeEqualsKvProtoValueType(currentType, pathIdVer); if (!resourceValue.isMultiInstances()) { - return LwM2mValueConverterImpl.getInstance().convertValue(resourceValue.getValue(), currentType, expectedType, + return LwM2MValueConverterImpl.getInstance().convertValue(resourceValue.getValue(), currentType, expectedType, new LwM2mPath(fromVersionedIdToObjectId(pathIdVer))); } else if (resourceValue.getInstances().size() > 0) { return resourceValue.getInstances(); diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/attributes/LwM2MAttributesService.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/attributes/LwM2MAttributesService.java index cce7a29c88..9f73390037 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/attributes/LwM2MAttributesService.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/attributes/LwM2MAttributesService.java @@ -17,18 +17,18 @@ package org.thingsboard.server.transport.lwm2m.server.attributes; import com.google.common.util.concurrent.ListenableFuture; import org.thingsboard.server.gen.transport.TransportProtos; -import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClient; import java.util.Collection; import java.util.List; public interface LwM2MAttributesService { - ListenableFuture> getSharedAttributes(LwM2mClient client, Collection keys); + ListenableFuture> getSharedAttributes(LwM2MClient client, Collection keys); void onGetAttributesResponse(TransportProtos.GetAttributeResponseMsg getAttributesResponse, TransportProtos.SessionInfoProto sessionInfo); void onAttributesUpdate(TransportProtos.AttributeUpdateNotificationMsg attributeUpdateNotification, TransportProtos.SessionInfoProto sessionInfo); - void onAttributesUpdate(LwM2mClient lwM2MClient, List tsKvProtos, boolean logFailedUpdateOfNonChangedValue); + void onAttributesUpdate(LwM2MClient lwM2MClient, List tsKvProtos, boolean logFailedUpdateOfNonChangedValue); } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2MClient.java similarity index 97% rename from common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java rename to common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2MClient.java index b5db43e66e..0a200262ae 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2MClient.java @@ -61,15 +61,15 @@ import java.util.stream.Collectors; import java.util.stream.Stream; import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPARATOR_PATH; -import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.convertMultiResourceValuesFromRpcBody; -import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.convertObjectIdToVersionedId; -import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.equalsResourceTypeGetSimpleName; -import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.fromVersionedIdToObjectId; -import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.getVerFromPathIdVerOrId; +import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.convertMultiResourceValuesFromRpcBody; +import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.convertObjectIdToVersionedId; +import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.equalsResourceTypeGetSimpleName; +import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.fromVersionedIdToObjectId; +import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.getVerFromPathIdVerOrId; @Slf4j @EqualsAndHashCode(of = {"endpoint"}) -public class LwM2mClient implements Serializable { +public class LwM2MClient implements Serializable { private static final long serialVersionUID = 8793482946289222623L; @@ -129,7 +129,7 @@ public class LwM2mClient implements Serializable { return super.clone(); } - public LwM2mClient(String nodeId, String endpoint) { + public LwM2MClient(String nodeId, String endpoint) { this.nodeId = nodeId; this.endpoint = endpoint; this.sharedAttributes = new ConcurrentHashMap<>(); @@ -325,9 +325,10 @@ public class LwM2mClient implements Serializable { Map resourceModels = modelProvider.getObjectModel(registration) .getObjectModel(pathIds.getObjectId()).resources; if (params != null && params instanceof Map && ((Map) params).size() > 0) { + Map paramsMap = (Map) params; resourceModels.forEach((resourceId, resourceModel) -> { - if (((Map) params).containsKey(String.valueOf(resourceId))) { - Object value = ((Map) params).get((String.valueOf(resourceId))); + if (paramsMap.containsKey(String.valueOf(resourceId))) { + Object value = paramsMap.get((String.valueOf(resourceId))); LwM2mResource resource; if (resourceModel.multiple) { try { diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContext.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2MClientContext.java similarity index 67% rename from common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContext.java rename to common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2MClientContext.java index 8d97e775c6..82d27f2a53 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContext.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2MClientContext.java @@ -26,19 +26,19 @@ import java.util.Optional; import java.util.Set; import java.util.UUID; -public interface LwM2mClientContext { +public interface LwM2MClientContext { - LwM2mClient getClientByEndpoint(String endpoint); + LwM2MClient getClientByEndpoint(String endpoint); - LwM2mClient getClientBySessionInfo(TransportProtos.SessionInfoProto sessionInfo); + LwM2MClient getClientBySessionInfo(TransportProtos.SessionInfoProto sessionInfo); - Optional register(LwM2mClient lwM2MClient, Registration registration) throws LwM2MClientStateException; + Optional register(LwM2MClient lwM2MClient, Registration registration) throws LwM2MClientStateException; - void updateRegistration(LwM2mClient client, Registration registration) throws LwM2MClientStateException; + void updateRegistration(LwM2MClient client, Registration registration) throws LwM2MClientStateException; - void unregister(LwM2mClient client, Registration registration) throws LwM2MClientStateException; + void unregister(LwM2MClient client, Registration registration) throws LwM2MClientStateException; - Collection getLwM2mClients(); + Collection getLwM2mClients(); //TODO: replace UUID with DeviceProfileId Lwm2mDeviceProfileTransportConfiguration getProfile(UUID profileUuId); @@ -47,28 +47,28 @@ public interface LwM2mClientContext { Lwm2mDeviceProfileTransportConfiguration profileUpdate(DeviceProfile deviceProfile); - Set getSupportedIdVerInClient(LwM2mClient registration); + Set getSupportedIdVerInClient(LwM2MClient registration); - LwM2mClient getClientByDeviceId(UUID deviceId); + LwM2MClient getClientByDeviceId(UUID deviceId); - String getObjectIdByKeyNameFromProfile(LwM2mClient lwM2mClient, String keyName); + String getObjectIdByKeyNameFromProfile(LwM2MClient lwM2mClient, String keyName); void registerClient(Registration registration, ValidateDeviceCredentialsResponse credentials); - void update(LwM2mClient lwM2MClient); + void update(LwM2MClient lwM2MClient); void removeCredentials(TransportProtos.SessionInfoProto sessionInfo); - void sendMsgsAfterSleeping(LwM2mClient lwM2MClient); + void sendMsgsAfterSleeping(LwM2MClient lwM2MClient); - void onUplink(LwM2mClient client); + void onUplink(LwM2MClient client); - Long getRequestTimeout(LwM2mClient client); + Long getRequestTimeout(LwM2MClient client); - boolean asleep(LwM2mClient client); + boolean asleep(LwM2MClient client); - boolean awake(LwM2mClient client); + boolean awake(LwM2MClient client); - boolean isDownlinkAllowed(LwM2mClient client); + boolean isDownlinkAllowed(LwM2MClient client); } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2MClientContextImpl.java similarity index 91% rename from common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java rename to common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2MClientContextImpl.java index 413629ebc1..6eab4eba54 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2MClientContextImpl.java @@ -36,8 +36,8 @@ import org.thingsboard.server.queue.util.AfterStartUp; import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; import org.thingsboard.server.transport.lwm2m.secure.TbLwM2MSecurityInfo; -import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportContext; -import org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil; +import org.thingsboard.server.transport.lwm2m.server.LwM2MTransportContext; +import org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil; import org.thingsboard.server.transport.lwm2m.server.ota.LwM2MOtaUpdateService; import org.thingsboard.server.transport.lwm2m.server.session.LwM2MSessionManager; import org.thingsboard.server.transport.lwm2m.server.store.TbLwM2MClientStore; @@ -56,15 +56,15 @@ import java.util.concurrent.TimeUnit; import java.util.function.Predicate; import static org.eclipse.leshan.core.SecurityMode.NO_SEC; -import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.convertObjectIdToVersionedId; +import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.convertObjectIdToVersionedId; @Slf4j @Service @TbLwM2mTransportComponent @RequiredArgsConstructor -public class LwM2mClientContextImpl implements LwM2mClientContext { +public class LwM2MClientContextImpl implements LwM2MClientContext { - private final LwM2mTransportContext context; + private final LwM2MTransportContext context; private final LwM2MTransportServerConfig config; private final TbMainSecurityStore securityStore; private final TbLwM2MClientStore clientStore; @@ -78,14 +78,14 @@ public class LwM2mClientContextImpl implements LwM2mClientContext { @Lazy private LwM2MOtaUpdateService otaUpdateService; - private final Map lwM2mClientsByEndpoint = new ConcurrentHashMap<>(); - private final Map lwM2mClientsByRegistrationId = new ConcurrentHashMap<>(); + private final Map lwM2mClientsByEndpoint = new ConcurrentHashMap<>(); + private final Map lwM2mClientsByRegistrationId = new ConcurrentHashMap<>(); private final Map profiles = new ConcurrentHashMap<>(); @AfterStartUp public void init() { String nodeId = context.getNodeId(); - Set fetchedClients = clientStore.getAll(); + Set fetchedClients = clientStore.getAll(); log.debug("Fetched clients from store: {}", fetchedClients); fetchedClients.forEach(client -> { lwM2mClientsByEndpoint.put(client.getEndpoint(), client); @@ -99,13 +99,13 @@ public class LwM2mClientContextImpl implements LwM2mClientContext { } @Override - public LwM2mClient getClientByEndpoint(String endpoint) { + public LwM2MClient getClientByEndpoint(String endpoint) { return lwM2mClientsByEndpoint.computeIfAbsent(endpoint, ep -> { - LwM2mClient client = clientStore.get(ep); + LwM2MClient client = clientStore.get(ep); String nodeId = context.getNodeId(); if (client == null) { log.info("[{}] initialized new client.", endpoint); - client = new LwM2mClient(nodeId, ep); + client = new LwM2MClient(nodeId, ep); } else { log.debug("[{}] fetched client from store: {}", endpoint, client); updateFetchedClient(nodeId, client); @@ -114,7 +114,7 @@ public class LwM2mClientContextImpl implements LwM2mClientContext { }); } - private void updateFetchedClient(String nodeId, LwM2mClient client) { + private void updateFetchedClient(String nodeId, LwM2MClient client) { boolean updated = false; if (client.getRegistration() != null) { lwM2mClientsByRegistrationId.put(client.getRegistration().getId(), client); @@ -130,7 +130,7 @@ public class LwM2mClientContextImpl implements LwM2mClientContext { } @Override - public Optional register(LwM2mClient client, Registration registration) throws LwM2MClientStateException { + public Optional register(LwM2MClient client, Registration registration) throws LwM2MClientStateException { TransportProtos.SessionInfoProto oldSession; client.lock(); try { @@ -172,7 +172,7 @@ public class LwM2mClientContextImpl implements LwM2mClientContext { } @Override - public boolean asleep(LwM2mClient client) { + public boolean asleep(LwM2MClient client) { boolean changed = compareAndSetSleepFlag(client, true); if (changed) { log.debug("[{}] client is sleeping", client.getEndpoint()); @@ -182,7 +182,7 @@ public class LwM2mClientContextImpl implements LwM2mClientContext { } @Override - public boolean awake(LwM2mClient client) { + public boolean awake(LwM2MClient client) { onUplink(client); boolean changed = compareAndSetSleepFlag(client, false); if (changed) { @@ -193,7 +193,7 @@ public class LwM2mClientContextImpl implements LwM2mClientContext { return changed; } - private boolean compareAndSetSleepFlag(LwM2mClient client, boolean sleeping) { + private boolean compareAndSetSleepFlag(LwM2MClient client, boolean sleeping) { if (sleeping == client.isAsleep()) { log.trace("[{}] Client is already at sleeping: {}, ignoring event: {}", client.getEndpoint(), client.isAsleep(), sleeping); return false; @@ -220,7 +220,7 @@ public class LwM2mClientContextImpl implements LwM2mClientContext { } @Override - public void updateRegistration(LwM2mClient client, Registration registration) throws LwM2MClientStateException { + public void updateRegistration(LwM2MClient client, Registration registration) throws LwM2MClientStateException { client.lock(); try { if (!LwM2MClientState.REGISTERED.equals(client.getState())) { @@ -239,7 +239,7 @@ public class LwM2mClientContextImpl implements LwM2mClientContext { } @Override - public void unregister(LwM2mClient client, Registration registration) throws LwM2MClientStateException { + public void unregister(LwM2MClient client, Registration registration) throws LwM2MClientStateException { client.lock(); try { if (!LwM2MClientState.REGISTERED.equals(client.getState())) { @@ -255,7 +255,7 @@ public class LwM2mClientContextImpl implements LwM2mClientContext { clientStore.remove(client.getEndpoint()); UUID profileId = client.getProfileId(); if (profileId != null) { - Optional otherClients = lwM2mClientsByRegistrationId.values().stream().filter(e -> e.getProfileId().equals(profileId)).findFirst(); + Optional otherClients = lwM2mClientsByRegistrationId.values().stream().filter(e -> e.getProfileId().equals(profileId)).findFirst(); if (otherClients.isEmpty()) { profiles.remove(profileId); } @@ -269,10 +269,10 @@ public class LwM2mClientContextImpl implements LwM2mClientContext { } @Override - public LwM2mClient getClientBySessionInfo(TransportProtos.SessionInfoProto sessionInfo) { - LwM2mClient lwM2mClient = null; + public LwM2MClient getClientBySessionInfo(TransportProtos.SessionInfoProto sessionInfo) { + LwM2MClient lwM2mClient = null; UUID sessionId = new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB()); - Predicate isClientFilter = c -> + Predicate isClientFilter = c -> sessionId.equals((new UUID(c.getSession().getSessionIdMSB(), c.getSession().getSessionIdLSB()))); if (this.lwM2mClientsByEndpoint.size() > 0) { lwM2mClient = this.lwM2mClientsByEndpoint.values().stream().filter(isClientFilter).findAny().orElse(null); @@ -287,7 +287,7 @@ public class LwM2mClientContextImpl implements LwM2mClientContext { } @Override - public String getObjectIdByKeyNameFromProfile(LwM2mClient client, String keyName) { + public String getObjectIdByKeyNameFromProfile(LwM2MClient client, String keyName) { Lwm2mDeviceProfileTransportConfiguration profile = getProfile(client.getProfileId()); for (Map.Entry entry : profile.getObserveAttr().getKeyName().entrySet()) { String k = entry.getKey(); @@ -305,14 +305,14 @@ public class LwM2mClientContextImpl implements LwM2mClientContext { @Override public void registerClient(Registration registration, ValidateDeviceCredentialsResponse credentials) { - LwM2mClient client = getClientByEndpoint(registration.getEndpoint()); + LwM2MClient client = getClientByEndpoint(registration.getEndpoint()); client.init(credentials, UUID.randomUUID()); lwM2mClientsByRegistrationId.put(registration.getId(), client); profileUpdate(credentials.getDeviceProfile()); } @Override - public void update(LwM2mClient client) { + public void update(LwM2MClient client) { client.lock(); try { if (client.getState().equals(LwM2MClientState.REGISTERED)) { @@ -331,7 +331,7 @@ public class LwM2mClientContextImpl implements LwM2mClientContext { } @Override - public void sendMsgsAfterSleeping(LwM2mClient lwM2MClient) { + public void sendMsgsAfterSleeping(LwM2MClient lwM2MClient) { if (LwM2MClientState.REGISTERED.equals(lwM2MClient.getState())) { PowerMode powerMode = getPowerMode(lwM2MClient); if (PowerMode.PSM.equals(powerMode) || PowerMode.E_DRX.equals(powerMode)) { @@ -347,7 +347,7 @@ public class LwM2mClientContextImpl implements LwM2mClientContext { } } - private PowerMode getPowerMode(LwM2mClient lwM2MClient) { + private PowerMode getPowerMode(LwM2MClient lwM2MClient) { PowerMode powerMode = lwM2MClient.getPowerMode(); if (powerMode == null) { Lwm2mDeviceProfileTransportConfiguration deviceProfile = getProfile(lwM2MClient.getProfileId()); @@ -357,7 +357,7 @@ public class LwM2mClientContextImpl implements LwM2mClientContext { } @Override - public Collection getLwM2mClients() { + public Collection getLwM2mClients() { return lwM2mClientsByEndpoint.values(); } @@ -388,13 +388,13 @@ public class LwM2mClientContextImpl implements LwM2mClientContext { @Override public Lwm2mDeviceProfileTransportConfiguration profileUpdate(DeviceProfile deviceProfile) { - Lwm2mDeviceProfileTransportConfiguration clientProfile = LwM2mTransportUtil.toLwM2MClientProfile(deviceProfile); + Lwm2mDeviceProfileTransportConfiguration clientProfile = LwM2MTransportUtil.toLwM2MClientProfile(deviceProfile); profiles.put(deviceProfile.getUuidId(), clientProfile); return clientProfile; } @Override - public Set getSupportedIdVerInClient(LwM2mClient client) { + public Set getSupportedIdVerInClient(LwM2MClient client) { Set clientObjects = ConcurrentHashMap.newKeySet(); Arrays.stream(client.getRegistration().getObjectLinks()).forEach(link -> { LwM2mPath pathIds = new LwM2mPath(link.getUrl()); @@ -406,12 +406,12 @@ public class LwM2mClientContextImpl implements LwM2mClientContext { } @Override - public LwM2mClient getClientByDeviceId(UUID deviceId) { + public LwM2MClient getClientByDeviceId(UUID deviceId) { return lwM2mClientsByRegistrationId.values().stream().filter(e -> deviceId.equals(e.getDeviceId())).findFirst().orElse(null); } @Override - public boolean isDownlinkAllowed(LwM2mClient client) { + public boolean isDownlinkAllowed(LwM2MClient client) { PowerMode powerMode = client.getPowerMode(); OtherConfiguration profileSettings = null; if (powerMode == null) { @@ -460,7 +460,7 @@ public class LwM2mClientContextImpl implements LwM2mClientContext { } @Override - public void onUplink(LwM2mClient client) { + public void onUplink(LwM2MClient client) { PowerMode powerMode = client.getPowerMode(); OtherConfiguration profileSettings = null; if (powerMode == null) { @@ -518,7 +518,7 @@ public class LwM2mClientContextImpl implements LwM2mClientContext { } @Override - public Long getRequestTimeout(LwM2mClient client) { + public Long getRequestTimeout(LwM2MClient client) { Long timeout = null; if (PowerMode.E_DRX.equals(client.getPowerMode()) && client.getEdrxCycle() != null) { timeout = client.getEdrxCycle(); diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/AbstractTbLwM2MRequestCallback.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/AbstractTbLwM2MRequestCallback.java index 830b7ee4ca..68e222004d 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/AbstractTbLwM2MRequestCallback.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/AbstractTbLwM2MRequestCallback.java @@ -16,18 +16,18 @@ package org.thingsboard.server.transport.lwm2m.server.downlink; import lombok.extern.slf4j.Slf4j; -import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClient; import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService; -import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.LOG_LWM2M_ERROR; +import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.LOG_LWM2M_ERROR; @Slf4j public abstract class AbstractTbLwM2MRequestCallback implements DownlinkRequestCallback { protected final LwM2MTelemetryLogService logService; - protected final LwM2mClient client; + protected final LwM2MClient client; - protected AbstractTbLwM2MRequestCallback(LwM2MTelemetryLogService logService, LwM2mClient client) { + protected AbstractTbLwM2MRequestCallback(LwM2MTelemetryLogService logService, LwM2MClient client) { this.logService = logService; this.client = client; } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2mDownlinkMsgHandler.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2MDownlinkMsgHandler.java similarity index 84% rename from common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2mDownlinkMsgHandler.java rename to common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2MDownlinkMsgHandler.java index c980fde4ad..927a3cbf09 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2mDownlinkMsgHandler.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2MDownlinkMsgHandler.java @@ -64,14 +64,14 @@ import org.springframework.stereotype.Service; import org.thingsboard.server.common.data.device.data.lwm2m.ObjectAttributes; import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; -import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportContext; -import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; -import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientContext; +import org.thingsboard.server.transport.lwm2m.server.LwM2MTransportContext; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClient; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClientContext; import org.thingsboard.server.transport.lwm2m.server.common.LwM2MExecutorAwareService; import org.thingsboard.server.transport.lwm2m.server.downlink.composite.TbLwM2MReadCompositeRequest; import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService; import org.thingsboard.server.transport.lwm2m.server.rpc.composite.RpcWriteCompositeRequest; -import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl; +import org.thingsboard.server.transport.lwm2m.utils.LwM2MValueConverterImpl; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; @@ -94,29 +94,29 @@ import static org.eclipse.leshan.core.attributes.Attribute.MINIMUM_PERIOD; import static org.eclipse.leshan.core.attributes.Attribute.STEP; import static org.eclipse.leshan.core.model.ResourceModel.Type.OBJLNK; import static org.eclipse.leshan.core.model.ResourceModel.Type.OPAQUE; -import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.convertMultiResourceValuesFromRpcBody; -import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.createModelsDefault; -import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.fromVersionedIdToObjectId; -import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.getVerFromPathIdVerOrId; -import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.validateVersionedId; +import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.convertMultiResourceValuesFromRpcBody; +import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.createModelsDefault; +import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.fromVersionedIdToObjectId; +import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.getVerFromPathIdVerOrId; +import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.validateVersionedId; @Slf4j @Service @TbLwM2mTransportComponent @RequiredArgsConstructor -public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService implements LwM2mDownlinkMsgHandler { +public class DefaultLwM2MDownlinkMsgHandler extends LwM2MExecutorAwareService implements LwM2MDownlinkMsgHandler { - public LwM2mValueConverterImpl converter; + public LwM2MValueConverterImpl converter; - private final LwM2mTransportContext context; + private final LwM2MTransportContext context; private final LwM2MTransportServerConfig config; private final LwM2MTelemetryLogService logService; - private final LwM2mClientContext clientContext; + private final LwM2MClientContext clientContext; @PostConstruct public void init() { super.init(); - this.converter = LwM2mValueConverterImpl.getInstance(); + this.converter = LwM2MValueConverterImpl.getInstance(); } @PreDestroy @@ -135,7 +135,7 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im } @Override - public void sendReadRequest(LwM2mClient client, TbLwM2MReadRequest request, DownlinkRequestCallback callback) { + public void sendReadRequest(LwM2MClient client, TbLwM2MReadRequest request, DownlinkRequestCallback callback) { try { validateVersionedId(client, request); ReadRequest downlink = new ReadRequest(getReadRequestContentFormat(client, request, this.config.getModelProvider()), request.getObjectId()); @@ -146,7 +146,7 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im } @Override - public void sendReadCompositeRequest(LwM2mClient client, TbLwM2MReadCompositeRequest request, + public void sendReadCompositeRequest(LwM2MClient client, TbLwM2MReadCompositeRequest request, DownlinkRequestCallback callback, ContentFormat compositeContentFormat) { try { ReadCompositeRequest downlink = new ReadCompositeRequest(compositeContentFormat, compositeContentFormat, request.getObjectIds()); @@ -157,7 +157,7 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im } @Override - public void sendObserveRequest(LwM2mClient client, TbLwM2MObserveRequest request, DownlinkRequestCallback callback) { + public void sendObserveRequest(LwM2MClient client, TbLwM2MObserveRequest request, DownlinkRequestCallback callback) { try { validateVersionedId(client, request); LwM2mPath resultIds = new LwM2mPath(request.getObjectId()); @@ -183,19 +183,19 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im } @Override - public void sendObserveAllRequest(LwM2mClient client, TbLwM2MObserveAllRequest request, DownlinkRequestCallback> callback) { + public void sendObserveAllRequest(LwM2MClient client, TbLwM2MObserveAllRequest request, DownlinkRequestCallback> callback) { Set observations = context.getServer().getObservationService().getObservations(client.getRegistration()); Set paths = observations.stream().map(observation -> observation.getPath().toString()).collect(Collectors.toUnmodifiableSet()); callback.onSuccess(request, paths); } @Override - public void sendDiscoverAllRequest(LwM2mClient client, TbLwM2MDiscoverAllRequest request, DownlinkRequestCallback> callback) { + public void sendDiscoverAllRequest(LwM2MClient client, TbLwM2MDiscoverAllRequest request, DownlinkRequestCallback> callback) { callback.onSuccess(request, Arrays.asList(client.getRegistration().getSortedObjectLinks())); } @Override - public void sendExecuteRequest(LwM2mClient client, TbLwM2MExecuteRequest request, DownlinkRequestCallback callback) { + public void sendExecuteRequest(LwM2MClient client, TbLwM2MExecuteRequest request, DownlinkRequestCallback callback) { try { validateVersionedId(client, request); LwM2mPath pathIds = new LwM2mPath(fromVersionedIdToObjectId(request.getVersionedId())); @@ -210,8 +210,7 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im callback.onValidationError(request.toString(), "ResourceModel with " + request.getVersionedId() + " is absent in system. Need ddd Lwm2m Model with id=" + pathIds.getObjectId() + " ver=" + getVerFromPathIdVerOrId(request.getVersionedId()) + " to profile."); - } - else if (resourceModelExecute.operations.isExecutable()) { + } else if (resourceModelExecute.operations.isExecutable()) { ExecuteRequest downlink; if (request.getParams() != null && !resourceModelExecute.multiple) { downlink = new ExecuteRequest(request.getObjectId(), (String) this.converter.convertValue(request.getParams(), @@ -220,8 +219,7 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im downlink = new ExecuteRequest(request.getObjectId()); } sendSimpleRequest(client, downlink, request.getTimeout(), callback); - } - else { + } else { callback.onValidationError(request.toString(), "Resource with " + request.getVersionedId() + " is not executable."); } } catch (InvalidRequestException e) { @@ -230,7 +228,7 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im } @Override - public void sendDeleteRequest(LwM2mClient client, TbLwM2MDeleteRequest request, DownlinkRequestCallback callback) { + public void sendDeleteRequest(LwM2MClient client, TbLwM2MDeleteRequest request, DownlinkRequestCallback callback) { try { validateVersionedId(client, request); sendSimpleRequest(client, new DeleteRequest(request.getObjectId()), request.getTimeout(), callback); @@ -240,20 +238,20 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im } @Override - public void sendCancelObserveRequest(LwM2mClient client, TbLwM2MCancelObserveRequest request, DownlinkRequestCallback callback) { + public void sendCancelObserveRequest(LwM2MClient client, TbLwM2MCancelObserveRequest request, DownlinkRequestCallback callback) { validateVersionedId(client, request); int observeCancelCnt = context.getServer().getObservationService().cancelObservations(client.getRegistration(), request.getObjectId()); callback.onSuccess(request, observeCancelCnt); } @Override - public void sendCancelAllRequest(LwM2mClient client, TbLwM2MCancelAllRequest request, DownlinkRequestCallback callback) { + public void sendCancelAllRequest(LwM2MClient client, TbLwM2MCancelAllRequest request, DownlinkRequestCallback callback) { int observeCancelCnt = context.getServer().getObservationService().cancelObservations(client.getRegistration()); callback.onSuccess(request, observeCancelCnt); } @Override - public void sendDiscoverRequest(LwM2mClient client, TbLwM2MDiscoverRequest request, DownlinkRequestCallback callback) { + public void sendDiscoverRequest(LwM2MClient client, TbLwM2MDiscoverRequest request, DownlinkRequestCallback callback) { validateVersionedId(client, request); sendSimpleRequest(client, new DiscoverRequest(request.getObjectId()), request.getTimeout(), callback); } @@ -271,7 +269,7 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im * addAttribute(attributes, OBJECT_VERSION, params.getVer(), StringUtils::isNotEmpty, Function.identity()); */ @Override - public void sendWriteAttributesRequest(LwM2mClient client, TbLwM2MWriteAttributesRequest request, DownlinkRequestCallback callback) { + public void sendWriteAttributesRequest(LwM2MClient client, TbLwM2MWriteAttributesRequest request, DownlinkRequestCallback callback) { try { validateVersionedId(client, request); if (request.getAttributes() == null) { @@ -292,7 +290,7 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im } @Override - public void sendWriteReplaceRequest(LwM2mClient client, TbLwM2MWriteReplaceRequest request, DownlinkRequestCallback callback) { + public void sendWriteReplaceRequest(LwM2MClient client, TbLwM2MWriteReplaceRequest request, DownlinkRequestCallback callback) { LwM2mPath resultIds = new LwM2mPath(request.getObjectId()); if (resultIds.isResource() || resultIds.isResourceInstance()) { validateVersionedId(client, request); @@ -301,14 +299,15 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im ContentFormat contentFormat = getWriteRequestContentFormat(client, request, this.config.getModelProvider()); try { WriteRequest downlink = null; + String msgError = ""; if (resourceModelWrite.multiple) { try { Map value = convertMultiResourceValuesFromRpcBody(request.getValue(), resourceModelWrite.type, request.getObjectId()); downlink = new WriteRequest(contentFormat, resultIds.getObjectId(), resultIds.getObjectInstanceId(), resultIds.getResourceId(), value, resourceModelWrite.type); } catch (Exception e) { - callback.onValidationError(toString(request), "Resource id=" + resultIds.toString() + ", value = " + request.getValue() + - ", class = " + request.getValue().getClass().getSimpleName() + "is bad. Value of Multi-Instance Resource must be in Json format!"); + msgError = "Resource id=" + resultIds.toString() + ", value = " + request.getValue() + + ", class = " + request.getValue().getClass().getSimpleName() + "is bad. Value of Multi-Instance Resource must be in Json format!"; } } else { downlink = this.getWriteRequestSingleResource(resourceModelWrite.type, contentFormat, @@ -317,7 +316,10 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im if (downlink != null) { sendSimpleRequest(client, downlink, request.getTimeout(), callback); } else { - callback.onValidationError(toString(request), "WriteRequest is null."); + if (msgError.isEmpty()) { + msgError = "WriteRequest is null."; + } + callback.onValidationError(toString(request), msgError); } } catch (Exception e) { callback.onError(toString(request), e); @@ -332,7 +334,7 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im } @Override - public void sendWriteCompositeRequest(LwM2mClient client, RpcWriteCompositeRequest rpcWriteCompositeRequest, + public void sendWriteCompositeRequest(LwM2MClient client, RpcWriteCompositeRequest rpcWriteCompositeRequest, DownlinkRequestCallback callback, ContentFormat contentFormatComposite) { try { WriteCompositeRequest downlink = new WriteCompositeRequest(contentFormatComposite, rpcWriteCompositeRequest.getNodes()); @@ -346,57 +348,55 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im } @Override - public void sendWriteUpdateRequest(LwM2mClient client, TbLwM2MWriteUpdateRequest request, DownlinkRequestCallback callback) { + public void sendWriteUpdateRequest(LwM2MClient client, TbLwM2MWriteUpdateRequest request, DownlinkRequestCallback callback) { try { LwM2mPath resultIds = new LwM2mPath(request.getObjectId()); if (resultIds.isObjectInstance() || resultIds.isResource()) { validateVersionedId(client, request); WriteRequest downlink = null; - ContentFormat contentFormat = getWriteRequestContentFormat(client, request, this.config.getModelProvider()); - if (resultIds.isObjectInstance()) { - /* - * params = "{\"id\":0,\"value\":[{\"id\":14,\"value\":\"+5\"},{\"id\":15,\"value\":\"+9\"}]}" - * int rscId = resultIds.getObjectInstanceId(); - * contentFormat – Format of the payload (TLV or JSON). - */ - Collection resources = client.getNewResourcesForInstance(request.getVersionedId(), - request.getValue(), this.config.getModelProvider(), this.converter); - if (resources.size() > 0) { - downlink = new WriteRequest(WriteRequest.Mode.UPDATE, contentFormat, resultIds.getObjectId(), - resultIds.getObjectInstanceId(), resources); - } else { - callback.onValidationError(toString(request), "No resources to update!"); - } + ContentFormat contentFormat = getWriteRequestContentFormat(client, request, this.config.getModelProvider()); + String msgError = ""; + if (resultIds.isObjectInstance()) { + /* + * params = "{\"id\":0,\"value\":[{\"id\":14,\"value\":\"+5\"},{\"id\":15,\"value\":\"+9\"}]}" + * int rscId = resultIds.getObjectInstanceId(); + * contentFormat – Format of the payload (TLV or JSON). + */ + Collection resources = client.getNewResourcesForInstance(request.getVersionedId(), + request.getValue(), this.config.getModelProvider(), this.converter); + if (resources.size() > 0) { + downlink = new WriteRequest(WriteRequest.Mode.UPDATE, contentFormat, resultIds.getObjectId(), + resultIds.getObjectInstanceId(), resources); + } else { + msgError = " No resources to update!"; } - else if (resultIds.isResource()) { - ResourceModel resourceModelWrite = client.getResourceModel(request.getVersionedId(), this.config.getModelProvider()); - if (resourceModelWrite != null) { - if (resourceModelWrite.multiple) { - try { - Map value = convertMultiResourceValuesFromRpcBody(request.getValue(), resourceModelWrite.type, request.getObjectId()); - downlink = new WriteRequest(WriteRequest.Mode.UPDATE, contentFormat, resultIds.getObjectId(), - resultIds.getObjectInstanceId(), resultIds.getResourceId(), - value, resourceModelWrite.type); - } catch (Exception e1) { - callback.onValidationError(toString(request), "Resource id=" + resultIds.toString() + - ", class = " + request.getValue().getClass().getSimpleName() + - ", value = " + request.getValue() + " is bad. " + - "Value of Multi-Instance Resource must be in Json format!"); - } + } else if (resultIds.isResource()) { + ResourceModel resourceModelWrite = client.getResourceModel(request.getVersionedId(), this.config.getModelProvider()); + if (resourceModelWrite != null) { + if (resourceModelWrite.multiple) { + try { + Map value = convertMultiResourceValuesFromRpcBody(request.getValue(), resourceModelWrite.type, request.getObjectId()); + downlink = new WriteRequest(WriteRequest.Mode.UPDATE, contentFormat, resultIds.getObjectId(), + resultIds.getObjectInstanceId(), resultIds.getResourceId(), + value, resourceModelWrite.type); + } catch (Exception e1) { + msgError = " Resource id=" + resultIds.toString() + + ", class = " + request.getValue().getClass().getSimpleName() + + ", value = " + request.getValue() + " is bad. " + + "Value of Multi-Instance Resource must be in Json format!"; } - } else { - callback.onValidationError(toString(request), "Resource " + request.getVersionedId() + - " is not configured in the device profile!"); } - } - if (downlink != null) { - sendSimpleRequest(client, downlink, request.getTimeout(), callback); } else { - callback.onValidationError(toString(request), "Resource " + request.getVersionedId() + - ". This operation can only be used for ObjectInstance or Multi-Instance Resource !"); + msgError = " Resource " + request.getVersionedId() + " is not configured in the device profile!"; } - } - else { + } + if (downlink != null) { + sendSimpleRequest(client, downlink, request.getTimeout(), callback); + } else { + callback.onValidationError(toString(request), "Resource " + request.getVersionedId() + + ". This operation can only be used for ObjectInstance or Multi-Instance Resource !" + msgError); + } + } else { callback.onValidationError(toString(request), "Resource " + request.getVersionedId() + ". This operation can only be used for ObjectInstance or Resource (multiple)"); } @@ -405,7 +405,7 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im } } - public void sendCreateRequest(LwM2mClient client, TbLwM2MCreateRequest request, DownlinkRequestCallback callback) { + public void sendCreateRequest(LwM2MClient client, TbLwM2MCreateRequest request, DownlinkRequestCallback callback) { validateVersionedId(client, request); CreateRequest downlink = null; LwM2mPath resultIds = new LwM2mPath(request.getObjectId()); @@ -454,15 +454,15 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im } } - private , T extends LwM2mResponse> void sendSimpleRequest(LwM2mClient client, R request, long timeoutInMs, DownlinkRequestCallback callback) { + private , T extends LwM2mResponse> void sendSimpleRequest(LwM2MClient client, R request, long timeoutInMs, DownlinkRequestCallback callback) { sendRequest(client, request, timeoutInMs, callback, r -> request.getPath().toString()); } - private , T extends LwM2mResponse> void sendCompositeRequest(LwM2mClient client, R request, long timeoutInMs, DownlinkRequestCallback callback) { + private , T extends LwM2mResponse> void sendCompositeRequest(LwM2MClient client, R request, long timeoutInMs, DownlinkRequestCallback callback) { sendRequest(client, request, timeoutInMs, callback, r -> request.getPaths().toString()); } - private , T extends LwM2mResponse> void sendRequest(LwM2mClient client, R request, long timeoutInMs, DownlinkRequestCallback callback, Function pathToStringFunction) { + private , T extends LwM2mResponse> void sendRequest(LwM2MClient client, R request, long timeoutInMs, DownlinkRequestCallback callback, Function pathToStringFunction) { if (!clientContext.isDownlinkAllowed(client)) { log.trace("[{}] ignore downlink request cause client is sleeping.", client.getEndpoint()); return; @@ -487,7 +487,7 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im } } - private , T extends LwM2mResponse> void sendWriteCompositeRequest(LwM2mClient client, WriteCompositeRequest request, long timeoutInMs, DownlinkRequestCallback callback) { + private , T extends LwM2mResponse> void sendWriteCompositeRequest(LwM2MClient client, WriteCompositeRequest request, long timeoutInMs, DownlinkRequestCallback callback) { if (!clientContext.isDownlinkAllowed(client)) { log.trace("[{}] ignore downlink request cause client is sleeping.", client.getEndpoint()); return; @@ -515,7 +515,7 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im } } - private , T extends LwM2mResponse> void handleDownlinkError(LwM2mClient client, R request, DownlinkRequestCallback callback, Exception e) { + private , T extends LwM2mResponse> void handleDownlinkError(LwM2MClient client, R request, DownlinkRequestCallback callback, Exception e) { log.trace("[{}] Received downlink error: {}.", client.getEndpoint(), e); executor.submit(() -> { if (e instanceof TimeoutException || e instanceof ClientSleepingException) { @@ -571,7 +571,7 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im } } - private static ContentFormat getReadRequestContentFormat(LwM2mClient client, T request, LwM2mModelProvider modelProvider) { + private static ContentFormat getReadRequestContentFormat(LwM2MClient client, T request, LwM2mModelProvider modelProvider) { if (request.getRequestContentFormat().isPresent()) { return request.getRequestContentFormat().get(); } else { @@ -579,7 +579,7 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im } } - private static ContentFormat getWriteRequestContentFormat(LwM2mClient client, TbLwM2MDownlinkRequest request, LwM2mModelProvider modelProvider) { + private static ContentFormat getWriteRequestContentFormat(LwM2MClient client, TbLwM2MDownlinkRequest request, LwM2mModelProvider modelProvider) { if (request instanceof TbLwM2MWriteReplaceRequest && ((TbLwM2MWriteReplaceRequest) request).getContentFormat() != null) { return ((TbLwM2MWriteReplaceRequest) request).getContentFormat(); } else if (request instanceof TbLwM2MWriteUpdateRequest && ((TbLwM2MWriteUpdateRequest) request).getObjectContentFormat() != null) { @@ -597,7 +597,7 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im } } - private static ContentFormat getRequestContentFormat(LwM2mClient client, String versionedId, LwM2mModelProvider modelProvider) { + private static ContentFormat getRequestContentFormat(LwM2MClient client, String versionedId, LwM2mModelProvider modelProvider) { LwM2mPath pathIds = new LwM2mPath(fromVersionedIdToObjectId(versionedId)); if (pathIds.isResource() || pathIds.isResourceInstance()) { ResourceModel resourceModel = client.getResourceModel(versionedId, modelProvider); @@ -617,7 +617,7 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im } } - private static ContentFormat getContentFormatForComplex(LwM2mClient client) { + private static ContentFormat getContentFormatForComplex(LwM2MClient client) { if (LwM2m.Version.V1_0.equals(client.getRegistration().getLwM2mVersion())) { return ContentFormat.TLV; } else if (LwM2m.Version.V1_1.equals(client.getRegistration().getLwM2mVersion())) { diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/HasVersionedId.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/HasVersionedId.java index 5e427fcb31..7e4c25a82d 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/HasVersionedId.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/HasVersionedId.java @@ -15,14 +15,14 @@ */ package org.thingsboard.server.transport.lwm2m.server.downlink; -import org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil; +import org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil; public interface HasVersionedId { String getVersionedId(); default String getObjectId(){ - return LwM2mTransportUtil.fromVersionedIdToObjectId(getVersionedId()); + return LwM2MTransportUtil.fromVersionedIdToObjectId(getVersionedId()); } } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/HasVersionedIds.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/HasVersionedIds.java index a24789a410..3dda62669f 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/HasVersionedIds.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/HasVersionedIds.java @@ -15,7 +15,7 @@ */ package org.thingsboard.server.transport.lwm2m.server.downlink; -import org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil; +import org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; @@ -27,7 +27,7 @@ public interface HasVersionedIds { default String[] getObjectIds() { Set objectIds = ConcurrentHashMap.newKeySet(); for (String versionedId : getVersionedIds()) { - objectIds.add(LwM2mTransportUtil.fromVersionedIdToObjectId(versionedId)); + objectIds.add(LwM2MTransportUtil.fromVersionedIdToObjectId(versionedId)); } return objectIds.toArray(String[]::new); } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/LwM2mDownlinkMsgHandler.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/LwM2MDownlinkMsgHandler.java similarity index 78% rename from common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/LwM2mDownlinkMsgHandler.java rename to common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/LwM2MDownlinkMsgHandler.java index a4537af703..73a61b0c9d 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/LwM2mDownlinkMsgHandler.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/LwM2MDownlinkMsgHandler.java @@ -37,43 +37,43 @@ import org.eclipse.leshan.core.response.ReadResponse; import org.eclipse.leshan.core.response.WriteAttributesResponse; import org.eclipse.leshan.core.response.WriteCompositeResponse; import org.eclipse.leshan.core.response.WriteResponse; -import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClient; import org.thingsboard.server.transport.lwm2m.server.downlink.composite.TbLwM2MReadCompositeRequest; import org.thingsboard.server.transport.lwm2m.server.rpc.composite.RpcWriteCompositeRequest; import java.util.List; import java.util.Set; -public interface LwM2mDownlinkMsgHandler { +public interface LwM2MDownlinkMsgHandler { - void sendReadRequest(LwM2mClient client, TbLwM2MReadRequest request, DownlinkRequestCallback callback); + void sendReadRequest(LwM2MClient client, TbLwM2MReadRequest request, DownlinkRequestCallback callback); - void sendReadCompositeRequest(LwM2mClient client, TbLwM2MReadCompositeRequest request, DownlinkRequestCallback callback, ContentFormat contentFormatComposite); + void sendReadCompositeRequest(LwM2MClient client, TbLwM2MReadCompositeRequest request, DownlinkRequestCallback callback, ContentFormat contentFormatComposite); - void sendObserveRequest(LwM2mClient client, TbLwM2MObserveRequest request, DownlinkRequestCallback callback); + void sendObserveRequest(LwM2MClient client, TbLwM2MObserveRequest request, DownlinkRequestCallback callback); - void sendObserveAllRequest(LwM2mClient client, TbLwM2MObserveAllRequest request, DownlinkRequestCallback> callback); + void sendObserveAllRequest(LwM2MClient client, TbLwM2MObserveAllRequest request, DownlinkRequestCallback> callback); - void sendExecuteRequest(LwM2mClient client, TbLwM2MExecuteRequest request, DownlinkRequestCallback callback); + void sendExecuteRequest(LwM2MClient client, TbLwM2MExecuteRequest request, DownlinkRequestCallback callback); - void sendDeleteRequest(LwM2mClient client, TbLwM2MDeleteRequest request, DownlinkRequestCallback callback); + void sendDeleteRequest(LwM2MClient client, TbLwM2MDeleteRequest request, DownlinkRequestCallback callback); - void sendCancelObserveRequest(LwM2mClient client, TbLwM2MCancelObserveRequest request, DownlinkRequestCallback callback); + void sendCancelObserveRequest(LwM2MClient client, TbLwM2MCancelObserveRequest request, DownlinkRequestCallback callback); - void sendCancelAllRequest(LwM2mClient client, TbLwM2MCancelAllRequest request, DownlinkRequestCallback callback); + void sendCancelAllRequest(LwM2MClient client, TbLwM2MCancelAllRequest request, DownlinkRequestCallback callback); - void sendDiscoverRequest(LwM2mClient client, TbLwM2MDiscoverRequest request, DownlinkRequestCallback callback); + void sendDiscoverRequest(LwM2MClient client, TbLwM2MDiscoverRequest request, DownlinkRequestCallback callback); - void sendDiscoverAllRequest(LwM2mClient client, TbLwM2MDiscoverAllRequest request, DownlinkRequestCallback> callback); + void sendDiscoverAllRequest(LwM2MClient client, TbLwM2MDiscoverAllRequest request, DownlinkRequestCallback> callback); - void sendWriteAttributesRequest(LwM2mClient client, TbLwM2MWriteAttributesRequest request, DownlinkRequestCallback callback); + void sendWriteAttributesRequest(LwM2MClient client, TbLwM2MWriteAttributesRequest request, DownlinkRequestCallback callback); - void sendWriteReplaceRequest(LwM2mClient client, TbLwM2MWriteReplaceRequest request, DownlinkRequestCallback callback); + void sendWriteReplaceRequest(LwM2MClient client, TbLwM2MWriteReplaceRequest request, DownlinkRequestCallback callback); - void sendWriteCompositeRequest(LwM2mClient client, RpcWriteCompositeRequest nodes, DownlinkRequestCallback callback, ContentFormat contentFormatComposite); + void sendWriteCompositeRequest(LwM2MClient client, RpcWriteCompositeRequest nodes, DownlinkRequestCallback callback, ContentFormat contentFormatComposite); - void sendWriteUpdateRequest(LwM2mClient client, TbLwM2MWriteUpdateRequest request, DownlinkRequestCallback callback); + void sendWriteUpdateRequest(LwM2MClient client, TbLwM2MWriteUpdateRequest request, DownlinkRequestCallback callback); - void sendCreateRequest(LwM2mClient client, TbLwM2MCreateRequest request, DownlinkRequestCallback callback); + void sendCreateRequest(LwM2MClient client, TbLwM2MCreateRequest request, DownlinkRequestCallback callback); } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MCancelAllObserveCallback.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MCancelAllObserveCallback.java index d59ab9f16d..d39b3286f9 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MCancelAllObserveCallback.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MCancelAllObserveCallback.java @@ -16,15 +16,15 @@ package org.thingsboard.server.transport.lwm2m.server.downlink; import lombok.extern.slf4j.Slf4j; -import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClient; import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService; -import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.LOG_LWM2M_INFO; +import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.LOG_LWM2M_INFO; @Slf4j public class TbLwM2MCancelAllObserveCallback extends AbstractTbLwM2MRequestCallback { - public TbLwM2MCancelAllObserveCallback(LwM2MTelemetryLogService logService, LwM2mClient client) { + public TbLwM2MCancelAllObserveCallback(LwM2MTelemetryLogService logService, LwM2MClient client) { super(logService, client); } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MCancelAllRequest.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MCancelAllRequest.java index f4e02e6222..4d80b0932e 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MCancelAllRequest.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MCancelAllRequest.java @@ -17,7 +17,7 @@ package org.thingsboard.server.transport.lwm2m.server.downlink; import lombok.Builder; import lombok.Getter; -import org.thingsboard.server.transport.lwm2m.server.LwM2mOperationType; +import org.thingsboard.server.transport.lwm2m.server.LwM2MOperationType; public class TbLwM2MCancelAllRequest implements TbLwM2MDownlinkRequest { @@ -30,8 +30,8 @@ public class TbLwM2MCancelAllRequest implements TbLwM2MDownlinkRequest } @Override - public LwM2mOperationType getType() { - return LwM2mOperationType.OBSERVE_CANCEL_ALL; + public LwM2MOperationType getType() { + return LwM2MOperationType.OBSERVE_CANCEL_ALL; } } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MCancelObserveCallback.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MCancelObserveCallback.java index 85accc5166..cd424b7047 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MCancelObserveCallback.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MCancelObserveCallback.java @@ -16,17 +16,17 @@ package org.thingsboard.server.transport.lwm2m.server.downlink; import lombok.extern.slf4j.Slf4j; -import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClient; import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService; -import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.LOG_LWM2M_INFO; +import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.LOG_LWM2M_INFO; @Slf4j public class TbLwM2MCancelObserveCallback extends AbstractTbLwM2MRequestCallback { private final String versionedId; - public TbLwM2MCancelObserveCallback(LwM2MTelemetryLogService logService, LwM2mClient client, String versionedId) { + public TbLwM2MCancelObserveCallback(LwM2MTelemetryLogService logService, LwM2MClient client, String versionedId) { super(logService, client); this.versionedId = versionedId; } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MCancelObserveRequest.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MCancelObserveRequest.java index cb4d056578..dd243e2a2e 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MCancelObserveRequest.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MCancelObserveRequest.java @@ -16,7 +16,7 @@ package org.thingsboard.server.transport.lwm2m.server.downlink; import lombok.Builder; -import org.thingsboard.server.transport.lwm2m.server.LwM2mOperationType; +import org.thingsboard.server.transport.lwm2m.server.LwM2MOperationType; public class TbLwM2MCancelObserveRequest extends AbstractTbLwM2MTargetedDownlinkRequest { @@ -26,8 +26,8 @@ public class TbLwM2MCancelObserveRequest extends AbstractTbLwM2MTargetedDownlink } @Override - public LwM2mOperationType getType() { - return LwM2mOperationType.OBSERVE_CANCEL; + public LwM2MOperationType getType() { + return LwM2MOperationType.OBSERVE_CANCEL; } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MCreateRequest.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MCreateRequest.java index 76e7ca845a..ecc66c20f9 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MCreateRequest.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MCreateRequest.java @@ -19,7 +19,7 @@ import lombok.Builder; import lombok.Getter; import org.eclipse.leshan.core.request.ContentFormat; import org.eclipse.leshan.core.response.CreateResponse; -import org.thingsboard.server.transport.lwm2m.server.LwM2mOperationType; +import org.thingsboard.server.transport.lwm2m.server.LwM2MOperationType; import java.util.Map; @@ -41,7 +41,7 @@ public class TbLwM2MCreateRequest extends AbstractTbLwM2MTargetedDownlinkRequest } @Override - public LwM2mOperationType getType() { - return LwM2mOperationType.CREATE; + public LwM2MOperationType getType() { + return LwM2MOperationType.CREATE; } } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MCreateResponseCallback.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MCreateResponseCallback.java index 316bbd4636..d0cf1e02e0 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MCreateResponseCallback.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MCreateResponseCallback.java @@ -17,13 +17,13 @@ package org.thingsboard.server.transport.lwm2m.server.downlink; import org.eclipse.leshan.core.request.CreateRequest; import org.eclipse.leshan.core.response.CreateResponse; -import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClient; import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService; -import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler; +import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2MUplinkMsgHandler; public class TbLwM2MCreateResponseCallback extends TbLwM2MUplinkTargetedCallback { - public TbLwM2MCreateResponseCallback(LwM2mUplinkMsgHandler handler, LwM2MTelemetryLogService logService, LwM2mClient client, String targetId) { + public TbLwM2MCreateResponseCallback(LwM2MUplinkMsgHandler handler, LwM2MTelemetryLogService logService, LwM2MClient client, String targetId) { super(handler, logService, client, targetId); } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MDeleteCallback.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MDeleteCallback.java index 2b3c544dae..798ad4e471 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MDeleteCallback.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MDeleteCallback.java @@ -17,12 +17,12 @@ package org.thingsboard.server.transport.lwm2m.server.downlink; import org.eclipse.leshan.core.request.DeleteRequest; import org.eclipse.leshan.core.response.DeleteResponse; -import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClient; import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService; public class TbLwM2MDeleteCallback extends TbLwM2MTargetedCallback { - public TbLwM2MDeleteCallback(LwM2MTelemetryLogService logService, LwM2mClient client, String targetId) { + public TbLwM2MDeleteCallback(LwM2MTelemetryLogService logService, LwM2MClient client, String targetId) { super(logService, client, targetId); } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MDeleteRequest.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MDeleteRequest.java index b9649c0708..053106ca2d 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MDeleteRequest.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MDeleteRequest.java @@ -17,7 +17,7 @@ package org.thingsboard.server.transport.lwm2m.server.downlink; import lombok.Builder; import org.eclipse.leshan.core.response.ReadResponse; -import org.thingsboard.server.transport.lwm2m.server.LwM2mOperationType; +import org.thingsboard.server.transport.lwm2m.server.LwM2MOperationType; public class TbLwM2MDeleteRequest extends AbstractTbLwM2MTargetedDownlinkRequest { @@ -27,8 +27,8 @@ public class TbLwM2MDeleteRequest extends AbstractTbLwM2MTargetedDownlinkRequest } @Override - public LwM2mOperationType getType() { - return LwM2mOperationType.DELETE; + public LwM2MOperationType getType() { + return LwM2MOperationType.DELETE; } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MDiscoverAllRequest.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MDiscoverAllRequest.java index 291bdc907c..bf29a0c027 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MDiscoverAllRequest.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MDiscoverAllRequest.java @@ -17,7 +17,7 @@ package org.thingsboard.server.transport.lwm2m.server.downlink; import lombok.Builder; import lombok.Getter; -import org.thingsboard.server.transport.lwm2m.server.LwM2mOperationType; +import org.thingsboard.server.transport.lwm2m.server.LwM2MOperationType; public class TbLwM2MDiscoverAllRequest implements TbLwM2MDownlinkRequest { @@ -30,8 +30,8 @@ public class TbLwM2MDiscoverAllRequest implements TbLwM2MDownlinkRequest } @Override - public LwM2mOperationType getType() { - return LwM2mOperationType.DISCOVER_ALL; + public LwM2MOperationType getType() { + return LwM2MOperationType.DISCOVER_ALL; } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MDiscoverCallback.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MDiscoverCallback.java index cc855fd3a8..e4ce1c0823 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MDiscoverCallback.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MDiscoverCallback.java @@ -17,12 +17,12 @@ package org.thingsboard.server.transport.lwm2m.server.downlink; import org.eclipse.leshan.core.request.DiscoverRequest; import org.eclipse.leshan.core.response.DiscoverResponse; -import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClient; import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService; public class TbLwM2MDiscoverCallback extends TbLwM2MTargetedCallback { - public TbLwM2MDiscoverCallback(LwM2MTelemetryLogService logService, LwM2mClient client, String targetId) { + public TbLwM2MDiscoverCallback(LwM2MTelemetryLogService logService, LwM2MClient client, String targetId) { super(logService, client, targetId); } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MDiscoverRequest.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MDiscoverRequest.java index 85aa75de3c..b4a5975ec4 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MDiscoverRequest.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MDiscoverRequest.java @@ -17,7 +17,7 @@ package org.thingsboard.server.transport.lwm2m.server.downlink; import lombok.Builder; import org.eclipse.leshan.core.response.DiscoverResponse; -import org.thingsboard.server.transport.lwm2m.server.LwM2mOperationType; +import org.thingsboard.server.transport.lwm2m.server.LwM2MOperationType; public class TbLwM2MDiscoverRequest extends AbstractTbLwM2MTargetedDownlinkRequest { @@ -27,8 +27,8 @@ public class TbLwM2MDiscoverRequest extends AbstractTbLwM2MTargetedDownlinkReque } @Override - public LwM2mOperationType getType() { - return LwM2mOperationType.DISCOVER; + public LwM2MOperationType getType() { + return LwM2MOperationType.DISCOVER; } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MDownlinkRequest.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MDownlinkRequest.java index 3ea174c72d..43e532a380 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MDownlinkRequest.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MDownlinkRequest.java @@ -15,11 +15,11 @@ */ package org.thingsboard.server.transport.lwm2m.server.downlink; -import org.thingsboard.server.transport.lwm2m.server.LwM2mOperationType; +import org.thingsboard.server.transport.lwm2m.server.LwM2MOperationType; public interface TbLwM2MDownlinkRequest { - LwM2mOperationType getType(); + LwM2MOperationType getType(); long getTimeout(); diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MExecuteCallback.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MExecuteCallback.java index 9315e9ded6..23e9734714 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MExecuteCallback.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MExecuteCallback.java @@ -17,12 +17,12 @@ package org.thingsboard.server.transport.lwm2m.server.downlink; import org.eclipse.leshan.core.request.ExecuteRequest; import org.eclipse.leshan.core.response.ExecuteResponse; -import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClient; import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService; public class TbLwM2MExecuteCallback extends TbLwM2MTargetedCallback { - public TbLwM2MExecuteCallback(LwM2MTelemetryLogService logService, LwM2mClient client, String targetId) { + public TbLwM2MExecuteCallback(LwM2MTelemetryLogService logService, LwM2MClient client, String targetId) { super(logService, client, targetId); } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MExecuteRequest.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MExecuteRequest.java index 76cf8cd0eb..dbdc692f53 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MExecuteRequest.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MExecuteRequest.java @@ -18,7 +18,7 @@ package org.thingsboard.server.transport.lwm2m.server.downlink; import lombok.Builder; import lombok.Getter; import org.eclipse.leshan.core.response.ReadResponse; -import org.thingsboard.server.transport.lwm2m.server.LwM2mOperationType; +import org.thingsboard.server.transport.lwm2m.server.LwM2MOperationType; public class TbLwM2MExecuteRequest extends AbstractTbLwM2MTargetedDownlinkRequest { @@ -32,8 +32,8 @@ public class TbLwM2MExecuteRequest extends AbstractTbLwM2MTargetedDownlinkReques } @Override - public LwM2mOperationType getType() { - return LwM2mOperationType.EXECUTE; + public LwM2MOperationType getType() { + return LwM2MOperationType.EXECUTE; } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MObserveAllRequest.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MObserveAllRequest.java index 2aba4f0a58..4813d38181 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MObserveAllRequest.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MObserveAllRequest.java @@ -17,7 +17,7 @@ package org.thingsboard.server.transport.lwm2m.server.downlink; import lombok.Builder; import lombok.Getter; -import org.thingsboard.server.transport.lwm2m.server.LwM2mOperationType; +import org.thingsboard.server.transport.lwm2m.server.LwM2MOperationType; import java.util.Set; @@ -32,8 +32,8 @@ public class TbLwM2MObserveAllRequest implements TbLwM2MDownlinkRequest { - public TbLwM2MObserveCallback(LwM2mUplinkMsgHandler handler, LwM2MTelemetryLogService logService, LwM2mClient client, String targetId) { + public TbLwM2MObserveCallback(LwM2MUplinkMsgHandler handler, LwM2MTelemetryLogService logService, LwM2MClient client, String targetId) { super(handler, logService, client, targetId); } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MObserveRequest.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MObserveRequest.java index 849d0dd2bf..1c41a48b2f 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MObserveRequest.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MObserveRequest.java @@ -18,7 +18,7 @@ package org.thingsboard.server.transport.lwm2m.server.downlink; import lombok.Builder; import org.eclipse.leshan.core.request.ContentFormat; import org.eclipse.leshan.core.response.ObserveResponse; -import org.thingsboard.server.transport.lwm2m.server.LwM2mOperationType; +import org.thingsboard.server.transport.lwm2m.server.LwM2MOperationType; import java.util.Optional; @@ -33,8 +33,8 @@ public class TbLwM2MObserveRequest extends AbstractTbLwM2MTargetedDownlinkReques } @Override - public LwM2mOperationType getType() { - return LwM2mOperationType.OBSERVE; + public LwM2MOperationType getType() { + return LwM2MOperationType.OBSERVE; } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MReadCallback.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MReadCallback.java index 0ae17ea449..6de67eea5e 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MReadCallback.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MReadCallback.java @@ -20,14 +20,14 @@ import org.eclipse.leshan.core.node.LwM2mSingleResource; import org.eclipse.leshan.core.request.ReadRequest; import org.eclipse.leshan.core.response.ReadResponse; import org.eclipse.leshan.core.util.Hex; -import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClient; import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService; -import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler; +import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2MUplinkMsgHandler; @Slf4j public class TbLwM2MReadCallback extends TbLwM2MUplinkTargetedCallback { - public TbLwM2MReadCallback(LwM2mUplinkMsgHandler handler, LwM2MTelemetryLogService logService, LwM2mClient client, String targetId) { + public TbLwM2MReadCallback(LwM2MUplinkMsgHandler handler, LwM2MTelemetryLogService logService, LwM2MClient client, String targetId) { super(handler, logService, client, targetId); } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MReadRequest.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MReadRequest.java index 39c4b0fb4b..5e5ffb163a 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MReadRequest.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MReadRequest.java @@ -18,7 +18,7 @@ package org.thingsboard.server.transport.lwm2m.server.downlink; import lombok.Builder; import org.eclipse.leshan.core.request.ContentFormat; import org.eclipse.leshan.core.response.ReadResponse; -import org.thingsboard.server.transport.lwm2m.server.LwM2mOperationType; +import org.thingsboard.server.transport.lwm2m.server.LwM2MOperationType; import java.util.Optional; @@ -33,8 +33,8 @@ public class TbLwM2MReadRequest extends AbstractTbLwM2MTargetedDownlinkRequest extends AbstractTbLwM2MRequestCallback { @@ -32,13 +32,13 @@ public abstract class TbLwM2MTargetedCallback extends AbstractTbLwM2MReque protected final String versionedId; protected final String[] versionedIds; - public TbLwM2MTargetedCallback(LwM2MTelemetryLogService logService, LwM2mClient client, String versionedId) { + public TbLwM2MTargetedCallback(LwM2MTelemetryLogService logService, LwM2MClient client, String versionedId) { super(logService, client); this.versionedId = versionedId; this.versionedIds = null; } - public TbLwM2MTargetedCallback(LwM2MTelemetryLogService logService, LwM2mClient client, String[] versionedIds) { + public TbLwM2MTargetedCallback(LwM2MTelemetryLogService logService, LwM2MClient client, String[] versionedIds) { super(logService, client); this.versionedId = null; this.versionedIds = versionedIds; diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MUplinkTargetedCallback.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MUplinkTargetedCallback.java index 520d49eb30..16c69237bb 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MUplinkTargetedCallback.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MUplinkTargetedCallback.java @@ -16,21 +16,21 @@ package org.thingsboard.server.transport.lwm2m.server.downlink; import lombok.extern.slf4j.Slf4j; -import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClient; import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService; -import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler; +import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2MUplinkMsgHandler; @Slf4j public abstract class TbLwM2MUplinkTargetedCallback extends TbLwM2MTargetedCallback { - protected LwM2mUplinkMsgHandler handler; + protected LwM2MUplinkMsgHandler handler; - public TbLwM2MUplinkTargetedCallback(LwM2mUplinkMsgHandler handler, LwM2MTelemetryLogService logService, LwM2mClient client, String versionedId) { + public TbLwM2MUplinkTargetedCallback(LwM2MUplinkMsgHandler handler, LwM2MTelemetryLogService logService, LwM2MClient client, String versionedId) { super(logService, client, versionedId); this.handler = handler; } - public TbLwM2MUplinkTargetedCallback(LwM2mUplinkMsgHandler handler, LwM2MTelemetryLogService logService, LwM2mClient client, String[] versionedIds) { + public TbLwM2MUplinkTargetedCallback(LwM2MUplinkMsgHandler handler, LwM2MTelemetryLogService logService, LwM2MClient client, String[] versionedIds) { super(logService, client, versionedIds); this.handler = handler; } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MWriteAttributesCallback.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MWriteAttributesCallback.java index 3e4847ce1e..8b30e9bfe4 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MWriteAttributesCallback.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MWriteAttributesCallback.java @@ -17,12 +17,12 @@ package org.thingsboard.server.transport.lwm2m.server.downlink; import org.eclipse.leshan.core.request.WriteAttributesRequest; import org.eclipse.leshan.core.response.WriteAttributesResponse; -import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClient; import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService; public class TbLwM2MWriteAttributesCallback extends TbLwM2MTargetedCallback { - public TbLwM2MWriteAttributesCallback(LwM2MTelemetryLogService logService, LwM2mClient client, String targetId) { + public TbLwM2MWriteAttributesCallback(LwM2MTelemetryLogService logService, LwM2MClient client, String targetId) { super(logService, client, targetId); } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MWriteAttributesRequest.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MWriteAttributesRequest.java index 6ef198a28f..1c56574b0f 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MWriteAttributesRequest.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MWriteAttributesRequest.java @@ -19,7 +19,7 @@ import lombok.Builder; import lombok.Getter; import org.eclipse.leshan.core.response.WriteAttributesResponse; import org.thingsboard.server.common.data.device.data.lwm2m.ObjectAttributes; -import org.thingsboard.server.transport.lwm2m.server.LwM2mOperationType; +import org.thingsboard.server.transport.lwm2m.server.LwM2MOperationType; public class TbLwM2MWriteAttributesRequest extends AbstractTbLwM2MTargetedDownlinkRequest { @@ -33,8 +33,8 @@ public class TbLwM2MWriteAttributesRequest extends AbstractTbLwM2MTargetedDownli } @Override - public LwM2mOperationType getType() { - return LwM2mOperationType.WRITE_ATTRIBUTES; + public LwM2MOperationType getType() { + return LwM2MOperationType.WRITE_ATTRIBUTES; } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MWriteReplaceRequest.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MWriteReplaceRequest.java index f4b1059944..9760e13e5a 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MWriteReplaceRequest.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MWriteReplaceRequest.java @@ -19,7 +19,7 @@ import lombok.Builder; import lombok.Getter; import org.eclipse.leshan.core.request.ContentFormat; import org.eclipse.leshan.core.response.WriteResponse; -import org.thingsboard.server.transport.lwm2m.server.LwM2mOperationType; +import org.thingsboard.server.transport.lwm2m.server.LwM2MOperationType; public class TbLwM2MWriteReplaceRequest extends AbstractTbLwM2MTargetedDownlinkRequest { @@ -36,8 +36,8 @@ public class TbLwM2MWriteReplaceRequest extends AbstractTbLwM2MTargetedDownlinkR } @Override - public LwM2mOperationType getType() { - return LwM2mOperationType.WRITE_REPLACE; + public LwM2MOperationType getType() { + return LwM2MOperationType.WRITE_REPLACE; } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MWriteResponseCallback.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MWriteResponseCallback.java index a452c3b187..11b7d3e4cd 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MWriteResponseCallback.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MWriteResponseCallback.java @@ -18,14 +18,14 @@ package org.thingsboard.server.transport.lwm2m.server.downlink; import lombok.extern.slf4j.Slf4j; import org.eclipse.leshan.core.request.WriteRequest; import org.eclipse.leshan.core.response.WriteResponse; -import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClient; import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService; -import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler; +import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2MUplinkMsgHandler; @Slf4j public class TbLwM2MWriteResponseCallback extends TbLwM2MUplinkTargetedCallback { - public TbLwM2MWriteResponseCallback(LwM2mUplinkMsgHandler handler, LwM2MTelemetryLogService logService, LwM2mClient client, String targetId) { + public TbLwM2MWriteResponseCallback(LwM2MUplinkMsgHandler handler, LwM2MTelemetryLogService logService, LwM2MClient client, String targetId) { super(handler, logService, client, targetId); } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MWriteUpdateRequest.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MWriteUpdateRequest.java index a9465e082d..6e8708053b 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MWriteUpdateRequest.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MWriteUpdateRequest.java @@ -19,7 +19,7 @@ import lombok.Builder; import lombok.Getter; import org.eclipse.leshan.core.request.ContentFormat; import org.eclipse.leshan.core.response.WriteResponse; -import org.thingsboard.server.transport.lwm2m.server.LwM2mOperationType; +import org.thingsboard.server.transport.lwm2m.server.LwM2MOperationType; public class TbLwM2MWriteUpdateRequest extends AbstractTbLwM2MTargetedDownlinkRequest { @@ -36,8 +36,8 @@ public class TbLwM2MWriteUpdateRequest extends AbstractTbLwM2MTargetedDownlinkRe } @Override - public LwM2mOperationType getType() { - return LwM2mOperationType.WRITE_UPDATE; + public LwM2MOperationType getType() { + return LwM2MOperationType.WRITE_UPDATE; } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/composite/TbLwM2MReadCompositeCallback.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/composite/TbLwM2MReadCompositeCallback.java index 82e0936b87..9c88be56f7 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/composite/TbLwM2MReadCompositeCallback.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/composite/TbLwM2MReadCompositeCallback.java @@ -18,15 +18,15 @@ package org.thingsboard.server.transport.lwm2m.server.downlink.composite; import lombok.extern.slf4j.Slf4j; import org.eclipse.leshan.core.request.ReadCompositeRequest; import org.eclipse.leshan.core.response.ReadCompositeResponse; -import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClient; import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MUplinkTargetedCallback; import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService; -import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler; +import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2MUplinkMsgHandler; @Slf4j public class TbLwM2MReadCompositeCallback extends TbLwM2MUplinkTargetedCallback { - public TbLwM2MReadCompositeCallback(LwM2mUplinkMsgHandler handler, LwM2MTelemetryLogService logService, LwM2mClient client, String[] versionedIds) { + public TbLwM2MReadCompositeCallback(LwM2MUplinkMsgHandler handler, LwM2MTelemetryLogService logService, LwM2MClient client, String[] versionedIds) { super(handler, logService, client, versionedIds); } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/composite/TbLwM2MReadCompositeRequest.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/composite/TbLwM2MReadCompositeRequest.java index 086a3d7049..f9c4afcc40 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/composite/TbLwM2MReadCompositeRequest.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/composite/TbLwM2MReadCompositeRequest.java @@ -19,7 +19,7 @@ import lombok.Builder; import lombok.Getter; import org.eclipse.leshan.core.request.ContentFormat; import org.eclipse.leshan.core.response.ReadCompositeResponse; -import org.thingsboard.server.transport.lwm2m.server.LwM2mOperationType; +import org.thingsboard.server.transport.lwm2m.server.LwM2MOperationType; import org.thingsboard.server.transport.lwm2m.server.downlink.HasContentFormat; import java.util.Optional; @@ -40,8 +40,8 @@ public class TbLwM2MReadCompositeRequest extends AbstractTbLwM2MTargetedDownlink } @Override - public LwM2mOperationType getType() { - return LwM2mOperationType.READ_COMPOSITE; + public LwM2MOperationType getType() { + return LwM2MOperationType.READ_COMPOSITE; } @Override diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/composite/TbLwM2MWriteCompositeRequest.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/composite/TbLwM2MWriteCompositeRequest.java index 0e3ffaed28..c3fe137cae 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/composite/TbLwM2MWriteCompositeRequest.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/composite/TbLwM2MWriteCompositeRequest.java @@ -19,7 +19,7 @@ import lombok.Builder; import lombok.Getter; import org.eclipse.leshan.core.request.ContentFormat; import org.eclipse.leshan.core.response.WriteCompositeResponse; -import org.thingsboard.server.transport.lwm2m.server.LwM2mOperationType; +import org.thingsboard.server.transport.lwm2m.server.LwM2MOperationType; import org.thingsboard.server.transport.lwm2m.server.downlink.AbstractTbLwM2MTargetedDownlinkRequest; public class TbLwM2MWriteCompositeRequest extends AbstractTbLwM2MTargetedDownlinkRequest { @@ -37,8 +37,8 @@ public class TbLwM2MWriteCompositeRequest extends AbstractTbLwM2MTargetedDownlin } @Override - public LwM2mOperationType getType() { - return LwM2mOperationType.WRITE_REPLACE; + public LwM2MOperationType getType() { + return LwM2MOperationType.WRITE_REPLACE; } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/composite/TbLwM2MWriteResponseCompositeCallback.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/composite/TbLwM2MWriteResponseCompositeCallback.java index 6d5de06e90..8c8d8de031 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/composite/TbLwM2MWriteResponseCompositeCallback.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/composite/TbLwM2MWriteResponseCompositeCallback.java @@ -17,14 +17,14 @@ package org.thingsboard.server.transport.lwm2m.server.downlink.composite; import org.eclipse.leshan.core.request.WriteCompositeRequest; import org.eclipse.leshan.core.response.WriteCompositeResponse; -import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClient; import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MUplinkTargetedCallback; import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService; -import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler; +import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2MUplinkMsgHandler; public class TbLwM2MWriteResponseCompositeCallback extends TbLwM2MUplinkTargetedCallback { - public TbLwM2MWriteResponseCompositeCallback(LwM2mUplinkMsgHandler handler, LwM2MTelemetryLogService logService, LwM2mClient client, String targetId) { + public TbLwM2MWriteResponseCompositeCallback(LwM2MUplinkMsgHandler handler, LwM2MTelemetryLogService logService, LwM2MClient client, String targetId) { super(handler, logService, client, targetId); } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/log/DefaultLwM2MTelemetryLogService.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/log/DefaultLwM2MTelemetryLogService.java index ceaa163b63..65ec45c83d 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/log/DefaultLwM2MTelemetryLogService.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/log/DefaultLwM2MTelemetryLogService.java @@ -19,10 +19,10 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; -import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportServerHelper; -import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; +import org.thingsboard.server.transport.lwm2m.server.LwM2MTransportServerHelper; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClient; -import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.LOG_LWM2M_TELEMETRY; +import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.LOG_LWM2M_TELEMETRY; @Slf4j @Service @@ -30,10 +30,10 @@ import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.LO @RequiredArgsConstructor public class DefaultLwM2MTelemetryLogService implements LwM2MTelemetryLogService { - private final LwM2mTransportServerHelper helper; + private final LwM2MTransportServerHelper helper; @Override - public void log(LwM2mClient client, String logMsg) { + public void log(LwM2MClient client, String logMsg) { if (logMsg != null && client != null && client.getSession() != null) { if (logMsg.length() > 1024) { logMsg = logMsg.substring(0, 1024); diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/log/LwM2MTelemetryLogService.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/log/LwM2MTelemetryLogService.java index f2276fa9af..f4c16602c9 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/log/LwM2MTelemetryLogService.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/log/LwM2MTelemetryLogService.java @@ -15,10 +15,10 @@ */ package org.thingsboard.server.transport.lwm2m.server.log; -import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClient; public interface LwM2MTelemetryLogService { - void log(LwM2mClient client, String msg); + void log(LwM2MClient client, String msg); } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/DefaultLwM2MOtaUpdateService.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/DefaultLwM2MOtaUpdateService.java index 6a9fc54971..1433cda361 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/DefaultLwM2MOtaUpdateService.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/DefaultLwM2MOtaUpdateService.java @@ -34,12 +34,12 @@ import org.thingsboard.server.common.transport.TransportServiceCallback; import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; -import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportServerHelper; +import org.thingsboard.server.transport.lwm2m.server.LwM2MTransportServerHelper; import org.thingsboard.server.transport.lwm2m.server.attributes.LwM2MAttributesService; -import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; -import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientContext; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClient; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClientContext; import org.thingsboard.server.transport.lwm2m.server.common.LwM2MExecutorAwareService; -import org.thingsboard.server.transport.lwm2m.server.downlink.LwM2mDownlinkMsgHandler; +import org.thingsboard.server.transport.lwm2m.server.downlink.LwM2MDownlinkMsgHandler; import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MExecuteCallback; import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MExecuteRequest; import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MWriteReplaceRequest; @@ -55,7 +55,7 @@ import org.thingsboard.server.transport.lwm2m.server.ota.software.LwM2MSoftwareU import org.thingsboard.server.transport.lwm2m.server.ota.software.SoftwareUpdateResult; import org.thingsboard.server.transport.lwm2m.server.ota.software.SoftwareUpdateState; import org.thingsboard.server.transport.lwm2m.server.store.TbLwM2MClientOtaInfoStore; -import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler; +import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2MUplinkMsgHandler; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; @@ -74,8 +74,8 @@ import static org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus.UPDA import static org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus.UPDATING; import static org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus.VERIFIED; import static org.thingsboard.server.common.data.ota.OtaPackageUtil.getAttributeKey; -import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.LOG_LWM2M_TELEMETRY; -import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.convertObjectIdToVersionedId; +import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.LOG_LWM2M_TELEMETRY; +import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.convertObjectIdToVersionedId; @Slf4j @Service @@ -124,13 +124,13 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl private final Map swStates = new ConcurrentHashMap<>(); private final TransportService transportService; - private final LwM2mClientContext clientContext; + private final LwM2MClientContext clientContext; private final LwM2MTransportServerConfig config; - private final LwM2mUplinkMsgHandler uplinkHandler; - private final LwM2mDownlinkMsgHandler downlinkHandler; + private final LwM2MUplinkMsgHandler uplinkHandler; + private final LwM2MDownlinkMsgHandler downlinkHandler; private final OtaPackageDataCache otaPackageDataCache; private final LwM2MTelemetryLogService logService; - private final LwM2mTransportServerHelper helper; + private final LwM2MTransportServerHelper helper; private final TbLwM2MClientOtaInfoStore otaInfoStore; @Autowired @@ -158,7 +158,7 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl } @Override - public void init(LwM2mClient client) { + public void init(LwM2MClient client) { //TODO: add locks by client fwInfo. //TODO: check that the client supports FW and SW by checking the supported objects in the model. List attributesToFetch = new ArrayList<>(); @@ -213,7 +213,7 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl } @Override - public void forceFirmwareUpdate(LwM2mClient client) { + public void forceFirmwareUpdate(LwM2MClient client) { LwM2MClientFwOtaInfo fwInfo = getOrInitFwInfo(client); fwInfo.setRetryAttempts(0); fwInfo.setFailedPackageId(null); @@ -221,7 +221,7 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl } @Override - public void onTargetFirmwareUpdate(LwM2mClient client, String newFirmwareTitle, String newFirmwareVersion, Optional newFirmwareUrl, Optional newFirmwareTag) { + public void onTargetFirmwareUpdate(LwM2MClient client, String newFirmwareTitle, String newFirmwareVersion, Optional newFirmwareUrl, Optional newFirmwareTag) { LwM2MClientFwOtaInfo fwInfo = getOrInitFwInfo(client); fwInfo.updateTarget(newFirmwareTitle, newFirmwareVersion, newFirmwareUrl, newFirmwareTag); update(fwInfo); @@ -229,19 +229,19 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl } @Override - public void onCurrentFirmwareNameUpdate(LwM2mClient client, String name) { + public void onCurrentFirmwareNameUpdate(LwM2MClient client, String name) { log.debug("[{}] Current fw name: {}", client.getEndpoint(), name); getOrInitFwInfo(client).setCurrentName(name); } @Override - public void onCurrentSoftwareNameUpdate(LwM2mClient client, String name) { + public void onCurrentSoftwareNameUpdate(LwM2MClient client, String name) { log.debug("[{}] Current sw name: {}", client.getEndpoint(), name); getOrInitSwInfo(client).setCurrentName(name); } @Override - public void onFirmwareStrategyUpdate(LwM2mClient client, OtherConfiguration configuration) { + public void onFirmwareStrategyUpdate(LwM2MClient client, OtherConfiguration configuration) { log.debug("[{}] Current fw strategy: {}", client.getEndpoint(), configuration.getFwUpdateStrategy()); LwM2MClientFwOtaInfo fwInfo = getOrInitFwInfo(client); fwInfo.setStrategy(LwM2MFirmwareUpdateStrategy.fromStrategyFwByCode(configuration.getFwUpdateStrategy())); @@ -250,7 +250,7 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl } @Override - public void onCurrentSoftwareStrategyUpdate(LwM2mClient client, OtherConfiguration configuration) { + public void onCurrentSoftwareStrategyUpdate(LwM2MClient client, OtherConfiguration configuration) { log.debug("[{}] Current sw strategy: {}", client.getEndpoint(), configuration.getSwUpdateStrategy()); LwM2MClientSwOtaInfo swInfo = getOrInitSwInfo(client); swInfo.setStrategy(LwM2MSoftwareUpdateStrategy.fromStrategySwByCode(configuration.getSwUpdateStrategy())); @@ -259,21 +259,21 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl } @Override - public void onCurrentFirmwareVersion3Update(LwM2mClient client, String version) { + public void onCurrentFirmwareVersion3Update(LwM2MClient client, String version) { log.debug("[{}] Current fw version(3): {}", client.getEndpoint(), version); LwM2MClientFwOtaInfo fwInfo = getOrInitFwInfo(client); fwInfo.setCurrentVersion3(version); } @Override - public void onCurrentFirmwareVersionUpdate(LwM2mClient client, String version) { + public void onCurrentFirmwareVersionUpdate(LwM2MClient client, String version) { log.debug("[{}] Current fw version(5): {}", client.getEndpoint(), version); LwM2MClientFwOtaInfo fwInfo = getOrInitFwInfo(client); fwInfo.setCurrentVersion(version); } @Override - public void onCurrentFirmwareStateUpdate(LwM2mClient client, Long stateCode) { + public void onCurrentFirmwareStateUpdate(LwM2MClient client, Long stateCode) { log.debug("[{}] Current fw state: {}", client.getEndpoint(), stateCode); LwM2MClientFwOtaInfo fwInfo = getOrInitFwInfo(client); FirmwareUpdateState state = FirmwareUpdateState.fromStateFwByCode(stateCode.intValue()); @@ -297,7 +297,7 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl } @Override - public void onCurrentFirmwareResultUpdate(LwM2mClient client, Long code) { + public void onCurrentFirmwareResultUpdate(LwM2MClient client, Long code) { log.debug("[{}] Current fw result: {}", client.getEndpoint(), code); LwM2MClientFwOtaInfo fwInfo = getOrInitFwInfo(client); FirmwareUpdateResult result = FirmwareUpdateResult.fromUpdateResultFwByCode(code.intValue()); @@ -325,26 +325,26 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl } @Override - public void onCurrentFirmwareDeliveryMethodUpdate(LwM2mClient client, Long value) { + public void onCurrentFirmwareDeliveryMethodUpdate(LwM2MClient client, Long value) { log.debug("[{}] Current fw delivery method: {}", client.getEndpoint(), value); LwM2MClientFwOtaInfo fwInfo = getOrInitFwInfo(client); fwInfo.setDeliveryMethod(value.intValue()); } @Override - public void onCurrentSoftwareVersion3Update(LwM2mClient client, String version) { + public void onCurrentSoftwareVersion3Update(LwM2MClient client, String version) { log.debug("[{}] Current sw version(3): {}", client.getEndpoint(), version); getOrInitSwInfo(client).setCurrentVersion3(version); } @Override - public void onCurrentSoftwareVersionUpdate(LwM2mClient client, String version) { + public void onCurrentSoftwareVersionUpdate(LwM2MClient client, String version) { log.debug("[{}] Current sw version(9): {}", client.getEndpoint(), version); getOrInitSwInfo(client).setCurrentVersion(version); } @Override - public void onCurrentSoftwareStateUpdate(LwM2mClient client, Long stateCode) { + public void onCurrentSoftwareStateUpdate(LwM2MClient client, Long stateCode) { log.debug("[{}] Current sw state: {}", client.getEndpoint(), stateCode); LwM2MClientSwOtaInfo swInfo = getOrInitSwInfo(client); SoftwareUpdateState state = SoftwareUpdateState.fromUpdateStateSwByCode(stateCode.intValue()); @@ -362,7 +362,7 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl @Override - public void onCurrentSoftwareResultUpdate(LwM2mClient client, Long code) { + public void onCurrentSoftwareResultUpdate(LwM2MClient client, Long code) { log.debug("[{}] Current sw result: {}", client.getEndpoint(), code); LwM2MClientSwOtaInfo swInfo = getOrInitSwInfo(client); SoftwareUpdateResult result = SoftwareUpdateResult.fromUpdateResultSwByCode(code.intValue()); @@ -379,14 +379,14 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl } @Override - public void onTargetSoftwareUpdate(LwM2mClient client, String newSoftwareTitle, String newSoftwareVersion, Optional newSoftwareUrl, Optional newSoftwareTag) { + public void onTargetSoftwareUpdate(LwM2MClient client, String newSoftwareTitle, String newSoftwareVersion, Optional newSoftwareUrl, Optional newSoftwareTag) { LwM2MClientSwOtaInfo fwInfo = getOrInitSwInfo(client); fwInfo.updateTarget(newSoftwareTitle, newSoftwareVersion, newSoftwareUrl, newSoftwareTag); update(fwInfo); startSoftwareUpdateIfNeeded(client, fwInfo); } - private void startFirmwareUpdateIfNeeded(LwM2mClient client, LwM2MClientFwOtaInfo fwInfo) { + private void startFirmwareUpdateIfNeeded(LwM2MClient client, LwM2MClientFwOtaInfo fwInfo) { try { if (!fwInfo.isSupported() && fwInfo.isAssigned()) { log.debug("[{}] Fw update is not supported: {}", client.getEndpoint(), fwInfo); @@ -406,7 +406,7 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl } } - private void startSoftwareUpdateIfNeeded(LwM2mClient client, LwM2MClientSwOtaInfo swInfo) { + private void startSoftwareUpdateIfNeeded(LwM2MClient client, LwM2MClientSwOtaInfo swInfo) { try { if (!swInfo.isSupported() && swInfo.isAssigned()) { log.debug("[{}] Sw update is not supported: {}", client.getEndpoint(), swInfo); @@ -431,7 +431,7 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl } } - public void startUpdateUsingBinary(LwM2mClient client, LwM2MClientSwOtaInfo swInfo) { + public void startUpdateUsingBinary(LwM2MClient client, LwM2MClientSwOtaInfo swInfo) { this.transportService.process(client.getSession(), createOtaPackageRequestMsg(client.getSession(), swInfo.getType().name()), new TransportServiceCallback<>() { @Override @@ -446,13 +446,13 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl }); } - private void startUpdateUsingUrl(LwM2mClient client, String id, String url) { + private void startUpdateUsingUrl(LwM2MClient client, String id, String url) { String targetIdVer = convertObjectIdToVersionedId(id, client.getRegistration()); TbLwM2MWriteReplaceRequest request = TbLwM2MWriteReplaceRequest.builder().versionedId(targetIdVer).value(url).timeout(clientContext.getRequestTimeout(client)).build(); downlinkHandler.sendWriteReplaceRequest(client, request, new TbLwM2MWriteResponseCallback(uplinkHandler, logService, client, targetIdVer)); } - public void startUpdateUsingBinary(LwM2mClient client, LwM2MClientFwOtaInfo fwInfo) { + public void startUpdateUsingBinary(LwM2MClient client, LwM2MClientFwOtaInfo fwInfo) { this.transportService.process(client.getSession(), createOtaPackageRequestMsg(client.getSession(), fwInfo.getType().name()), new TransportServiceCallback<>() { @Override @@ -467,7 +467,7 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl }); } - private void doUpdateFirmwareUsingBinary(TransportProtos.GetOtaPackageResponseMsg response, LwM2MClientFwOtaInfo info, LwM2mClient client) { + private void doUpdateFirmwareUsingBinary(TransportProtos.GetOtaPackageResponseMsg response, LwM2MClientFwOtaInfo info, LwM2MClient client) { if (TransportProtos.ResponseStatus.SUCCESS.equals(response.getResponseStatus())) { UUID otaPackageId = new UUID(response.getOtaPackageIdMSB(), response.getOtaPackageIdLSB()); LwM2MFirmwareUpdateStrategy strategy; @@ -494,7 +494,7 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl } } - private void doUpdateSoftwareUsingBinary(TransportProtos.GetOtaPackageResponseMsg response, LwM2MClientSwOtaInfo info, LwM2mClient client) { + private void doUpdateSoftwareUsingBinary(TransportProtos.GetOtaPackageResponseMsg response, LwM2MClientSwOtaInfo info, LwM2MClient client) { if (TransportProtos.ResponseStatus.SUCCESS.equals(response.getResponseStatus())) { UUID otaPackageId = new UUID(response.getOtaPackageIdMSB(), response.getOtaPackageIdLSB()); LwM2MSoftwareUpdateStrategy strategy = info.getStrategy(); @@ -513,7 +513,7 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl } } - private void startUpdateUsingBinary(LwM2mClient client, String versionedId, UUID otaPackageId) { + private void startUpdateUsingBinary(LwM2MClient client, String versionedId, UUID otaPackageId) { byte[] firmwareChunk = otaPackageDataCache.get(otaPackageId.toString(), 0, 0); TbLwM2MWriteReplaceRequest writeRequest = TbLwM2MWriteReplaceRequest.builder().versionedId(versionedId) .value(firmwareChunk).contentFormat(ContentFormat.OPAQUE) @@ -531,17 +531,17 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl .build(); } - private void executeFwUpdate(LwM2mClient client) { + private void executeFwUpdate(LwM2MClient client) { TbLwM2MExecuteRequest request = TbLwM2MExecuteRequest.builder().versionedId(FW_EXECUTE_ID).timeout(clientContext.getRequestTimeout(client)).build(); downlinkHandler.sendExecuteRequest(client, request, new TbLwM2MExecuteCallback(logService, client, FW_EXECUTE_ID)); } - private void executeSwInstall(LwM2mClient client) { + private void executeSwInstall(LwM2MClient client) { TbLwM2MExecuteRequest request = TbLwM2MExecuteRequest.builder().versionedId(SW_INSTALL_ID).timeout(clientContext.getRequestTimeout(client)).build(); downlinkHandler.sendExecuteRequest(client, request, new TbLwM2MExecuteCallback(logService, client, SW_INSTALL_ID)); } - private void executeSwUninstallForUpdate(LwM2mClient client) { + private void executeSwUninstallForUpdate(LwM2MClient client) { TbLwM2MExecuteRequest request = TbLwM2MExecuteRequest.builder().versionedId(SW_UN_INSTALL_ID).params("1").timeout(clientContext.getRequestTimeout(client)).build(); downlinkHandler.sendExecuteRequest(client, request, new TbLwM2MExecuteCallback(logService, client, SW_INSTALL_ID)); } @@ -559,7 +559,7 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl return Optional.empty(); } - private LwM2MClientFwOtaInfo getOrInitFwInfo(LwM2mClient client) { + private LwM2MClientFwOtaInfo getOrInitFwInfo(LwM2MClient client) { return this.fwStates.computeIfAbsent(client.getEndpoint(), endpoint -> { LwM2MClientFwOtaInfo info = otaInfoStore.getFw(endpoint); if (info == null) { @@ -572,7 +572,7 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl }); } - private LwM2MClientSwOtaInfo getOrInitSwInfo(LwM2mClient client) { + private LwM2MClientSwOtaInfo getOrInitSwInfo(LwM2MClient client) { return this.swStates.computeIfAbsent(client.getEndpoint(), endpoint -> { LwM2MClientSwOtaInfo info = otaInfoStore.getSw(endpoint); if (info == null) { @@ -593,7 +593,7 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl otaInfoStore.putSw(info); } - private void sendStateUpdateToTelemetry(LwM2mClient client, LwM2MClientOtaInfo fwInfo, OtaPackageUpdateStatus status, String log) { + private void sendStateUpdateToTelemetry(LwM2MClient client, LwM2MClientOtaInfo fwInfo, OtaPackageUpdateStatus status, String log) { List result = new ArrayList<>(); TransportProtos.KeyValueProto.Builder kvProto = TransportProtos.KeyValueProto.newBuilder().setKey(getAttributeKey(fwInfo.getType(), STATE)); kvProto.setType(TransportProtos.KeyValueType.STRING_V).setStringV(status.name()); diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/LwM2MOtaUpdateService.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/LwM2MOtaUpdateService.java index b03fe81d28..af3905882e 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/LwM2MOtaUpdateService.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/LwM2MOtaUpdateService.java @@ -16,43 +16,43 @@ package org.thingsboard.server.transport.lwm2m.server.ota; import org.thingsboard.server.common.data.device.data.lwm2m.OtherConfiguration; -import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClient; import java.util.Optional; public interface LwM2MOtaUpdateService { - void init(LwM2mClient client); + void init(LwM2MClient client); - void forceFirmwareUpdate(LwM2mClient client); + void forceFirmwareUpdate(LwM2MClient client); - void onTargetFirmwareUpdate(LwM2mClient client, String newFwTitle, String newFwVersion, Optional newFwUrl, Optional newFwTag); + void onTargetFirmwareUpdate(LwM2MClient client, String newFwTitle, String newFwVersion, Optional newFwUrl, Optional newFwTag); - void onTargetSoftwareUpdate(LwM2mClient client, String newSwTitle, String newSwVersion, Optional newSwUrl, Optional newSwTag); + void onTargetSoftwareUpdate(LwM2MClient client, String newSwTitle, String newSwVersion, Optional newSwUrl, Optional newSwTag); - void onCurrentFirmwareNameUpdate(LwM2mClient client, String name); + void onCurrentFirmwareNameUpdate(LwM2MClient client, String name); - void onFirmwareStrategyUpdate(LwM2mClient client, OtherConfiguration configuration); + void onFirmwareStrategyUpdate(LwM2MClient client, OtherConfiguration configuration); - void onCurrentSoftwareStrategyUpdate(LwM2mClient client, OtherConfiguration configuration); + void onCurrentSoftwareStrategyUpdate(LwM2MClient client, OtherConfiguration configuration); - void onCurrentFirmwareVersion3Update(LwM2mClient client, String version); + void onCurrentFirmwareVersion3Update(LwM2MClient client, String version); - void onCurrentFirmwareVersionUpdate(LwM2mClient client, String version); + void onCurrentFirmwareVersionUpdate(LwM2MClient client, String version); - void onCurrentFirmwareStateUpdate(LwM2mClient client, Long state); + void onCurrentFirmwareStateUpdate(LwM2MClient client, Long state); - void onCurrentFirmwareResultUpdate(LwM2mClient client, Long result); + void onCurrentFirmwareResultUpdate(LwM2MClient client, Long result); - void onCurrentFirmwareDeliveryMethodUpdate(LwM2mClient lwM2MClient, Long value); + void onCurrentFirmwareDeliveryMethodUpdate(LwM2MClient lwM2MClient, Long value); - void onCurrentSoftwareNameUpdate(LwM2mClient lwM2MClient, String name); + void onCurrentSoftwareNameUpdate(LwM2MClient lwM2MClient, String name); - void onCurrentSoftwareVersion3Update(LwM2mClient lwM2MClient, String version); + void onCurrentSoftwareVersion3Update(LwM2MClient lwM2MClient, String version); - void onCurrentSoftwareVersionUpdate(LwM2mClient client, String version); + void onCurrentSoftwareVersionUpdate(LwM2MClient client, String version); - void onCurrentSoftwareStateUpdate(LwM2mClient lwM2MClient, Long value); + void onCurrentSoftwareStateUpdate(LwM2MClient lwM2MClient, Long value); - void onCurrentSoftwareResultUpdate(LwM2mClient client, Long result); + void onCurrentSoftwareResultUpdate(LwM2MClient client, Long result); } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/DefaultLwM2MRpcRequestHandler.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/DefaultLwM2MRpcRequestHandler.java index 6501d443a2..e4ce78f589 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/DefaultLwM2MRpcRequestHandler.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/DefaultLwM2MRpcRequestHandler.java @@ -31,10 +31,10 @@ import org.thingsboard.server.common.transport.util.JsonUtils; import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; -import org.thingsboard.server.transport.lwm2m.server.LwM2mOperationType; -import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; -import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientContext; -import org.thingsboard.server.transport.lwm2m.server.downlink.LwM2mDownlinkMsgHandler; +import org.thingsboard.server.transport.lwm2m.server.LwM2MOperationType; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClient; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClientContext; +import org.thingsboard.server.transport.lwm2m.server.downlink.LwM2MDownlinkMsgHandler; import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MCancelAllObserveCallback; import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MCancelAllRequest; import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MCancelObserveCallback; @@ -65,7 +65,7 @@ import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogServic import org.thingsboard.server.transport.lwm2m.server.rpc.composite.RpcReadCompositeRequest; import org.thingsboard.server.transport.lwm2m.server.rpc.composite.RpcReadResponseCompositeCallback; import org.thingsboard.server.transport.lwm2m.server.rpc.composite.RpcWriteCompositeRequest; -import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler; +import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2MUplinkMsgHandler; import java.util.LinkedHashMap; import java.util.Map; @@ -73,8 +73,8 @@ import java.util.Set; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; -import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.convertMultiResourceValuesFromRpcBody; -import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.fromVersionedIdToObjectId; +import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.convertMultiResourceValuesFromRpcBody; +import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.fromVersionedIdToObjectId; @Slf4j @Service @@ -83,21 +83,21 @@ import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.fr public class DefaultLwM2MRpcRequestHandler implements LwM2MRpcRequestHandler { private final TransportService transportService; - private final LwM2mClientContext clientContext; + private final LwM2MClientContext clientContext; private final LwM2MTransportServerConfig config; - private final LwM2mUplinkMsgHandler uplinkHandler; - private final LwM2mDownlinkMsgHandler downlinkHandler; + private final LwM2MUplinkMsgHandler uplinkHandler; + private final LwM2MDownlinkMsgHandler downlinkHandler; private final LwM2MTelemetryLogService logService; @Override public void onToDeviceRpcRequest(TransportProtos.ToDeviceRpcRequestMsg rpcRequest, TransportProtos.SessionInfoProto sessionInfo) { log.debug("Received params: {}", rpcRequest.getParams()); - LwM2mOperationType operationType = LwM2mOperationType.fromType(rpcRequest.getMethodName()); + LwM2MOperationType operationType = LwM2MOperationType.fromType(rpcRequest.getMethodName()); if (operationType == null) { this.sendErrorRpcResponse(sessionInfo, rpcRequest.getRequestId(), ResponseCode.METHOD_NOT_ALLOWED, "Unsupported operation type: " + rpcRequest.getMethodName()); return; } - LwM2mClient client = clientContext.getClientBySessionInfo(sessionInfo); + LwM2MClient client = clientContext.getClientBySessionInfo(sessionInfo); if (client.getRegistration() == null) { this.sendErrorRpcResponse(sessionInfo, rpcRequest.getRequestId(), ResponseCode.INTERNAL_SERVER_ERROR, "Registration is empty"); return; @@ -141,7 +141,7 @@ public class DefaultLwM2MRpcRequestHandler implements LwM2MRpcRequestHandler { throw new IllegalArgumentException("Unsupported operation: " + operationType.name()); } } else if (operationType.isComposite()) { - ContentFormat contentFormatComposite = this.getContentFormatComposite(client); + ContentFormat contentFormatComposite = this.getCompositeContentFormat(client); if (contentFormatComposite != null) { switch (operationType) { case READ_COMPOSITE: @@ -177,14 +177,14 @@ public class DefaultLwM2MRpcRequestHandler implements LwM2MRpcRequestHandler { } } - private void sendReadRequest(LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, String versionedId) { + private void sendReadRequest(LwM2MClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, String versionedId) { TbLwM2MReadRequest request = TbLwM2MReadRequest.builder().versionedId(versionedId).timeout(clientContext.getRequestTimeout(client)).build(); var mainCallback = new TbLwM2MReadCallback(uplinkHandler, logService, client, versionedId); var rpcCallback = new RpcReadResponseCallback<>(transportService, client, requestMsg, mainCallback); downlinkHandler.sendReadRequest(client, request, rpcCallback); } - private void sendReadCompositeRequest(LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, ContentFormat contentFormatComposite) { + private void sendReadCompositeRequest(LwM2MClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, ContentFormat contentFormatComposite) { String[] versionedIds = getIdsFromParameters(client, requestMsg); TbLwM2MReadCompositeRequest request = TbLwM2MReadCompositeRequest.builder().versionedIds(versionedIds).timeout(clientContext.getRequestTimeout(client)).build(); var mainCallback = new TbLwM2MReadCompositeCallback(uplinkHandler, logService, client, versionedIds); @@ -192,38 +192,38 @@ public class DefaultLwM2MRpcRequestHandler implements LwM2MRpcRequestHandler { downlinkHandler.sendReadCompositeRequest(client, request, rpcCallback, contentFormatComposite); } - private void sendObserveRequest(LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, String versionedId) { + private void sendObserveRequest(LwM2MClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, String versionedId) { TbLwM2MObserveRequest request = TbLwM2MObserveRequest.builder().versionedId(versionedId).timeout(clientContext.getRequestTimeout(client)).build(); var mainCallback = new TbLwM2MObserveCallback(uplinkHandler, logService, client, versionedId); var rpcCallback = new RpcReadResponseCallback<>(transportService, client, requestMsg, mainCallback); downlinkHandler.sendObserveRequest(client, request, rpcCallback); } - private void sendObserveAllRequest(LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg) { + private void sendObserveAllRequest(LwM2MClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg) { TbLwM2MObserveAllRequest request = TbLwM2MObserveAllRequest.builder().timeout(clientContext.getRequestTimeout(client)).build(); downlinkHandler.sendObserveAllRequest(client, request, new RpcLinkSetCallback<>(transportService, client, requestMsg, null)); } - private void sendDiscoverAllRequest(LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg) { + private void sendDiscoverAllRequest(LwM2MClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg) { TbLwM2MDiscoverAllRequest request = TbLwM2MDiscoverAllRequest.builder().timeout(clientContext.getRequestTimeout(client)).build(); downlinkHandler.sendDiscoverAllRequest(client, request, new RpcLinkSetCallback<>(transportService, client, requestMsg, null)); } - private void sendDiscoverRequest(LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, String versionedId) { + private void sendDiscoverRequest(LwM2MClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, String versionedId) { TbLwM2MDiscoverRequest request = TbLwM2MDiscoverRequest.builder().versionedId(versionedId).timeout(clientContext.getRequestTimeout(client)).build(); var mainCallback = new TbLwM2MDiscoverCallback(logService, client, versionedId); var rpcCallback = new RpcDiscoverCallback(transportService, client, requestMsg, mainCallback); downlinkHandler.sendDiscoverRequest(client, request, rpcCallback); } - private void sendExecuteRequest(LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, String versionedId) { + private void sendExecuteRequest(LwM2MClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, String versionedId) { TbLwM2MExecuteRequest downlink = TbLwM2MExecuteRequest.builder().versionedId(versionedId).timeout(clientContext.getRequestTimeout(client)).build(); var mainCallback = new TbLwM2MExecuteCallback(logService, client, versionedId); var rpcCallback = new RpcEmptyResponseCallback<>(transportService, client, requestMsg, mainCallback); downlinkHandler.sendExecuteRequest(client, downlink, rpcCallback); } - private void sendWriteAttributesRequest(LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, String versionedId) { + private void sendWriteAttributesRequest(LwM2MClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, String versionedId) { RpcWriteAttributesRequest requestBody = JacksonUtil.fromString(requestMsg.getParams(), RpcWriteAttributesRequest.class); TbLwM2MWriteAttributesRequest request = TbLwM2MWriteAttributesRequest.builder().versionedId(versionedId) .attributes(requestBody.getAttributes()) @@ -233,7 +233,7 @@ public class DefaultLwM2MRpcRequestHandler implements LwM2MRpcRequestHandler { downlinkHandler.sendWriteAttributesRequest(client, request, rpcCallback); } - private void sendWriteUpdateRequest(LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, String versionedId) { + private void sendWriteUpdateRequest(LwM2MClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, String versionedId) { RpcWriteUpdateRequest requestBody = JacksonUtil.fromString(requestMsg.getParams(), RpcWriteUpdateRequest.class); TbLwM2MWriteUpdateRequest.TbLwM2MWriteUpdateRequestBuilder builder = TbLwM2MWriteUpdateRequest.builder().versionedId(versionedId); builder.value(requestBody.getValue()).timeout(clientContext.getRequestTimeout(client)); @@ -242,7 +242,7 @@ public class DefaultLwM2MRpcRequestHandler implements LwM2MRpcRequestHandler { downlinkHandler.sendWriteUpdateRequest(client, builder.build(), rpcCallback); } - private void sendCreateRequest(LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, String versionedId) { + private void sendCreateRequest(LwM2MClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, String versionedId) { RpcCreateRequest requestBody = JacksonUtil.fromString(requestMsg.getParams(), RpcCreateRequest.class); TbLwM2MCreateRequest.TbLwM2MCreateRequestBuilder builder = TbLwM2MCreateRequest.builder().versionedId(versionedId); builder.value(requestBody.getValue()).nodes(requestBody.getNodes()).timeout(clientContext.getRequestTimeout(client)); @@ -251,7 +251,7 @@ public class DefaultLwM2MRpcRequestHandler implements LwM2MRpcRequestHandler { downlinkHandler.sendCreateRequest(client, builder.build(), rpcCallback); } - private void sendWriteReplaceRequest(LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, String versionedId) { + private void sendWriteReplaceRequest(LwM2MClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, String versionedId) { RpcWriteReplaceRequest requestBody = JacksonUtil.fromString(requestMsg.getParams(), RpcWriteReplaceRequest.class); LwM2mPath path = new LwM2mPath(fromVersionedIdToObjectId(versionedId)); if (path.isResource()) { @@ -282,7 +282,7 @@ public class DefaultLwM2MRpcRequestHandler implements LwM2MRpcRequestHandler { * nodes.put("/1/0/2", 100); * nodes.put("/5/0/1", "coap://localhost:5685"); */ - private void sendWriteCompositeRequest(LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, ContentFormat contentFormatComposite) { + private void sendWriteCompositeRequest(LwM2MClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, ContentFormat contentFormatComposite) { RpcWriteCompositeRequest rpcWriteCompositeRequest = JacksonUtil.fromString(requestMsg.getParams(), RpcWriteCompositeRequest.class); Map validNodes = validateNodes(client, rpcWriteCompositeRequest.getNodes()); if (validNodes.size() > 0) { @@ -295,7 +295,7 @@ public class DefaultLwM2MRpcRequestHandler implements LwM2MRpcRequestHandler { } } - private Map validateNodes(LwM2mClient client, Map nodes) { + private Map validateNodes(LwM2MClient client, Map nodes) { Map newNodes = new LinkedHashMap(); nodes.forEach((key, value) -> { String versionedId; @@ -331,28 +331,28 @@ public class DefaultLwM2MRpcRequestHandler implements LwM2MRpcRequestHandler { return newNodes; } - private void sendCancelObserveRequest(LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, String versionedId) { + private void sendCancelObserveRequest(LwM2MClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, String versionedId) { TbLwM2MCancelObserveRequest downlink = TbLwM2MCancelObserveRequest.builder().versionedId(versionedId).timeout(clientContext.getRequestTimeout(client)).build(); var mainCallback = new TbLwM2MCancelObserveCallback(logService, client, versionedId); var rpcCallback = new RpcCancelObserveCallback(transportService, client, requestMsg, mainCallback); downlinkHandler.sendCancelObserveRequest(client, downlink, rpcCallback); } - private void sendDeleteRequest(LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, String versionedId) { + private void sendDeleteRequest(LwM2MClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, String versionedId) { TbLwM2MDeleteRequest downlink = TbLwM2MDeleteRequest.builder().versionedId(versionedId).timeout(clientContext.getRequestTimeout(client)).build(); var mainCallback = new TbLwM2MDeleteCallback(logService, client, versionedId); var rpcCallback = new RpcEmptyResponseCallback<>(transportService, client, requestMsg, mainCallback); downlinkHandler.sendDeleteRequest(client, downlink, rpcCallback); } - private void sendCancelAllObserveRequest(LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg) { + private void sendCancelAllObserveRequest(LwM2MClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg) { TbLwM2MCancelAllRequest downlink = TbLwM2MCancelAllRequest.builder().timeout(clientContext.getRequestTimeout(client)).build(); var mainCallback = new TbLwM2MCancelAllObserveCallback(logService, client); var rpcCallback = new RpcCancelAllObserveCallback(transportService, client, requestMsg, mainCallback); downlinkHandler.sendCancelAllRequest(client, downlink, rpcCallback); } - private String getIdFromParameters(LwM2mClient client, LwM2MRpcRequestHeader header) { + private String getIdFromParameters(LwM2MClient client, LwM2MRpcRequestHeader header) { String targetId; if (StringUtils.isNotEmpty(header.getKey())) { targetId = clientContext.getObjectIdByKeyNameFromProfile(client, header.getKey()); @@ -364,7 +364,7 @@ public class DefaultLwM2MRpcRequestHandler implements LwM2MRpcRequestHandler { return targetId; } - private String[] getIdsFromParameters(LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg rpcRequest) { + private String[] getIdsFromParameters(LwM2MClient client, TransportProtos.ToDeviceRpcRequestMsg rpcRequest) { RpcReadCompositeRequest requestParams = JacksonUtil.fromString(rpcRequest.getParams(), RpcReadCompositeRequest.class); if (requestParams.getKeys() != null && requestParams.getKeys().length > 0) { Set targetIds = ConcurrentHashMap.newKeySet(); @@ -398,7 +398,7 @@ public class DefaultLwM2MRpcRequestHandler implements LwM2MRpcRequestHandler { log.info("[{}] toServerRpcResponse", toServerResponse); } - private ContentFormat getContentFormatComposite(LwM2mClient client) { + private ContentFormat getCompositeContentFormat(LwM2MClient client) { if (client.getClientSupportContentFormats().contains(ContentFormat.SENML_JSON)) { return ContentFormat.SENML_JSON; } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcCancelAllObserveCallback.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcCancelAllObserveCallback.java index c40d21cc4b..a65dab2b8a 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcCancelAllObserveCallback.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcCancelAllObserveCallback.java @@ -18,13 +18,13 @@ package org.thingsboard.server.transport.lwm2m.server.rpc; import org.eclipse.leshan.core.ResponseCode; import org.thingsboard.server.common.transport.TransportService; import org.thingsboard.server.gen.transport.TransportProtos; -import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClient; import org.thingsboard.server.transport.lwm2m.server.downlink.DownlinkRequestCallback; import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MCancelAllRequest; public class RpcCancelAllObserveCallback extends RpcDownlinkRequestCallbackProxy { - public RpcCancelAllObserveCallback(TransportService transportService, LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, DownlinkRequestCallback callback) { + public RpcCancelAllObserveCallback(TransportService transportService, LwM2MClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, DownlinkRequestCallback callback) { super(transportService, client, requestMsg, callback); } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcCancelObserveCallback.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcCancelObserveCallback.java index f7971783ac..0c782c4271 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcCancelObserveCallback.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcCancelObserveCallback.java @@ -18,13 +18,13 @@ package org.thingsboard.server.transport.lwm2m.server.rpc; import org.eclipse.leshan.core.ResponseCode; import org.thingsboard.server.common.transport.TransportService; import org.thingsboard.server.gen.transport.TransportProtos; -import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClient; import org.thingsboard.server.transport.lwm2m.server.downlink.DownlinkRequestCallback; import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MCancelObserveRequest; public class RpcCancelObserveCallback extends RpcDownlinkRequestCallbackProxy { - public RpcCancelObserveCallback(TransportService transportService, LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, DownlinkRequestCallback callback) { + public RpcCancelObserveCallback(TransportService transportService, LwM2MClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, DownlinkRequestCallback callback) { super(transportService, client, requestMsg, callback); } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcCreateResponseCallback.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcCreateResponseCallback.java index f27d8e89d7..41e20b8ec9 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcCreateResponseCallback.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcCreateResponseCallback.java @@ -19,14 +19,14 @@ import org.eclipse.leshan.core.request.LwM2mRequest; import org.eclipse.leshan.core.response.CreateResponse; import org.thingsboard.server.common.transport.TransportService; import org.thingsboard.server.gen.transport.TransportProtos; -import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClient; import org.thingsboard.server.transport.lwm2m.server.downlink.DownlinkRequestCallback; import java.util.Optional; public class RpcCreateResponseCallback, T extends CreateResponse> extends RpcLwM2MDownlinkCallback { - public RpcCreateResponseCallback(TransportService transportService, LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, DownlinkRequestCallback callback) { + public RpcCreateResponseCallback(TransportService transportService, LwM2MClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, DownlinkRequestCallback callback) { super(transportService, client, requestMsg, callback); } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcDiscoverCallback.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcDiscoverCallback.java index 936d177b2b..92a802a2b8 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcDiscoverCallback.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcDiscoverCallback.java @@ -20,14 +20,14 @@ import org.eclipse.leshan.core.request.DiscoverRequest; import org.eclipse.leshan.core.response.DiscoverResponse; import org.thingsboard.server.common.transport.TransportService; import org.thingsboard.server.gen.transport.TransportProtos; -import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClient; import org.thingsboard.server.transport.lwm2m.server.downlink.DownlinkRequestCallback; import java.util.Optional; public class RpcDiscoverCallback extends RpcLwM2MDownlinkCallback { - public RpcDiscoverCallback(TransportService transportService, LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, DownlinkRequestCallback callback) { + public RpcDiscoverCallback(TransportService transportService, LwM2MClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, DownlinkRequestCallback callback) { super(transportService, client, requestMsg, callback); } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcDownlinkRequestCallbackProxy.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcDownlinkRequestCallbackProxy.java index acd88abee1..64103e5695 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcDownlinkRequestCallbackProxy.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcDownlinkRequestCallbackProxy.java @@ -23,7 +23,7 @@ import org.thingsboard.server.common.data.rpc.RpcStatus; import org.thingsboard.server.common.transport.TransportService; import org.thingsboard.server.common.transport.TransportServiceCallback; import org.thingsboard.server.gen.transport.TransportProtos; -import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClient; import org.thingsboard.server.transport.lwm2m.server.downlink.DownlinkRequestCallback; import java.util.concurrent.TimeoutException; @@ -34,9 +34,9 @@ public abstract class RpcDownlinkRequestCallbackProxy implements DownlinkR private final TransportProtos.ToDeviceRpcRequestMsg request; private final DownlinkRequestCallback callback; - protected final LwM2mClient client; + protected final LwM2MClient client; - public RpcDownlinkRequestCallbackProxy(TransportService transportService, LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, DownlinkRequestCallback callback) { + public RpcDownlinkRequestCallbackProxy(TransportService transportService, LwM2MClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, DownlinkRequestCallback callback) { this.transportService = transportService; this.client = client; this.request = requestMsg; diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcEmptyResponseCallback.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcEmptyResponseCallback.java index 5bb2a8550f..2ca7f50f8a 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcEmptyResponseCallback.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcEmptyResponseCallback.java @@ -19,14 +19,14 @@ import org.eclipse.leshan.core.request.LwM2mRequest; import org.eclipse.leshan.core.response.LwM2mResponse; import org.thingsboard.server.common.transport.TransportService; import org.thingsboard.server.gen.transport.TransportProtos; -import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClient; import org.thingsboard.server.transport.lwm2m.server.downlink.DownlinkRequestCallback; import java.util.Optional; public class RpcEmptyResponseCallback, T extends LwM2mResponse> extends RpcLwM2MDownlinkCallback { - public RpcEmptyResponseCallback(TransportService transportService, LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, DownlinkRequestCallback callback) { + public RpcEmptyResponseCallback(TransportService transportService, LwM2MClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, DownlinkRequestCallback callback) { super(transportService, client, requestMsg, callback); } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcLinkSetCallback.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcLinkSetCallback.java index 115b3df90d..b8e4df0e1e 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcLinkSetCallback.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcLinkSetCallback.java @@ -19,12 +19,12 @@ import org.eclipse.leshan.core.ResponseCode; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.transport.TransportService; import org.thingsboard.server.gen.transport.TransportProtos; -import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClient; import org.thingsboard.server.transport.lwm2m.server.downlink.DownlinkRequestCallback; public class RpcLinkSetCallback extends RpcDownlinkRequestCallbackProxy { - public RpcLinkSetCallback(TransportService transportService, LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, DownlinkRequestCallback callback) { + public RpcLinkSetCallback(TransportService transportService, LwM2MClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, DownlinkRequestCallback callback) { super(transportService, client, requestMsg, callback); } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcLwM2MDownlinkCallback.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcLwM2MDownlinkCallback.java index 70536d1be8..6338c43666 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcLwM2MDownlinkCallback.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcLwM2MDownlinkCallback.java @@ -20,14 +20,14 @@ import org.eclipse.leshan.core.response.LwM2mResponse; import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.transport.TransportService; import org.thingsboard.server.gen.transport.TransportProtos; -import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClient; import org.thingsboard.server.transport.lwm2m.server.downlink.DownlinkRequestCallback; import java.util.Optional; public abstract class RpcLwM2MDownlinkCallback, T extends LwM2mResponse> extends RpcDownlinkRequestCallbackProxy { - public RpcLwM2MDownlinkCallback(TransportService transportService, LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, DownlinkRequestCallback callback) { + public RpcLwM2MDownlinkCallback(TransportService transportService, LwM2MClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, DownlinkRequestCallback callback) { super(transportService, client, requestMsg, callback); } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcReadResponseCallback.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcReadResponseCallback.java index de033548fb..965aa7414e 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcReadResponseCallback.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcReadResponseCallback.java @@ -19,16 +19,16 @@ import org.eclipse.leshan.core.request.LwM2mRequest; import org.eclipse.leshan.core.response.ReadResponse; import org.thingsboard.server.common.transport.TransportService; import org.thingsboard.server.gen.transport.TransportProtos; -import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClient; import org.thingsboard.server.transport.lwm2m.server.downlink.DownlinkRequestCallback; import java.util.Optional; -import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.contentToString; +import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.contentToString; public class RpcReadResponseCallback, T extends ReadResponse> extends RpcLwM2MDownlinkCallback { - public RpcReadResponseCallback(TransportService transportService, LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, DownlinkRequestCallback callback) { + public RpcReadResponseCallback(TransportService transportService, LwM2MClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, DownlinkRequestCallback callback) { super(transportService, client, requestMsg, callback); } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/composite/RpcReadResponseCompositeCallback.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/composite/RpcReadResponseCompositeCallback.java index ea10ca90ca..bcc9a3188d 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/composite/RpcReadResponseCompositeCallback.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/composite/RpcReadResponseCompositeCallback.java @@ -19,17 +19,17 @@ import org.eclipse.leshan.core.request.LwM2mRequest; import org.eclipse.leshan.core.response.ReadCompositeResponse; import org.thingsboard.server.common.transport.TransportService; import org.thingsboard.server.gen.transport.TransportProtos; -import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClient; import org.thingsboard.server.transport.lwm2m.server.downlink.DownlinkRequestCallback; import org.thingsboard.server.transport.lwm2m.server.rpc.RpcLwM2MDownlinkCallback; import java.util.Optional; -import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.contentToString; +import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.contentToString; public class RpcReadResponseCompositeCallback, T extends ReadCompositeResponse> extends RpcLwM2MDownlinkCallback { - public RpcReadResponseCompositeCallback(TransportService transportService, LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, DownlinkRequestCallback callback) { + public RpcReadResponseCompositeCallback(TransportService transportService, LwM2MClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, DownlinkRequestCallback callback) { super(transportService, client, requestMsg, callback); } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/session/DefaultLwM2MSessionManager.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/session/DefaultLwM2MSessionManager.java index ee6e4a779b..2714ae071c 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/session/DefaultLwM2MSessionManager.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/session/DefaultLwM2MSessionManager.java @@ -22,10 +22,10 @@ import org.thingsboard.server.common.transport.TransportService; import org.thingsboard.server.common.transport.service.DefaultTransportService; import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; -import org.thingsboard.server.transport.lwm2m.server.LwM2mSessionMsgListener; +import org.thingsboard.server.transport.lwm2m.server.LwM2MSessionMsgListener; import org.thingsboard.server.transport.lwm2m.server.attributes.LwM2MAttributesService; import org.thingsboard.server.transport.lwm2m.server.rpc.LwM2MRpcRequestHandler; -import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler; +import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2MUplinkMsgHandler; @Slf4j @Service @@ -35,12 +35,12 @@ public class DefaultLwM2MSessionManager implements LwM2MSessionManager { private final TransportService transportService; private final LwM2MAttributesService attributesService; private final LwM2MRpcRequestHandler rpcHandler; - private final LwM2mUplinkMsgHandler uplinkHandler; + private final LwM2MUplinkMsgHandler uplinkHandler; public DefaultLwM2MSessionManager(TransportService transportService, @Lazy LwM2MAttributesService attributesService, @Lazy LwM2MRpcRequestHandler rpcHandler, - @Lazy LwM2mUplinkMsgHandler uplinkHandler) { + @Lazy LwM2MUplinkMsgHandler uplinkHandler) { this.transportService = transportService; this.attributesService = attributesService; this.rpcHandler = rpcHandler; @@ -49,7 +49,7 @@ public class DefaultLwM2MSessionManager implements LwM2MSessionManager { @Override public void register(TransportProtos.SessionInfoProto sessionInfo) { - transportService.registerAsyncSession(sessionInfo, new LwM2mSessionMsgListener(uplinkHandler, attributesService, rpcHandler, sessionInfo, transportService)); + transportService.registerAsyncSession(sessionInfo, new LwM2MSessionMsgListener(uplinkHandler, attributesService, rpcHandler, sessionInfo, transportService)); TransportProtos.TransportToDeviceActorMsg msg = TransportProtos.TransportToDeviceActorMsg.newBuilder() .setSessionInfo(sessionInfo) .setSessionEvent(DefaultTransportService.getSessionEventMsg(TransportProtos.SessionEvent.OPEN)) diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbDummyLwM2MClientStore.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbDummyLwM2MClientStore.java index 767ab43493..2796e9d657 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbDummyLwM2MClientStore.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbDummyLwM2MClientStore.java @@ -15,24 +15,24 @@ */ package org.thingsboard.server.transport.lwm2m.server.store; -import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClient; import java.util.Collections; import java.util.Set; public class TbDummyLwM2MClientStore implements TbLwM2MClientStore { @Override - public LwM2mClient get(String endpoint) { + public LwM2MClient get(String endpoint) { return null; } @Override - public Set getAll() { + public Set getAll() { return Collections.emptySet(); } @Override - public void put(LwM2mClient client) { + public void put(LwM2MClient client) { } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2MClientStore.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2MClientStore.java index 55b0423b05..c25b2663fa 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2MClientStore.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2MClientStore.java @@ -15,17 +15,17 @@ */ package org.thingsboard.server.transport.lwm2m.server.store; -import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClient; import java.util.Set; public interface TbLwM2MClientStore { - LwM2mClient get(String endpoint); + LwM2MClient get(String endpoint); - Set getAll(); + Set getAll(); - void put(LwM2mClient client); + void put(LwM2MClient client); void remove(String endpoint); } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mSecurityStore.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mSecurityStore.java index ac0d3d0e68..73782d9b50 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mSecurityStore.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mSecurityStore.java @@ -19,7 +19,7 @@ import lombok.extern.slf4j.Slf4j; import org.eclipse.leshan.server.security.NonUniqueSecurityInfoException; import org.eclipse.leshan.server.security.SecurityInfo; import org.jetbrains.annotations.Nullable; -import org.thingsboard.server.transport.lwm2m.secure.LwM2mCredentialsSecurityInfoValidator; +import org.thingsboard.server.transport.lwm2m.secure.LwM2MCredentialsSecurityInfoValidator; import org.thingsboard.server.transport.lwm2m.secure.TbLwM2MSecurityInfo; import java.util.HashSet; @@ -27,16 +27,16 @@ import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; -import static org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mTypeServer.CLIENT; +import static org.thingsboard.server.transport.lwm2m.server.uplink.LwM2MTypeServer.CLIENT; @Slf4j public class TbLwM2mSecurityStore implements TbMainSecurityStore { private final TbEditableSecurityStore securityStore; - private final LwM2mCredentialsSecurityInfoValidator validator; + private final LwM2MCredentialsSecurityInfoValidator validator; private final ConcurrentMap> endpointRegistrations = new ConcurrentHashMap<>(); - public TbLwM2mSecurityStore(TbEditableSecurityStore securityStore, LwM2mCredentialsSecurityInfoValidator validator) { + public TbLwM2mSecurityStore(TbEditableSecurityStore securityStore, LwM2MCredentialsSecurityInfoValidator validator) { this.securityStore = securityStore; this.validator = validator; } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mStoreFactory.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mStoreFactory.java index 9156d73181..b3792b8e43 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mStoreFactory.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mStoreFactory.java @@ -25,7 +25,7 @@ import org.springframework.stereotype.Component; import org.thingsboard.server.cache.TBRedisCacheConfiguration; import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; -import org.thingsboard.server.transport.lwm2m.secure.LwM2mCredentialsSecurityInfoValidator; +import org.thingsboard.server.transport.lwm2m.secure.LwM2MCredentialsSecurityInfoValidator; import java.util.Optional; @@ -40,7 +40,7 @@ public class TbLwM2mStoreFactory { private LwM2MTransportServerConfig config; @Autowired - private LwM2mCredentialsSecurityInfoValidator validator; + private LwM2MCredentialsSecurityInfoValidator validator; @Value("${transport.lwm2m.redis.enabled:false}") private boolean useRedis; diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbRedisLwM2MClientStore.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbRedisLwM2MClientStore.java index 2a111a9f81..a1dc09084b 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbRedisLwM2MClientStore.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbRedisLwM2MClientStore.java @@ -22,7 +22,7 @@ import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.core.Cursor; import org.springframework.data.redis.core.ScanOptions; import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClientState; -import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClient; import java.util.ArrayList; import java.util.HashSet; @@ -42,21 +42,21 @@ public class TbRedisLwM2MClientStore implements TbLwM2MClientStore { } @Override - public LwM2mClient get(String endpoint) { + public LwM2MClient get(String endpoint) { try (var connection = connectionFactory.getConnection()) { byte[] data = connection.get(getKey(endpoint)); if (data == null) { return null; } else { - return (LwM2mClient) serializer.asObject(data); + return (LwM2MClient) serializer.asObject(data); } } } @Override - public Set getAll() { + public Set getAll() { try (var connection = connectionFactory.getConnection()) { - Set clients = new HashSet<>(); + Set clients = new HashSet<>(); ScanOptions scanOptions = ScanOptions.scanOptions().count(100).match(CLIENT_EP + "*").build(); List> scans = new ArrayList<>(); if (connection instanceof RedisClusterConnection) { @@ -70,7 +70,7 @@ public class TbRedisLwM2MClientStore implements TbLwM2MClientStore { scans.forEach(scan -> { scan.forEachRemaining(key -> { byte[] element = connection.get(key); - clients.add((LwM2mClient) serializer.asObject(element)); + clients.add((LwM2MClient) serializer.asObject(element)); }); }); return clients; @@ -78,7 +78,7 @@ public class TbRedisLwM2MClientStore implements TbLwM2MClientStore { } @Override - public void put(LwM2mClient client) { + public void put(LwM2MClient client) { if (client.getState().equals(LwM2MClientState.UNREGISTERED)) { log.error("[{}] Client is in invalid state: {}!", client.getEndpoint(), client.getState(), new Exception()); } else { diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/DefaultLwM2MUplinkMsgHandler.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/DefaultLwM2MUplinkMsgHandler.java index b6f8095b60..46475f4b25 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/DefaultLwM2MUplinkMsgHandler.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/DefaultLwM2MUplinkMsgHandler.java @@ -59,19 +59,19 @@ import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.gen.transport.TransportProtos.SessionInfoProto; import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; -import org.thingsboard.server.transport.lwm2m.server.LwM2mOtaConvert; -import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportContext; -import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportServerHelper; +import org.thingsboard.server.transport.lwm2m.server.LwM2MOtaConvert; +import org.thingsboard.server.transport.lwm2m.server.LwM2MTransportContext; +import org.thingsboard.server.transport.lwm2m.server.LwM2MTransportServerHelper; import org.thingsboard.server.transport.lwm2m.server.attributes.LwM2MAttributesService; import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClientState; import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClientStateException; -import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; -import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientContext; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClient; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClientContext; import org.thingsboard.server.transport.lwm2m.server.client.ParametersAnalyzeResult; import org.thingsboard.server.transport.lwm2m.server.client.ResultsAddKeyValueProto; import org.thingsboard.server.transport.lwm2m.server.common.LwM2MExecutorAwareService; import org.thingsboard.server.transport.lwm2m.server.downlink.DownlinkRequestCallback; -import org.thingsboard.server.transport.lwm2m.server.downlink.LwM2mDownlinkMsgHandler; +import org.thingsboard.server.transport.lwm2m.server.downlink.LwM2MDownlinkMsgHandler; import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MCancelObserveCallback; import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MCancelObserveRequest; import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MLatchCallback; @@ -86,8 +86,8 @@ import org.thingsboard.server.transport.lwm2m.server.ota.LwM2MOtaUpdateService; import org.thingsboard.server.transport.lwm2m.server.rpc.LwM2MRpcRequestHandler; import org.thingsboard.server.transport.lwm2m.server.session.LwM2MSessionManager; import org.thingsboard.server.transport.lwm2m.server.store.TbLwM2MDtlsSessionStore; -import org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil; -import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl; +import org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil; +import org.thingsboard.server.transport.lwm2m.utils.LwM2MValueConverterImpl; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; @@ -118,45 +118,45 @@ import static org.thingsboard.server.transport.lwm2m.server.ota.DefaultLwM2MOtaU import static org.thingsboard.server.transport.lwm2m.server.ota.DefaultLwM2MOtaUpdateService.SW_RESULT_ID; import static org.thingsboard.server.transport.lwm2m.server.ota.DefaultLwM2MOtaUpdateService.SW_STATE_ID; import static org.thingsboard.server.transport.lwm2m.server.ota.DefaultLwM2MOtaUpdateService.SW_VER_ID; -import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.LOG_LWM2M_ERROR; -import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.LOG_LWM2M_INFO; -import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.LOG_LWM2M_WARN; -import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.convertObjectIdToVersionedId; -import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.convertOtaUpdateValueToString; -import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.fromVersionedIdToObjectId; +import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.LOG_LWM2M_ERROR; +import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.LOG_LWM2M_INFO; +import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.LOG_LWM2M_WARN; +import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.convertObjectIdToVersionedId; +import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.convertOtaUpdateValueToString; +import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.fromVersionedIdToObjectId; @Slf4j @Service @TbLwM2mTransportComponent -public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService implements LwM2mUplinkMsgHandler { +public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService implements LwM2MUplinkMsgHandler { - public LwM2mValueConverterImpl converter; + public LwM2MValueConverterImpl converter; private final TransportService transportService; - private final LwM2mTransportContext context; + private final LwM2MTransportContext context; private final LwM2MAttributesService attributesService; private final LwM2MSessionManager sessionManager; private final LwM2MOtaUpdateService otaService; private final LwM2MTransportServerConfig config; private final LwM2MTelemetryLogService logService; - private final LwM2mTransportServerHelper helper; + private final LwM2MTransportServerHelper helper; private final TbLwM2MDtlsSessionStore sessionStore; - private final LwM2mClientContext clientContext; + private final LwM2MClientContext clientContext; private final LwM2MRpcRequestHandler rpcHandler; - private final LwM2mDownlinkMsgHandler defaultLwM2MDownlinkMsgHandler; + private final LwM2MDownlinkMsgHandler defaultLwM2MDownlinkMsgHandler; public DefaultLwM2MUplinkMsgHandler(TransportService transportService, LwM2MTransportServerConfig config, - LwM2mTransportServerHelper helper, - LwM2mClientContext clientContext, + LwM2MTransportServerHelper helper, + LwM2MClientContext clientContext, LwM2MTelemetryLogService logService, LwM2MSessionManager sessionManager, @Lazy LwM2MOtaUpdateService otaService, @Lazy LwM2MAttributesService attributesService, @Lazy LwM2MRpcRequestHandler rpcHandler, - @Lazy LwM2mDownlinkMsgHandler defaultLwM2MDownlinkMsgHandler, - LwM2mTransportContext context, TbLwM2MDtlsSessionStore sessionStore) { + @Lazy LwM2MDownlinkMsgHandler defaultLwM2MDownlinkMsgHandler, + LwM2MTransportContext context, TbLwM2MDtlsSessionStore sessionStore) { this.transportService = transportService; this.sessionManager = sessionManager; this.attributesService = attributesService; @@ -175,7 +175,7 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl public void init() { super.init(); this.context.getScheduler().scheduleAtFixedRate(this::reportActivity, new Random().nextInt((int) config.getSessionReportTimeout()), config.getSessionReportTimeout(), TimeUnit.MILLISECONDS); - this.converter = LwM2mValueConverterImpl.getInstance(); + this.converter = LwM2MValueConverterImpl.getInstance(); } @PreDestroy @@ -209,7 +209,7 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl */ public void onRegistered(Registration registration, Collection previousObservations) { executor.submit(() -> { - LwM2mClient lwM2MClient = this.clientContext.getClientByEndpoint(registration.getEndpoint()); + LwM2MClient lwM2MClient = this.clientContext.getClientByEndpoint(registration.getEndpoint()); try { log.debug("[{}] [{{}] Client: create after Registration", registration.getEndpoint(), registration.getId()); Optional oldSessionInfo = this.clientContext.register(lwM2MClient, registration); @@ -250,7 +250,7 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl */ public void updatedReg(Registration registration) { executor.submit(() -> { - LwM2mClient lwM2MClient = clientContext.getClientByEndpoint(registration.getEndpoint()); + LwM2MClient lwM2MClient = clientContext.getClientByEndpoint(registration.getEndpoint()); try { log.info("[{}] [{{}] Client: update after Registration", registration.getEndpoint(), registration.getId()); logService.log(lwM2MClient, String.format("[%s][%s] Updated registration.", registration.getId(), registration.getSocketAddress())); @@ -275,7 +275,7 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl */ public void unReg(Registration registration, Collection observations) { executor.submit(() -> { - LwM2mClient client = clientContext.getClientByEndpoint(registration.getEndpoint()); + LwM2MClient client = clientContext.getClientByEndpoint(registration.getEndpoint()); try { logService.log(client, LOG_LWM2M_INFO + ": Client unRegistration"); clientContext.unregister(client, registration); @@ -312,7 +312,7 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl @Override public void onUpdateValueAfterReadResponse(Registration registration, String path, ReadResponse response) { if (response.getContent() != null) { - LwM2mClient lwM2MClient = clientContext.getClientByEndpoint(registration.getEndpoint()); + LwM2MClient lwM2MClient = clientContext.getClientByEndpoint(registration.getEndpoint()); ObjectModel objectModelVersion = lwM2MClient.getObjectModel(path, this.config.getModelProvider()); if (objectModelVersion != null) { if (response.getContent() instanceof LwM2mObject) { @@ -338,7 +338,7 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl public void onUpdateValueAfterReadCompositeResponse(Registration registration, ReadCompositeResponse response) { log.trace("ReadCompositeResponse: [{}]", response); if (response.getContent() != null) { - LwM2mClient lwM2MClient = clientContext.getClientByEndpoint(registration.getEndpoint()); + LwM2MClient lwM2MClient = clientContext.getClientByEndpoint(registration.getEndpoint()); response.getContent().forEach((k, v) -> { if (v != null) { if (v instanceof LwM2mObject) { @@ -367,7 +367,7 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl @Override public void onDeviceProfileUpdate(SessionInfoProto sessionInfo, DeviceProfile deviceProfile) { try { - List clients = clientContext.getLwM2mClients() + List clients = clientContext.getLwM2mClients() .stream().filter(e -> e.getProfileId() != null) .filter(e -> e.getProfileId().equals(deviceProfile.getUuidId())).collect(Collectors.toList()); clients.forEach(client -> client.onDeviceProfileUpdate(deviceProfile)); @@ -382,7 +382,7 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl @Override public void onDeviceUpdate(SessionInfoProto sessionInfo, Device device, Optional deviceProfileOpt) { try { - LwM2mClient client = clientContext.getClientByDeviceId(device.getUuidId()); + LwM2MClient client = clientContext.getClientByDeviceId(device.getUuidId()); if (client != null) { this.onDeviceUpdate(client, device, deviceProfileOpt); } @@ -424,7 +424,7 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl * * @param lwM2MClient - object with All parameters off client */ - private void initClientTelemetry(LwM2mClient lwM2MClient) { + private void initClientTelemetry(LwM2MClient lwM2MClient) { Lwm2mDeviceProfileTransportConfiguration profile = clientContext.getProfile(lwM2MClient.getProfileId()); Set supportedObjects = clientContext.getSupportedIdVerInClient(lwM2MClient); if (supportedObjects != null && supportedObjects.size() > 0) { @@ -436,7 +436,7 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl } } - private void sendReadRequests(LwM2mClient lwM2MClient, Lwm2mDeviceProfileTransportConfiguration profile, Set supportedObjects) { + private void sendReadRequests(LwM2MClient lwM2MClient, Lwm2mDeviceProfileTransportConfiguration profile, Set supportedObjects) { try { Set targetIds = new HashSet<>(profile.getObserveAttr().getAttribute()); targetIds.addAll(profile.getObserveAttr().getTelemetry()); @@ -455,7 +455,7 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl } } - private void sendObserveRequests(LwM2mClient lwM2MClient, Lwm2mDeviceProfileTransportConfiguration profile, Set supportedObjects) { + private void sendObserveRequests(LwM2MClient lwM2MClient, Lwm2mDeviceProfileTransportConfiguration profile, Set supportedObjects) { try { Set targetIds = profile.getObserveAttr().getObserve(); targetIds = targetIds.stream().filter(target -> isSupportedTargetId(supportedObjects, target)).collect(Collectors.toSet()); @@ -473,7 +473,7 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl } } - private void sendWriteAttributeRequests(LwM2mClient lwM2MClient, Lwm2mDeviceProfileTransportConfiguration profile, Set supportedObjects) { + private void sendWriteAttributeRequests(LwM2MClient lwM2MClient, Lwm2mDeviceProfileTransportConfiguration profile, Set supportedObjects) { try { Map attributesMap = profile.getObserveAttr().getAttributeLwm2m(); attributesMap = attributesMap.entrySet().stream().filter(target -> isSupportedTargetId(supportedObjects, target.getKey())).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); @@ -484,35 +484,35 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl } } - private void sendReadRequest(LwM2mClient lwM2MClient, String versionedId) { + private void sendReadRequest(LwM2MClient lwM2MClient, String versionedId) { sendReadRequest(lwM2MClient, versionedId, new TbLwM2MReadCallback(this, logService, lwM2MClient, versionedId)); } - private void sendReadRequest(LwM2mClient lwM2MClient, String versionedId, DownlinkRequestCallback callback) { + private void sendReadRequest(LwM2MClient lwM2MClient, String versionedId, DownlinkRequestCallback callback) { TbLwM2MReadRequest request = TbLwM2MReadRequest.builder().versionedId(versionedId).timeout(clientContext.getRequestTimeout(lwM2MClient)).build(); defaultLwM2MDownlinkMsgHandler.sendReadRequest(lwM2MClient, request, callback); } - private void sendObserveRequest(LwM2mClient lwM2MClient, String versionedId) { + private void sendObserveRequest(LwM2MClient lwM2MClient, String versionedId) { sendObserveRequest(lwM2MClient, versionedId, new TbLwM2MObserveCallback(this, logService, lwM2MClient, versionedId)); } - private void sendObserveRequest(LwM2mClient lwM2MClient, String versionedId, DownlinkRequestCallback callback) { + private void sendObserveRequest(LwM2MClient lwM2MClient, String versionedId, DownlinkRequestCallback callback) { TbLwM2MObserveRequest request = TbLwM2MObserveRequest.builder().versionedId(versionedId).timeout(clientContext.getRequestTimeout(lwM2MClient)).build(); defaultLwM2MDownlinkMsgHandler.sendObserveRequest(lwM2MClient, request, callback); } - private void sendWriteAttributesRequest(LwM2mClient lwM2MClient, String targetId, ObjectAttributes params) { + private void sendWriteAttributesRequest(LwM2MClient lwM2MClient, String targetId, ObjectAttributes params) { TbLwM2MWriteAttributesRequest request = TbLwM2MWriteAttributesRequest.builder().versionedId(targetId).attributes(params).timeout(clientContext.getRequestTimeout(lwM2MClient)).build(); defaultLwM2MDownlinkMsgHandler.sendWriteAttributesRequest(lwM2MClient, request, new TbLwM2MWriteAttributesCallback(logService, lwM2MClient, targetId)); } - private void sendCancelObserveRequest(String versionedId, LwM2mClient client) { + private void sendCancelObserveRequest(String versionedId, LwM2MClient client) { TbLwM2MCancelObserveRequest request = TbLwM2MCancelObserveRequest.builder().versionedId(versionedId).timeout(clientContext.getRequestTimeout(client)).build(); defaultLwM2MDownlinkMsgHandler.sendCancelObserveRequest(client, request, new TbLwM2MCancelObserveCallback(logService, client, versionedId)); } - private void updateObjectResourceValue(LwM2mClient client, LwM2mObject lwM2mObject, String pathIdVer, int code) { + private void updateObjectResourceValue(LwM2MClient client, LwM2mObject lwM2mObject, String pathIdVer, int code) { LwM2mPath pathIds = new LwM2mPath(fromVersionedIdToObjectId(pathIdVer)); lwM2mObject.getInstances().forEach((instanceId, instance) -> { String pathInstance = pathIds.toString() + "/" + instanceId; @@ -520,7 +520,7 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl }); } - private void updateObjectInstanceResourceValue(LwM2mClient client, LwM2mObjectInstance lwM2mObjectInstance, String pathIdVer, int code) { + private void updateObjectInstanceResourceValue(LwM2MClient client, LwM2mObjectInstance lwM2mObjectInstance, String pathIdVer, int code) { LwM2mPath pathIds = new LwM2mPath(fromVersionedIdToObjectId(pathIdVer)); lwM2mObjectInstance.getResources().forEach((resourceId, resource) -> { String pathRez = pathIds.toString() + "/" + resourceId; @@ -539,7 +539,7 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl * @param path - resource * @param mode - Replace, Update */ - private void updateResourcesValue(LwM2mClient lwM2MClient, LwM2mResource lwM2mResource, String path, Mode mode, int code) { + private void updateResourcesValue(LwM2MClient lwM2MClient, LwM2mResource lwM2mResource, String path, Mode mode, int code) { Registration registration = lwM2MClient.getRegistration(); if (lwM2MClient.saveResourceValue(path, lwM2mResource, this.config.getModelProvider(), mode)) { if (path.equals(convertObjectIdToVersionedId(FW_NAME_ID, registration))) { @@ -622,7 +622,7 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl return pathAttributes; } - private void onDeviceUpdate(LwM2mClient lwM2MClient, Device device, Optional deviceProfileOpt) { + private void onDeviceUpdate(LwM2MClient lwM2MClient, Device device, Optional deviceProfileOpt) { deviceProfileOpt.ifPresent(deviceProfile -> this.onDeviceProfileUpdate(Collections.singletonList(lwM2MClient), deviceProfile)); lwM2MClient.onDeviceUpdate(device, deviceProfileOpt); } @@ -668,13 +668,13 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl } private TransportProtos.KeyValueProto getKvToThingsBoard(String pathIdVer, Registration registration) { - LwM2mClient lwM2MClient = this.clientContext.getClientByEndpoint(registration.getEndpoint()); + LwM2MClient lwM2MClient = this.clientContext.getClientByEndpoint(registration.getEndpoint()); Map names = clientContext.getProfile(lwM2MClient.getProfileId()).getObserveAttr().getKeyName(); if (names != null && names.containsKey(pathIdVer)) { String resourceName = names.get(pathIdVer); if (resourceName != null && !resourceName.isEmpty()) { try { - LwM2mResource resourceValue = LwM2mTransportUtil.getResourceValueFromLwM2MClient(lwM2MClient, pathIdVer); + LwM2mResource resourceValue = LwM2MTransportUtil.getResourceValueFromLwM2MClient(lwM2MClient, pathIdVer); if (resourceValue != null) { ResourceModel.Type currentType = resourceValue.getType(); ResourceModel.Type expectedType = this.helper.getResourceModelTypeEqualsKvProtoValueType(currentType, pathIdVer); @@ -695,7 +695,7 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl valueKvProto = this.converter.convertValue(resourceValue.getValue(), currentType, expectedType, new LwM2mPath(fromVersionedIdToObjectId(pathIdVer))); } - LwM2mOtaConvert lwM2mOtaConvert = convertOtaUpdateValueToString(pathIdVer, valueKvProto, currentType); + LwM2MOtaConvert lwM2mOtaConvert = convertOtaUpdateValueToString(pathIdVer, valueKvProto, currentType); valueKvProto = lwM2mOtaConvert.getValue(); currentType = lwM2mOtaConvert.getCurrentType(); return valueKvProto != null ? this.helper.getKvAttrTelemetryToThingsboard(currentType, resourceName, valueKvProto, resourceValue.isMultiInstances()) : null; @@ -711,7 +711,7 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl } @Override - public void onWriteResponseOk(LwM2mClient client, String path, WriteRequest request, int code) { + public void onWriteResponseOk(LwM2MClient client, String path, WriteRequest request, int code) { if (request.getNode() instanceof LwM2mResource) { this.updateResourcesValue(client, ((LwM2mResource) request.getNode()), path, request.isReplaceRequest() ? Mode.REPLACE : Mode.UPDATE, code); } else if (request.getNode() instanceof LwM2mObjectInstance) { @@ -725,7 +725,7 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl } @Override - public void onCreateResponseOk(LwM2mClient client, String path, CreateRequest request) { + public void onCreateResponseOk(LwM2MClient client, String path, CreateRequest request) { if (request.getObjectInstances() != null && request.getObjectInstances().size() > 0) { request.getObjectInstances().forEach(instance -> instance.getResources() @@ -735,7 +735,7 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl } @Override - public void onWriteCompositeResponseOk(LwM2mClient client, WriteCompositeRequest request, int code) { + public void onWriteCompositeResponseOk(LwM2MClient client, WriteCompositeRequest request, int code) { log.trace("ReadCompositeResponse: [{}]", request.getNodes()); request.getNodes().forEach((k, v) -> { if (v instanceof LwM2mSingleResource) { @@ -749,7 +749,7 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl } //TODO: review and optimize the logic to minimize number of the requests to device. - private void onDeviceProfileUpdate(List clients, DeviceProfile deviceProfile) { + private void onDeviceProfileUpdate(List clients, DeviceProfile deviceProfile) { var oldProfile = clientContext.getProfile(deviceProfile.getUuidId()); if (clientContext.profileUpdate(deviceProfile) != null) { // #1 @@ -851,7 +851,7 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl * #6.1 - send update WriteAttribute * #6.2 - send empty WriteAttribute */ - private void compareAndSendWriteAttributes(List clients, Map lwm2mAttributesOld, Map lwm2mAttributesNew) { + private void compareAndSendWriteAttributes(List clients, Map lwm2mAttributesOld, Map lwm2mAttributesNew) { ParametersAnalyzeResult analyzerParameters = new ParametersAnalyzeResult(); Set pathOld = lwm2mAttributesOld.keySet(); Set pathNew = lwm2mAttributesNew.keySet(); @@ -903,7 +903,7 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl * @param lwM2MClient - * @return SessionInfoProto - */ - private SessionInfoProto getSessionInfo(LwM2mClient lwM2MClient) { + private SessionInfoProto getSessionInfo(LwM2MClient lwM2MClient) { if (lwM2MClient != null && lwM2MClient.getSession() != null) { return lwM2MClient.getSession(); } @@ -944,7 +944,7 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl * * @param lwM2MClient - LwM2M Client */ - public void initAttributes(LwM2mClient lwM2MClient, boolean logFailedUpdateOfNonChangedValue) { + public void initAttributes(LwM2MClient lwM2MClient, boolean logFailedUpdateOfNonChangedValue) { Map keyNamesMap = this.getNamesFromProfileForSharedAttributes(lwM2MClient); if (!keyNamesMap.isEmpty()) { Set keysToFetch = new HashSet<>(keyNamesMap.values()); @@ -957,7 +957,7 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl } } - private Map getNamesFromProfileForSharedAttributes(LwM2mClient lwM2MClient) { + private Map getNamesFromProfileForSharedAttributes(LwM2MClient lwM2MClient) { Lwm2mDeviceProfileTransportConfiguration profile = clientContext.getProfile(lwM2MClient.getProfileId()); return profile.getObserveAttr().getKeyName(); } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/LwM2mTypeServer.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/LwM2MTypeServer.java similarity index 83% rename from common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/LwM2mTypeServer.java rename to common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/LwM2MTypeServer.java index 0ecd59f41c..63f7431cd2 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/LwM2mTypeServer.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/LwM2MTypeServer.java @@ -15,20 +15,20 @@ */ package org.thingsboard.server.transport.lwm2m.server.uplink; -public enum LwM2mTypeServer { +public enum LwM2MTypeServer { BOOTSTRAP(0, "bootstrap"), CLIENT(1, "client"); public int code; public String type; - LwM2mTypeServer(int code, String type) { + LwM2MTypeServer(int code, String type) { this.code = code; this.type = type; } - public static LwM2mTypeServer fromLwM2mTypeServer(String type) { - for (LwM2mTypeServer sm : LwM2mTypeServer.values()) { + public static LwM2MTypeServer fromLwM2mTypeServer(String type) { + for (LwM2MTypeServer sm : LwM2MTypeServer.values()) { if (sm.type.equals(type)) { return sm; } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/LwM2mUplinkMsgHandler.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/LwM2MUplinkMsgHandler.java similarity index 91% rename from common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/LwM2mUplinkMsgHandler.java rename to common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/LwM2MUplinkMsgHandler.java index af0d349687..6650795f98 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/LwM2mUplinkMsgHandler.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/LwM2MUplinkMsgHandler.java @@ -26,12 +26,12 @@ import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; -import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClient; import java.util.Collection; import java.util.Optional; -public interface LwM2mUplinkMsgHandler { +public interface LwM2MUplinkMsgHandler { void onRegistered(Registration registration, Collection previousObsersations); @@ -55,11 +55,11 @@ public interface LwM2mUplinkMsgHandler { void onAwakeDev(Registration registration); - void onWriteResponseOk(LwM2mClient client, String path, WriteRequest request, int code); + void onWriteResponseOk(LwM2MClient client, String path, WriteRequest request, int code); - void onCreateResponseOk(LwM2mClient client, String path, CreateRequest request); + void onCreateResponseOk(LwM2MClient client, String path, CreateRequest request); - void onWriteCompositeResponseOk(LwM2mClient client, WriteCompositeRequest request, int code); + void onWriteCompositeResponseOk(LwM2MClient client, WriteCompositeRequest request, int code); void onToTransportUpdateCredentials(TransportProtos.SessionInfoProto sessionInfo, TransportProtos.ToTransportUpdateCredentialsProto updateCredentials); diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2mTransportUtil.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2MTransportUtil.java similarity index 97% rename from common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2mTransportUtil.java rename to common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2MTransportUtil.java index 23ee5a0a57..ad6550e9a8 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2mTransportUtil.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2MTransportUtil.java @@ -43,11 +43,10 @@ import org.thingsboard.server.common.data.device.data.lwm2m.BootstrapConfigurati import org.thingsboard.server.common.data.device.profile.DeviceProfileTransportConfiguration; import org.thingsboard.server.common.data.device.profile.Lwm2mDeviceProfileTransportConfiguration; import org.thingsboard.server.common.data.ota.OtaPackageKey; -import org.thingsboard.server.common.data.ota.OtaPackageType; import org.thingsboard.server.common.transport.util.JsonUtils; import org.thingsboard.server.transport.lwm2m.config.LwM2mVersion; -import org.thingsboard.server.transport.lwm2m.server.LwM2mOtaConvert; -import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; +import org.thingsboard.server.transport.lwm2m.server.LwM2MOtaConvert; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClient; import org.thingsboard.server.transport.lwm2m.server.client.ResourceValue; import org.thingsboard.server.transport.lwm2m.server.downlink.HasVersionedId; import org.thingsboard.server.transport.lwm2m.server.ota.firmware.FirmwareUpdateResult; @@ -80,14 +79,13 @@ import static org.eclipse.leshan.core.model.ResourceModel.Type.STRING; import static org.eclipse.leshan.core.model.ResourceModel.Type.TIME; import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPARATOR_KEY; import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPARATOR_PATH; -import static org.thingsboard.server.common.data.ota.OtaPackageUtil.getAttributeKey; import static org.thingsboard.server.transport.lwm2m.server.ota.DefaultLwM2MOtaUpdateService.FW_RESULT_ID; import static org.thingsboard.server.transport.lwm2m.server.ota.DefaultLwM2MOtaUpdateService.FW_STATE_ID; import static org.thingsboard.server.transport.lwm2m.server.ota.DefaultLwM2MOtaUpdateService.SW_RESULT_ID; import static org.thingsboard.server.transport.lwm2m.server.ota.DefaultLwM2MOtaUpdateService.SW_STATE_ID; @Slf4j -public class LwM2mTransportUtil { +public class LwM2MTransportUtil { public static final String LWM2M_OBJECT_VERSION_DEFAULT = "1.0"; @@ -146,9 +144,9 @@ public class LwM2mTransportUtil { } } - public static LwM2mOtaConvert convertOtaUpdateValueToString(String pathIdVer, Object value, ResourceModel.Type currentType) { + public static LwM2MOtaConvert convertOtaUpdateValueToString(String pathIdVer, Object value, ResourceModel.Type currentType) { String path = fromVersionedIdToObjectId(pathIdVer); - LwM2mOtaConvert lwM2mOtaConvert = new LwM2mOtaConvert(); + LwM2MOtaConvert lwM2mOtaConvert = new LwM2MOtaConvert(); if (path != null) { if (FW_STATE_ID.equals(path)) { lwM2mOtaConvert.setCurrentType(STRING); @@ -341,7 +339,7 @@ public class LwM2mTransportUtil { } } - public static void validateVersionedId(LwM2mClient client, HasVersionedId request) { + public static void validateVersionedId(LwM2MClient client, HasVersionedId request) { String msgExceptionStr = ""; if (request.getObjectId() == null) { msgExceptionStr = "Specified object id is null!"; @@ -362,7 +360,7 @@ public class LwM2mTransportUtil { public static Map convertMultiResourceValuesFromJson(JsonElement newValProto, ResourceModel.Type type, String versionedId) throws Exception{ Map newValues = equalsMultiResourceValuesResourceType(type); newValProto.getAsJsonObject().entrySet().forEach((obj) -> { - newValues.put(Integer.valueOf(obj.getKey()), LwM2mValueConverterImpl.getInstance().convertValue(obj.getValue().getAsString(), + newValues.put(Integer.valueOf(obj.getKey()), LwM2MValueConverterImpl.getInstance().convertValue(obj.getValue().getAsString(), STRING, type, new LwM2mPath(fromVersionedIdToObjectId(versionedId)))); }); return newValues; @@ -429,7 +427,7 @@ public class LwM2mTransportUtil { * @param path - * @return - return value of Resource by idPath */ - public static LwM2mResource getResourceValueFromLwM2MClient(LwM2mClient lwM2MClient, String path) { + public static LwM2mResource getResourceValueFromLwM2MClient(LwM2MClient lwM2MClient, String path) { LwM2mResource lwm2mResourceValue = null; ResourceValue resourceValue = lwM2MClient.getResources().get(path); if (resourceValue != null) { @@ -523,8 +521,7 @@ public class LwM2mTransportUtil { public static boolean compareAttNameKeyOta(String attrName) { for (OtaPackageKey value : OtaPackageKey.values()) { - if (getAttributeKey(OtaPackageType.FIRMWARE, value).equals(attrName)) return true; - if (getAttributeKey(OtaPackageType.SOFTWARE, value).equals(attrName)) return true; + if (attrName.contains(value.getValue())) return true; } return false; } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2mValueConverterImpl.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2MValueConverterImpl.java similarity index 97% rename from common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2mValueConverterImpl.java rename to common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2MValueConverterImpl.java index 0427caa3a6..1c5dcdff95 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2mValueConverterImpl.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2MValueConverterImpl.java @@ -33,11 +33,11 @@ import java.util.Date; import static org.eclipse.leshan.core.model.ResourceModel.Type.OPAQUE; @Slf4j -public class LwM2mValueConverterImpl implements LwM2mValueConverter { +public class LwM2MValueConverterImpl implements LwM2mValueConverter { - private static final LwM2mValueConverterImpl INSTANCE = new LwM2mValueConverterImpl(); + private static final LwM2MValueConverterImpl INSTANCE = new LwM2MValueConverterImpl(); - public static LwM2mValueConverterImpl getInstance() { + public static LwM2MValueConverterImpl getInstance() { return INSTANCE; } From 157e2361f6537284a05a84c5effff7b1701232d6 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Tue, 21 Sep 2021 17:35:19 +0300 Subject: [PATCH 044/432] Lwm2m Fix bug review edit formatting --- .../lwm2m/server/client/LwM2MClient.java | 9 ++--- .../server/client/LwM2MClientContextImpl.java | 4 +-- .../lwm2m/utils/LwM2MTransportUtil.java | 2 +- .../common/transport/util/JsonUtils.java | 2 +- .../thingsboard/common/util/JacksonUtil.java | 35 ------------------- 5 files changed, 7 insertions(+), 45 deletions(-) diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2MClient.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2MClient.java index 0a200262ae..055912ed96 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2MClient.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2MClient.java @@ -348,16 +348,13 @@ public class LwM2MClient implements Serializable { } else if (resourceModel.operations.isWritable() && resourceModel.mandatory) { throw new IllegalArgumentException("Resource id=" + resourceId + " is mandatory. The value of this resource must not be null."); } - } - else if (resourceModel.operations.isWritable() && resourceModel.mandatory) { + } else if (resourceModel.operations.isWritable() && resourceModel.mandatory) { throw new IllegalArgumentException("Resource id=" + resourceId + " is mandatory. The value of this resource must not be null."); } }); - } - else if (params == null) { + } else if (params == null) { throw new IllegalArgumentException("The value of this resource must not be null."); - } - else { + } else { throw new IllegalArgumentException("The value of this resource must be in Map format and size > 0"); } return resources; diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2MClientContextImpl.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2MClientContextImpl.java index 6eab4eba54..74e9884545 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2MClientContextImpl.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2MClientContextImpl.java @@ -37,12 +37,12 @@ import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; import org.thingsboard.server.transport.lwm2m.secure.TbLwM2MSecurityInfo; import org.thingsboard.server.transport.lwm2m.server.LwM2MTransportContext; -import org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil; import org.thingsboard.server.transport.lwm2m.server.ota.LwM2MOtaUpdateService; import org.thingsboard.server.transport.lwm2m.server.session.LwM2MSessionManager; import org.thingsboard.server.transport.lwm2m.server.store.TbLwM2MClientStore; import org.thingsboard.server.transport.lwm2m.server.store.TbMainSecurityStore; import org.thingsboard.server.transport.lwm2m.server.uplink.DefaultLwM2MUplinkMsgHandler; +import org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil; import java.util.Arrays; import java.util.Collection; @@ -293,7 +293,7 @@ public class LwM2MClientContextImpl implements LwM2MClientContext { String k = entry.getKey(); String v = entry.getValue(); if (v.equals(keyName) && client.isValidObjectVersion(k).isEmpty()) { - return k; + return k; } } throw new IllegalArgumentException(keyName + " is not configured in the device profile!"); diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2MTransportUtil.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2MTransportUtil.java index ad6550e9a8..311a806afa 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2MTransportUtil.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2MTransportUtil.java @@ -352,7 +352,7 @@ public class LwM2MTransportUtil { } public static Map convertMultiResourceValuesFromRpcBody(Object value, ResourceModel.Type type, String versionedId) throws Exception { - String valueJsonStr = JsonUtils.riteValueAsString(value); + String valueJsonStr = JsonUtils.writeValueAsString(value); JsonElement element = JsonUtils.parse(valueJsonStr); return convertMultiResourceValuesFromJson(element, type, versionedId); } diff --git a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/util/JsonUtils.java b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/util/JsonUtils.java index 82f7c2cf3a..76320da164 100644 --- a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/util/JsonUtils.java +++ b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/util/JsonUtils.java @@ -57,7 +57,7 @@ public class JsonUtils { return jsonParser.parse(params); } - public static String riteValueAsString (Object value) throws JsonProcessingException { + public static String writeValueAsString(Object value) throws JsonProcessingException { return json.writeValueAsString(value); } diff --git a/common/util/src/main/java/org/thingsboard/common/util/JacksonUtil.java b/common/util/src/main/java/org/thingsboard/common/util/JacksonUtil.java index ddd074fc6c..2b8f0c04c5 100644 --- a/common/util/src/main/java/org/thingsboard/common/util/JacksonUtil.java +++ b/common/util/src/main/java/org/thingsboard/common/util/JacksonUtil.java @@ -124,39 +124,4 @@ public class JacksonUtil { public static T treeToValue(JsonNode tree, Class type) throws JsonProcessingException { return OBJECT_MAPPER.treeToValue(tree, type); } - - - /** - * - * @param {bootstrap:client:host, client, client:port, client:endpoint} - * @param ":" - * @return - * - "bootstrap:client:host" - * -- if in nodeCredentialsValue is absent: - * --- "bootstrap" or "bootstrap:client" or "bootstrap:client:host" -> return "host" - * -- if in nodeCredentialsValue is absent: - * --- "client:port" -> return "port" - * -- if the nodeCredentialsValue contains: - * --- "client" and "client:port" -> "port" not add to Set - */ - public static String validateFieldsToTree(JsonNode nodeCredentialsValue, String[] fields, String delimiter) { - try { - StringBuilder msgSet = new StringBuilder(); - for (String field : fields) { - String[] keys = field.split(delimiter); - JsonNode nodeVal = nodeCredentialsValue; - for (String key : keys) { - if (!nodeVal.hasNonNull(key)) { - msgSet.append(" " + keys[keys.length - 1]); - break; - } else { - nodeVal = nodeVal.get(key); - } - } - } - return msgSet.toString().trim(); - } catch (Exception e) { - throw new IllegalArgumentException(e); - } - } } From f3cefc8b2ca541754adbb7414d499eb16d8a452e Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Wed, 22 Sep 2021 18:31:56 +0300 Subject: [PATCH 045/432] Lwm2m revert rename --- .../lwm2m/client/LwM2MTestClient.java | 16 +-- ....java => LwM2mBinaryAppDataContainer.java} | 6 +- ...{LwM2MLocation.java => LwM2mLocation.java} | 8 +- ...ensor.java => LwM2mTemperatureSensor.java} | 6 +- ...ava => RpcLwm2mIntegrationCreateTest.java} | 2 +- ...ava => RpcLwm2mIntegrationDeleteTest.java} | 2 +- ...a => RpcLwm2mIntegrationDiscoverTest.java} | 2 +- ...va => RpcLwm2mIntegrationExecuteTest.java} | 2 +- ...va => RpcLwm2mIntegrationObserveTest.java} | 2 +- ....java => RpcLwm2mIntegrationReadTest.java} | 2 +- ...cLwm2mIntegrationWriteAttributesTest.java} | 2 +- ...java => RpcLwm2mIntegrationWriteTest.java} | 2 +- ...Test.java => PskLwm2mIntegrationTest.java} | 2 +- .../LwM2mTransportServerHelperTest.java | 8 +- .../LwM2MTransportBootstrapService.java | 4 +- .../secure/LwM2MBootstrapSecurityStore.java | 20 ++-- ...wM2mCredentialsSecurityInfoValidator.java} | 14 +-- ...dentials.java => LwM2mRPkCredentials.java} | 4 +- .../lwm2m/secure/TbLwM2MAuthorizer.java | 4 +- .../TbLwM2MDtlsCertificateVerifier.java | 4 +- ...va => AbstractLwM2mTransportResource.java} | 4 +- ...java => DefaultLwM2mTransportService.java} | 24 ++--- ...2MOtaConvert.java => LwM2mOtaConvert.java} | 2 +- ...edRequest.java => LwM2mQueuedRequest.java} | 2 +- ...Listener.java => LwM2mServerListener.java} | 8 +- ...ener.java => LwM2mSessionMsgListener.java} | 6 +- ...e.java => LwM2mTransportCoapResource.java} | 4 +- ...ontext.java => LwM2mTransportContext.java} | 2 +- ...r.java => LwM2mTransportServerHelper.java} | 4 +- ....java => LwM2mVersionedModelProvider.java} | 10 +- .../DefaultLwM2MAttributesService.java | 36 +++---- .../attributes/LwM2MAttributesService.java | 6 +- .../{LwM2MClient.java => LwM2mClient.java} | 4 +- ...ntContext.java => LwM2mClientContext.java} | 34 +++--- ...tImpl.java => LwM2mClientContextImpl.java} | 66 ++++++------ .../AbstractTbLwM2MRequestCallback.java | 6 +- ...va => DefaultLwM2mDownlinkMsgHandler.java} | 66 ++++++------ ...dler.java => LwM2mDownlinkMsgHandler.java} | 34 +++--- .../TbLwM2MCancelAllObserveCallback.java | 4 +- .../TbLwM2MCancelObserveCallback.java | 4 +- .../TbLwM2MCreateResponseCallback.java | 6 +- .../downlink/TbLwM2MDeleteCallback.java | 4 +- .../downlink/TbLwM2MDiscoverCallback.java | 4 +- .../downlink/TbLwM2MExecuteCallback.java | 4 +- .../downlink/TbLwM2MObserveCallback.java | 6 +- .../server/downlink/TbLwM2MReadCallback.java | 6 +- .../downlink/TbLwM2MTargetedCallback.java | 6 +- .../TbLwM2MUplinkTargetedCallback.java | 10 +- .../TbLwM2MWriteAttributesCallback.java | 4 +- .../TbLwM2MWriteResponseCallback.java | 6 +- .../TbLwM2MReadCompositeCallback.java | 6 +- ...TbLwM2MWriteResponseCompositeCallback.java | 6 +- .../log/DefaultLwM2MTelemetryLogService.java | 8 +- .../server/log/LwM2MTelemetryLogService.java | 4 +- .../ota/DefaultLwM2MOtaUpdateService.java | 80 +++++++------- .../server/ota/LwM2MOtaUpdateService.java | 36 +++---- .../rpc/DefaultLwM2MRpcRequestHandler.java | 54 +++++----- .../rpc/RpcCancelAllObserveCallback.java | 4 +- .../server/rpc/RpcCancelObserveCallback.java | 4 +- .../server/rpc/RpcCreateResponseCallback.java | 4 +- .../lwm2m/server/rpc/RpcDiscoverCallback.java | 4 +- .../rpc/RpcDownlinkRequestCallbackProxy.java | 6 +- .../server/rpc/RpcEmptyResponseCallback.java | 4 +- .../lwm2m/server/rpc/RpcLinkSetCallback.java | 4 +- .../server/rpc/RpcLwM2MDownlinkCallback.java | 4 +- .../server/rpc/RpcReadResponseCallback.java | 4 +- .../RpcReadResponseCompositeCallback.java | 4 +- .../session/DefaultLwM2MSessionManager.java | 10 +- .../server/store/TbDummyLwM2MClientStore.java | 8 +- .../server/store/TbLwM2MClientStore.java | 8 +- .../server/store/TbLwM2mSecurityStore.java | 8 +- .../server/store/TbLwM2mStoreFactory.java | 4 +- .../server/store/TbRedisLwM2MClientStore.java | 14 +-- ...java => DefaultLwM2mUplinkMsgHandler.java} | 100 +++++++++--------- ...2MTypeServer.java => LwM2mTypeServer.java} | 8 +- ...andler.java => LwM2mUplinkMsgHandler.java} | 10 +- .../lwm2m/utils/LwM2MTransportUtil.java | 22 ++-- ...Impl.java => LwM2mValueConverterImpl.java} | 6 +- 78 files changed, 464 insertions(+), 464 deletions(-) rename application/src/test/java/org/thingsboard/server/transport/lwm2m/client/{LwM2MBinaryAppDataContainer.java => LwM2mBinaryAppDataContainer.java} (97%) rename application/src/test/java/org/thingsboard/server/transport/lwm2m/client/{LwM2MLocation.java => LwM2mLocation.java} (95%) rename application/src/test/java/org/thingsboard/server/transport/lwm2m/client/{LwM2MTemperatureSensor.java => LwM2mTemperatureSensor.java} (96%) rename application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/{RpcLwM2MIntegrationCreateTest.java => RpcLwm2mIntegrationCreateTest.java} (99%) rename application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/{RpcLwM2MIntegrationDeleteTest.java => RpcLwm2mIntegrationDeleteTest.java} (98%) rename application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/{RpcLwM2MIntegrationDiscoverTest.java => RpcLwm2mIntegrationDiscoverTest.java} (99%) rename application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/{RpcLwM2MIntegrationExecuteTest.java => RpcLwm2mIntegrationExecuteTest.java} (99%) rename application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/{RpcLwM2MIntegrationObserveTest.java => RpcLwm2mIntegrationObserveTest.java} (99%) rename application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/{RpcLwM2MIntegrationReadTest.java => RpcLwm2mIntegrationReadTest.java} (99%) rename application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/{RpcLwM2MIntegrationWriteAttributesTest.java => RpcLwm2mIntegrationWriteAttributesTest.java} (97%) rename application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/{RpcLwM2MIntegrationWriteTest.java => RpcLwm2mIntegrationWriteTest.java} (99%) rename application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/{PskLwM2MIntegrationTest.java => PskLwm2mIntegrationTest.java} (96%) rename common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/{LwM2MCredentialsSecurityInfoValidator.java => LwM2mCredentialsSecurityInfoValidator.java} (96%) rename common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/{LwM2MRPkCredentials.java => LwM2mRPkCredentials.java} (97%) rename common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/{AbstractLwM2MTransportResource.java => AbstractLwM2mTransportResource.java} (91%) rename common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/{DefaultLwM2MTransportService.java => DefaultLwM2mTransportService.java} (92%) rename common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/{LwM2MOtaConvert.java => LwM2mOtaConvert.java} (96%) rename common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/{LwM2MQueuedRequest.java => LwM2mQueuedRequest.java} (94%) rename common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/{LwM2MServerListener.java => LwM2mServerListener.java} (96%) rename common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/{LwM2MSessionMsgListener.java => LwM2mSessionMsgListener.java} (97%) rename common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/{LwM2MTransportCoapResource.java => LwM2mTransportCoapResource.java} (97%) rename common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/{LwM2MTransportContext.java => LwM2mTransportContext.java} (94%) rename common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/{LwM2MTransportServerHelper.java => LwM2mTransportServerHelper.java} (99%) rename common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/{LwM2MVersionedModelProvider.java => LwM2mVersionedModelProvider.java} (95%) rename common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/{LwM2MClient.java => LwM2mClient.java} (99%) rename common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/{LwM2MClientContext.java => LwM2mClientContext.java} (67%) rename common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/{LwM2MClientContextImpl.java => LwM2mClientContextImpl.java} (91%) rename common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/{DefaultLwM2MDownlinkMsgHandler.java => DefaultLwM2mDownlinkMsgHandler.java} (94%) rename common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/{LwM2MDownlinkMsgHandler.java => LwM2mDownlinkMsgHandler.java} (78%) rename common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/{DefaultLwM2MUplinkMsgHandler.java => DefaultLwM2mUplinkMsgHandler.java} (94%) rename common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/{LwM2MTypeServer.java => LwM2mTypeServer.java} (83%) rename common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/{LwM2MUplinkMsgHandler.java => LwM2mUplinkMsgHandler.java} (91%) rename common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/{LwM2MValueConverterImpl.java => LwM2mValueConverterImpl.java} (97%) diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2MTestClient.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2MTestClient.java index 33f5382ca8..1c62b2b79d 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2MTestClient.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2MTestClient.java @@ -44,7 +44,7 @@ import org.eclipse.leshan.core.request.BootstrapRequest; import org.eclipse.leshan.core.request.DeregisterRequest; import org.eclipse.leshan.core.request.RegisterRequest; import org.eclipse.leshan.core.request.UpdateRequest; -import org.thingsboard.server.transport.lwm2m.utils.LwM2MValueConverterImpl; +import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl; import org.junit.Assert; import java.io.IOException; @@ -80,9 +80,9 @@ public class LwM2MTestClient { private SimpleLwM2MDevice lwM2MDevice; private FwLwM2MDevice fwLwM2MDevice; private SwLwM2MDevice swLwM2MDevice; - private LwM2MBinaryAppDataContainer lwM2MBinaryAppDataContainer; + private LwM2mBinaryAppDataContainer lwM2MBinaryAppDataContainer; private LwM2MLocationParams locationParams; - private LwM2MTemperatureSensor lwM2MTemperatureSensor; + private LwM2mTemperatureSensor lwM2MTemperatureSensor; public void init(Security security, NetworkConfig coapConfig, int port, boolean isRpc) throws InvalidDDFFileException, IOException { Assert.assertNull("client already initialized", client); @@ -99,12 +99,12 @@ public class LwM2MTestClient { initializer.setInstancesForObject(FIRMWARE, fwLwM2MDevice = new FwLwM2MDevice()); initializer.setInstancesForObject(SOFTWARE_MANAGEMENT, swLwM2MDevice = new SwLwM2MDevice()); initializer.setClassForObject(ACCESS_CONTROL, DummyInstanceEnabler.class); - initializer.setInstancesForObject(BINARY_APP_DATA_CONTAINER, lwM2MBinaryAppDataContainer = new LwM2MBinaryAppDataContainer(executor, objectInstanceId_0), - new LwM2MBinaryAppDataContainer(executor, objectInstanceId_1)); + initializer.setInstancesForObject(BINARY_APP_DATA_CONTAINER, lwM2MBinaryAppDataContainer = new LwM2mBinaryAppDataContainer(executor, objectInstanceId_0), + new LwM2mBinaryAppDataContainer(executor, objectInstanceId_1)); locationParams = new LwM2MLocationParams(); locationParams.getPos(); - initializer.setInstancesForObject(LOCATION, new LwM2MLocation(locationParams.getLatitude(), locationParams.getLongitude(), locationParams.getScaleFactor(), executor, objectInstanceId_0)); - initializer.setInstancesForObject(TEMPERATURE_SENSOR, lwM2MTemperatureSensor = new LwM2MTemperatureSensor(executor, objectInstanceId_0), new LwM2MTemperatureSensor(executor, objectInstanceId_12)); + initializer.setInstancesForObject(LOCATION, new LwM2mLocation(locationParams.getLatitude(), locationParams.getLongitude(), locationParams.getScaleFactor(), executor, objectInstanceId_0)); + initializer.setInstancesForObject(TEMPERATURE_SENSOR, lwM2MTemperatureSensor = new LwM2mTemperatureSensor(executor, objectInstanceId_0), new LwM2mTemperatureSensor(executor, objectInstanceId_12)); DtlsConnectorConfig.Builder dtlsConfig = new DtlsConnectorConfig.Builder(); dtlsConfig.setRecommendedCipherSuitesOnly(true); @@ -157,7 +157,7 @@ public class LwM2MTestClient { builder.setSharedExecutor(executor); builder.setDecoder(new DefaultLwM2mDecoder(false)); - builder.setEncoder(new DefaultLwM2mEncoder(new LwM2MValueConverterImpl(), false)); + builder.setEncoder(new DefaultLwM2mEncoder(new LwM2mValueConverterImpl(), false)); client = builder.build(); LwM2mClientObserver observer = new LwM2mClientObserver() { diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2MBinaryAppDataContainer.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2mBinaryAppDataContainer.java similarity index 97% rename from application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2MBinaryAppDataContainer.java rename to application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2mBinaryAppDataContainer.java index e8d028cf73..b7ac889649 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2MBinaryAppDataContainer.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2mBinaryAppDataContainer.java @@ -37,7 +37,7 @@ import java.util.concurrent.TimeUnit; @Slf4j -public class LwM2MBinaryAppDataContainer extends BaseInstanceEnabler implements Destroyable { +public class LwM2mBinaryAppDataContainer extends BaseInstanceEnabler implements Destroyable { /** * id = 0 @@ -76,10 +76,10 @@ public class LwM2MBinaryAppDataContainer extends BaseInstanceEnabler implements private Integer appID = -1; private static final List supportedResources = Arrays.asList(0, 1, 2, 3, 4, 5); - public LwM2MBinaryAppDataContainer() { + public LwM2mBinaryAppDataContainer() { } - public LwM2MBinaryAppDataContainer(ScheduledExecutorService executorService, Integer id) { + public LwM2mBinaryAppDataContainer(ScheduledExecutorService executorService, Integer id) { try { if (id != null) this.setId(id); executorService.scheduleWithFixedDelay(() -> diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2MLocation.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2mLocation.java similarity index 95% rename from application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2MLocation.java rename to application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2mLocation.java index 6ee267d466..079cd9fdac 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2MLocation.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2mLocation.java @@ -30,7 +30,7 @@ import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; @Slf4j -public class LwM2MLocation extends BaseInstanceEnabler implements Destroyable { +public class LwM2mLocation extends BaseInstanceEnabler implements Destroyable { private float latitude; private float longitude; @@ -39,11 +39,11 @@ public class LwM2MLocation extends BaseInstanceEnabler implements Destroyable { protected static final Random RANDOM = new Random(); private static final List supportedResources = Arrays.asList(0, 1, 5); - public LwM2MLocation() { + public LwM2mLocation() { this(null, null, 1.0f); } - public LwM2MLocation(Float latitude, Float longitude, float scaleFactor) { + public LwM2mLocation(Float latitude, Float longitude, float scaleFactor) { if (latitude != null) { this.latitude = latitude + 90f; @@ -59,7 +59,7 @@ public class LwM2MLocation extends BaseInstanceEnabler implements Destroyable { timestamp = new Date(); } - public LwM2MLocation(Float latitude, Float longitude, float scaleFactor, ScheduledExecutorService executorService, Integer id) { + public LwM2mLocation(Float latitude, Float longitude, float scaleFactor, ScheduledExecutorService executorService, Integer id) { try { if (id != null) this.setId(id); if (latitude != null) { diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2MTemperatureSensor.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2mTemperatureSensor.java similarity index 96% rename from application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2MTemperatureSensor.java rename to application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2mTemperatureSensor.java index 6b592bdeaa..2e52cfc812 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2MTemperatureSensor.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2mTemperatureSensor.java @@ -32,7 +32,7 @@ import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; @Slf4j -public class LwM2MTemperatureSensor extends BaseInstanceEnabler implements Destroyable { +public class LwM2mTemperatureSensor extends BaseInstanceEnabler implements Destroyable { private static final String UNIT_CELSIUS = "cel"; private double currentTemp = 20d; @@ -41,11 +41,11 @@ public class LwM2MTemperatureSensor extends BaseInstanceEnabler implements Destr protected static final Random RANDOM = new Random(); private static final List supportedResources = Arrays.asList(5601, 5602, 5700, 5701); - public LwM2MTemperatureSensor() { + public LwM2mTemperatureSensor() { } - public LwM2MTemperatureSensor(ScheduledExecutorService executorService, Integer id) { + public LwM2mTemperatureSensor(ScheduledExecutorService executorService, Integer id) { try { if (id != null) this.setId(id); executorService.scheduleWithFixedDelay(this::adjustTemperature, 2000, 2000, TimeUnit.MILLISECONDS); diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwM2MIntegrationCreateTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationCreateTest.java similarity index 99% rename from application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwM2MIntegrationCreateTest.java rename to application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationCreateTest.java index 3c8c9efda2..4ab0d68794 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwM2MIntegrationCreateTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationCreateTest.java @@ -31,7 +31,7 @@ import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.objectInsta import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_0; -public class RpcLwM2MIntegrationCreateTest extends AbstractRpcLwM2MIntegrationTest { +public class RpcLwm2mIntegrationCreateTest extends AbstractRpcLwM2MIntegrationTest { /** * Create {"id":"/19_1.1","value":{"0":{"0":"00AC"}, "1":1}} diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwM2MIntegrationDeleteTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationDeleteTest.java similarity index 98% rename from application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwM2MIntegrationDeleteTest.java rename to application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationDeleteTest.java index a974bb4aaa..6f24d7176c 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwM2MIntegrationDeleteTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationDeleteTest.java @@ -29,7 +29,7 @@ import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.objectInsta import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_9; -public class RpcLwM2MIntegrationDeleteTest extends AbstractRpcLwM2MIntegrationTest { +public class RpcLwm2mIntegrationDeleteTest extends AbstractRpcLwM2MIntegrationTest { /** * if there is such an instance diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwM2MIntegrationDiscoverTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationDiscoverTest.java similarity index 99% rename from application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwM2MIntegrationDiscoverTest.java rename to application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationDiscoverTest.java index 39b7ffda08..b8ca7be61f 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwM2MIntegrationDiscoverTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationDiscoverTest.java @@ -35,7 +35,7 @@ import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.objectInsta import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_2; -public class RpcLwM2MIntegrationDiscoverTest extends AbstractRpcLwM2MIntegrationTest { +public class RpcLwm2mIntegrationDiscoverTest extends AbstractRpcLwM2MIntegrationTest { /** * DiscoverAll diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwM2MIntegrationExecuteTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationExecuteTest.java similarity index 99% rename from application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwM2MIntegrationExecuteTest.java rename to application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationExecuteTest.java index 0ea38d56a2..73ea0fb74c 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwM2MIntegrationExecuteTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationExecuteTest.java @@ -33,7 +33,7 @@ import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_ import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_9; -public class RpcLwM2MIntegrationExecuteTest extends AbstractRpcLwM2MIntegrationTest { +public class RpcLwm2mIntegrationExecuteTest extends AbstractRpcLwM2MIntegrationTest { /** diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwM2MIntegrationObserveTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationObserveTest.java similarity index 99% rename from application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwM2MIntegrationObserveTest.java rename to application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationObserveTest.java index a31e01c59e..848a9563ed 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwM2MIntegrationObserveTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationObserveTest.java @@ -32,7 +32,7 @@ import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_ import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_3; import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_9; -public class RpcLwM2MIntegrationObserveTest extends AbstractRpcLwM2MIntegrationTest { +public class RpcLwm2mIntegrationObserveTest extends AbstractRpcLwM2MIntegrationTest { /** * ObserveReadAll diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwM2MIntegrationReadTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationReadTest.java similarity index 99% rename from application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwM2MIntegrationReadTest.java rename to application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationReadTest.java index d78498a364..9116659bc3 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwM2MIntegrationReadTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationReadTest.java @@ -41,7 +41,7 @@ import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_ import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_9; -public class RpcLwM2MIntegrationReadTest extends AbstractRpcLwM2MIntegrationTest { +public class RpcLwm2mIntegrationReadTest extends AbstractRpcLwM2MIntegrationTest { /** * Read {"id":"/3"} diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwM2MIntegrationWriteAttributesTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationWriteAttributesTest.java similarity index 97% rename from application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwM2MIntegrationWriteAttributesTest.java rename to application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationWriteAttributesTest.java index 49bc79f1c0..ea23ab48b9 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwM2MIntegrationWriteAttributesTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationWriteAttributesTest.java @@ -34,7 +34,7 @@ import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_ import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_9; -public class RpcLwM2MIntegrationWriteAttributesTest extends AbstractRpcLwM2MIntegrationTest { +public class RpcLwm2mIntegrationWriteAttributesTest extends AbstractRpcLwM2MIntegrationTest { /** * WriteAttributes {"id":"/3/0/14","attributes":{"pmax":100, "pmin":10}} diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwM2MIntegrationWriteTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationWriteTest.java similarity index 99% rename from application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwM2MIntegrationWriteTest.java rename to application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationWriteTest.java index cbea43b418..de0a22756d 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwM2MIntegrationWriteTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationWriteTest.java @@ -36,7 +36,7 @@ import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_ import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_9; import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceInstanceId_2; -public class RpcLwM2MIntegrationWriteTest extends AbstractRpcLwM2MIntegrationTest { +public class RpcLwm2mIntegrationWriteTest extends AbstractRpcLwM2MIntegrationTest { /** diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/PskLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/PskLwm2mIntegrationTest.java similarity index 96% rename from application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/PskLwM2MIntegrationTest.java rename to application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/PskLwm2mIntegrationTest.java index 7e49dacca7..23b60482f0 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/PskLwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/PskLwm2mIntegrationTest.java @@ -28,7 +28,7 @@ import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SECURE_COAP import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SECURE_URI; import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SHORT_SERVER_ID; -public class PskLwM2MIntegrationTest extends AbstractSecurityLwM2MIntegrationTest { +public class PskLwm2mIntegrationTest extends AbstractSecurityLwM2MIntegrationTest { @Test public void testConnectWithPSKAndObserveTelemetry() throws Exception { diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportServerHelperTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportServerHelperTest.java index 71fb4e8a91..fabb2ba36f 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportServerHelperTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportServerHelperTest.java @@ -47,15 +47,15 @@ class LwM2mTransportServerHelperTest { long now; List kvList; ConcurrentMap keyTsLatestMap; - LwM2MTransportServerHelper helper; - LwM2MTransportContext context; + LwM2mTransportServerHelper helper; + LwM2mTransportContext context; @BeforeEach void setUp() { now = System.currentTimeMillis(); - context = mock(LwM2MTransportContext.class); - helper = spy(new LwM2MTransportServerHelper(context)); + context = mock(LwM2mTransportContext.class); + helper = spy(new LwM2mTransportServerHelper(context)); willReturn(now).given(helper).getCurrentTimeMillis(); kvList = List.of( TransportProtos.KeyValueProto.newBuilder().setKey(KEY_SW_STATE).setStringV(DOWNLOADING).build(), diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportBootstrapService.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportBootstrapService.java index 4284512687..50cbc075c3 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportBootstrapService.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportBootstrapService.java @@ -30,7 +30,7 @@ import org.thingsboard.server.transport.lwm2m.bootstrap.secure.LwM2MInMemoryBoot import org.thingsboard.server.transport.lwm2m.bootstrap.secure.LwM2mDefaultBootstrapSessionManager; import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportBootstrapConfig; import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; -import org.thingsboard.server.transport.lwm2m.server.DefaultLwM2MTransportService; +import org.thingsboard.server.transport.lwm2m.server.DefaultLwM2mTransportService; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; @@ -93,7 +93,7 @@ public class LwM2MTransportBootstrapService { DtlsConnectorConfig.Builder dtlsConfig = new DtlsConnectorConfig.Builder(); dtlsConfig.setRecommendedSupportedGroupsOnly(serverConfig.isRecommendedSupportedGroups()); dtlsConfig.setRecommendedCipherSuitesOnly(serverConfig.isRecommendedCiphers()); - dtlsConfig.setSupportedCipherSuites(this.pskMode ? DefaultLwM2MTransportService.PSK_CIPHER_SUITES : DefaultLwM2MTransportService.RPK_OR_X509_CIPHER_SUITES); + dtlsConfig.setSupportedCipherSuites(this.pskMode ? DefaultLwM2mTransportService.PSK_CIPHER_SUITES : DefaultLwM2mTransportService.RPK_OR_X509_CIPHER_SUITES); /* Set DTLS Config */ builder.setDtlsConfig(dtlsConfig); diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapSecurityStore.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapSecurityStore.java index ebaefc10b0..e15520406f 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapSecurityStore.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapSecurityStore.java @@ -29,11 +29,11 @@ import org.springframework.stereotype.Service; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.device.data.lwm2m.BootstrapConfiguration; import org.thingsboard.server.gen.transport.TransportProtos; -import org.thingsboard.server.transport.lwm2m.secure.LwM2MCredentialsSecurityInfoValidator; +import org.thingsboard.server.transport.lwm2m.secure.LwM2mCredentialsSecurityInfoValidator; import org.thingsboard.server.transport.lwm2m.secure.TbLwM2MSecurityInfo; -import org.thingsboard.server.transport.lwm2m.server.LwM2MSessionMsgListener; -import org.thingsboard.server.transport.lwm2m.server.LwM2MTransportContext; -import org.thingsboard.server.transport.lwm2m.server.LwM2MTransportServerHelper; +import org.thingsboard.server.transport.lwm2m.server.LwM2mSessionMsgListener; +import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportContext; +import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportServerHelper; import java.io.IOException; import java.security.GeneralSecurityException; @@ -43,7 +43,7 @@ import java.util.Map; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; -import static org.thingsboard.server.transport.lwm2m.server.uplink.LwM2MTypeServer.BOOTSTRAP; +import static org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mTypeServer.BOOTSTRAP; import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.LOG_LWM2M_ERROR; import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.LOG_LWM2M_INFO; import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.LOG_LWM2M_TELEMETRY; @@ -56,13 +56,13 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore { private final EditableBootstrapConfigStore bootstrapConfigStore; - private final LwM2MCredentialsSecurityInfoValidator lwM2MCredentialsSecurityInfoValidator; + private final LwM2mCredentialsSecurityInfoValidator lwM2MCredentialsSecurityInfoValidator; - private final LwM2MTransportContext context; - private final LwM2MTransportServerHelper helper; + private final LwM2mTransportContext context; + private final LwM2mTransportServerHelper helper; private final Map bsSessions = new ConcurrentHashMap<>(); - public LwM2MBootstrapSecurityStore(EditableBootstrapConfigStore bootstrapConfigStore, LwM2MCredentialsSecurityInfoValidator lwM2MCredentialsSecurityInfoValidator, LwM2MTransportContext context, LwM2MTransportServerHelper helper) { + public LwM2MBootstrapSecurityStore(EditableBootstrapConfigStore bootstrapConfigStore, LwM2mCredentialsSecurityInfoValidator lwM2MCredentialsSecurityInfoValidator, LwM2mTransportContext context, LwM2mTransportServerHelper helper) { this.bootstrapConfigStore = bootstrapConfigStore; this.lwM2MCredentialsSecurityInfoValidator = lwM2MCredentialsSecurityInfoValidator; this.context = context; @@ -172,7 +172,7 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore { UUID sessionUUiD = UUID.randomUUID(); TransportProtos.SessionInfoProto sessionInfo = helper.getValidateSessionInfo(store.getMsg(), sessionUUiD.getMostSignificantBits(), sessionUUiD.getLeastSignificantBits()); bsSessions.put(store.getEndpoint(), sessionInfo); - context.getTransportService().registerAsyncSession(sessionInfo, new LwM2MSessionMsgListener(null, null, null, sessionInfo, context.getTransportService())); + context.getTransportService().registerAsyncSession(sessionInfo, new LwM2mSessionMsgListener(null, null, null, sessionInfo, context.getTransportService())); if (this.getValidatedSecurityMode(lwM2MBootstrapConfig.getBootstrapServer(), bootstrapServerProfile, lwM2MBootstrapConfig.getLwm2mServer(), profileLwm2mServer)) { lwM2MBootstrapConfig.setBootstrapServer(new LwM2MServerBootstrap(lwM2MBootstrapConfig.getBootstrapServer(), bootstrapServerProfile)); lwM2MBootstrapConfig.setLwm2mServer(new LwM2MServerBootstrap(lwM2MBootstrapConfig.getLwm2mServer(), profileLwm2mServer)); diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LwM2MCredentialsSecurityInfoValidator.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LwM2mCredentialsSecurityInfoValidator.java similarity index 96% rename from common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LwM2MCredentialsSecurityInfoValidator.java rename to common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LwM2mCredentialsSecurityInfoValidator.java index ccbd30b11b..bf30723ce0 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LwM2MCredentialsSecurityInfoValidator.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LwM2mCredentialsSecurityInfoValidator.java @@ -32,9 +32,9 @@ import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceLwM2MC import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; import org.thingsboard.server.transport.lwm2m.secure.credentials.LwM2MCredentials; -import org.thingsboard.server.transport.lwm2m.server.LwM2MTransportContext; +import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportContext; import org.thingsboard.server.transport.lwm2m.server.client.LwM2MAuthException; -import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2MTypeServer; +import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mTypeServer; import java.io.IOException; import java.security.GeneralSecurityException; @@ -46,18 +46,18 @@ import static org.eclipse.leshan.core.SecurityMode.NO_SEC; import static org.eclipse.leshan.core.SecurityMode.PSK; import static org.eclipse.leshan.core.SecurityMode.RPK; import static org.eclipse.leshan.core.SecurityMode.X509; -import static org.thingsboard.server.transport.lwm2m.server.uplink.LwM2MTypeServer.BOOTSTRAP; +import static org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mTypeServer.BOOTSTRAP; @Slf4j @Component @TbLwM2mTransportComponent @RequiredArgsConstructor -public class LwM2MCredentialsSecurityInfoValidator { +public class LwM2mCredentialsSecurityInfoValidator { - private final LwM2MTransportContext context; + private final LwM2mTransportContext context; private final LwM2MTransportServerConfig config; - public TbLwM2MSecurityInfo getEndpointSecurityInfoByCredentialsId(String credentialsId, LwM2MTypeServer keyValue) { + public TbLwM2MSecurityInfo getEndpointSecurityInfoByCredentialsId(String credentialsId, LwM2mTypeServer keyValue) { CountDownLatch latch = new CountDownLatch(1); final TbLwM2MSecurityInfo[] resultSecurityStore = new TbLwM2MSecurityInfo[1]; log.trace("Validating credentials [{}]", credentialsId); @@ -102,7 +102,7 @@ public class LwM2MCredentialsSecurityInfoValidator { * @param keyValue - * @return SecurityInfo */ - private TbLwM2MSecurityInfo createSecurityInfo(String endpoint, String jsonStr, LwM2MTypeServer keyValue) { + private TbLwM2MSecurityInfo createSecurityInfo(String endpoint, String jsonStr, LwM2mTypeServer keyValue) { TbLwM2MSecurityInfo result = new TbLwM2MSecurityInfo(); LwM2MCredentials credentials = JacksonUtil.fromString(jsonStr, LwM2MCredentials.class); if (credentials != null) { diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LwM2MRPkCredentials.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LwM2mRPkCredentials.java similarity index 97% rename from common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LwM2MRPkCredentials.java rename to common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LwM2mRPkCredentials.java index 445a0c18c3..47fa2f8090 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LwM2MRPkCredentials.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LwM2mRPkCredentials.java @@ -37,7 +37,7 @@ import java.util.List; @Slf4j @Data -public class LwM2MRPkCredentials { +public class LwM2mRPkCredentials { private PublicKey serverPublicKey; private PrivateKey serverPrivateKey; private X509Certificate certificate; @@ -49,7 +49,7 @@ public class LwM2MRPkCredentials { * @param publY * @param privS */ - public LwM2MRPkCredentials(String publX, String publY, String privS) { + public LwM2mRPkCredentials(String publX, String publY, String privS) { generatePublicKeyRPK(publX, publY, privS); } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MAuthorizer.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MAuthorizer.java index ee5dd0112b..04c6a2b160 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MAuthorizer.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MAuthorizer.java @@ -26,7 +26,7 @@ import org.eclipse.leshan.server.security.SecurityInfo; import org.springframework.stereotype.Component; import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; import org.thingsboard.server.transport.lwm2m.server.client.LwM2MAuthException; -import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClientContext; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientContext; import org.thingsboard.server.transport.lwm2m.server.store.TbLwM2MDtlsSessionStore; import org.thingsboard.server.transport.lwm2m.server.store.TbSecurityStore; @@ -39,7 +39,7 @@ public class TbLwM2MAuthorizer implements Authorizer { private final TbLwM2MDtlsSessionStore sessionStorage; private final TbSecurityStore securityStore; private final SecurityChecker securityChecker = new SecurityChecker(); - private final LwM2MClientContext clientContext; + private final LwM2mClientContext clientContext; @Override public Registration isAuthorized(UplinkRequest request, Registration registration, Identity senderIdentity) { diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MDtlsCertificateVerifier.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MDtlsCertificateVerifier.java index 8f0358b0c9..fe04410c17 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MDtlsCertificateVerifier.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MDtlsCertificateVerifier.java @@ -57,7 +57,7 @@ import java.security.cert.X509Certificate; import java.util.Arrays; import java.util.List; -import static org.thingsboard.server.transport.lwm2m.server.uplink.LwM2MTypeServer.CLIENT; +import static org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mTypeServer.CLIENT; @Slf4j @Component @@ -67,7 +67,7 @@ public class TbLwM2MDtlsCertificateVerifier implements NewAdvancedCertificateVer private final TbLwM2MDtlsSessionStore sessionStorage; private final LwM2MTransportServerConfig config; - private final LwM2MCredentialsSecurityInfoValidator securityInfoValidator; + private final LwM2mCredentialsSecurityInfoValidator securityInfoValidator; private final TbMainSecurityStore securityStore; @SuppressWarnings("deprecation") diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/AbstractLwM2MTransportResource.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/AbstractLwM2mTransportResource.java similarity index 91% rename from common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/AbstractLwM2MTransportResource.java rename to common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/AbstractLwM2mTransportResource.java index 2d8aa2c1a7..5aed494934 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/AbstractLwM2MTransportResource.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/AbstractLwM2mTransportResource.java @@ -20,9 +20,9 @@ import org.eclipse.californium.core.server.resources.CoapExchange; import org.eclipse.leshan.core.californium.LwM2mCoapResource; @Slf4j -public abstract class AbstractLwM2MTransportResource extends LwM2mCoapResource { +public abstract class AbstractLwM2mTransportResource extends LwM2mCoapResource { - public AbstractLwM2MTransportResource(String name) { + public AbstractLwM2mTransportResource(String name) { super(name); } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2MTransportService.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2mTransportService.java similarity index 92% rename from common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2MTransportService.java rename to common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2mTransportService.java index c1b91dd451..0a8f663dd8 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2MTransportService.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2mTransportService.java @@ -33,10 +33,10 @@ import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; import org.thingsboard.server.transport.lwm2m.secure.TbLwM2MAuthorizer; import org.thingsboard.server.transport.lwm2m.secure.TbLwM2MDtlsCertificateVerifier; -import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClientContext; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientContext; import org.thingsboard.server.transport.lwm2m.server.store.TbSecurityStore; -import org.thingsboard.server.transport.lwm2m.server.uplink.DefaultLwM2MUplinkMsgHandler; -import org.thingsboard.server.transport.lwm2m.utils.LwM2MValueConverterImpl; +import org.thingsboard.server.transport.lwm2m.server.uplink.DefaultLwM2mUplinkMsgHandler; +import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; @@ -55,19 +55,19 @@ import static org.thingsboard.server.transport.lwm2m.server.ota.DefaultLwM2MOtaU @Component @TbLwM2mTransportComponent @RequiredArgsConstructor -public class DefaultLwM2MTransportService implements LwM2MTransportService { +public class DefaultLwM2mTransportService implements LwM2MTransportService { public static final CipherSuite[] RPK_OR_X509_CIPHER_SUITES = {TLS_PSK_WITH_AES_128_CCM_8, TLS_PSK_WITH_AES_128_CBC_SHA256, TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256}; public static final CipherSuite[] PSK_CIPHER_SUITES = {TLS_PSK_WITH_AES_128_CCM_8, TLS_PSK_WITH_AES_128_CBC_SHA256}; - private final LwM2MTransportContext context; + private final LwM2mTransportContext context; private final LwM2MTransportServerConfig config; - private final LwM2MTransportServerHelper helper; + private final LwM2mTransportServerHelper helper; private final OtaPackageDataCache otaPackageDataCache; - private final DefaultLwM2MUplinkMsgHandler handler; + private final DefaultLwM2mUplinkMsgHandler handler; private final CaliforniumRegistrationStore registrationStore; private final TbSecurityStore securityStore; - private final LwM2MClientContext lwM2mClientContext; + private final LwM2mClientContext lwM2mClientContext; private final TbLwM2MDtlsCertificateVerifier certificateVerifier; private final TbLwM2MAuthorizer authorizer; @@ -83,7 +83,7 @@ public class DefaultLwM2MTransportService implements LwM2MTransportService { * nameFile = "BC68JAR01A09_TO_BC68JAR01A10.bin" * "coap://host:port/{path}/{token}/{nameFile}" */ - LwM2MTransportCoapResource otaCoapResource = new LwM2MTransportCoapResource(otaPackageDataCache, FIRMWARE_UPDATE_COAP_RESOURCE); + LwM2mTransportCoapResource otaCoapResource = new LwM2mTransportCoapResource(otaPackageDataCache, FIRMWARE_UPDATE_COAP_RESOURCE); this.server.coap().getServer().add(otaCoapResource); this.startLhServer(); this.context.setServer(server); @@ -92,7 +92,7 @@ public class DefaultLwM2MTransportService implements LwM2MTransportService { private void startLhServer() { log.info("Starting LwM2M transport server..."); this.server.start(); - LwM2MServerListener lhServerCertListener = new LwM2MServerListener(handler); + LwM2mServerListener lhServerCertListener = new LwM2mServerListener(handler); this.server.getRegistrationService().addListener(lhServerCertListener.registrationListener); this.server.getPresenceService().addListener(lhServerCertListener.presenceListener); this.server.getObservationService().addListener(lhServerCertListener.observationListener); @@ -112,13 +112,13 @@ public class DefaultLwM2MTransportService implements LwM2MTransportService { builder.setLocalSecureAddress(config.getSecureHost(), config.getSecurePort()); builder.setDecoder(new DefaultLwM2mDecoder()); /* Use a magic converter to support bad type send by the UI. */ - builder.setEncoder(new DefaultLwM2mEncoder(LwM2MValueConverterImpl.getInstance())); + builder.setEncoder(new DefaultLwM2mEncoder(LwM2mValueConverterImpl.getInstance())); /* Create CoAP Config */ builder.setCoapConfig(getCoapConfig(config.getPort(), config.getSecurePort(), config)); /* Define model provider (Create Models )*/ - LwM2mModelProvider modelProvider = new LwM2MVersionedModelProvider(this.lwM2mClientContext, this.helper, this.context); + LwM2mModelProvider modelProvider = new LwM2mVersionedModelProvider(this.lwM2mClientContext, this.helper, this.context); config.setModelProvider(modelProvider); builder.setObjectModelProvider(modelProvider); diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MOtaConvert.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mOtaConvert.java similarity index 96% rename from common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MOtaConvert.java rename to common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mOtaConvert.java index 07534a1be4..7b7c56adb3 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MOtaConvert.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mOtaConvert.java @@ -19,7 +19,7 @@ import lombok.Data; import org.eclipse.leshan.core.model.ResourceModel; @Data -public class LwM2MOtaConvert { +public class LwM2mOtaConvert { private ResourceModel.Type currentType; private Object value; } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MQueuedRequest.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mQueuedRequest.java similarity index 94% rename from common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MQueuedRequest.java rename to common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mQueuedRequest.java index 2e6951ebe4..dfc88a3331 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MQueuedRequest.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mQueuedRequest.java @@ -15,6 +15,6 @@ */ package org.thingsboard.server.transport.lwm2m.server; -public interface LwM2MQueuedRequest { +public interface LwM2mQueuedRequest { void send(); } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MServerListener.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mServerListener.java similarity index 96% rename from common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MServerListener.java rename to common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mServerListener.java index 1e66bc2924..a2797487a8 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MServerListener.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mServerListener.java @@ -23,18 +23,18 @@ import org.eclipse.leshan.server.queue.PresenceListener; import org.eclipse.leshan.server.registration.Registration; import org.eclipse.leshan.server.registration.RegistrationListener; import org.eclipse.leshan.server.registration.RegistrationUpdate; -import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2MUplinkMsgHandler; +import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler; import java.util.Collection; import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.convertObjectIdToVersionedId; @Slf4j -public class LwM2MServerListener { +public class LwM2mServerListener { - private final LwM2MUplinkMsgHandler service; + private final LwM2mUplinkMsgHandler service; - public LwM2MServerListener(LwM2MUplinkMsgHandler service) { + public LwM2mServerListener(LwM2mUplinkMsgHandler service) { this.service = service; } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MSessionMsgListener.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mSessionMsgListener.java similarity index 97% rename from common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MSessionMsgListener.java rename to common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mSessionMsgListener.java index 704a29ee9b..463823e583 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MSessionMsgListener.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mSessionMsgListener.java @@ -34,15 +34,15 @@ import org.thingsboard.server.gen.transport.TransportProtos.ToServerRpcResponseM import org.thingsboard.server.gen.transport.TransportProtos.ToTransportUpdateCredentialsProto; import org.thingsboard.server.transport.lwm2m.server.attributes.LwM2MAttributesService; import org.thingsboard.server.transport.lwm2m.server.rpc.LwM2MRpcRequestHandler; -import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2MUplinkMsgHandler; +import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler; import java.util.Optional; import java.util.UUID; @Slf4j @RequiredArgsConstructor -public class LwM2MSessionMsgListener implements GenericFutureListener>, SessionMsgListener { - private final LwM2MUplinkMsgHandler handler; +public class LwM2mSessionMsgListener implements GenericFutureListener>, SessionMsgListener { + private final LwM2mUplinkMsgHandler handler; private final LwM2MAttributesService attributesService; private final LwM2MRpcRequestHandler rpcHandler; private final TransportProtos.SessionInfoProto sessionInfo; diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportCoapResource.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportCoapResource.java similarity index 97% rename from common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportCoapResource.java rename to common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportCoapResource.java index 17a1f61856..bde1725807 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportCoapResource.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportCoapResource.java @@ -36,12 +36,12 @@ import static org.thingsboard.server.transport.lwm2m.server.ota.DefaultLwM2MOtaU import static org.thingsboard.server.transport.lwm2m.server.ota.DefaultLwM2MOtaUpdateService.SOFTWARE_UPDATE_COAP_RESOURCE; @Slf4j -public class LwM2MTransportCoapResource extends AbstractLwM2MTransportResource { +public class LwM2mTransportCoapResource extends AbstractLwM2mTransportResource { private final ConcurrentMap tokenToObserveRelationMap = new ConcurrentHashMap<>(); private final ConcurrentMap tokenToObserveNotificationSeqMap = new ConcurrentHashMap<>(); private final OtaPackageDataCache otaPackageDataCache; - public LwM2MTransportCoapResource(OtaPackageDataCache otaPackageDataCache, String name) { + public LwM2mTransportCoapResource(OtaPackageDataCache otaPackageDataCache, String name) { super(name); this.otaPackageDataCache = otaPackageDataCache; this.setObservable(true); // enable observing diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportContext.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportContext.java similarity index 94% rename from common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportContext.java rename to common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportContext.java index 370743394e..6ae204affc 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportContext.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportContext.java @@ -24,7 +24,7 @@ import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; @Component @TbLwM2mTransportComponent -public class LwM2MTransportContext extends TransportContext { +public class LwM2mTransportContext extends TransportContext { @Getter @Setter private LeshanServer server; diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportServerHelper.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportServerHelper.java similarity index 99% rename from common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportServerHelper.java rename to common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportServerHelper.java index 0a02dee97e..136f95dd35 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportServerHelper.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportServerHelper.java @@ -48,9 +48,9 @@ import static org.thingsboard.server.gen.transport.TransportProtos.KeyValueType. @Component @TbLwM2mTransportComponent @RequiredArgsConstructor -public class LwM2MTransportServerHelper { +public class LwM2mTransportServerHelper { - private final LwM2MTransportContext context; + private final LwM2mTransportContext context; private final static JsonParser JSON_PARSER = new JsonParser(); public void sendParametersOnThingsboardAttribute(List result, SessionInfoProto sessionInfo) { diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MVersionedModelProvider.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mVersionedModelProvider.java similarity index 95% rename from common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MVersionedModelProvider.java rename to common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mVersionedModelProvider.java index 1107731a01..650726604f 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MVersionedModelProvider.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mVersionedModelProvider.java @@ -25,7 +25,7 @@ import org.eclipse.leshan.server.model.LwM2mModelProvider; import org.eclipse.leshan.server.registration.Registration; import org.thingsboard.server.common.data.TbResource; import org.thingsboard.server.common.data.id.TenantId; -import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClientContext; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientContext; import java.util.ArrayList; import java.util.Base64; @@ -38,7 +38,7 @@ import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPA @Slf4j @RequiredArgsConstructor -public class LwM2MVersionedModelProvider implements LwM2mModelProvider { +public class LwM2mVersionedModelProvider implements LwM2mModelProvider { /** * int objectId @@ -46,9 +46,9 @@ public class LwM2MVersionedModelProvider implements LwM2mModelProvider { * Key = objectId + "##" + version * Value = TenantId */ - private final LwM2MClientContext lwM2mClientContext; - private final LwM2MTransportServerHelper helper; - private final LwM2MTransportContext context; + private final LwM2mClientContext lwM2mClientContext; + private final LwM2mTransportServerHelper helper; + private final LwM2mTransportContext context; private String getKeyIdVer(Integer objectId, String version) { return objectId != null ? objectId + LWM2M_SEPARATOR_KEY + ((version == null || version.isEmpty()) ? ObjectModel.DEFAULT_VERSION : version) : null; diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/attributes/DefaultLwM2MAttributesService.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/attributes/DefaultLwM2MAttributesService.java index 00e4fee3f9..a4a4fa58ed 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/attributes/DefaultLwM2MAttributesService.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/attributes/DefaultLwM2MAttributesService.java @@ -31,17 +31,17 @@ import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.gen.transport.TransportProtos.GetAttributeResponseMsg; import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; -import org.thingsboard.server.transport.lwm2m.server.LwM2MTransportServerHelper; +import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportServerHelper; import org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil; -import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClient; -import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClientContext; -import org.thingsboard.server.transport.lwm2m.server.downlink.LwM2MDownlinkMsgHandler; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientContext; +import org.thingsboard.server.transport.lwm2m.server.downlink.LwM2mDownlinkMsgHandler; import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MWriteReplaceRequest; import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MWriteResponseCallback; import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService; import org.thingsboard.server.transport.lwm2m.server.ota.LwM2MOtaUpdateService; -import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2MUplinkMsgHandler; -import org.thingsboard.server.transport.lwm2m.utils.LwM2MValueConverterImpl; +import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler; +import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl; import java.util.ArrayList; import java.util.Arrays; @@ -53,7 +53,7 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicInteger; import static org.eclipse.leshan.core.model.ResourceModel.Type.OPAQUE; -import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportServerHelper.getValueFromKvProto; +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportServerHelper.getValueFromKvProto; import static org.thingsboard.server.transport.lwm2m.server.ota.DefaultLwM2MOtaUpdateService.FIRMWARE_TAG; import static org.thingsboard.server.transport.lwm2m.server.ota.DefaultLwM2MOtaUpdateService.FIRMWARE_TITLE; import static org.thingsboard.server.transport.lwm2m.server.ota.DefaultLwM2MOtaUpdateService.FIRMWARE_URL; @@ -79,16 +79,16 @@ public class DefaultLwM2MAttributesService implements LwM2MAttributesService { private final Map>> futures; private final TransportService transportService; - private final LwM2MTransportServerHelper helper; - private final LwM2MClientContext clientContext; + private final LwM2mTransportServerHelper helper; + private final LwM2mClientContext clientContext; private final LwM2MTransportServerConfig config; - private final LwM2MUplinkMsgHandler uplinkHandler; - private final LwM2MDownlinkMsgHandler downlinkHandler; + private final LwM2mUplinkMsgHandler uplinkHandler; + private final LwM2mDownlinkMsgHandler downlinkHandler; private final LwM2MTelemetryLogService logService; private final LwM2MOtaUpdateService otaUpdateService; @Override - public ListenableFuture> getSharedAttributes(LwM2MClient client, Collection keys) { + public ListenableFuture> getSharedAttributes(LwM2mClient client, Collection keys) { SettableFuture> future = SettableFuture.create(); int requestId = reqIdSeq.incrementAndGet(); futures.put(requestId, future); @@ -131,7 +131,7 @@ public class DefaultLwM2MAttributesService implements LwM2MAttributesService { */ @Override public void onAttributesUpdate(TransportProtos.AttributeUpdateNotificationMsg msg, TransportProtos.SessionInfoProto sessionInfo) { - LwM2MClient lwM2MClient = clientContext.getClientBySessionInfo(sessionInfo); + LwM2mClient lwM2MClient = clientContext.getClientBySessionInfo(sessionInfo); if (msg.getSharedUpdatedCount() > 0 && lwM2MClient != null) { String newFirmwareTitle = null; String newFirmwareVersion = null; @@ -188,7 +188,7 @@ public class DefaultLwM2MAttributesService implements LwM2MAttributesService { * #2.1 if there is not a difference in values between the current resource values and the shared attribute values */ @Override - public void onAttributesUpdate(LwM2MClient lwM2MClient, List tsKvProtos, boolean logFailedUpdateOfNonChangedValue) { + public void onAttributesUpdate(LwM2mClient lwM2MClient, List tsKvProtos, boolean logFailedUpdateOfNonChangedValue) { log.trace("[{}] onAttributesUpdate [{}]", lwM2MClient.getEndpoint(), tsKvProtos); Map attributesUpdate = new ConcurrentHashMap<>(); tsKvProtos.forEach(tsKvProto -> { @@ -235,7 +235,7 @@ public class DefaultLwM2MAttributesService implements LwM2MAttributesService { }); } - private void pushUpdateToClientIfNeeded(LwM2MClient lwM2MClient, Object valueOld, Object newValue, + private void pushUpdateToClientIfNeeded(LwM2mClient lwM2MClient, Object valueOld, Object newValue, String versionedId, boolean logFailedUpdateOfNonChangedValue, ResourceModel.Type type) { if (newValue == null) { String logMsg = String.format("%s: Failed update resource versionedId - %s value - %s. New value is bad", @@ -255,7 +255,7 @@ public class DefaultLwM2MAttributesService implements LwM2MAttributesService { } } - private void pushUpdateMultiToClientIfNeeded(LwM2MClient client, ResourceModel resourceModel, JsonElement newValProto, + private void pushUpdateMultiToClientIfNeeded(LwM2mClient client, ResourceModel resourceModel, JsonElement newValProto, Map valueOld, String versionedId, boolean logFailedUpdateOfNonChangedValue) throws Exception { Map newValues = convertMultiResourceValuesFromJson(newValProto, resourceModel.type, versionedId); @@ -290,13 +290,13 @@ public class DefaultLwM2MAttributesService implements LwM2MAttributesService { * @param pathIdVer - path resource * @return - value of Resource into format KvProto or null */ - private Object getResourceValueFormatKv(LwM2MClient lwM2MClient, String pathIdVer) { + private Object getResourceValueFormatKv(LwM2mClient lwM2MClient, String pathIdVer) { LwM2mResource resourceValue = LwM2MTransportUtil.getResourceValueFromLwM2MClient(lwM2MClient, pathIdVer); if (resourceValue != null) { ResourceModel.Type currentType = resourceValue.getType(); ResourceModel.Type expectedType = helper.getResourceModelTypeEqualsKvProtoValueType(currentType, pathIdVer); if (!resourceValue.isMultiInstances()) { - return LwM2MValueConverterImpl.getInstance().convertValue(resourceValue.getValue(), currentType, expectedType, + return LwM2mValueConverterImpl.getInstance().convertValue(resourceValue.getValue(), currentType, expectedType, new LwM2mPath(fromVersionedIdToObjectId(pathIdVer))); } else if (resourceValue.getInstances().size() > 0) { return resourceValue.getInstances(); diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/attributes/LwM2MAttributesService.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/attributes/LwM2MAttributesService.java index 9f73390037..cce7a29c88 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/attributes/LwM2MAttributesService.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/attributes/LwM2MAttributesService.java @@ -17,18 +17,18 @@ package org.thingsboard.server.transport.lwm2m.server.attributes; import com.google.common.util.concurrent.ListenableFuture; import org.thingsboard.server.gen.transport.TransportProtos; -import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClient; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; import java.util.Collection; import java.util.List; public interface LwM2MAttributesService { - ListenableFuture> getSharedAttributes(LwM2MClient client, Collection keys); + ListenableFuture> getSharedAttributes(LwM2mClient client, Collection keys); void onGetAttributesResponse(TransportProtos.GetAttributeResponseMsg getAttributesResponse, TransportProtos.SessionInfoProto sessionInfo); void onAttributesUpdate(TransportProtos.AttributeUpdateNotificationMsg attributeUpdateNotification, TransportProtos.SessionInfoProto sessionInfo); - void onAttributesUpdate(LwM2MClient lwM2MClient, List tsKvProtos, boolean logFailedUpdateOfNonChangedValue); + void onAttributesUpdate(LwM2mClient lwM2MClient, List tsKvProtos, boolean logFailedUpdateOfNonChangedValue); } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2MClient.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java similarity index 99% rename from common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2MClient.java rename to common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java index 055912ed96..f120bf84a2 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2MClient.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java @@ -69,7 +69,7 @@ import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.ge @Slf4j @EqualsAndHashCode(of = {"endpoint"}) -public class LwM2MClient implements Serializable { +public class LwM2mClient implements Serializable { private static final long serialVersionUID = 8793482946289222623L; @@ -129,7 +129,7 @@ public class LwM2MClient implements Serializable { return super.clone(); } - public LwM2MClient(String nodeId, String endpoint) { + public LwM2mClient(String nodeId, String endpoint) { this.nodeId = nodeId; this.endpoint = endpoint; this.sharedAttributes = new ConcurrentHashMap<>(); diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2MClientContext.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContext.java similarity index 67% rename from common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2MClientContext.java rename to common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContext.java index 82d27f2a53..8d97e775c6 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2MClientContext.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContext.java @@ -26,19 +26,19 @@ import java.util.Optional; import java.util.Set; import java.util.UUID; -public interface LwM2MClientContext { +public interface LwM2mClientContext { - LwM2MClient getClientByEndpoint(String endpoint); + LwM2mClient getClientByEndpoint(String endpoint); - LwM2MClient getClientBySessionInfo(TransportProtos.SessionInfoProto sessionInfo); + LwM2mClient getClientBySessionInfo(TransportProtos.SessionInfoProto sessionInfo); - Optional register(LwM2MClient lwM2MClient, Registration registration) throws LwM2MClientStateException; + Optional register(LwM2mClient lwM2MClient, Registration registration) throws LwM2MClientStateException; - void updateRegistration(LwM2MClient client, Registration registration) throws LwM2MClientStateException; + void updateRegistration(LwM2mClient client, Registration registration) throws LwM2MClientStateException; - void unregister(LwM2MClient client, Registration registration) throws LwM2MClientStateException; + void unregister(LwM2mClient client, Registration registration) throws LwM2MClientStateException; - Collection getLwM2mClients(); + Collection getLwM2mClients(); //TODO: replace UUID with DeviceProfileId Lwm2mDeviceProfileTransportConfiguration getProfile(UUID profileUuId); @@ -47,28 +47,28 @@ public interface LwM2MClientContext { Lwm2mDeviceProfileTransportConfiguration profileUpdate(DeviceProfile deviceProfile); - Set getSupportedIdVerInClient(LwM2MClient registration); + Set getSupportedIdVerInClient(LwM2mClient registration); - LwM2MClient getClientByDeviceId(UUID deviceId); + LwM2mClient getClientByDeviceId(UUID deviceId); - String getObjectIdByKeyNameFromProfile(LwM2MClient lwM2mClient, String keyName); + String getObjectIdByKeyNameFromProfile(LwM2mClient lwM2mClient, String keyName); void registerClient(Registration registration, ValidateDeviceCredentialsResponse credentials); - void update(LwM2MClient lwM2MClient); + void update(LwM2mClient lwM2MClient); void removeCredentials(TransportProtos.SessionInfoProto sessionInfo); - void sendMsgsAfterSleeping(LwM2MClient lwM2MClient); + void sendMsgsAfterSleeping(LwM2mClient lwM2MClient); - void onUplink(LwM2MClient client); + void onUplink(LwM2mClient client); - Long getRequestTimeout(LwM2MClient client); + Long getRequestTimeout(LwM2mClient client); - boolean asleep(LwM2MClient client); + boolean asleep(LwM2mClient client); - boolean awake(LwM2MClient client); + boolean awake(LwM2mClient client); - boolean isDownlinkAllowed(LwM2MClient client); + boolean isDownlinkAllowed(LwM2mClient client); } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2MClientContextImpl.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java similarity index 91% rename from common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2MClientContextImpl.java rename to common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java index 74e9884545..2c56a2d32b 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2MClientContextImpl.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java @@ -36,12 +36,12 @@ import org.thingsboard.server.queue.util.AfterStartUp; import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; import org.thingsboard.server.transport.lwm2m.secure.TbLwM2MSecurityInfo; -import org.thingsboard.server.transport.lwm2m.server.LwM2MTransportContext; +import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportContext; import org.thingsboard.server.transport.lwm2m.server.ota.LwM2MOtaUpdateService; import org.thingsboard.server.transport.lwm2m.server.session.LwM2MSessionManager; import org.thingsboard.server.transport.lwm2m.server.store.TbLwM2MClientStore; import org.thingsboard.server.transport.lwm2m.server.store.TbMainSecurityStore; -import org.thingsboard.server.transport.lwm2m.server.uplink.DefaultLwM2MUplinkMsgHandler; +import org.thingsboard.server.transport.lwm2m.server.uplink.DefaultLwM2mUplinkMsgHandler; import org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil; import java.util.Arrays; @@ -62,9 +62,9 @@ import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.co @Service @TbLwM2mTransportComponent @RequiredArgsConstructor -public class LwM2MClientContextImpl implements LwM2MClientContext { +public class LwM2mClientContextImpl implements LwM2mClientContext { - private final LwM2MTransportContext context; + private final LwM2mTransportContext context; private final LwM2MTransportServerConfig config; private final TbMainSecurityStore securityStore; private final TbLwM2MClientStore clientStore; @@ -73,19 +73,19 @@ public class LwM2MClientContextImpl implements LwM2MClientContext { @Autowired @Lazy - private DefaultLwM2MUplinkMsgHandler defaultLwM2MUplinkMsgHandler; + private DefaultLwM2mUplinkMsgHandler defaultLwM2MUplinkMsgHandler; @Autowired @Lazy private LwM2MOtaUpdateService otaUpdateService; - private final Map lwM2mClientsByEndpoint = new ConcurrentHashMap<>(); - private final Map lwM2mClientsByRegistrationId = new ConcurrentHashMap<>(); + private final Map lwM2mClientsByEndpoint = new ConcurrentHashMap<>(); + private final Map lwM2mClientsByRegistrationId = new ConcurrentHashMap<>(); private final Map profiles = new ConcurrentHashMap<>(); @AfterStartUp public void init() { String nodeId = context.getNodeId(); - Set fetchedClients = clientStore.getAll(); + Set fetchedClients = clientStore.getAll(); log.debug("Fetched clients from store: {}", fetchedClients); fetchedClients.forEach(client -> { lwM2mClientsByEndpoint.put(client.getEndpoint(), client); @@ -99,13 +99,13 @@ public class LwM2MClientContextImpl implements LwM2MClientContext { } @Override - public LwM2MClient getClientByEndpoint(String endpoint) { + public LwM2mClient getClientByEndpoint(String endpoint) { return lwM2mClientsByEndpoint.computeIfAbsent(endpoint, ep -> { - LwM2MClient client = clientStore.get(ep); + LwM2mClient client = clientStore.get(ep); String nodeId = context.getNodeId(); if (client == null) { log.info("[{}] initialized new client.", endpoint); - client = new LwM2MClient(nodeId, ep); + client = new LwM2mClient(nodeId, ep); } else { log.debug("[{}] fetched client from store: {}", endpoint, client); updateFetchedClient(nodeId, client); @@ -114,7 +114,7 @@ public class LwM2MClientContextImpl implements LwM2MClientContext { }); } - private void updateFetchedClient(String nodeId, LwM2MClient client) { + private void updateFetchedClient(String nodeId, LwM2mClient client) { boolean updated = false; if (client.getRegistration() != null) { lwM2mClientsByRegistrationId.put(client.getRegistration().getId(), client); @@ -130,7 +130,7 @@ public class LwM2MClientContextImpl implements LwM2MClientContext { } @Override - public Optional register(LwM2MClient client, Registration registration) throws LwM2MClientStateException { + public Optional register(LwM2mClient client, Registration registration) throws LwM2MClientStateException { TransportProtos.SessionInfoProto oldSession; client.lock(); try { @@ -172,7 +172,7 @@ public class LwM2MClientContextImpl implements LwM2MClientContext { } @Override - public boolean asleep(LwM2MClient client) { + public boolean asleep(LwM2mClient client) { boolean changed = compareAndSetSleepFlag(client, true); if (changed) { log.debug("[{}] client is sleeping", client.getEndpoint()); @@ -182,7 +182,7 @@ public class LwM2MClientContextImpl implements LwM2MClientContext { } @Override - public boolean awake(LwM2MClient client) { + public boolean awake(LwM2mClient client) { onUplink(client); boolean changed = compareAndSetSleepFlag(client, false); if (changed) { @@ -193,7 +193,7 @@ public class LwM2MClientContextImpl implements LwM2MClientContext { return changed; } - private boolean compareAndSetSleepFlag(LwM2MClient client, boolean sleeping) { + private boolean compareAndSetSleepFlag(LwM2mClient client, boolean sleeping) { if (sleeping == client.isAsleep()) { log.trace("[{}] Client is already at sleeping: {}, ignoring event: {}", client.getEndpoint(), client.isAsleep(), sleeping); return false; @@ -220,7 +220,7 @@ public class LwM2MClientContextImpl implements LwM2MClientContext { } @Override - public void updateRegistration(LwM2MClient client, Registration registration) throws LwM2MClientStateException { + public void updateRegistration(LwM2mClient client, Registration registration) throws LwM2MClientStateException { client.lock(); try { if (!LwM2MClientState.REGISTERED.equals(client.getState())) { @@ -239,7 +239,7 @@ public class LwM2MClientContextImpl implements LwM2MClientContext { } @Override - public void unregister(LwM2MClient client, Registration registration) throws LwM2MClientStateException { + public void unregister(LwM2mClient client, Registration registration) throws LwM2MClientStateException { client.lock(); try { if (!LwM2MClientState.REGISTERED.equals(client.getState())) { @@ -255,7 +255,7 @@ public class LwM2MClientContextImpl implements LwM2MClientContext { clientStore.remove(client.getEndpoint()); UUID profileId = client.getProfileId(); if (profileId != null) { - Optional otherClients = lwM2mClientsByRegistrationId.values().stream().filter(e -> e.getProfileId().equals(profileId)).findFirst(); + Optional otherClients = lwM2mClientsByRegistrationId.values().stream().filter(e -> e.getProfileId().equals(profileId)).findFirst(); if (otherClients.isEmpty()) { profiles.remove(profileId); } @@ -269,10 +269,10 @@ public class LwM2MClientContextImpl implements LwM2MClientContext { } @Override - public LwM2MClient getClientBySessionInfo(TransportProtos.SessionInfoProto sessionInfo) { - LwM2MClient lwM2mClient = null; + public LwM2mClient getClientBySessionInfo(TransportProtos.SessionInfoProto sessionInfo) { + LwM2mClient lwM2mClient = null; UUID sessionId = new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB()); - Predicate isClientFilter = c -> + Predicate isClientFilter = c -> sessionId.equals((new UUID(c.getSession().getSessionIdMSB(), c.getSession().getSessionIdLSB()))); if (this.lwM2mClientsByEndpoint.size() > 0) { lwM2mClient = this.lwM2mClientsByEndpoint.values().stream().filter(isClientFilter).findAny().orElse(null); @@ -287,7 +287,7 @@ public class LwM2MClientContextImpl implements LwM2MClientContext { } @Override - public String getObjectIdByKeyNameFromProfile(LwM2MClient client, String keyName) { + public String getObjectIdByKeyNameFromProfile(LwM2mClient client, String keyName) { Lwm2mDeviceProfileTransportConfiguration profile = getProfile(client.getProfileId()); for (Map.Entry entry : profile.getObserveAttr().getKeyName().entrySet()) { String k = entry.getKey(); @@ -305,14 +305,14 @@ public class LwM2MClientContextImpl implements LwM2MClientContext { @Override public void registerClient(Registration registration, ValidateDeviceCredentialsResponse credentials) { - LwM2MClient client = getClientByEndpoint(registration.getEndpoint()); + LwM2mClient client = getClientByEndpoint(registration.getEndpoint()); client.init(credentials, UUID.randomUUID()); lwM2mClientsByRegistrationId.put(registration.getId(), client); profileUpdate(credentials.getDeviceProfile()); } @Override - public void update(LwM2MClient client) { + public void update(LwM2mClient client) { client.lock(); try { if (client.getState().equals(LwM2MClientState.REGISTERED)) { @@ -331,7 +331,7 @@ public class LwM2MClientContextImpl implements LwM2MClientContext { } @Override - public void sendMsgsAfterSleeping(LwM2MClient lwM2MClient) { + public void sendMsgsAfterSleeping(LwM2mClient lwM2MClient) { if (LwM2MClientState.REGISTERED.equals(lwM2MClient.getState())) { PowerMode powerMode = getPowerMode(lwM2MClient); if (PowerMode.PSM.equals(powerMode) || PowerMode.E_DRX.equals(powerMode)) { @@ -347,7 +347,7 @@ public class LwM2MClientContextImpl implements LwM2MClientContext { } } - private PowerMode getPowerMode(LwM2MClient lwM2MClient) { + private PowerMode getPowerMode(LwM2mClient lwM2MClient) { PowerMode powerMode = lwM2MClient.getPowerMode(); if (powerMode == null) { Lwm2mDeviceProfileTransportConfiguration deviceProfile = getProfile(lwM2MClient.getProfileId()); @@ -357,7 +357,7 @@ public class LwM2MClientContextImpl implements LwM2MClientContext { } @Override - public Collection getLwM2mClients() { + public Collection getLwM2mClients() { return lwM2mClientsByEndpoint.values(); } @@ -394,7 +394,7 @@ public class LwM2MClientContextImpl implements LwM2MClientContext { } @Override - public Set getSupportedIdVerInClient(LwM2MClient client) { + public Set getSupportedIdVerInClient(LwM2mClient client) { Set clientObjects = ConcurrentHashMap.newKeySet(); Arrays.stream(client.getRegistration().getObjectLinks()).forEach(link -> { LwM2mPath pathIds = new LwM2mPath(link.getUrl()); @@ -406,12 +406,12 @@ public class LwM2MClientContextImpl implements LwM2MClientContext { } @Override - public LwM2MClient getClientByDeviceId(UUID deviceId) { + public LwM2mClient getClientByDeviceId(UUID deviceId) { return lwM2mClientsByRegistrationId.values().stream().filter(e -> deviceId.equals(e.getDeviceId())).findFirst().orElse(null); } @Override - public boolean isDownlinkAllowed(LwM2MClient client) { + public boolean isDownlinkAllowed(LwM2mClient client) { PowerMode powerMode = client.getPowerMode(); OtherConfiguration profileSettings = null; if (powerMode == null) { @@ -460,7 +460,7 @@ public class LwM2MClientContextImpl implements LwM2MClientContext { } @Override - public void onUplink(LwM2MClient client) { + public void onUplink(LwM2mClient client) { PowerMode powerMode = client.getPowerMode(); OtherConfiguration profileSettings = null; if (powerMode == null) { @@ -518,7 +518,7 @@ public class LwM2MClientContextImpl implements LwM2MClientContext { } @Override - public Long getRequestTimeout(LwM2MClient client) { + public Long getRequestTimeout(LwM2mClient client) { Long timeout = null; if (PowerMode.E_DRX.equals(client.getPowerMode()) && client.getEdrxCycle() != null) { timeout = client.getEdrxCycle(); diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/AbstractTbLwM2MRequestCallback.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/AbstractTbLwM2MRequestCallback.java index 68e222004d..aba73f8d5d 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/AbstractTbLwM2MRequestCallback.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/AbstractTbLwM2MRequestCallback.java @@ -16,7 +16,7 @@ package org.thingsboard.server.transport.lwm2m.server.downlink; import lombok.extern.slf4j.Slf4j; -import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClient; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService; import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.LOG_LWM2M_ERROR; @@ -25,9 +25,9 @@ import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.LO public abstract class AbstractTbLwM2MRequestCallback implements DownlinkRequestCallback { protected final LwM2MTelemetryLogService logService; - protected final LwM2MClient client; + protected final LwM2mClient client; - protected AbstractTbLwM2MRequestCallback(LwM2MTelemetryLogService logService, LwM2MClient client) { + protected AbstractTbLwM2MRequestCallback(LwM2MTelemetryLogService logService, LwM2mClient client) { this.logService = logService; this.client = client; } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2MDownlinkMsgHandler.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2mDownlinkMsgHandler.java similarity index 94% rename from common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2MDownlinkMsgHandler.java rename to common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2mDownlinkMsgHandler.java index 927a3cbf09..07acf224c8 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2MDownlinkMsgHandler.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2mDownlinkMsgHandler.java @@ -64,14 +64,14 @@ import org.springframework.stereotype.Service; import org.thingsboard.server.common.data.device.data.lwm2m.ObjectAttributes; import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; -import org.thingsboard.server.transport.lwm2m.server.LwM2MTransportContext; -import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClient; -import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClientContext; +import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportContext; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientContext; import org.thingsboard.server.transport.lwm2m.server.common.LwM2MExecutorAwareService; import org.thingsboard.server.transport.lwm2m.server.downlink.composite.TbLwM2MReadCompositeRequest; import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService; import org.thingsboard.server.transport.lwm2m.server.rpc.composite.RpcWriteCompositeRequest; -import org.thingsboard.server.transport.lwm2m.utils.LwM2MValueConverterImpl; +import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; @@ -104,19 +104,19 @@ import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.va @Service @TbLwM2mTransportComponent @RequiredArgsConstructor -public class DefaultLwM2MDownlinkMsgHandler extends LwM2MExecutorAwareService implements LwM2MDownlinkMsgHandler { +public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService implements LwM2mDownlinkMsgHandler { - public LwM2MValueConverterImpl converter; + public LwM2mValueConverterImpl converter; - private final LwM2MTransportContext context; + private final LwM2mTransportContext context; private final LwM2MTransportServerConfig config; private final LwM2MTelemetryLogService logService; - private final LwM2MClientContext clientContext; + private final LwM2mClientContext clientContext; @PostConstruct public void init() { super.init(); - this.converter = LwM2MValueConverterImpl.getInstance(); + this.converter = LwM2mValueConverterImpl.getInstance(); } @PreDestroy @@ -135,7 +135,7 @@ public class DefaultLwM2MDownlinkMsgHandler extends LwM2MExecutorAwareService im } @Override - public void sendReadRequest(LwM2MClient client, TbLwM2MReadRequest request, DownlinkRequestCallback callback) { + public void sendReadRequest(LwM2mClient client, TbLwM2MReadRequest request, DownlinkRequestCallback callback) { try { validateVersionedId(client, request); ReadRequest downlink = new ReadRequest(getReadRequestContentFormat(client, request, this.config.getModelProvider()), request.getObjectId()); @@ -146,7 +146,7 @@ public class DefaultLwM2MDownlinkMsgHandler extends LwM2MExecutorAwareService im } @Override - public void sendReadCompositeRequest(LwM2MClient client, TbLwM2MReadCompositeRequest request, + public void sendReadCompositeRequest(LwM2mClient client, TbLwM2MReadCompositeRequest request, DownlinkRequestCallback callback, ContentFormat compositeContentFormat) { try { ReadCompositeRequest downlink = new ReadCompositeRequest(compositeContentFormat, compositeContentFormat, request.getObjectIds()); @@ -157,7 +157,7 @@ public class DefaultLwM2MDownlinkMsgHandler extends LwM2MExecutorAwareService im } @Override - public void sendObserveRequest(LwM2MClient client, TbLwM2MObserveRequest request, DownlinkRequestCallback callback) { + public void sendObserveRequest(LwM2mClient client, TbLwM2MObserveRequest request, DownlinkRequestCallback callback) { try { validateVersionedId(client, request); LwM2mPath resultIds = new LwM2mPath(request.getObjectId()); @@ -183,19 +183,19 @@ public class DefaultLwM2MDownlinkMsgHandler extends LwM2MExecutorAwareService im } @Override - public void sendObserveAllRequest(LwM2MClient client, TbLwM2MObserveAllRequest request, DownlinkRequestCallback> callback) { + public void sendObserveAllRequest(LwM2mClient client, TbLwM2MObserveAllRequest request, DownlinkRequestCallback> callback) { Set observations = context.getServer().getObservationService().getObservations(client.getRegistration()); Set paths = observations.stream().map(observation -> observation.getPath().toString()).collect(Collectors.toUnmodifiableSet()); callback.onSuccess(request, paths); } @Override - public void sendDiscoverAllRequest(LwM2MClient client, TbLwM2MDiscoverAllRequest request, DownlinkRequestCallback> callback) { + public void sendDiscoverAllRequest(LwM2mClient client, TbLwM2MDiscoverAllRequest request, DownlinkRequestCallback> callback) { callback.onSuccess(request, Arrays.asList(client.getRegistration().getSortedObjectLinks())); } @Override - public void sendExecuteRequest(LwM2MClient client, TbLwM2MExecuteRequest request, DownlinkRequestCallback callback) { + public void sendExecuteRequest(LwM2mClient client, TbLwM2MExecuteRequest request, DownlinkRequestCallback callback) { try { validateVersionedId(client, request); LwM2mPath pathIds = new LwM2mPath(fromVersionedIdToObjectId(request.getVersionedId())); @@ -228,7 +228,7 @@ public class DefaultLwM2MDownlinkMsgHandler extends LwM2MExecutorAwareService im } @Override - public void sendDeleteRequest(LwM2MClient client, TbLwM2MDeleteRequest request, DownlinkRequestCallback callback) { + public void sendDeleteRequest(LwM2mClient client, TbLwM2MDeleteRequest request, DownlinkRequestCallback callback) { try { validateVersionedId(client, request); sendSimpleRequest(client, new DeleteRequest(request.getObjectId()), request.getTimeout(), callback); @@ -238,20 +238,20 @@ public class DefaultLwM2MDownlinkMsgHandler extends LwM2MExecutorAwareService im } @Override - public void sendCancelObserveRequest(LwM2MClient client, TbLwM2MCancelObserveRequest request, DownlinkRequestCallback callback) { + public void sendCancelObserveRequest(LwM2mClient client, TbLwM2MCancelObserveRequest request, DownlinkRequestCallback callback) { validateVersionedId(client, request); int observeCancelCnt = context.getServer().getObservationService().cancelObservations(client.getRegistration(), request.getObjectId()); callback.onSuccess(request, observeCancelCnt); } @Override - public void sendCancelAllRequest(LwM2MClient client, TbLwM2MCancelAllRequest request, DownlinkRequestCallback callback) { + public void sendCancelAllRequest(LwM2mClient client, TbLwM2MCancelAllRequest request, DownlinkRequestCallback callback) { int observeCancelCnt = context.getServer().getObservationService().cancelObservations(client.getRegistration()); callback.onSuccess(request, observeCancelCnt); } @Override - public void sendDiscoverRequest(LwM2MClient client, TbLwM2MDiscoverRequest request, DownlinkRequestCallback callback) { + public void sendDiscoverRequest(LwM2mClient client, TbLwM2MDiscoverRequest request, DownlinkRequestCallback callback) { validateVersionedId(client, request); sendSimpleRequest(client, new DiscoverRequest(request.getObjectId()), request.getTimeout(), callback); } @@ -269,7 +269,7 @@ public class DefaultLwM2MDownlinkMsgHandler extends LwM2MExecutorAwareService im * addAttribute(attributes, OBJECT_VERSION, params.getVer(), StringUtils::isNotEmpty, Function.identity()); */ @Override - public void sendWriteAttributesRequest(LwM2MClient client, TbLwM2MWriteAttributesRequest request, DownlinkRequestCallback callback) { + public void sendWriteAttributesRequest(LwM2mClient client, TbLwM2MWriteAttributesRequest request, DownlinkRequestCallback callback) { try { validateVersionedId(client, request); if (request.getAttributes() == null) { @@ -290,7 +290,7 @@ public class DefaultLwM2MDownlinkMsgHandler extends LwM2MExecutorAwareService im } @Override - public void sendWriteReplaceRequest(LwM2MClient client, TbLwM2MWriteReplaceRequest request, DownlinkRequestCallback callback) { + public void sendWriteReplaceRequest(LwM2mClient client, TbLwM2MWriteReplaceRequest request, DownlinkRequestCallback callback) { LwM2mPath resultIds = new LwM2mPath(request.getObjectId()); if (resultIds.isResource() || resultIds.isResourceInstance()) { validateVersionedId(client, request); @@ -334,7 +334,7 @@ public class DefaultLwM2MDownlinkMsgHandler extends LwM2MExecutorAwareService im } @Override - public void sendWriteCompositeRequest(LwM2MClient client, RpcWriteCompositeRequest rpcWriteCompositeRequest, + public void sendWriteCompositeRequest(LwM2mClient client, RpcWriteCompositeRequest rpcWriteCompositeRequest, DownlinkRequestCallback callback, ContentFormat contentFormatComposite) { try { WriteCompositeRequest downlink = new WriteCompositeRequest(contentFormatComposite, rpcWriteCompositeRequest.getNodes()); @@ -348,7 +348,7 @@ public class DefaultLwM2MDownlinkMsgHandler extends LwM2MExecutorAwareService im } @Override - public void sendWriteUpdateRequest(LwM2MClient client, TbLwM2MWriteUpdateRequest request, DownlinkRequestCallback callback) { + public void sendWriteUpdateRequest(LwM2mClient client, TbLwM2MWriteUpdateRequest request, DownlinkRequestCallback callback) { try { LwM2mPath resultIds = new LwM2mPath(request.getObjectId()); if (resultIds.isObjectInstance() || resultIds.isResource()) { @@ -405,7 +405,7 @@ public class DefaultLwM2MDownlinkMsgHandler extends LwM2MExecutorAwareService im } } - public void sendCreateRequest(LwM2MClient client, TbLwM2MCreateRequest request, DownlinkRequestCallback callback) { + public void sendCreateRequest(LwM2mClient client, TbLwM2MCreateRequest request, DownlinkRequestCallback callback) { validateVersionedId(client, request); CreateRequest downlink = null; LwM2mPath resultIds = new LwM2mPath(request.getObjectId()); @@ -454,15 +454,15 @@ public class DefaultLwM2MDownlinkMsgHandler extends LwM2MExecutorAwareService im } } - private , T extends LwM2mResponse> void sendSimpleRequest(LwM2MClient client, R request, long timeoutInMs, DownlinkRequestCallback callback) { + private , T extends LwM2mResponse> void sendSimpleRequest(LwM2mClient client, R request, long timeoutInMs, DownlinkRequestCallback callback) { sendRequest(client, request, timeoutInMs, callback, r -> request.getPath().toString()); } - private , T extends LwM2mResponse> void sendCompositeRequest(LwM2MClient client, R request, long timeoutInMs, DownlinkRequestCallback callback) { + private , T extends LwM2mResponse> void sendCompositeRequest(LwM2mClient client, R request, long timeoutInMs, DownlinkRequestCallback callback) { sendRequest(client, request, timeoutInMs, callback, r -> request.getPaths().toString()); } - private , T extends LwM2mResponse> void sendRequest(LwM2MClient client, R request, long timeoutInMs, DownlinkRequestCallback callback, Function pathToStringFunction) { + private , T extends LwM2mResponse> void sendRequest(LwM2mClient client, R request, long timeoutInMs, DownlinkRequestCallback callback, Function pathToStringFunction) { if (!clientContext.isDownlinkAllowed(client)) { log.trace("[{}] ignore downlink request cause client is sleeping.", client.getEndpoint()); return; @@ -487,7 +487,7 @@ public class DefaultLwM2MDownlinkMsgHandler extends LwM2MExecutorAwareService im } } - private , T extends LwM2mResponse> void sendWriteCompositeRequest(LwM2MClient client, WriteCompositeRequest request, long timeoutInMs, DownlinkRequestCallback callback) { + private , T extends LwM2mResponse> void sendWriteCompositeRequest(LwM2mClient client, WriteCompositeRequest request, long timeoutInMs, DownlinkRequestCallback callback) { if (!clientContext.isDownlinkAllowed(client)) { log.trace("[{}] ignore downlink request cause client is sleeping.", client.getEndpoint()); return; @@ -515,7 +515,7 @@ public class DefaultLwM2MDownlinkMsgHandler extends LwM2MExecutorAwareService im } } - private , T extends LwM2mResponse> void handleDownlinkError(LwM2MClient client, R request, DownlinkRequestCallback callback, Exception e) { + private , T extends LwM2mResponse> void handleDownlinkError(LwM2mClient client, R request, DownlinkRequestCallback callback, Exception e) { log.trace("[{}] Received downlink error: {}.", client.getEndpoint(), e); executor.submit(() -> { if (e instanceof TimeoutException || e instanceof ClientSleepingException) { @@ -571,7 +571,7 @@ public class DefaultLwM2MDownlinkMsgHandler extends LwM2MExecutorAwareService im } } - private static ContentFormat getReadRequestContentFormat(LwM2MClient client, T request, LwM2mModelProvider modelProvider) { + private static ContentFormat getReadRequestContentFormat(LwM2mClient client, T request, LwM2mModelProvider modelProvider) { if (request.getRequestContentFormat().isPresent()) { return request.getRequestContentFormat().get(); } else { @@ -579,7 +579,7 @@ public class DefaultLwM2MDownlinkMsgHandler extends LwM2MExecutorAwareService im } } - private static ContentFormat getWriteRequestContentFormat(LwM2MClient client, TbLwM2MDownlinkRequest request, LwM2mModelProvider modelProvider) { + private static ContentFormat getWriteRequestContentFormat(LwM2mClient client, TbLwM2MDownlinkRequest request, LwM2mModelProvider modelProvider) { if (request instanceof TbLwM2MWriteReplaceRequest && ((TbLwM2MWriteReplaceRequest) request).getContentFormat() != null) { return ((TbLwM2MWriteReplaceRequest) request).getContentFormat(); } else if (request instanceof TbLwM2MWriteUpdateRequest && ((TbLwM2MWriteUpdateRequest) request).getObjectContentFormat() != null) { @@ -597,7 +597,7 @@ public class DefaultLwM2MDownlinkMsgHandler extends LwM2MExecutorAwareService im } } - private static ContentFormat getRequestContentFormat(LwM2MClient client, String versionedId, LwM2mModelProvider modelProvider) { + private static ContentFormat getRequestContentFormat(LwM2mClient client, String versionedId, LwM2mModelProvider modelProvider) { LwM2mPath pathIds = new LwM2mPath(fromVersionedIdToObjectId(versionedId)); if (pathIds.isResource() || pathIds.isResourceInstance()) { ResourceModel resourceModel = client.getResourceModel(versionedId, modelProvider); @@ -617,7 +617,7 @@ public class DefaultLwM2MDownlinkMsgHandler extends LwM2MExecutorAwareService im } } - private static ContentFormat getContentFormatForComplex(LwM2MClient client) { + private static ContentFormat getContentFormatForComplex(LwM2mClient client) { if (LwM2m.Version.V1_0.equals(client.getRegistration().getLwM2mVersion())) { return ContentFormat.TLV; } else if (LwM2m.Version.V1_1.equals(client.getRegistration().getLwM2mVersion())) { diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/LwM2MDownlinkMsgHandler.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/LwM2mDownlinkMsgHandler.java similarity index 78% rename from common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/LwM2MDownlinkMsgHandler.java rename to common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/LwM2mDownlinkMsgHandler.java index 73a61b0c9d..a4537af703 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/LwM2MDownlinkMsgHandler.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/LwM2mDownlinkMsgHandler.java @@ -37,43 +37,43 @@ import org.eclipse.leshan.core.response.ReadResponse; import org.eclipse.leshan.core.response.WriteAttributesResponse; import org.eclipse.leshan.core.response.WriteCompositeResponse; import org.eclipse.leshan.core.response.WriteResponse; -import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClient; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; import org.thingsboard.server.transport.lwm2m.server.downlink.composite.TbLwM2MReadCompositeRequest; import org.thingsboard.server.transport.lwm2m.server.rpc.composite.RpcWriteCompositeRequest; import java.util.List; import java.util.Set; -public interface LwM2MDownlinkMsgHandler { +public interface LwM2mDownlinkMsgHandler { - void sendReadRequest(LwM2MClient client, TbLwM2MReadRequest request, DownlinkRequestCallback callback); + void sendReadRequest(LwM2mClient client, TbLwM2MReadRequest request, DownlinkRequestCallback callback); - void sendReadCompositeRequest(LwM2MClient client, TbLwM2MReadCompositeRequest request, DownlinkRequestCallback callback, ContentFormat contentFormatComposite); + void sendReadCompositeRequest(LwM2mClient client, TbLwM2MReadCompositeRequest request, DownlinkRequestCallback callback, ContentFormat contentFormatComposite); - void sendObserveRequest(LwM2MClient client, TbLwM2MObserveRequest request, DownlinkRequestCallback callback); + void sendObserveRequest(LwM2mClient client, TbLwM2MObserveRequest request, DownlinkRequestCallback callback); - void sendObserveAllRequest(LwM2MClient client, TbLwM2MObserveAllRequest request, DownlinkRequestCallback> callback); + void sendObserveAllRequest(LwM2mClient client, TbLwM2MObserveAllRequest request, DownlinkRequestCallback> callback); - void sendExecuteRequest(LwM2MClient client, TbLwM2MExecuteRequest request, DownlinkRequestCallback callback); + void sendExecuteRequest(LwM2mClient client, TbLwM2MExecuteRequest request, DownlinkRequestCallback callback); - void sendDeleteRequest(LwM2MClient client, TbLwM2MDeleteRequest request, DownlinkRequestCallback callback); + void sendDeleteRequest(LwM2mClient client, TbLwM2MDeleteRequest request, DownlinkRequestCallback callback); - void sendCancelObserveRequest(LwM2MClient client, TbLwM2MCancelObserveRequest request, DownlinkRequestCallback callback); + void sendCancelObserveRequest(LwM2mClient client, TbLwM2MCancelObserveRequest request, DownlinkRequestCallback callback); - void sendCancelAllRequest(LwM2MClient client, TbLwM2MCancelAllRequest request, DownlinkRequestCallback callback); + void sendCancelAllRequest(LwM2mClient client, TbLwM2MCancelAllRequest request, DownlinkRequestCallback callback); - void sendDiscoverRequest(LwM2MClient client, TbLwM2MDiscoverRequest request, DownlinkRequestCallback callback); + void sendDiscoverRequest(LwM2mClient client, TbLwM2MDiscoverRequest request, DownlinkRequestCallback callback); - void sendDiscoverAllRequest(LwM2MClient client, TbLwM2MDiscoverAllRequest request, DownlinkRequestCallback> callback); + void sendDiscoverAllRequest(LwM2mClient client, TbLwM2MDiscoverAllRequest request, DownlinkRequestCallback> callback); - void sendWriteAttributesRequest(LwM2MClient client, TbLwM2MWriteAttributesRequest request, DownlinkRequestCallback callback); + void sendWriteAttributesRequest(LwM2mClient client, TbLwM2MWriteAttributesRequest request, DownlinkRequestCallback callback); - void sendWriteReplaceRequest(LwM2MClient client, TbLwM2MWriteReplaceRequest request, DownlinkRequestCallback callback); + void sendWriteReplaceRequest(LwM2mClient client, TbLwM2MWriteReplaceRequest request, DownlinkRequestCallback callback); - void sendWriteCompositeRequest(LwM2MClient client, RpcWriteCompositeRequest nodes, DownlinkRequestCallback callback, ContentFormat contentFormatComposite); + void sendWriteCompositeRequest(LwM2mClient client, RpcWriteCompositeRequest nodes, DownlinkRequestCallback callback, ContentFormat contentFormatComposite); - void sendWriteUpdateRequest(LwM2MClient client, TbLwM2MWriteUpdateRequest request, DownlinkRequestCallback callback); + void sendWriteUpdateRequest(LwM2mClient client, TbLwM2MWriteUpdateRequest request, DownlinkRequestCallback callback); - void sendCreateRequest(LwM2MClient client, TbLwM2MCreateRequest request, DownlinkRequestCallback callback); + void sendCreateRequest(LwM2mClient client, TbLwM2MCreateRequest request, DownlinkRequestCallback callback); } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MCancelAllObserveCallback.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MCancelAllObserveCallback.java index d39b3286f9..961d6db928 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MCancelAllObserveCallback.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MCancelAllObserveCallback.java @@ -16,7 +16,7 @@ package org.thingsboard.server.transport.lwm2m.server.downlink; import lombok.extern.slf4j.Slf4j; -import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClient; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService; import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.LOG_LWM2M_INFO; @@ -24,7 +24,7 @@ import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.LO @Slf4j public class TbLwM2MCancelAllObserveCallback extends AbstractTbLwM2MRequestCallback { - public TbLwM2MCancelAllObserveCallback(LwM2MTelemetryLogService logService, LwM2MClient client) { + public TbLwM2MCancelAllObserveCallback(LwM2MTelemetryLogService logService, LwM2mClient client) { super(logService, client); } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MCancelObserveCallback.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MCancelObserveCallback.java index cd424b7047..9647519cf0 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MCancelObserveCallback.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MCancelObserveCallback.java @@ -16,7 +16,7 @@ package org.thingsboard.server.transport.lwm2m.server.downlink; import lombok.extern.slf4j.Slf4j; -import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClient; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService; import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.LOG_LWM2M_INFO; @@ -26,7 +26,7 @@ public class TbLwM2MCancelObserveCallback extends AbstractTbLwM2MRequestCallback private final String versionedId; - public TbLwM2MCancelObserveCallback(LwM2MTelemetryLogService logService, LwM2MClient client, String versionedId) { + public TbLwM2MCancelObserveCallback(LwM2MTelemetryLogService logService, LwM2mClient client, String versionedId) { super(logService, client); this.versionedId = versionedId; } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MCreateResponseCallback.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MCreateResponseCallback.java index d0cf1e02e0..316bbd4636 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MCreateResponseCallback.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MCreateResponseCallback.java @@ -17,13 +17,13 @@ package org.thingsboard.server.transport.lwm2m.server.downlink; import org.eclipse.leshan.core.request.CreateRequest; import org.eclipse.leshan.core.response.CreateResponse; -import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClient; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService; -import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2MUplinkMsgHandler; +import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler; public class TbLwM2MCreateResponseCallback extends TbLwM2MUplinkTargetedCallback { - public TbLwM2MCreateResponseCallback(LwM2MUplinkMsgHandler handler, LwM2MTelemetryLogService logService, LwM2MClient client, String targetId) { + public TbLwM2MCreateResponseCallback(LwM2mUplinkMsgHandler handler, LwM2MTelemetryLogService logService, LwM2mClient client, String targetId) { super(handler, logService, client, targetId); } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MDeleteCallback.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MDeleteCallback.java index 798ad4e471..2b3c544dae 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MDeleteCallback.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MDeleteCallback.java @@ -17,12 +17,12 @@ package org.thingsboard.server.transport.lwm2m.server.downlink; import org.eclipse.leshan.core.request.DeleteRequest; import org.eclipse.leshan.core.response.DeleteResponse; -import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClient; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService; public class TbLwM2MDeleteCallback extends TbLwM2MTargetedCallback { - public TbLwM2MDeleteCallback(LwM2MTelemetryLogService logService, LwM2MClient client, String targetId) { + public TbLwM2MDeleteCallback(LwM2MTelemetryLogService logService, LwM2mClient client, String targetId) { super(logService, client, targetId); } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MDiscoverCallback.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MDiscoverCallback.java index e4ce1c0823..cc855fd3a8 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MDiscoverCallback.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MDiscoverCallback.java @@ -17,12 +17,12 @@ package org.thingsboard.server.transport.lwm2m.server.downlink; import org.eclipse.leshan.core.request.DiscoverRequest; import org.eclipse.leshan.core.response.DiscoverResponse; -import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClient; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService; public class TbLwM2MDiscoverCallback extends TbLwM2MTargetedCallback { - public TbLwM2MDiscoverCallback(LwM2MTelemetryLogService logService, LwM2MClient client, String targetId) { + public TbLwM2MDiscoverCallback(LwM2MTelemetryLogService logService, LwM2mClient client, String targetId) { super(logService, client, targetId); } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MExecuteCallback.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MExecuteCallback.java index 23e9734714..9315e9ded6 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MExecuteCallback.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MExecuteCallback.java @@ -17,12 +17,12 @@ package org.thingsboard.server.transport.lwm2m.server.downlink; import org.eclipse.leshan.core.request.ExecuteRequest; import org.eclipse.leshan.core.response.ExecuteResponse; -import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClient; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService; public class TbLwM2MExecuteCallback extends TbLwM2MTargetedCallback { - public TbLwM2MExecuteCallback(LwM2MTelemetryLogService logService, LwM2MClient client, String targetId) { + public TbLwM2MExecuteCallback(LwM2MTelemetryLogService logService, LwM2mClient client, String targetId) { super(logService, client, targetId); } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MObserveCallback.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MObserveCallback.java index 913b207b34..97be9fbff3 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MObserveCallback.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MObserveCallback.java @@ -18,14 +18,14 @@ package org.thingsboard.server.transport.lwm2m.server.downlink; import lombok.extern.slf4j.Slf4j; import org.eclipse.leshan.core.request.ObserveRequest; import org.eclipse.leshan.core.response.ObserveResponse; -import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClient; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService; -import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2MUplinkMsgHandler; +import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler; @Slf4j public class TbLwM2MObserveCallback extends TbLwM2MUplinkTargetedCallback { - public TbLwM2MObserveCallback(LwM2MUplinkMsgHandler handler, LwM2MTelemetryLogService logService, LwM2MClient client, String targetId) { + public TbLwM2MObserveCallback(LwM2mUplinkMsgHandler handler, LwM2MTelemetryLogService logService, LwM2mClient client, String targetId) { super(handler, logService, client, targetId); } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MReadCallback.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MReadCallback.java index 6de67eea5e..0ae17ea449 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MReadCallback.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MReadCallback.java @@ -20,14 +20,14 @@ import org.eclipse.leshan.core.node.LwM2mSingleResource; import org.eclipse.leshan.core.request.ReadRequest; import org.eclipse.leshan.core.response.ReadResponse; import org.eclipse.leshan.core.util.Hex; -import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClient; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService; -import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2MUplinkMsgHandler; +import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler; @Slf4j public class TbLwM2MReadCallback extends TbLwM2MUplinkTargetedCallback { - public TbLwM2MReadCallback(LwM2MUplinkMsgHandler handler, LwM2MTelemetryLogService logService, LwM2MClient client, String targetId) { + public TbLwM2MReadCallback(LwM2mUplinkMsgHandler handler, LwM2MTelemetryLogService logService, LwM2mClient client, String targetId) { super(handler, logService, client, targetId); } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MTargetedCallback.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MTargetedCallback.java index 21e8665e85..e61067b382 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MTargetedCallback.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MTargetedCallback.java @@ -18,7 +18,7 @@ package org.thingsboard.server.transport.lwm2m.server.downlink; import lombok.extern.slf4j.Slf4j; import org.eclipse.leshan.core.ResponseCode; import org.eclipse.leshan.core.response.LwM2mResponse; -import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClient; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService; import java.util.Arrays; @@ -32,13 +32,13 @@ public abstract class TbLwM2MTargetedCallback extends AbstractTbLwM2MReque protected final String versionedId; protected final String[] versionedIds; - public TbLwM2MTargetedCallback(LwM2MTelemetryLogService logService, LwM2MClient client, String versionedId) { + public TbLwM2MTargetedCallback(LwM2MTelemetryLogService logService, LwM2mClient client, String versionedId) { super(logService, client); this.versionedId = versionedId; this.versionedIds = null; } - public TbLwM2MTargetedCallback(LwM2MTelemetryLogService logService, LwM2MClient client, String[] versionedIds) { + public TbLwM2MTargetedCallback(LwM2MTelemetryLogService logService, LwM2mClient client, String[] versionedIds) { super(logService, client); this.versionedId = null; this.versionedIds = versionedIds; diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MUplinkTargetedCallback.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MUplinkTargetedCallback.java index 16c69237bb..520d49eb30 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MUplinkTargetedCallback.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MUplinkTargetedCallback.java @@ -16,21 +16,21 @@ package org.thingsboard.server.transport.lwm2m.server.downlink; import lombok.extern.slf4j.Slf4j; -import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClient; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService; -import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2MUplinkMsgHandler; +import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler; @Slf4j public abstract class TbLwM2MUplinkTargetedCallback extends TbLwM2MTargetedCallback { - protected LwM2MUplinkMsgHandler handler; + protected LwM2mUplinkMsgHandler handler; - public TbLwM2MUplinkTargetedCallback(LwM2MUplinkMsgHandler handler, LwM2MTelemetryLogService logService, LwM2MClient client, String versionedId) { + public TbLwM2MUplinkTargetedCallback(LwM2mUplinkMsgHandler handler, LwM2MTelemetryLogService logService, LwM2mClient client, String versionedId) { super(logService, client, versionedId); this.handler = handler; } - public TbLwM2MUplinkTargetedCallback(LwM2MUplinkMsgHandler handler, LwM2MTelemetryLogService logService, LwM2MClient client, String[] versionedIds) { + public TbLwM2MUplinkTargetedCallback(LwM2mUplinkMsgHandler handler, LwM2MTelemetryLogService logService, LwM2mClient client, String[] versionedIds) { super(logService, client, versionedIds); this.handler = handler; } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MWriteAttributesCallback.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MWriteAttributesCallback.java index 8b30e9bfe4..3e4847ce1e 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MWriteAttributesCallback.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MWriteAttributesCallback.java @@ -17,12 +17,12 @@ package org.thingsboard.server.transport.lwm2m.server.downlink; import org.eclipse.leshan.core.request.WriteAttributesRequest; import org.eclipse.leshan.core.response.WriteAttributesResponse; -import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClient; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService; public class TbLwM2MWriteAttributesCallback extends TbLwM2MTargetedCallback { - public TbLwM2MWriteAttributesCallback(LwM2MTelemetryLogService logService, LwM2MClient client, String targetId) { + public TbLwM2MWriteAttributesCallback(LwM2MTelemetryLogService logService, LwM2mClient client, String targetId) { super(logService, client, targetId); } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MWriteResponseCallback.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MWriteResponseCallback.java index 11b7d3e4cd..a452c3b187 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MWriteResponseCallback.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MWriteResponseCallback.java @@ -18,14 +18,14 @@ package org.thingsboard.server.transport.lwm2m.server.downlink; import lombok.extern.slf4j.Slf4j; import org.eclipse.leshan.core.request.WriteRequest; import org.eclipse.leshan.core.response.WriteResponse; -import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClient; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService; -import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2MUplinkMsgHandler; +import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler; @Slf4j public class TbLwM2MWriteResponseCallback extends TbLwM2MUplinkTargetedCallback { - public TbLwM2MWriteResponseCallback(LwM2MUplinkMsgHandler handler, LwM2MTelemetryLogService logService, LwM2MClient client, String targetId) { + public TbLwM2MWriteResponseCallback(LwM2mUplinkMsgHandler handler, LwM2MTelemetryLogService logService, LwM2mClient client, String targetId) { super(handler, logService, client, targetId); } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/composite/TbLwM2MReadCompositeCallback.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/composite/TbLwM2MReadCompositeCallback.java index 9c88be56f7..82e0936b87 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/composite/TbLwM2MReadCompositeCallback.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/composite/TbLwM2MReadCompositeCallback.java @@ -18,15 +18,15 @@ package org.thingsboard.server.transport.lwm2m.server.downlink.composite; import lombok.extern.slf4j.Slf4j; import org.eclipse.leshan.core.request.ReadCompositeRequest; import org.eclipse.leshan.core.response.ReadCompositeResponse; -import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClient; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MUplinkTargetedCallback; import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService; -import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2MUplinkMsgHandler; +import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler; @Slf4j public class TbLwM2MReadCompositeCallback extends TbLwM2MUplinkTargetedCallback { - public TbLwM2MReadCompositeCallback(LwM2MUplinkMsgHandler handler, LwM2MTelemetryLogService logService, LwM2MClient client, String[] versionedIds) { + public TbLwM2MReadCompositeCallback(LwM2mUplinkMsgHandler handler, LwM2MTelemetryLogService logService, LwM2mClient client, String[] versionedIds) { super(handler, logService, client, versionedIds); } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/composite/TbLwM2MWriteResponseCompositeCallback.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/composite/TbLwM2MWriteResponseCompositeCallback.java index 8c8d8de031..6d5de06e90 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/composite/TbLwM2MWriteResponseCompositeCallback.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/composite/TbLwM2MWriteResponseCompositeCallback.java @@ -17,14 +17,14 @@ package org.thingsboard.server.transport.lwm2m.server.downlink.composite; import org.eclipse.leshan.core.request.WriteCompositeRequest; import org.eclipse.leshan.core.response.WriteCompositeResponse; -import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClient; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MUplinkTargetedCallback; import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService; -import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2MUplinkMsgHandler; +import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler; public class TbLwM2MWriteResponseCompositeCallback extends TbLwM2MUplinkTargetedCallback { - public TbLwM2MWriteResponseCompositeCallback(LwM2MUplinkMsgHandler handler, LwM2MTelemetryLogService logService, LwM2MClient client, String targetId) { + public TbLwM2MWriteResponseCompositeCallback(LwM2mUplinkMsgHandler handler, LwM2MTelemetryLogService logService, LwM2mClient client, String targetId) { super(handler, logService, client, targetId); } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/log/DefaultLwM2MTelemetryLogService.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/log/DefaultLwM2MTelemetryLogService.java index 65ec45c83d..214c7c2d5e 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/log/DefaultLwM2MTelemetryLogService.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/log/DefaultLwM2MTelemetryLogService.java @@ -19,8 +19,8 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; -import org.thingsboard.server.transport.lwm2m.server.LwM2MTransportServerHelper; -import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClient; +import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportServerHelper; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.LOG_LWM2M_TELEMETRY; @@ -30,10 +30,10 @@ import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.LO @RequiredArgsConstructor public class DefaultLwM2MTelemetryLogService implements LwM2MTelemetryLogService { - private final LwM2MTransportServerHelper helper; + private final LwM2mTransportServerHelper helper; @Override - public void log(LwM2MClient client, String logMsg) { + public void log(LwM2mClient client, String logMsg) { if (logMsg != null && client != null && client.getSession() != null) { if (logMsg.length() > 1024) { logMsg = logMsg.substring(0, 1024); diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/log/LwM2MTelemetryLogService.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/log/LwM2MTelemetryLogService.java index f4c16602c9..f2276fa9af 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/log/LwM2MTelemetryLogService.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/log/LwM2MTelemetryLogService.java @@ -15,10 +15,10 @@ */ package org.thingsboard.server.transport.lwm2m.server.log; -import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClient; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; public interface LwM2MTelemetryLogService { - void log(LwM2MClient client, String msg); + void log(LwM2mClient client, String msg); } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/DefaultLwM2MOtaUpdateService.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/DefaultLwM2MOtaUpdateService.java index 1433cda361..0a30f2df72 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/DefaultLwM2MOtaUpdateService.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/DefaultLwM2MOtaUpdateService.java @@ -34,12 +34,12 @@ import org.thingsboard.server.common.transport.TransportServiceCallback; import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; -import org.thingsboard.server.transport.lwm2m.server.LwM2MTransportServerHelper; +import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportServerHelper; import org.thingsboard.server.transport.lwm2m.server.attributes.LwM2MAttributesService; -import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClient; -import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClientContext; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientContext; import org.thingsboard.server.transport.lwm2m.server.common.LwM2MExecutorAwareService; -import org.thingsboard.server.transport.lwm2m.server.downlink.LwM2MDownlinkMsgHandler; +import org.thingsboard.server.transport.lwm2m.server.downlink.LwM2mDownlinkMsgHandler; import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MExecuteCallback; import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MExecuteRequest; import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MWriteReplaceRequest; @@ -55,7 +55,7 @@ import org.thingsboard.server.transport.lwm2m.server.ota.software.LwM2MSoftwareU import org.thingsboard.server.transport.lwm2m.server.ota.software.SoftwareUpdateResult; import org.thingsboard.server.transport.lwm2m.server.ota.software.SoftwareUpdateState; import org.thingsboard.server.transport.lwm2m.server.store.TbLwM2MClientOtaInfoStore; -import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2MUplinkMsgHandler; +import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; @@ -124,13 +124,13 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl private final Map swStates = new ConcurrentHashMap<>(); private final TransportService transportService; - private final LwM2MClientContext clientContext; + private final LwM2mClientContext clientContext; private final LwM2MTransportServerConfig config; - private final LwM2MUplinkMsgHandler uplinkHandler; - private final LwM2MDownlinkMsgHandler downlinkHandler; + private final LwM2mUplinkMsgHandler uplinkHandler; + private final LwM2mDownlinkMsgHandler downlinkHandler; private final OtaPackageDataCache otaPackageDataCache; private final LwM2MTelemetryLogService logService; - private final LwM2MTransportServerHelper helper; + private final LwM2mTransportServerHelper helper; private final TbLwM2MClientOtaInfoStore otaInfoStore; @Autowired @@ -158,7 +158,7 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl } @Override - public void init(LwM2MClient client) { + public void init(LwM2mClient client) { //TODO: add locks by client fwInfo. //TODO: check that the client supports FW and SW by checking the supported objects in the model. List attributesToFetch = new ArrayList<>(); @@ -213,7 +213,7 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl } @Override - public void forceFirmwareUpdate(LwM2MClient client) { + public void forceFirmwareUpdate(LwM2mClient client) { LwM2MClientFwOtaInfo fwInfo = getOrInitFwInfo(client); fwInfo.setRetryAttempts(0); fwInfo.setFailedPackageId(null); @@ -221,7 +221,7 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl } @Override - public void onTargetFirmwareUpdate(LwM2MClient client, String newFirmwareTitle, String newFirmwareVersion, Optional newFirmwareUrl, Optional newFirmwareTag) { + public void onTargetFirmwareUpdate(LwM2mClient client, String newFirmwareTitle, String newFirmwareVersion, Optional newFirmwareUrl, Optional newFirmwareTag) { LwM2MClientFwOtaInfo fwInfo = getOrInitFwInfo(client); fwInfo.updateTarget(newFirmwareTitle, newFirmwareVersion, newFirmwareUrl, newFirmwareTag); update(fwInfo); @@ -229,19 +229,19 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl } @Override - public void onCurrentFirmwareNameUpdate(LwM2MClient client, String name) { + public void onCurrentFirmwareNameUpdate(LwM2mClient client, String name) { log.debug("[{}] Current fw name: {}", client.getEndpoint(), name); getOrInitFwInfo(client).setCurrentName(name); } @Override - public void onCurrentSoftwareNameUpdate(LwM2MClient client, String name) { + public void onCurrentSoftwareNameUpdate(LwM2mClient client, String name) { log.debug("[{}] Current sw name: {}", client.getEndpoint(), name); getOrInitSwInfo(client).setCurrentName(name); } @Override - public void onFirmwareStrategyUpdate(LwM2MClient client, OtherConfiguration configuration) { + public void onFirmwareStrategyUpdate(LwM2mClient client, OtherConfiguration configuration) { log.debug("[{}] Current fw strategy: {}", client.getEndpoint(), configuration.getFwUpdateStrategy()); LwM2MClientFwOtaInfo fwInfo = getOrInitFwInfo(client); fwInfo.setStrategy(LwM2MFirmwareUpdateStrategy.fromStrategyFwByCode(configuration.getFwUpdateStrategy())); @@ -250,7 +250,7 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl } @Override - public void onCurrentSoftwareStrategyUpdate(LwM2MClient client, OtherConfiguration configuration) { + public void onCurrentSoftwareStrategyUpdate(LwM2mClient client, OtherConfiguration configuration) { log.debug("[{}] Current sw strategy: {}", client.getEndpoint(), configuration.getSwUpdateStrategy()); LwM2MClientSwOtaInfo swInfo = getOrInitSwInfo(client); swInfo.setStrategy(LwM2MSoftwareUpdateStrategy.fromStrategySwByCode(configuration.getSwUpdateStrategy())); @@ -259,21 +259,21 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl } @Override - public void onCurrentFirmwareVersion3Update(LwM2MClient client, String version) { + public void onCurrentFirmwareVersion3Update(LwM2mClient client, String version) { log.debug("[{}] Current fw version(3): {}", client.getEndpoint(), version); LwM2MClientFwOtaInfo fwInfo = getOrInitFwInfo(client); fwInfo.setCurrentVersion3(version); } @Override - public void onCurrentFirmwareVersionUpdate(LwM2MClient client, String version) { + public void onCurrentFirmwareVersionUpdate(LwM2mClient client, String version) { log.debug("[{}] Current fw version(5): {}", client.getEndpoint(), version); LwM2MClientFwOtaInfo fwInfo = getOrInitFwInfo(client); fwInfo.setCurrentVersion(version); } @Override - public void onCurrentFirmwareStateUpdate(LwM2MClient client, Long stateCode) { + public void onCurrentFirmwareStateUpdate(LwM2mClient client, Long stateCode) { log.debug("[{}] Current fw state: {}", client.getEndpoint(), stateCode); LwM2MClientFwOtaInfo fwInfo = getOrInitFwInfo(client); FirmwareUpdateState state = FirmwareUpdateState.fromStateFwByCode(stateCode.intValue()); @@ -297,7 +297,7 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl } @Override - public void onCurrentFirmwareResultUpdate(LwM2MClient client, Long code) { + public void onCurrentFirmwareResultUpdate(LwM2mClient client, Long code) { log.debug("[{}] Current fw result: {}", client.getEndpoint(), code); LwM2MClientFwOtaInfo fwInfo = getOrInitFwInfo(client); FirmwareUpdateResult result = FirmwareUpdateResult.fromUpdateResultFwByCode(code.intValue()); @@ -325,26 +325,26 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl } @Override - public void onCurrentFirmwareDeliveryMethodUpdate(LwM2MClient client, Long value) { + public void onCurrentFirmwareDeliveryMethodUpdate(LwM2mClient client, Long value) { log.debug("[{}] Current fw delivery method: {}", client.getEndpoint(), value); LwM2MClientFwOtaInfo fwInfo = getOrInitFwInfo(client); fwInfo.setDeliveryMethod(value.intValue()); } @Override - public void onCurrentSoftwareVersion3Update(LwM2MClient client, String version) { + public void onCurrentSoftwareVersion3Update(LwM2mClient client, String version) { log.debug("[{}] Current sw version(3): {}", client.getEndpoint(), version); getOrInitSwInfo(client).setCurrentVersion3(version); } @Override - public void onCurrentSoftwareVersionUpdate(LwM2MClient client, String version) { + public void onCurrentSoftwareVersionUpdate(LwM2mClient client, String version) { log.debug("[{}] Current sw version(9): {}", client.getEndpoint(), version); getOrInitSwInfo(client).setCurrentVersion(version); } @Override - public void onCurrentSoftwareStateUpdate(LwM2MClient client, Long stateCode) { + public void onCurrentSoftwareStateUpdate(LwM2mClient client, Long stateCode) { log.debug("[{}] Current sw state: {}", client.getEndpoint(), stateCode); LwM2MClientSwOtaInfo swInfo = getOrInitSwInfo(client); SoftwareUpdateState state = SoftwareUpdateState.fromUpdateStateSwByCode(stateCode.intValue()); @@ -362,7 +362,7 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl @Override - public void onCurrentSoftwareResultUpdate(LwM2MClient client, Long code) { + public void onCurrentSoftwareResultUpdate(LwM2mClient client, Long code) { log.debug("[{}] Current sw result: {}", client.getEndpoint(), code); LwM2MClientSwOtaInfo swInfo = getOrInitSwInfo(client); SoftwareUpdateResult result = SoftwareUpdateResult.fromUpdateResultSwByCode(code.intValue()); @@ -379,14 +379,14 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl } @Override - public void onTargetSoftwareUpdate(LwM2MClient client, String newSoftwareTitle, String newSoftwareVersion, Optional newSoftwareUrl, Optional newSoftwareTag) { + public void onTargetSoftwareUpdate(LwM2mClient client, String newSoftwareTitle, String newSoftwareVersion, Optional newSoftwareUrl, Optional newSoftwareTag) { LwM2MClientSwOtaInfo fwInfo = getOrInitSwInfo(client); fwInfo.updateTarget(newSoftwareTitle, newSoftwareVersion, newSoftwareUrl, newSoftwareTag); update(fwInfo); startSoftwareUpdateIfNeeded(client, fwInfo); } - private void startFirmwareUpdateIfNeeded(LwM2MClient client, LwM2MClientFwOtaInfo fwInfo) { + private void startFirmwareUpdateIfNeeded(LwM2mClient client, LwM2MClientFwOtaInfo fwInfo) { try { if (!fwInfo.isSupported() && fwInfo.isAssigned()) { log.debug("[{}] Fw update is not supported: {}", client.getEndpoint(), fwInfo); @@ -406,7 +406,7 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl } } - private void startSoftwareUpdateIfNeeded(LwM2MClient client, LwM2MClientSwOtaInfo swInfo) { + private void startSoftwareUpdateIfNeeded(LwM2mClient client, LwM2MClientSwOtaInfo swInfo) { try { if (!swInfo.isSupported() && swInfo.isAssigned()) { log.debug("[{}] Sw update is not supported: {}", client.getEndpoint(), swInfo); @@ -431,7 +431,7 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl } } - public void startUpdateUsingBinary(LwM2MClient client, LwM2MClientSwOtaInfo swInfo) { + public void startUpdateUsingBinary(LwM2mClient client, LwM2MClientSwOtaInfo swInfo) { this.transportService.process(client.getSession(), createOtaPackageRequestMsg(client.getSession(), swInfo.getType().name()), new TransportServiceCallback<>() { @Override @@ -446,13 +446,13 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl }); } - private void startUpdateUsingUrl(LwM2MClient client, String id, String url) { + private void startUpdateUsingUrl(LwM2mClient client, String id, String url) { String targetIdVer = convertObjectIdToVersionedId(id, client.getRegistration()); TbLwM2MWriteReplaceRequest request = TbLwM2MWriteReplaceRequest.builder().versionedId(targetIdVer).value(url).timeout(clientContext.getRequestTimeout(client)).build(); downlinkHandler.sendWriteReplaceRequest(client, request, new TbLwM2MWriteResponseCallback(uplinkHandler, logService, client, targetIdVer)); } - public void startUpdateUsingBinary(LwM2MClient client, LwM2MClientFwOtaInfo fwInfo) { + public void startUpdateUsingBinary(LwM2mClient client, LwM2MClientFwOtaInfo fwInfo) { this.transportService.process(client.getSession(), createOtaPackageRequestMsg(client.getSession(), fwInfo.getType().name()), new TransportServiceCallback<>() { @Override @@ -467,7 +467,7 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl }); } - private void doUpdateFirmwareUsingBinary(TransportProtos.GetOtaPackageResponseMsg response, LwM2MClientFwOtaInfo info, LwM2MClient client) { + private void doUpdateFirmwareUsingBinary(TransportProtos.GetOtaPackageResponseMsg response, LwM2MClientFwOtaInfo info, LwM2mClient client) { if (TransportProtos.ResponseStatus.SUCCESS.equals(response.getResponseStatus())) { UUID otaPackageId = new UUID(response.getOtaPackageIdMSB(), response.getOtaPackageIdLSB()); LwM2MFirmwareUpdateStrategy strategy; @@ -494,7 +494,7 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl } } - private void doUpdateSoftwareUsingBinary(TransportProtos.GetOtaPackageResponseMsg response, LwM2MClientSwOtaInfo info, LwM2MClient client) { + private void doUpdateSoftwareUsingBinary(TransportProtos.GetOtaPackageResponseMsg response, LwM2MClientSwOtaInfo info, LwM2mClient client) { if (TransportProtos.ResponseStatus.SUCCESS.equals(response.getResponseStatus())) { UUID otaPackageId = new UUID(response.getOtaPackageIdMSB(), response.getOtaPackageIdLSB()); LwM2MSoftwareUpdateStrategy strategy = info.getStrategy(); @@ -513,7 +513,7 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl } } - private void startUpdateUsingBinary(LwM2MClient client, String versionedId, UUID otaPackageId) { + private void startUpdateUsingBinary(LwM2mClient client, String versionedId, UUID otaPackageId) { byte[] firmwareChunk = otaPackageDataCache.get(otaPackageId.toString(), 0, 0); TbLwM2MWriteReplaceRequest writeRequest = TbLwM2MWriteReplaceRequest.builder().versionedId(versionedId) .value(firmwareChunk).contentFormat(ContentFormat.OPAQUE) @@ -531,17 +531,17 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl .build(); } - private void executeFwUpdate(LwM2MClient client) { + private void executeFwUpdate(LwM2mClient client) { TbLwM2MExecuteRequest request = TbLwM2MExecuteRequest.builder().versionedId(FW_EXECUTE_ID).timeout(clientContext.getRequestTimeout(client)).build(); downlinkHandler.sendExecuteRequest(client, request, new TbLwM2MExecuteCallback(logService, client, FW_EXECUTE_ID)); } - private void executeSwInstall(LwM2MClient client) { + private void executeSwInstall(LwM2mClient client) { TbLwM2MExecuteRequest request = TbLwM2MExecuteRequest.builder().versionedId(SW_INSTALL_ID).timeout(clientContext.getRequestTimeout(client)).build(); downlinkHandler.sendExecuteRequest(client, request, new TbLwM2MExecuteCallback(logService, client, SW_INSTALL_ID)); } - private void executeSwUninstallForUpdate(LwM2MClient client) { + private void executeSwUninstallForUpdate(LwM2mClient client) { TbLwM2MExecuteRequest request = TbLwM2MExecuteRequest.builder().versionedId(SW_UN_INSTALL_ID).params("1").timeout(clientContext.getRequestTimeout(client)).build(); downlinkHandler.sendExecuteRequest(client, request, new TbLwM2MExecuteCallback(logService, client, SW_INSTALL_ID)); } @@ -559,7 +559,7 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl return Optional.empty(); } - private LwM2MClientFwOtaInfo getOrInitFwInfo(LwM2MClient client) { + private LwM2MClientFwOtaInfo getOrInitFwInfo(LwM2mClient client) { return this.fwStates.computeIfAbsent(client.getEndpoint(), endpoint -> { LwM2MClientFwOtaInfo info = otaInfoStore.getFw(endpoint); if (info == null) { @@ -572,7 +572,7 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl }); } - private LwM2MClientSwOtaInfo getOrInitSwInfo(LwM2MClient client) { + private LwM2MClientSwOtaInfo getOrInitSwInfo(LwM2mClient client) { return this.swStates.computeIfAbsent(client.getEndpoint(), endpoint -> { LwM2MClientSwOtaInfo info = otaInfoStore.getSw(endpoint); if (info == null) { @@ -593,7 +593,7 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl otaInfoStore.putSw(info); } - private void sendStateUpdateToTelemetry(LwM2MClient client, LwM2MClientOtaInfo fwInfo, OtaPackageUpdateStatus status, String log) { + private void sendStateUpdateToTelemetry(LwM2mClient client, LwM2MClientOtaInfo fwInfo, OtaPackageUpdateStatus status, String log) { List result = new ArrayList<>(); TransportProtos.KeyValueProto.Builder kvProto = TransportProtos.KeyValueProto.newBuilder().setKey(getAttributeKey(fwInfo.getType(), STATE)); kvProto.setType(TransportProtos.KeyValueType.STRING_V).setStringV(status.name()); diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/LwM2MOtaUpdateService.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/LwM2MOtaUpdateService.java index af3905882e..b03fe81d28 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/LwM2MOtaUpdateService.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/LwM2MOtaUpdateService.java @@ -16,43 +16,43 @@ package org.thingsboard.server.transport.lwm2m.server.ota; import org.thingsboard.server.common.data.device.data.lwm2m.OtherConfiguration; -import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClient; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; import java.util.Optional; public interface LwM2MOtaUpdateService { - void init(LwM2MClient client); + void init(LwM2mClient client); - void forceFirmwareUpdate(LwM2MClient client); + void forceFirmwareUpdate(LwM2mClient client); - void onTargetFirmwareUpdate(LwM2MClient client, String newFwTitle, String newFwVersion, Optional newFwUrl, Optional newFwTag); + void onTargetFirmwareUpdate(LwM2mClient client, String newFwTitle, String newFwVersion, Optional newFwUrl, Optional newFwTag); - void onTargetSoftwareUpdate(LwM2MClient client, String newSwTitle, String newSwVersion, Optional newSwUrl, Optional newSwTag); + void onTargetSoftwareUpdate(LwM2mClient client, String newSwTitle, String newSwVersion, Optional newSwUrl, Optional newSwTag); - void onCurrentFirmwareNameUpdate(LwM2MClient client, String name); + void onCurrentFirmwareNameUpdate(LwM2mClient client, String name); - void onFirmwareStrategyUpdate(LwM2MClient client, OtherConfiguration configuration); + void onFirmwareStrategyUpdate(LwM2mClient client, OtherConfiguration configuration); - void onCurrentSoftwareStrategyUpdate(LwM2MClient client, OtherConfiguration configuration); + void onCurrentSoftwareStrategyUpdate(LwM2mClient client, OtherConfiguration configuration); - void onCurrentFirmwareVersion3Update(LwM2MClient client, String version); + void onCurrentFirmwareVersion3Update(LwM2mClient client, String version); - void onCurrentFirmwareVersionUpdate(LwM2MClient client, String version); + void onCurrentFirmwareVersionUpdate(LwM2mClient client, String version); - void onCurrentFirmwareStateUpdate(LwM2MClient client, Long state); + void onCurrentFirmwareStateUpdate(LwM2mClient client, Long state); - void onCurrentFirmwareResultUpdate(LwM2MClient client, Long result); + void onCurrentFirmwareResultUpdate(LwM2mClient client, Long result); - void onCurrentFirmwareDeliveryMethodUpdate(LwM2MClient lwM2MClient, Long value); + void onCurrentFirmwareDeliveryMethodUpdate(LwM2mClient lwM2MClient, Long value); - void onCurrentSoftwareNameUpdate(LwM2MClient lwM2MClient, String name); + void onCurrentSoftwareNameUpdate(LwM2mClient lwM2MClient, String name); - void onCurrentSoftwareVersion3Update(LwM2MClient lwM2MClient, String version); + void onCurrentSoftwareVersion3Update(LwM2mClient lwM2MClient, String version); - void onCurrentSoftwareVersionUpdate(LwM2MClient client, String version); + void onCurrentSoftwareVersionUpdate(LwM2mClient client, String version); - void onCurrentSoftwareStateUpdate(LwM2MClient lwM2MClient, Long value); + void onCurrentSoftwareStateUpdate(LwM2mClient lwM2MClient, Long value); - void onCurrentSoftwareResultUpdate(LwM2MClient client, Long result); + void onCurrentSoftwareResultUpdate(LwM2mClient client, Long result); } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/DefaultLwM2MRpcRequestHandler.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/DefaultLwM2MRpcRequestHandler.java index e4ce78f589..306547a966 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/DefaultLwM2MRpcRequestHandler.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/DefaultLwM2MRpcRequestHandler.java @@ -32,9 +32,9 @@ import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; import org.thingsboard.server.transport.lwm2m.server.LwM2MOperationType; -import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClient; -import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClientContext; -import org.thingsboard.server.transport.lwm2m.server.downlink.LwM2MDownlinkMsgHandler; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientContext; +import org.thingsboard.server.transport.lwm2m.server.downlink.LwM2mDownlinkMsgHandler; import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MCancelAllObserveCallback; import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MCancelAllRequest; import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MCancelObserveCallback; @@ -65,7 +65,7 @@ import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogServic import org.thingsboard.server.transport.lwm2m.server.rpc.composite.RpcReadCompositeRequest; import org.thingsboard.server.transport.lwm2m.server.rpc.composite.RpcReadResponseCompositeCallback; import org.thingsboard.server.transport.lwm2m.server.rpc.composite.RpcWriteCompositeRequest; -import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2MUplinkMsgHandler; +import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler; import java.util.LinkedHashMap; import java.util.Map; @@ -83,10 +83,10 @@ import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.fr public class DefaultLwM2MRpcRequestHandler implements LwM2MRpcRequestHandler { private final TransportService transportService; - private final LwM2MClientContext clientContext; + private final LwM2mClientContext clientContext; private final LwM2MTransportServerConfig config; - private final LwM2MUplinkMsgHandler uplinkHandler; - private final LwM2MDownlinkMsgHandler downlinkHandler; + private final LwM2mUplinkMsgHandler uplinkHandler; + private final LwM2mDownlinkMsgHandler downlinkHandler; private final LwM2MTelemetryLogService logService; @Override @@ -97,7 +97,7 @@ public class DefaultLwM2MRpcRequestHandler implements LwM2MRpcRequestHandler { this.sendErrorRpcResponse(sessionInfo, rpcRequest.getRequestId(), ResponseCode.METHOD_NOT_ALLOWED, "Unsupported operation type: " + rpcRequest.getMethodName()); return; } - LwM2MClient client = clientContext.getClientBySessionInfo(sessionInfo); + LwM2mClient client = clientContext.getClientBySessionInfo(sessionInfo); if (client.getRegistration() == null) { this.sendErrorRpcResponse(sessionInfo, rpcRequest.getRequestId(), ResponseCode.INTERNAL_SERVER_ERROR, "Registration is empty"); return; @@ -177,14 +177,14 @@ public class DefaultLwM2MRpcRequestHandler implements LwM2MRpcRequestHandler { } } - private void sendReadRequest(LwM2MClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, String versionedId) { + private void sendReadRequest(LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, String versionedId) { TbLwM2MReadRequest request = TbLwM2MReadRequest.builder().versionedId(versionedId).timeout(clientContext.getRequestTimeout(client)).build(); var mainCallback = new TbLwM2MReadCallback(uplinkHandler, logService, client, versionedId); var rpcCallback = new RpcReadResponseCallback<>(transportService, client, requestMsg, mainCallback); downlinkHandler.sendReadRequest(client, request, rpcCallback); } - private void sendReadCompositeRequest(LwM2MClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, ContentFormat contentFormatComposite) { + private void sendReadCompositeRequest(LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, ContentFormat contentFormatComposite) { String[] versionedIds = getIdsFromParameters(client, requestMsg); TbLwM2MReadCompositeRequest request = TbLwM2MReadCompositeRequest.builder().versionedIds(versionedIds).timeout(clientContext.getRequestTimeout(client)).build(); var mainCallback = new TbLwM2MReadCompositeCallback(uplinkHandler, logService, client, versionedIds); @@ -192,38 +192,38 @@ public class DefaultLwM2MRpcRequestHandler implements LwM2MRpcRequestHandler { downlinkHandler.sendReadCompositeRequest(client, request, rpcCallback, contentFormatComposite); } - private void sendObserveRequest(LwM2MClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, String versionedId) { + private void sendObserveRequest(LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, String versionedId) { TbLwM2MObserveRequest request = TbLwM2MObserveRequest.builder().versionedId(versionedId).timeout(clientContext.getRequestTimeout(client)).build(); var mainCallback = new TbLwM2MObserveCallback(uplinkHandler, logService, client, versionedId); var rpcCallback = new RpcReadResponseCallback<>(transportService, client, requestMsg, mainCallback); downlinkHandler.sendObserveRequest(client, request, rpcCallback); } - private void sendObserveAllRequest(LwM2MClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg) { + private void sendObserveAllRequest(LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg) { TbLwM2MObserveAllRequest request = TbLwM2MObserveAllRequest.builder().timeout(clientContext.getRequestTimeout(client)).build(); downlinkHandler.sendObserveAllRequest(client, request, new RpcLinkSetCallback<>(transportService, client, requestMsg, null)); } - private void sendDiscoverAllRequest(LwM2MClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg) { + private void sendDiscoverAllRequest(LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg) { TbLwM2MDiscoverAllRequest request = TbLwM2MDiscoverAllRequest.builder().timeout(clientContext.getRequestTimeout(client)).build(); downlinkHandler.sendDiscoverAllRequest(client, request, new RpcLinkSetCallback<>(transportService, client, requestMsg, null)); } - private void sendDiscoverRequest(LwM2MClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, String versionedId) { + private void sendDiscoverRequest(LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, String versionedId) { TbLwM2MDiscoverRequest request = TbLwM2MDiscoverRequest.builder().versionedId(versionedId).timeout(clientContext.getRequestTimeout(client)).build(); var mainCallback = new TbLwM2MDiscoverCallback(logService, client, versionedId); var rpcCallback = new RpcDiscoverCallback(transportService, client, requestMsg, mainCallback); downlinkHandler.sendDiscoverRequest(client, request, rpcCallback); } - private void sendExecuteRequest(LwM2MClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, String versionedId) { + private void sendExecuteRequest(LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, String versionedId) { TbLwM2MExecuteRequest downlink = TbLwM2MExecuteRequest.builder().versionedId(versionedId).timeout(clientContext.getRequestTimeout(client)).build(); var mainCallback = new TbLwM2MExecuteCallback(logService, client, versionedId); var rpcCallback = new RpcEmptyResponseCallback<>(transportService, client, requestMsg, mainCallback); downlinkHandler.sendExecuteRequest(client, downlink, rpcCallback); } - private void sendWriteAttributesRequest(LwM2MClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, String versionedId) { + private void sendWriteAttributesRequest(LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, String versionedId) { RpcWriteAttributesRequest requestBody = JacksonUtil.fromString(requestMsg.getParams(), RpcWriteAttributesRequest.class); TbLwM2MWriteAttributesRequest request = TbLwM2MWriteAttributesRequest.builder().versionedId(versionedId) .attributes(requestBody.getAttributes()) @@ -233,7 +233,7 @@ public class DefaultLwM2MRpcRequestHandler implements LwM2MRpcRequestHandler { downlinkHandler.sendWriteAttributesRequest(client, request, rpcCallback); } - private void sendWriteUpdateRequest(LwM2MClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, String versionedId) { + private void sendWriteUpdateRequest(LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, String versionedId) { RpcWriteUpdateRequest requestBody = JacksonUtil.fromString(requestMsg.getParams(), RpcWriteUpdateRequest.class); TbLwM2MWriteUpdateRequest.TbLwM2MWriteUpdateRequestBuilder builder = TbLwM2MWriteUpdateRequest.builder().versionedId(versionedId); builder.value(requestBody.getValue()).timeout(clientContext.getRequestTimeout(client)); @@ -242,7 +242,7 @@ public class DefaultLwM2MRpcRequestHandler implements LwM2MRpcRequestHandler { downlinkHandler.sendWriteUpdateRequest(client, builder.build(), rpcCallback); } - private void sendCreateRequest(LwM2MClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, String versionedId) { + private void sendCreateRequest(LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, String versionedId) { RpcCreateRequest requestBody = JacksonUtil.fromString(requestMsg.getParams(), RpcCreateRequest.class); TbLwM2MCreateRequest.TbLwM2MCreateRequestBuilder builder = TbLwM2MCreateRequest.builder().versionedId(versionedId); builder.value(requestBody.getValue()).nodes(requestBody.getNodes()).timeout(clientContext.getRequestTimeout(client)); @@ -251,7 +251,7 @@ public class DefaultLwM2MRpcRequestHandler implements LwM2MRpcRequestHandler { downlinkHandler.sendCreateRequest(client, builder.build(), rpcCallback); } - private void sendWriteReplaceRequest(LwM2MClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, String versionedId) { + private void sendWriteReplaceRequest(LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, String versionedId) { RpcWriteReplaceRequest requestBody = JacksonUtil.fromString(requestMsg.getParams(), RpcWriteReplaceRequest.class); LwM2mPath path = new LwM2mPath(fromVersionedIdToObjectId(versionedId)); if (path.isResource()) { @@ -282,7 +282,7 @@ public class DefaultLwM2MRpcRequestHandler implements LwM2MRpcRequestHandler { * nodes.put("/1/0/2", 100); * nodes.put("/5/0/1", "coap://localhost:5685"); */ - private void sendWriteCompositeRequest(LwM2MClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, ContentFormat contentFormatComposite) { + private void sendWriteCompositeRequest(LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, ContentFormat contentFormatComposite) { RpcWriteCompositeRequest rpcWriteCompositeRequest = JacksonUtil.fromString(requestMsg.getParams(), RpcWriteCompositeRequest.class); Map validNodes = validateNodes(client, rpcWriteCompositeRequest.getNodes()); if (validNodes.size() > 0) { @@ -295,7 +295,7 @@ public class DefaultLwM2MRpcRequestHandler implements LwM2MRpcRequestHandler { } } - private Map validateNodes(LwM2MClient client, Map nodes) { + private Map validateNodes(LwM2mClient client, Map nodes) { Map newNodes = new LinkedHashMap(); nodes.forEach((key, value) -> { String versionedId; @@ -331,28 +331,28 @@ public class DefaultLwM2MRpcRequestHandler implements LwM2MRpcRequestHandler { return newNodes; } - private void sendCancelObserveRequest(LwM2MClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, String versionedId) { + private void sendCancelObserveRequest(LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, String versionedId) { TbLwM2MCancelObserveRequest downlink = TbLwM2MCancelObserveRequest.builder().versionedId(versionedId).timeout(clientContext.getRequestTimeout(client)).build(); var mainCallback = new TbLwM2MCancelObserveCallback(logService, client, versionedId); var rpcCallback = new RpcCancelObserveCallback(transportService, client, requestMsg, mainCallback); downlinkHandler.sendCancelObserveRequest(client, downlink, rpcCallback); } - private void sendDeleteRequest(LwM2MClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, String versionedId) { + private void sendDeleteRequest(LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, String versionedId) { TbLwM2MDeleteRequest downlink = TbLwM2MDeleteRequest.builder().versionedId(versionedId).timeout(clientContext.getRequestTimeout(client)).build(); var mainCallback = new TbLwM2MDeleteCallback(logService, client, versionedId); var rpcCallback = new RpcEmptyResponseCallback<>(transportService, client, requestMsg, mainCallback); downlinkHandler.sendDeleteRequest(client, downlink, rpcCallback); } - private void sendCancelAllObserveRequest(LwM2MClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg) { + private void sendCancelAllObserveRequest(LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg) { TbLwM2MCancelAllRequest downlink = TbLwM2MCancelAllRequest.builder().timeout(clientContext.getRequestTimeout(client)).build(); var mainCallback = new TbLwM2MCancelAllObserveCallback(logService, client); var rpcCallback = new RpcCancelAllObserveCallback(transportService, client, requestMsg, mainCallback); downlinkHandler.sendCancelAllRequest(client, downlink, rpcCallback); } - private String getIdFromParameters(LwM2MClient client, LwM2MRpcRequestHeader header) { + private String getIdFromParameters(LwM2mClient client, LwM2MRpcRequestHeader header) { String targetId; if (StringUtils.isNotEmpty(header.getKey())) { targetId = clientContext.getObjectIdByKeyNameFromProfile(client, header.getKey()); @@ -364,7 +364,7 @@ public class DefaultLwM2MRpcRequestHandler implements LwM2MRpcRequestHandler { return targetId; } - private String[] getIdsFromParameters(LwM2MClient client, TransportProtos.ToDeviceRpcRequestMsg rpcRequest) { + private String[] getIdsFromParameters(LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg rpcRequest) { RpcReadCompositeRequest requestParams = JacksonUtil.fromString(rpcRequest.getParams(), RpcReadCompositeRequest.class); if (requestParams.getKeys() != null && requestParams.getKeys().length > 0) { Set targetIds = ConcurrentHashMap.newKeySet(); @@ -398,7 +398,7 @@ public class DefaultLwM2MRpcRequestHandler implements LwM2MRpcRequestHandler { log.info("[{}] toServerRpcResponse", toServerResponse); } - private ContentFormat getCompositeContentFormat(LwM2MClient client) { + private ContentFormat getCompositeContentFormat(LwM2mClient client) { if (client.getClientSupportContentFormats().contains(ContentFormat.SENML_JSON)) { return ContentFormat.SENML_JSON; } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcCancelAllObserveCallback.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcCancelAllObserveCallback.java index a65dab2b8a..c40d21cc4b 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcCancelAllObserveCallback.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcCancelAllObserveCallback.java @@ -18,13 +18,13 @@ package org.thingsboard.server.transport.lwm2m.server.rpc; import org.eclipse.leshan.core.ResponseCode; import org.thingsboard.server.common.transport.TransportService; import org.thingsboard.server.gen.transport.TransportProtos; -import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClient; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; import org.thingsboard.server.transport.lwm2m.server.downlink.DownlinkRequestCallback; import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MCancelAllRequest; public class RpcCancelAllObserveCallback extends RpcDownlinkRequestCallbackProxy { - public RpcCancelAllObserveCallback(TransportService transportService, LwM2MClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, DownlinkRequestCallback callback) { + public RpcCancelAllObserveCallback(TransportService transportService, LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, DownlinkRequestCallback callback) { super(transportService, client, requestMsg, callback); } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcCancelObserveCallback.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcCancelObserveCallback.java index 0c782c4271..f7971783ac 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcCancelObserveCallback.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcCancelObserveCallback.java @@ -18,13 +18,13 @@ package org.thingsboard.server.transport.lwm2m.server.rpc; import org.eclipse.leshan.core.ResponseCode; import org.thingsboard.server.common.transport.TransportService; import org.thingsboard.server.gen.transport.TransportProtos; -import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClient; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; import org.thingsboard.server.transport.lwm2m.server.downlink.DownlinkRequestCallback; import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MCancelObserveRequest; public class RpcCancelObserveCallback extends RpcDownlinkRequestCallbackProxy { - public RpcCancelObserveCallback(TransportService transportService, LwM2MClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, DownlinkRequestCallback callback) { + public RpcCancelObserveCallback(TransportService transportService, LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, DownlinkRequestCallback callback) { super(transportService, client, requestMsg, callback); } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcCreateResponseCallback.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcCreateResponseCallback.java index 41e20b8ec9..f27d8e89d7 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcCreateResponseCallback.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcCreateResponseCallback.java @@ -19,14 +19,14 @@ import org.eclipse.leshan.core.request.LwM2mRequest; import org.eclipse.leshan.core.response.CreateResponse; import org.thingsboard.server.common.transport.TransportService; import org.thingsboard.server.gen.transport.TransportProtos; -import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClient; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; import org.thingsboard.server.transport.lwm2m.server.downlink.DownlinkRequestCallback; import java.util.Optional; public class RpcCreateResponseCallback, T extends CreateResponse> extends RpcLwM2MDownlinkCallback { - public RpcCreateResponseCallback(TransportService transportService, LwM2MClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, DownlinkRequestCallback callback) { + public RpcCreateResponseCallback(TransportService transportService, LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, DownlinkRequestCallback callback) { super(transportService, client, requestMsg, callback); } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcDiscoverCallback.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcDiscoverCallback.java index 92a802a2b8..936d177b2b 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcDiscoverCallback.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcDiscoverCallback.java @@ -20,14 +20,14 @@ import org.eclipse.leshan.core.request.DiscoverRequest; import org.eclipse.leshan.core.response.DiscoverResponse; import org.thingsboard.server.common.transport.TransportService; import org.thingsboard.server.gen.transport.TransportProtos; -import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClient; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; import org.thingsboard.server.transport.lwm2m.server.downlink.DownlinkRequestCallback; import java.util.Optional; public class RpcDiscoverCallback extends RpcLwM2MDownlinkCallback { - public RpcDiscoverCallback(TransportService transportService, LwM2MClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, DownlinkRequestCallback callback) { + public RpcDiscoverCallback(TransportService transportService, LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, DownlinkRequestCallback callback) { super(transportService, client, requestMsg, callback); } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcDownlinkRequestCallbackProxy.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcDownlinkRequestCallbackProxy.java index 64103e5695..acd88abee1 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcDownlinkRequestCallbackProxy.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcDownlinkRequestCallbackProxy.java @@ -23,7 +23,7 @@ import org.thingsboard.server.common.data.rpc.RpcStatus; import org.thingsboard.server.common.transport.TransportService; import org.thingsboard.server.common.transport.TransportServiceCallback; import org.thingsboard.server.gen.transport.TransportProtos; -import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClient; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; import org.thingsboard.server.transport.lwm2m.server.downlink.DownlinkRequestCallback; import java.util.concurrent.TimeoutException; @@ -34,9 +34,9 @@ public abstract class RpcDownlinkRequestCallbackProxy implements DownlinkR private final TransportProtos.ToDeviceRpcRequestMsg request; private final DownlinkRequestCallback callback; - protected final LwM2MClient client; + protected final LwM2mClient client; - public RpcDownlinkRequestCallbackProxy(TransportService transportService, LwM2MClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, DownlinkRequestCallback callback) { + public RpcDownlinkRequestCallbackProxy(TransportService transportService, LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, DownlinkRequestCallback callback) { this.transportService = transportService; this.client = client; this.request = requestMsg; diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcEmptyResponseCallback.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcEmptyResponseCallback.java index 2ca7f50f8a..5bb2a8550f 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcEmptyResponseCallback.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcEmptyResponseCallback.java @@ -19,14 +19,14 @@ import org.eclipse.leshan.core.request.LwM2mRequest; import org.eclipse.leshan.core.response.LwM2mResponse; import org.thingsboard.server.common.transport.TransportService; import org.thingsboard.server.gen.transport.TransportProtos; -import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClient; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; import org.thingsboard.server.transport.lwm2m.server.downlink.DownlinkRequestCallback; import java.util.Optional; public class RpcEmptyResponseCallback, T extends LwM2mResponse> extends RpcLwM2MDownlinkCallback { - public RpcEmptyResponseCallback(TransportService transportService, LwM2MClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, DownlinkRequestCallback callback) { + public RpcEmptyResponseCallback(TransportService transportService, LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, DownlinkRequestCallback callback) { super(transportService, client, requestMsg, callback); } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcLinkSetCallback.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcLinkSetCallback.java index b8e4df0e1e..115b3df90d 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcLinkSetCallback.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcLinkSetCallback.java @@ -19,12 +19,12 @@ import org.eclipse.leshan.core.ResponseCode; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.transport.TransportService; import org.thingsboard.server.gen.transport.TransportProtos; -import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClient; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; import org.thingsboard.server.transport.lwm2m.server.downlink.DownlinkRequestCallback; public class RpcLinkSetCallback extends RpcDownlinkRequestCallbackProxy { - public RpcLinkSetCallback(TransportService transportService, LwM2MClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, DownlinkRequestCallback callback) { + public RpcLinkSetCallback(TransportService transportService, LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, DownlinkRequestCallback callback) { super(transportService, client, requestMsg, callback); } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcLwM2MDownlinkCallback.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcLwM2MDownlinkCallback.java index 6338c43666..70536d1be8 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcLwM2MDownlinkCallback.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcLwM2MDownlinkCallback.java @@ -20,14 +20,14 @@ import org.eclipse.leshan.core.response.LwM2mResponse; import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.transport.TransportService; import org.thingsboard.server.gen.transport.TransportProtos; -import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClient; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; import org.thingsboard.server.transport.lwm2m.server.downlink.DownlinkRequestCallback; import java.util.Optional; public abstract class RpcLwM2MDownlinkCallback, T extends LwM2mResponse> extends RpcDownlinkRequestCallbackProxy { - public RpcLwM2MDownlinkCallback(TransportService transportService, LwM2MClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, DownlinkRequestCallback callback) { + public RpcLwM2MDownlinkCallback(TransportService transportService, LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, DownlinkRequestCallback callback) { super(transportService, client, requestMsg, callback); } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcReadResponseCallback.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcReadResponseCallback.java index 965aa7414e..453c1e361c 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcReadResponseCallback.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcReadResponseCallback.java @@ -19,7 +19,7 @@ import org.eclipse.leshan.core.request.LwM2mRequest; import org.eclipse.leshan.core.response.ReadResponse; import org.thingsboard.server.common.transport.TransportService; import org.thingsboard.server.gen.transport.TransportProtos; -import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClient; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; import org.thingsboard.server.transport.lwm2m.server.downlink.DownlinkRequestCallback; import java.util.Optional; @@ -28,7 +28,7 @@ import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.co public class RpcReadResponseCallback, T extends ReadResponse> extends RpcLwM2MDownlinkCallback { - public RpcReadResponseCallback(TransportService transportService, LwM2MClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, DownlinkRequestCallback callback) { + public RpcReadResponseCallback(TransportService transportService, LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, DownlinkRequestCallback callback) { super(transportService, client, requestMsg, callback); } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/composite/RpcReadResponseCompositeCallback.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/composite/RpcReadResponseCompositeCallback.java index bcc9a3188d..f8a5e1c60c 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/composite/RpcReadResponseCompositeCallback.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/composite/RpcReadResponseCompositeCallback.java @@ -19,7 +19,7 @@ import org.eclipse.leshan.core.request.LwM2mRequest; import org.eclipse.leshan.core.response.ReadCompositeResponse; import org.thingsboard.server.common.transport.TransportService; import org.thingsboard.server.gen.transport.TransportProtos; -import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClient; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; import org.thingsboard.server.transport.lwm2m.server.downlink.DownlinkRequestCallback; import org.thingsboard.server.transport.lwm2m.server.rpc.RpcLwM2MDownlinkCallback; @@ -29,7 +29,7 @@ import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.co public class RpcReadResponseCompositeCallback, T extends ReadCompositeResponse> extends RpcLwM2MDownlinkCallback { - public RpcReadResponseCompositeCallback(TransportService transportService, LwM2MClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, DownlinkRequestCallback callback) { + public RpcReadResponseCompositeCallback(TransportService transportService, LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, DownlinkRequestCallback callback) { super(transportService, client, requestMsg, callback); } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/session/DefaultLwM2MSessionManager.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/session/DefaultLwM2MSessionManager.java index 2714ae071c..ee6e4a779b 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/session/DefaultLwM2MSessionManager.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/session/DefaultLwM2MSessionManager.java @@ -22,10 +22,10 @@ import org.thingsboard.server.common.transport.TransportService; import org.thingsboard.server.common.transport.service.DefaultTransportService; import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; -import org.thingsboard.server.transport.lwm2m.server.LwM2MSessionMsgListener; +import org.thingsboard.server.transport.lwm2m.server.LwM2mSessionMsgListener; import org.thingsboard.server.transport.lwm2m.server.attributes.LwM2MAttributesService; import org.thingsboard.server.transport.lwm2m.server.rpc.LwM2MRpcRequestHandler; -import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2MUplinkMsgHandler; +import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler; @Slf4j @Service @@ -35,12 +35,12 @@ public class DefaultLwM2MSessionManager implements LwM2MSessionManager { private final TransportService transportService; private final LwM2MAttributesService attributesService; private final LwM2MRpcRequestHandler rpcHandler; - private final LwM2MUplinkMsgHandler uplinkHandler; + private final LwM2mUplinkMsgHandler uplinkHandler; public DefaultLwM2MSessionManager(TransportService transportService, @Lazy LwM2MAttributesService attributesService, @Lazy LwM2MRpcRequestHandler rpcHandler, - @Lazy LwM2MUplinkMsgHandler uplinkHandler) { + @Lazy LwM2mUplinkMsgHandler uplinkHandler) { this.transportService = transportService; this.attributesService = attributesService; this.rpcHandler = rpcHandler; @@ -49,7 +49,7 @@ public class DefaultLwM2MSessionManager implements LwM2MSessionManager { @Override public void register(TransportProtos.SessionInfoProto sessionInfo) { - transportService.registerAsyncSession(sessionInfo, new LwM2MSessionMsgListener(uplinkHandler, attributesService, rpcHandler, sessionInfo, transportService)); + transportService.registerAsyncSession(sessionInfo, new LwM2mSessionMsgListener(uplinkHandler, attributesService, rpcHandler, sessionInfo, transportService)); TransportProtos.TransportToDeviceActorMsg msg = TransportProtos.TransportToDeviceActorMsg.newBuilder() .setSessionInfo(sessionInfo) .setSessionEvent(DefaultTransportService.getSessionEventMsg(TransportProtos.SessionEvent.OPEN)) diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbDummyLwM2MClientStore.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbDummyLwM2MClientStore.java index 2796e9d657..767ab43493 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbDummyLwM2MClientStore.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbDummyLwM2MClientStore.java @@ -15,24 +15,24 @@ */ package org.thingsboard.server.transport.lwm2m.server.store; -import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClient; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; import java.util.Collections; import java.util.Set; public class TbDummyLwM2MClientStore implements TbLwM2MClientStore { @Override - public LwM2MClient get(String endpoint) { + public LwM2mClient get(String endpoint) { return null; } @Override - public Set getAll() { + public Set getAll() { return Collections.emptySet(); } @Override - public void put(LwM2MClient client) { + public void put(LwM2mClient client) { } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2MClientStore.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2MClientStore.java index c25b2663fa..55b0423b05 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2MClientStore.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2MClientStore.java @@ -15,17 +15,17 @@ */ package org.thingsboard.server.transport.lwm2m.server.store; -import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClient; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; import java.util.Set; public interface TbLwM2MClientStore { - LwM2MClient get(String endpoint); + LwM2mClient get(String endpoint); - Set getAll(); + Set getAll(); - void put(LwM2MClient client); + void put(LwM2mClient client); void remove(String endpoint); } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mSecurityStore.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mSecurityStore.java index 73782d9b50..ac0d3d0e68 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mSecurityStore.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mSecurityStore.java @@ -19,7 +19,7 @@ import lombok.extern.slf4j.Slf4j; import org.eclipse.leshan.server.security.NonUniqueSecurityInfoException; import org.eclipse.leshan.server.security.SecurityInfo; import org.jetbrains.annotations.Nullable; -import org.thingsboard.server.transport.lwm2m.secure.LwM2MCredentialsSecurityInfoValidator; +import org.thingsboard.server.transport.lwm2m.secure.LwM2mCredentialsSecurityInfoValidator; import org.thingsboard.server.transport.lwm2m.secure.TbLwM2MSecurityInfo; import java.util.HashSet; @@ -27,16 +27,16 @@ import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; -import static org.thingsboard.server.transport.lwm2m.server.uplink.LwM2MTypeServer.CLIENT; +import static org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mTypeServer.CLIENT; @Slf4j public class TbLwM2mSecurityStore implements TbMainSecurityStore { private final TbEditableSecurityStore securityStore; - private final LwM2MCredentialsSecurityInfoValidator validator; + private final LwM2mCredentialsSecurityInfoValidator validator; private final ConcurrentMap> endpointRegistrations = new ConcurrentHashMap<>(); - public TbLwM2mSecurityStore(TbEditableSecurityStore securityStore, LwM2MCredentialsSecurityInfoValidator validator) { + public TbLwM2mSecurityStore(TbEditableSecurityStore securityStore, LwM2mCredentialsSecurityInfoValidator validator) { this.securityStore = securityStore; this.validator = validator; } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mStoreFactory.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mStoreFactory.java index b3792b8e43..9156d73181 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mStoreFactory.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mStoreFactory.java @@ -25,7 +25,7 @@ import org.springframework.stereotype.Component; import org.thingsboard.server.cache.TBRedisCacheConfiguration; import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; -import org.thingsboard.server.transport.lwm2m.secure.LwM2MCredentialsSecurityInfoValidator; +import org.thingsboard.server.transport.lwm2m.secure.LwM2mCredentialsSecurityInfoValidator; import java.util.Optional; @@ -40,7 +40,7 @@ public class TbLwM2mStoreFactory { private LwM2MTransportServerConfig config; @Autowired - private LwM2MCredentialsSecurityInfoValidator validator; + private LwM2mCredentialsSecurityInfoValidator validator; @Value("${transport.lwm2m.redis.enabled:false}") private boolean useRedis; diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbRedisLwM2MClientStore.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbRedisLwM2MClientStore.java index a1dc09084b..2a111a9f81 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbRedisLwM2MClientStore.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbRedisLwM2MClientStore.java @@ -22,7 +22,7 @@ import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.core.Cursor; import org.springframework.data.redis.core.ScanOptions; import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClientState; -import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClient; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; import java.util.ArrayList; import java.util.HashSet; @@ -42,21 +42,21 @@ public class TbRedisLwM2MClientStore implements TbLwM2MClientStore { } @Override - public LwM2MClient get(String endpoint) { + public LwM2mClient get(String endpoint) { try (var connection = connectionFactory.getConnection()) { byte[] data = connection.get(getKey(endpoint)); if (data == null) { return null; } else { - return (LwM2MClient) serializer.asObject(data); + return (LwM2mClient) serializer.asObject(data); } } } @Override - public Set getAll() { + public Set getAll() { try (var connection = connectionFactory.getConnection()) { - Set clients = new HashSet<>(); + Set clients = new HashSet<>(); ScanOptions scanOptions = ScanOptions.scanOptions().count(100).match(CLIENT_EP + "*").build(); List> scans = new ArrayList<>(); if (connection instanceof RedisClusterConnection) { @@ -70,7 +70,7 @@ public class TbRedisLwM2MClientStore implements TbLwM2MClientStore { scans.forEach(scan -> { scan.forEachRemaining(key -> { byte[] element = connection.get(key); - clients.add((LwM2MClient) serializer.asObject(element)); + clients.add((LwM2mClient) serializer.asObject(element)); }); }); return clients; @@ -78,7 +78,7 @@ public class TbRedisLwM2MClientStore implements TbLwM2MClientStore { } @Override - public void put(LwM2MClient client) { + public void put(LwM2mClient client) { if (client.getState().equals(LwM2MClientState.UNREGISTERED)) { log.error("[{}] Client is in invalid state: {}!", client.getEndpoint(), client.getState(), new Exception()); } else { diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/DefaultLwM2MUplinkMsgHandler.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/DefaultLwM2mUplinkMsgHandler.java similarity index 94% rename from common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/DefaultLwM2MUplinkMsgHandler.java rename to common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/DefaultLwM2mUplinkMsgHandler.java index 46475f4b25..c3dc1d61be 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/DefaultLwM2MUplinkMsgHandler.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/DefaultLwM2mUplinkMsgHandler.java @@ -59,19 +59,19 @@ import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.gen.transport.TransportProtos.SessionInfoProto; import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; -import org.thingsboard.server.transport.lwm2m.server.LwM2MOtaConvert; -import org.thingsboard.server.transport.lwm2m.server.LwM2MTransportContext; -import org.thingsboard.server.transport.lwm2m.server.LwM2MTransportServerHelper; +import org.thingsboard.server.transport.lwm2m.server.LwM2mOtaConvert; +import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportContext; +import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportServerHelper; import org.thingsboard.server.transport.lwm2m.server.attributes.LwM2MAttributesService; import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClientState; import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClientStateException; -import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClient; -import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClientContext; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientContext; import org.thingsboard.server.transport.lwm2m.server.client.ParametersAnalyzeResult; import org.thingsboard.server.transport.lwm2m.server.client.ResultsAddKeyValueProto; import org.thingsboard.server.transport.lwm2m.server.common.LwM2MExecutorAwareService; import org.thingsboard.server.transport.lwm2m.server.downlink.DownlinkRequestCallback; -import org.thingsboard.server.transport.lwm2m.server.downlink.LwM2MDownlinkMsgHandler; +import org.thingsboard.server.transport.lwm2m.server.downlink.LwM2mDownlinkMsgHandler; import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MCancelObserveCallback; import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MCancelObserveRequest; import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MLatchCallback; @@ -87,7 +87,7 @@ import org.thingsboard.server.transport.lwm2m.server.rpc.LwM2MRpcRequestHandler; import org.thingsboard.server.transport.lwm2m.server.session.LwM2MSessionManager; import org.thingsboard.server.transport.lwm2m.server.store.TbLwM2MDtlsSessionStore; import org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil; -import org.thingsboard.server.transport.lwm2m.utils.LwM2MValueConverterImpl; +import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; @@ -129,34 +129,34 @@ import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.fr @Slf4j @Service @TbLwM2mTransportComponent -public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService implements LwM2MUplinkMsgHandler { +public class DefaultLwM2mUplinkMsgHandler extends LwM2MExecutorAwareService implements LwM2mUplinkMsgHandler { - public LwM2MValueConverterImpl converter; + public LwM2mValueConverterImpl converter; private final TransportService transportService; - private final LwM2MTransportContext context; + private final LwM2mTransportContext context; private final LwM2MAttributesService attributesService; private final LwM2MSessionManager sessionManager; private final LwM2MOtaUpdateService otaService; private final LwM2MTransportServerConfig config; private final LwM2MTelemetryLogService logService; - private final LwM2MTransportServerHelper helper; + private final LwM2mTransportServerHelper helper; private final TbLwM2MDtlsSessionStore sessionStore; - private final LwM2MClientContext clientContext; + private final LwM2mClientContext clientContext; private final LwM2MRpcRequestHandler rpcHandler; - private final LwM2MDownlinkMsgHandler defaultLwM2MDownlinkMsgHandler; + private final LwM2mDownlinkMsgHandler defaultLwM2MDownlinkMsgHandler; - public DefaultLwM2MUplinkMsgHandler(TransportService transportService, + public DefaultLwM2mUplinkMsgHandler(TransportService transportService, LwM2MTransportServerConfig config, - LwM2MTransportServerHelper helper, - LwM2MClientContext clientContext, + LwM2mTransportServerHelper helper, + LwM2mClientContext clientContext, LwM2MTelemetryLogService logService, LwM2MSessionManager sessionManager, @Lazy LwM2MOtaUpdateService otaService, @Lazy LwM2MAttributesService attributesService, @Lazy LwM2MRpcRequestHandler rpcHandler, - @Lazy LwM2MDownlinkMsgHandler defaultLwM2MDownlinkMsgHandler, - LwM2MTransportContext context, TbLwM2MDtlsSessionStore sessionStore) { + @Lazy LwM2mDownlinkMsgHandler defaultLwM2MDownlinkMsgHandler, + LwM2mTransportContext context, TbLwM2MDtlsSessionStore sessionStore) { this.transportService = transportService; this.sessionManager = sessionManager; this.attributesService = attributesService; @@ -175,7 +175,7 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl public void init() { super.init(); this.context.getScheduler().scheduleAtFixedRate(this::reportActivity, new Random().nextInt((int) config.getSessionReportTimeout()), config.getSessionReportTimeout(), TimeUnit.MILLISECONDS); - this.converter = LwM2MValueConverterImpl.getInstance(); + this.converter = LwM2mValueConverterImpl.getInstance(); } @PreDestroy @@ -209,7 +209,7 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl */ public void onRegistered(Registration registration, Collection previousObservations) { executor.submit(() -> { - LwM2MClient lwM2MClient = this.clientContext.getClientByEndpoint(registration.getEndpoint()); + LwM2mClient lwM2MClient = this.clientContext.getClientByEndpoint(registration.getEndpoint()); try { log.debug("[{}] [{{}] Client: create after Registration", registration.getEndpoint(), registration.getId()); Optional oldSessionInfo = this.clientContext.register(lwM2MClient, registration); @@ -250,7 +250,7 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl */ public void updatedReg(Registration registration) { executor.submit(() -> { - LwM2MClient lwM2MClient = clientContext.getClientByEndpoint(registration.getEndpoint()); + LwM2mClient lwM2MClient = clientContext.getClientByEndpoint(registration.getEndpoint()); try { log.info("[{}] [{{}] Client: update after Registration", registration.getEndpoint(), registration.getId()); logService.log(lwM2MClient, String.format("[%s][%s] Updated registration.", registration.getId(), registration.getSocketAddress())); @@ -275,7 +275,7 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl */ public void unReg(Registration registration, Collection observations) { executor.submit(() -> { - LwM2MClient client = clientContext.getClientByEndpoint(registration.getEndpoint()); + LwM2mClient client = clientContext.getClientByEndpoint(registration.getEndpoint()); try { logService.log(client, LOG_LWM2M_INFO + ": Client unRegistration"); clientContext.unregister(client, registration); @@ -312,7 +312,7 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl @Override public void onUpdateValueAfterReadResponse(Registration registration, String path, ReadResponse response) { if (response.getContent() != null) { - LwM2MClient lwM2MClient = clientContext.getClientByEndpoint(registration.getEndpoint()); + LwM2mClient lwM2MClient = clientContext.getClientByEndpoint(registration.getEndpoint()); ObjectModel objectModelVersion = lwM2MClient.getObjectModel(path, this.config.getModelProvider()); if (objectModelVersion != null) { if (response.getContent() instanceof LwM2mObject) { @@ -338,7 +338,7 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl public void onUpdateValueAfterReadCompositeResponse(Registration registration, ReadCompositeResponse response) { log.trace("ReadCompositeResponse: [{}]", response); if (response.getContent() != null) { - LwM2MClient lwM2MClient = clientContext.getClientByEndpoint(registration.getEndpoint()); + LwM2mClient lwM2MClient = clientContext.getClientByEndpoint(registration.getEndpoint()); response.getContent().forEach((k, v) -> { if (v != null) { if (v instanceof LwM2mObject) { @@ -367,7 +367,7 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl @Override public void onDeviceProfileUpdate(SessionInfoProto sessionInfo, DeviceProfile deviceProfile) { try { - List clients = clientContext.getLwM2mClients() + List clients = clientContext.getLwM2mClients() .stream().filter(e -> e.getProfileId() != null) .filter(e -> e.getProfileId().equals(deviceProfile.getUuidId())).collect(Collectors.toList()); clients.forEach(client -> client.onDeviceProfileUpdate(deviceProfile)); @@ -382,7 +382,7 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl @Override public void onDeviceUpdate(SessionInfoProto sessionInfo, Device device, Optional deviceProfileOpt) { try { - LwM2MClient client = clientContext.getClientByDeviceId(device.getUuidId()); + LwM2mClient client = clientContext.getClientByDeviceId(device.getUuidId()); if (client != null) { this.onDeviceUpdate(client, device, deviceProfileOpt); } @@ -424,7 +424,7 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl * * @param lwM2MClient - object with All parameters off client */ - private void initClientTelemetry(LwM2MClient lwM2MClient) { + private void initClientTelemetry(LwM2mClient lwM2MClient) { Lwm2mDeviceProfileTransportConfiguration profile = clientContext.getProfile(lwM2MClient.getProfileId()); Set supportedObjects = clientContext.getSupportedIdVerInClient(lwM2MClient); if (supportedObjects != null && supportedObjects.size() > 0) { @@ -436,7 +436,7 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl } } - private void sendReadRequests(LwM2MClient lwM2MClient, Lwm2mDeviceProfileTransportConfiguration profile, Set supportedObjects) { + private void sendReadRequests(LwM2mClient lwM2MClient, Lwm2mDeviceProfileTransportConfiguration profile, Set supportedObjects) { try { Set targetIds = new HashSet<>(profile.getObserveAttr().getAttribute()); targetIds.addAll(profile.getObserveAttr().getTelemetry()); @@ -455,7 +455,7 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl } } - private void sendObserveRequests(LwM2MClient lwM2MClient, Lwm2mDeviceProfileTransportConfiguration profile, Set supportedObjects) { + private void sendObserveRequests(LwM2mClient lwM2MClient, Lwm2mDeviceProfileTransportConfiguration profile, Set supportedObjects) { try { Set targetIds = profile.getObserveAttr().getObserve(); targetIds = targetIds.stream().filter(target -> isSupportedTargetId(supportedObjects, target)).collect(Collectors.toSet()); @@ -473,7 +473,7 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl } } - private void sendWriteAttributeRequests(LwM2MClient lwM2MClient, Lwm2mDeviceProfileTransportConfiguration profile, Set supportedObjects) { + private void sendWriteAttributeRequests(LwM2mClient lwM2MClient, Lwm2mDeviceProfileTransportConfiguration profile, Set supportedObjects) { try { Map attributesMap = profile.getObserveAttr().getAttributeLwm2m(); attributesMap = attributesMap.entrySet().stream().filter(target -> isSupportedTargetId(supportedObjects, target.getKey())).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); @@ -484,35 +484,35 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl } } - private void sendReadRequest(LwM2MClient lwM2MClient, String versionedId) { + private void sendReadRequest(LwM2mClient lwM2MClient, String versionedId) { sendReadRequest(lwM2MClient, versionedId, new TbLwM2MReadCallback(this, logService, lwM2MClient, versionedId)); } - private void sendReadRequest(LwM2MClient lwM2MClient, String versionedId, DownlinkRequestCallback callback) { + private void sendReadRequest(LwM2mClient lwM2MClient, String versionedId, DownlinkRequestCallback callback) { TbLwM2MReadRequest request = TbLwM2MReadRequest.builder().versionedId(versionedId).timeout(clientContext.getRequestTimeout(lwM2MClient)).build(); defaultLwM2MDownlinkMsgHandler.sendReadRequest(lwM2MClient, request, callback); } - private void sendObserveRequest(LwM2MClient lwM2MClient, String versionedId) { + private void sendObserveRequest(LwM2mClient lwM2MClient, String versionedId) { sendObserveRequest(lwM2MClient, versionedId, new TbLwM2MObserveCallback(this, logService, lwM2MClient, versionedId)); } - private void sendObserveRequest(LwM2MClient lwM2MClient, String versionedId, DownlinkRequestCallback callback) { + private void sendObserveRequest(LwM2mClient lwM2MClient, String versionedId, DownlinkRequestCallback callback) { TbLwM2MObserveRequest request = TbLwM2MObserveRequest.builder().versionedId(versionedId).timeout(clientContext.getRequestTimeout(lwM2MClient)).build(); defaultLwM2MDownlinkMsgHandler.sendObserveRequest(lwM2MClient, request, callback); } - private void sendWriteAttributesRequest(LwM2MClient lwM2MClient, String targetId, ObjectAttributes params) { + private void sendWriteAttributesRequest(LwM2mClient lwM2MClient, String targetId, ObjectAttributes params) { TbLwM2MWriteAttributesRequest request = TbLwM2MWriteAttributesRequest.builder().versionedId(targetId).attributes(params).timeout(clientContext.getRequestTimeout(lwM2MClient)).build(); defaultLwM2MDownlinkMsgHandler.sendWriteAttributesRequest(lwM2MClient, request, new TbLwM2MWriteAttributesCallback(logService, lwM2MClient, targetId)); } - private void sendCancelObserveRequest(String versionedId, LwM2MClient client) { + private void sendCancelObserveRequest(String versionedId, LwM2mClient client) { TbLwM2MCancelObserveRequest request = TbLwM2MCancelObserveRequest.builder().versionedId(versionedId).timeout(clientContext.getRequestTimeout(client)).build(); defaultLwM2MDownlinkMsgHandler.sendCancelObserveRequest(client, request, new TbLwM2MCancelObserveCallback(logService, client, versionedId)); } - private void updateObjectResourceValue(LwM2MClient client, LwM2mObject lwM2mObject, String pathIdVer, int code) { + private void updateObjectResourceValue(LwM2mClient client, LwM2mObject lwM2mObject, String pathIdVer, int code) { LwM2mPath pathIds = new LwM2mPath(fromVersionedIdToObjectId(pathIdVer)); lwM2mObject.getInstances().forEach((instanceId, instance) -> { String pathInstance = pathIds.toString() + "/" + instanceId; @@ -520,7 +520,7 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl }); } - private void updateObjectInstanceResourceValue(LwM2MClient client, LwM2mObjectInstance lwM2mObjectInstance, String pathIdVer, int code) { + private void updateObjectInstanceResourceValue(LwM2mClient client, LwM2mObjectInstance lwM2mObjectInstance, String pathIdVer, int code) { LwM2mPath pathIds = new LwM2mPath(fromVersionedIdToObjectId(pathIdVer)); lwM2mObjectInstance.getResources().forEach((resourceId, resource) -> { String pathRez = pathIds.toString() + "/" + resourceId; @@ -539,7 +539,7 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl * @param path - resource * @param mode - Replace, Update */ - private void updateResourcesValue(LwM2MClient lwM2MClient, LwM2mResource lwM2mResource, String path, Mode mode, int code) { + private void updateResourcesValue(LwM2mClient lwM2MClient, LwM2mResource lwM2mResource, String path, Mode mode, int code) { Registration registration = lwM2MClient.getRegistration(); if (lwM2MClient.saveResourceValue(path, lwM2mResource, this.config.getModelProvider(), mode)) { if (path.equals(convertObjectIdToVersionedId(FW_NAME_ID, registration))) { @@ -622,7 +622,7 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl return pathAttributes; } - private void onDeviceUpdate(LwM2MClient lwM2MClient, Device device, Optional deviceProfileOpt) { + private void onDeviceUpdate(LwM2mClient lwM2MClient, Device device, Optional deviceProfileOpt) { deviceProfileOpt.ifPresent(deviceProfile -> this.onDeviceProfileUpdate(Collections.singletonList(lwM2MClient), deviceProfile)); lwM2MClient.onDeviceUpdate(device, deviceProfileOpt); } @@ -668,7 +668,7 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl } private TransportProtos.KeyValueProto getKvToThingsBoard(String pathIdVer, Registration registration) { - LwM2MClient lwM2MClient = this.clientContext.getClientByEndpoint(registration.getEndpoint()); + LwM2mClient lwM2MClient = this.clientContext.getClientByEndpoint(registration.getEndpoint()); Map names = clientContext.getProfile(lwM2MClient.getProfileId()).getObserveAttr().getKeyName(); if (names != null && names.containsKey(pathIdVer)) { String resourceName = names.get(pathIdVer); @@ -695,7 +695,7 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl valueKvProto = this.converter.convertValue(resourceValue.getValue(), currentType, expectedType, new LwM2mPath(fromVersionedIdToObjectId(pathIdVer))); } - LwM2MOtaConvert lwM2mOtaConvert = convertOtaUpdateValueToString(pathIdVer, valueKvProto, currentType); + LwM2mOtaConvert lwM2mOtaConvert = convertOtaUpdateValueToString(pathIdVer, valueKvProto, currentType); valueKvProto = lwM2mOtaConvert.getValue(); currentType = lwM2mOtaConvert.getCurrentType(); return valueKvProto != null ? this.helper.getKvAttrTelemetryToThingsboard(currentType, resourceName, valueKvProto, resourceValue.isMultiInstances()) : null; @@ -711,7 +711,7 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl } @Override - public void onWriteResponseOk(LwM2MClient client, String path, WriteRequest request, int code) { + public void onWriteResponseOk(LwM2mClient client, String path, WriteRequest request, int code) { if (request.getNode() instanceof LwM2mResource) { this.updateResourcesValue(client, ((LwM2mResource) request.getNode()), path, request.isReplaceRequest() ? Mode.REPLACE : Mode.UPDATE, code); } else if (request.getNode() instanceof LwM2mObjectInstance) { @@ -725,7 +725,7 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl } @Override - public void onCreateResponseOk(LwM2MClient client, String path, CreateRequest request) { + public void onCreateResponseOk(LwM2mClient client, String path, CreateRequest request) { if (request.getObjectInstances() != null && request.getObjectInstances().size() > 0) { request.getObjectInstances().forEach(instance -> instance.getResources() @@ -735,7 +735,7 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl } @Override - public void onWriteCompositeResponseOk(LwM2MClient client, WriteCompositeRequest request, int code) { + public void onWriteCompositeResponseOk(LwM2mClient client, WriteCompositeRequest request, int code) { log.trace("ReadCompositeResponse: [{}]", request.getNodes()); request.getNodes().forEach((k, v) -> { if (v instanceof LwM2mSingleResource) { @@ -749,7 +749,7 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl } //TODO: review and optimize the logic to minimize number of the requests to device. - private void onDeviceProfileUpdate(List clients, DeviceProfile deviceProfile) { + private void onDeviceProfileUpdate(List clients, DeviceProfile deviceProfile) { var oldProfile = clientContext.getProfile(deviceProfile.getUuidId()); if (clientContext.profileUpdate(deviceProfile) != null) { // #1 @@ -851,7 +851,7 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl * #6.1 - send update WriteAttribute * #6.2 - send empty WriteAttribute */ - private void compareAndSendWriteAttributes(List clients, Map lwm2mAttributesOld, Map lwm2mAttributesNew) { + private void compareAndSendWriteAttributes(List clients, Map lwm2mAttributesOld, Map lwm2mAttributesNew) { ParametersAnalyzeResult analyzerParameters = new ParametersAnalyzeResult(); Set pathOld = lwm2mAttributesOld.keySet(); Set pathNew = lwm2mAttributesNew.keySet(); @@ -903,7 +903,7 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl * @param lwM2MClient - * @return SessionInfoProto - */ - private SessionInfoProto getSessionInfo(LwM2MClient lwM2MClient) { + private SessionInfoProto getSessionInfo(LwM2mClient lwM2MClient) { if (lwM2MClient != null && lwM2MClient.getSession() != null) { return lwM2MClient.getSession(); } @@ -944,7 +944,7 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl * * @param lwM2MClient - LwM2M Client */ - public void initAttributes(LwM2MClient lwM2MClient, boolean logFailedUpdateOfNonChangedValue) { + public void initAttributes(LwM2mClient lwM2MClient, boolean logFailedUpdateOfNonChangedValue) { Map keyNamesMap = this.getNamesFromProfileForSharedAttributes(lwM2MClient); if (!keyNamesMap.isEmpty()) { Set keysToFetch = new HashSet<>(keyNamesMap.values()); @@ -957,7 +957,7 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl } } - private Map getNamesFromProfileForSharedAttributes(LwM2MClient lwM2MClient) { + private Map getNamesFromProfileForSharedAttributes(LwM2mClient lwM2MClient) { Lwm2mDeviceProfileTransportConfiguration profile = clientContext.getProfile(lwM2MClient.getProfileId()); return profile.getObserveAttr().getKeyName(); } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/LwM2MTypeServer.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/LwM2mTypeServer.java similarity index 83% rename from common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/LwM2MTypeServer.java rename to common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/LwM2mTypeServer.java index 63f7431cd2..0ecd59f41c 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/LwM2MTypeServer.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/LwM2mTypeServer.java @@ -15,20 +15,20 @@ */ package org.thingsboard.server.transport.lwm2m.server.uplink; -public enum LwM2MTypeServer { +public enum LwM2mTypeServer { BOOTSTRAP(0, "bootstrap"), CLIENT(1, "client"); public int code; public String type; - LwM2MTypeServer(int code, String type) { + LwM2mTypeServer(int code, String type) { this.code = code; this.type = type; } - public static LwM2MTypeServer fromLwM2mTypeServer(String type) { - for (LwM2MTypeServer sm : LwM2MTypeServer.values()) { + public static LwM2mTypeServer fromLwM2mTypeServer(String type) { + for (LwM2mTypeServer sm : LwM2mTypeServer.values()) { if (sm.type.equals(type)) { return sm; } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/LwM2MUplinkMsgHandler.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/LwM2mUplinkMsgHandler.java similarity index 91% rename from common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/LwM2MUplinkMsgHandler.java rename to common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/LwM2mUplinkMsgHandler.java index 6650795f98..af0d349687 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/LwM2MUplinkMsgHandler.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/LwM2mUplinkMsgHandler.java @@ -26,12 +26,12 @@ import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; -import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClient; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; import java.util.Collection; import java.util.Optional; -public interface LwM2MUplinkMsgHandler { +public interface LwM2mUplinkMsgHandler { void onRegistered(Registration registration, Collection previousObsersations); @@ -55,11 +55,11 @@ public interface LwM2MUplinkMsgHandler { void onAwakeDev(Registration registration); - void onWriteResponseOk(LwM2MClient client, String path, WriteRequest request, int code); + void onWriteResponseOk(LwM2mClient client, String path, WriteRequest request, int code); - void onCreateResponseOk(LwM2MClient client, String path, CreateRequest request); + void onCreateResponseOk(LwM2mClient client, String path, CreateRequest request); - void onWriteCompositeResponseOk(LwM2MClient client, WriteCompositeRequest request, int code); + void onWriteCompositeResponseOk(LwM2mClient client, WriteCompositeRequest request, int code); void onToTransportUpdateCredentials(TransportProtos.SessionInfoProto sessionInfo, TransportProtos.ToTransportUpdateCredentialsProto updateCredentials); diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2MTransportUtil.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2MTransportUtil.java index 311a806afa..1a209fd7a3 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2MTransportUtil.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2MTransportUtil.java @@ -45,15 +45,15 @@ import org.thingsboard.server.common.data.device.profile.Lwm2mDeviceProfileTrans import org.thingsboard.server.common.data.ota.OtaPackageKey; import org.thingsboard.server.common.transport.util.JsonUtils; import org.thingsboard.server.transport.lwm2m.config.LwM2mVersion; -import org.thingsboard.server.transport.lwm2m.server.LwM2MOtaConvert; -import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClient; +import org.thingsboard.server.transport.lwm2m.server.LwM2mOtaConvert; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; import org.thingsboard.server.transport.lwm2m.server.client.ResourceValue; import org.thingsboard.server.transport.lwm2m.server.downlink.HasVersionedId; import org.thingsboard.server.transport.lwm2m.server.ota.firmware.FirmwareUpdateResult; import org.thingsboard.server.transport.lwm2m.server.ota.firmware.FirmwareUpdateState; import org.thingsboard.server.transport.lwm2m.server.ota.software.SoftwareUpdateResult; import org.thingsboard.server.transport.lwm2m.server.ota.software.SoftwareUpdateState; -import org.thingsboard.server.transport.lwm2m.server.uplink.DefaultLwM2MUplinkMsgHandler; +import org.thingsboard.server.transport.lwm2m.server.uplink.DefaultLwM2mUplinkMsgHandler; import java.util.ArrayList; import java.util.Arrays; @@ -144,9 +144,9 @@ public class LwM2MTransportUtil { } } - public static LwM2MOtaConvert convertOtaUpdateValueToString(String pathIdVer, Object value, ResourceModel.Type currentType) { + public static LwM2mOtaConvert convertOtaUpdateValueToString(String pathIdVer, Object value, ResourceModel.Type currentType) { String path = fromVersionedIdToObjectId(pathIdVer); - LwM2MOtaConvert lwM2mOtaConvert = new LwM2MOtaConvert(); + LwM2mOtaConvert lwM2mOtaConvert = new LwM2mOtaConvert(); if (path != null) { if (FW_STATE_ID.equals(path)) { lwM2mOtaConvert.setCurrentType(STRING); @@ -289,12 +289,12 @@ public class LwM2MTransportUtil { * Attribute pmax = new Attribute(MAXIMUM_PERIOD, "60"); * Attribute [] attrs = {gt, st}; */ - public static SimpleDownlinkRequest createWriteAttributeRequest(String target, Object params, DefaultLwM2MUplinkMsgHandler serviceImpl) { + public static SimpleDownlinkRequest createWriteAttributeRequest(String target, Object params, DefaultLwM2mUplinkMsgHandler serviceImpl) { AttributeSet attrSet = new AttributeSet(createWriteAttributes(params, serviceImpl, target)); return attrSet.getAttributes().size() > 0 ? new WriteAttributesRequest(target, attrSet) : null; } - private static Attribute[] createWriteAttributes(Object params, DefaultLwM2MUplinkMsgHandler serviceImpl, String target) { + private static Attribute[] createWriteAttributes(Object params, DefaultLwM2mUplinkMsgHandler serviceImpl, String target) { List attributeLists = new ArrayList<>(); Map map = JacksonUtil.convertValue(params, new TypeReference<>() { }); @@ -339,7 +339,7 @@ public class LwM2MTransportUtil { } } - public static void validateVersionedId(LwM2MClient client, HasVersionedId request) { + public static void validateVersionedId(LwM2mClient client, HasVersionedId request) { String msgExceptionStr = ""; if (request.getObjectId() == null) { msgExceptionStr = "Specified object id is null!"; @@ -360,7 +360,7 @@ public class LwM2MTransportUtil { public static Map convertMultiResourceValuesFromJson(JsonElement newValProto, ResourceModel.Type type, String versionedId) throws Exception{ Map newValues = equalsMultiResourceValuesResourceType(type); newValProto.getAsJsonObject().entrySet().forEach((obj) -> { - newValues.put(Integer.valueOf(obj.getKey()), LwM2MValueConverterImpl.getInstance().convertValue(obj.getValue().getAsString(), + newValues.put(Integer.valueOf(obj.getKey()), LwM2mValueConverterImpl.getInstance().convertValue(obj.getValue().getAsString(), STRING, type, new LwM2mPath(fromVersionedIdToObjectId(versionedId)))); }); return newValues; @@ -387,7 +387,7 @@ public class LwM2MTransportUtil { } } - public static Object convertWriteAttributes(String type, Object value, DefaultLwM2MUplinkMsgHandler serviceImpl, String target) { + public static Object convertWriteAttributes(String type, Object value, DefaultLwM2mUplinkMsgHandler serviceImpl, String target) { switch (type) { /** Integer [0:255]; */ case DIMENSION: @@ -427,7 +427,7 @@ public class LwM2MTransportUtil { * @param path - * @return - return value of Resource by idPath */ - public static LwM2mResource getResourceValueFromLwM2MClient(LwM2MClient lwM2MClient, String path) { + public static LwM2mResource getResourceValueFromLwM2MClient(LwM2mClient lwM2MClient, String path) { LwM2mResource lwm2mResourceValue = null; ResourceValue resourceValue = lwM2MClient.getResources().get(path); if (resourceValue != null) { diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2MValueConverterImpl.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2mValueConverterImpl.java similarity index 97% rename from common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2MValueConverterImpl.java rename to common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2mValueConverterImpl.java index 1c5dcdff95..0427caa3a6 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2MValueConverterImpl.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2mValueConverterImpl.java @@ -33,11 +33,11 @@ import java.util.Date; import static org.eclipse.leshan.core.model.ResourceModel.Type.OPAQUE; @Slf4j -public class LwM2MValueConverterImpl implements LwM2mValueConverter { +public class LwM2mValueConverterImpl implements LwM2mValueConverter { - private static final LwM2MValueConverterImpl INSTANCE = new LwM2MValueConverterImpl(); + private static final LwM2mValueConverterImpl INSTANCE = new LwM2mValueConverterImpl(); - public static LwM2MValueConverterImpl getInstance() { + public static LwM2mValueConverterImpl getInstance() { return INSTANCE; } From bb2efb145bd4e848ef33b6b85bbfd95bebe9096e Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Thu, 23 Sep 2021 13:24:48 +0300 Subject: [PATCH 046/432] UI: Remove HEX and length validations in device lwm2m credentials --- ...ce-credentials-lwm2m-server.component.html | 16 --------- ...vice-credentials-lwm2m-server.component.ts | 34 ++----------------- .../device-credentials-lwm2m.component.html | 12 ------- .../device-credentials-lwm2m.component.ts | 21 +----------- .../lwm2m-device-config-server.component.html | 3 -- .../lwm2m-device-config-server.component.ts | 6 +--- .../lwm2m/lwm2m-profile-config.models.ts | 1 - .../models/lwm2m-security-config.models.ts | 4 --- .../assets/locale/locale.constant-cs_CZ.json | 6 ---- .../assets/locale/locale.constant-en_US.json | 6 ---- .../assets/locale/locale.constant-tr_TR.json | 6 ---- 11 files changed, 5 insertions(+), 110 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/device/device-credentials-lwm2m-server.component.html b/ui-ngx/src/app/modules/home/components/device/device-credentials-lwm2m-server.component.html index 429a13ddb2..3c3806882f 100644 --- a/ui-ngx/src/app/modules/home/components/device/device-credentials-lwm2m-server.component.html +++ b/ui-ngx/src/app/modules/home/components/device/device-credentials-lwm2m-server.component.html @@ -37,35 +37,19 @@ {{ 'device.lwm2m-security-config.client-publicKey-or-id-required' | translate }} - - {{ 'device.lwm2m-security-config.client-publicKey-or-id-pattern' | translate }} - {{ 'device.lwm2m-security-config.client-secret-key' | translate }} - - {{clientSecretKey.value?.length || 0}}/{{lengthClientSecretKey}} - {{ 'device.lwm2m-security-config.client-secret-key-required' | translate }} - - {{ 'device.lwm2m-security-config.client-secret-key-pattern' | translate }} - - - {{ 'device.lwm2m-security-config.client-secret-key-length' | translate: { - count: allowLengthKey.join(', ') - } }} - diff --git a/ui-ngx/src/app/modules/home/components/device/device-credentials-lwm2m-server.component.ts b/ui-ngx/src/app/modules/home/components/device/device-credentials-lwm2m-server.component.ts index 7c6ad485f3..96b1e74fb9 100644 --- a/ui-ngx/src/app/modules/home/components/device/device-credentials-lwm2m-server.component.ts +++ b/ui-ngx/src/app/modules/home/components/device/device-credentials-lwm2m-server.component.ts @@ -16,7 +16,6 @@ import { Component, forwardRef, OnDestroy } from '@angular/core'; import { - AbstractControl, ControlValueAccessor, FormBuilder, FormGroup, @@ -27,9 +26,6 @@ import { Validators } from '@angular/forms'; import { - KEY_REGEXP_HEX_DEC, - LEN_MAX_PRIVATE_KEY, - LEN_MAX_PSK, Lwm2mSecurityType, Lwm2mSecurityTypeTranslationMap, ServerSecurityConfig @@ -61,8 +57,6 @@ export class DeviceCredentialsLwm2mServerComponent implements OnDestroy, Control securityConfigLwM2MType = Lwm2mSecurityType; securityConfigLwM2MTypes = Object.values(Lwm2mSecurityType); lwm2mSecurityTypeTranslationMap = Lwm2mSecurityTypeTranslationMap; - lengthClientSecretKey = LEN_MAX_PRIVATE_KEY; - allowLengthKey = [32, 64, LEN_MAX_PSK]; private destroy$ = new Subject(); private propagateChange = (v: any) => {}; @@ -132,30 +126,18 @@ export class DeviceCredentialsLwm2mServerComponent implements OnDestroy, Control this.serverFormGroup.get('clientSecretKey').disable(); break; case Lwm2mSecurityType.PSK: - this.lengthClientSecretKey = LEN_MAX_PSK; - this.setValidatorsSecurity(securityMode); - break; case Lwm2mSecurityType.RPK: - this.lengthClientSecretKey = null; - this.setValidatorsSecurity(securityMode); - break; case Lwm2mSecurityType.X509: - this.lengthClientSecretKey = null; - this.setValidatorsSecurity(securityMode); + this.setValidatorsSecurity(); break; } this.serverFormGroup.get('clientPublicKeyOrId').updateValueAndValidity({emitEvent: false}); this.serverFormGroup.get('clientSecretKey').updateValueAndValidity({emitEvent: !initValue}); } - private setValidatorsSecurity = (securityMode: Lwm2mSecurityType): void => { - const clientSecretKeyValidators = [Validators.required, Validators.pattern(KEY_REGEXP_HEX_DEC)]; + private setValidatorsSecurity = (): void => { + const clientSecretKeyValidators = [Validators.required]; const clientPublicKeyOrIdValidators = [Validators.required]; - if (securityMode === Lwm2mSecurityType.PSK) { - clientSecretKeyValidators.push(this.maxLength(this.allowLengthKey)); - } else { - clientPublicKeyOrIdValidators.push(Validators.pattern(KEY_REGEXP_HEX_DEC)); - } this.serverFormGroup.get('clientPublicKeyOrId').setValidators(clientPublicKeyOrIdValidators); this.serverFormGroup.get('clientSecretKey').setValidators(clientSecretKeyValidators); @@ -163,14 +145,4 @@ export class DeviceCredentialsLwm2mServerComponent implements OnDestroy, Control this.serverFormGroup.get('clientPublicKeyOrId').enable({emitEvent: false}); this.serverFormGroup.get('clientSecretKey').enable(); } - - private maxLength(keyLengths: number[]) { - return (control: AbstractControl): ValidationErrors | null => { - const value = control.value; - if (keyLengths.some(len => value.length === len)) { - return null; - } - return {length: true}; - }; - } } diff --git a/ui-ngx/src/app/modules/home/components/device/device-credentials-lwm2m.component.html b/ui-ngx/src/app/modules/home/components/device/device-credentials-lwm2m.component.html index b588f1af72..b10eaf68ae 100644 --- a/ui-ngx/src/app/modules/home/components/device/device-credentials-lwm2m.component.html +++ b/ui-ngx/src/app/modules/home/components/device/device-credentials-lwm2m.component.html @@ -45,27 +45,15 @@ lwm2mConfigFormGroup.get('client.securityConfigClientMode').value === securityConfigLwM2MType.PSK"> {{ 'device.lwm2m-security-config.client-key' | translate }} - {{key.value?.length || 0}}/{{lenMaxKeyClient}} {{ 'device.lwm2m-security-config.client-key-required' | translate }} - - {{ 'device.lwm2m-security-config.client-key-pattern' | translate }} - - - {{ 'device.lwm2m-security-config.client-key-length' | translate: { - count: allowLengthKey.join(', ') - } }} - device.lwm2m-security-config.client-public-key diff --git a/ui-ngx/src/app/modules/home/components/device/device-credentials-lwm2m.component.ts b/ui-ngx/src/app/modules/home/components/device/device-credentials-lwm2m.component.ts index ff5fba9bdd..1645d3317d 100644 --- a/ui-ngx/src/app/modules/home/components/device/device-credentials-lwm2m.component.ts +++ b/ui-ngx/src/app/modules/home/components/device/device-credentials-lwm2m.component.ts @@ -16,7 +16,6 @@ import { Component, forwardRef, OnDestroy } from '@angular/core'; import { - AbstractControl, ControlValueAccessor, FormBuilder, FormGroup, @@ -29,8 +28,6 @@ import { import { getDefaultClientSecurityConfig, getDefaultServerSecurityConfig, - KEY_REGEXP_HEX_DEC, - LEN_MAX_PSK, Lwm2mSecurityConfigModels, Lwm2mSecurityType, Lwm2mSecurityTypeTranslationMap @@ -63,8 +60,6 @@ export class DeviceCredentialsLwm2mComponent implements ControlValueAccessor, Va securityConfigLwM2MType = Lwm2mSecurityType; securityConfigLwM2MTypes = Object.keys(Lwm2mSecurityType); credentialTypeLwM2MNamesMap = Lwm2mSecurityTypeTranslationMap; - lenMaxKeyClient = LEN_MAX_PSK; - allowLengthKey = [32, 64, LEN_MAX_PSK]; private destroy$ = new Subject(); private propagateChange = (v: any) => {}; @@ -135,12 +130,10 @@ export class DeviceCredentialsLwm2mComponent implements ControlValueAccessor, Va this.lwm2mConfigFormGroup.get('client.cert').enable({emitEvent: false}); break; case Lwm2mSecurityType.PSK: - this.lenMaxKeyClient = LEN_MAX_PSK; this.setValidatorsPskRpk(mode); this.lwm2mConfigFormGroup.get('client.identity').enable({emitEvent: false}); break; case Lwm2mSecurityType.RPK: - this.lenMaxKeyClient = null; this.setValidatorsPskRpk(mode); this.lwm2mConfigFormGroup.get('client.identity').disable({emitEvent: false}); break; @@ -157,28 +150,16 @@ export class DeviceCredentialsLwm2mComponent implements ControlValueAccessor, Va } private setValidatorsPskRpk = (mode: Lwm2mSecurityType): void => { - const keyValidators = [Validators.required, Validators.pattern(KEY_REGEXP_HEX_DEC)]; if (mode === Lwm2mSecurityType.PSK) { this.lwm2mConfigFormGroup.get('client.identity').setValidators([Validators.required]); - keyValidators.push(this.maxLength(this.allowLengthKey)); } else { this.lwm2mConfigFormGroup.get('client.identity').clearValidators(); } - this.lwm2mConfigFormGroup.get('client.key').setValidators(keyValidators); + this.lwm2mConfigFormGroup.get('client.key').setValidators([Validators.required]); this.lwm2mConfigFormGroup.get('client.key').enable({emitEvent: false}); this.lwm2mConfigFormGroup.get('client.cert').disable({emitEvent: false}); } - private maxLength(keyLengths: number[]) { - return (control: AbstractControl): ValidationErrors | null => { - const value = control.value; - if (keyLengths.some(len => value.length === len)) { - return null; - } - return {length: true}; - }; - } - private initLwm2mConfigForm = (): FormGroup => { const formGroup = this.fb.group({ client: this.fb.group({ diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-config-server.component.html b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-config-server.component.html index b2d69c252f..9c2ce132d8 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-config-server.component.html +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-config-server.component.html @@ -103,9 +103,6 @@ {{ 'device-profile.lwm2m.server-public-key-required' | translate }} - - {{ 'device-profile.lwm2m.server-public-key-pattern' | translate }} - diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-config-server.component.ts b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-config-server.component.ts index 63cde444ba..93c22d44b1 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-config-server.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-config-server.component.ts @@ -28,7 +28,6 @@ import { import { DEFAULT_PORT_BOOTSTRAP_NO_SEC, DEFAULT_PORT_SERVER_NO_SEC, - KEY_REGEXP_HEX_DEC, securityConfigMode, securityConfigModeNames, ServerSecurityConfig @@ -158,10 +157,7 @@ export class Lwm2mDeviceConfigServerComponent implements OnInit, ControlValueAcc } private setValidators(): void { - this.serverFormGroup.get('serverPublicKey').setValidators([ - Validators.required, - Validators.pattern(KEY_REGEXP_HEX_DEC) - ]); + this.serverFormGroup.get('serverPublicKey').setValidators([Validators.required]); } private propagateChangeState = (value: ServerSecurityConfig): void => { diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-profile-config.models.ts b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-profile-config.models.ts index 3be58c7f7f..2845ad75b3 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-profile-config.models.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-profile-config.models.ts @@ -34,7 +34,6 @@ export const DEFAULT_MIN_PERIOD = 1; export const DEFAULT_NOTIF_IF_DESIBLED = true; export const DEFAULT_BINDING = 'UQ'; export const DEFAULT_BOOTSTRAP_SERVER_ACCOUNT_TIME_OUT = 0; -export const KEY_REGEXP_HEX_DEC = /^[-+]?[0-9A-Fa-f]+\.?[0-9A-Fa-f]*?$/; export const INSTANCES_ID_VALUE_MIN = 0; export const INSTANCES_ID_VALUE_MAX = 65535; export const DEFAULT_OTA_UPDATE_PROTOCOL = 'coap://'; diff --git a/ui-ngx/src/app/shared/models/lwm2m-security-config.models.ts b/ui-ngx/src/app/shared/models/lwm2m-security-config.models.ts index d18ea56644..d3b4171b80 100644 --- a/ui-ngx/src/app/shared/models/lwm2m-security-config.models.ts +++ b/ui-ngx/src/app/shared/models/lwm2m-security-config.models.ts @@ -14,10 +14,6 @@ /// limitations under the License. /// -export const LEN_MAX_PSK = 128; -export const LEN_MAX_PRIVATE_KEY = 134; -export const KEY_REGEXP_HEX_DEC = /^[-+]?[0-9A-Fa-f]+\.?[0-9A-Fa-f]*?$/; - export enum Lwm2mSecurityType { PSK = 'PSK', RPK = 'RPK', diff --git a/ui-ngx/src/assets/locale/locale.constant-cs_CZ.json b/ui-ngx/src/assets/locale/locale.constant-cs_CZ.json index b5a23c0150..4e1ec64412 100644 --- a/ui-ngx/src/assets/locale/locale.constant-cs_CZ.json +++ b/ui-ngx/src/assets/locale/locale.constant-cs_CZ.json @@ -961,8 +961,6 @@ "identity-required": "Identita klienta je povinná.", "client-key": "Klíč klienta", "client-key-required": "Klíč klienta je povinný.", - "client-key-pattern": "Klíč klienta musí být v hexadecimálním formátu.", - "client-key-length": "Klíč klienta musí mít {{ count }} znaků.", "endpoint": "Název endpointu klienta", "endpoint-required": "Název endpointu klienta je povinný.", "mode": "Režim konfigurace bezpečnosti", @@ -973,11 +971,8 @@ "lwm2m-server": "LwM2M server", "client-publicKey-or-id": "Veřejný klíč nebo Id klienta", "client-publicKey-or-id-required": "Veřejný klíč nebo Id klienta jsou povinné.", - "client-publicKey-or-id-pattern": "Veřejný klíč klienta nebo Id musí být v hexadecimálním formátu.", "client-secret-key": "Tajný klíč klienta", "client-secret-key-required": "Tajný klíč klienta je povinný.", - "client-secret-key-pattern": "Tajný klíč klienta musí být v hexadecimálním formátu.", - "client-secret-key-length": "Tajný klíč klienta musí mít {{ count }} znaků.", "client-public-key": "Veřejný klíč klienta", "client-public-key-hint": "Jestliže je veřejný klíč klienta prázdný, bude použit důvěryhodný certifikát" }, @@ -1299,7 +1294,6 @@ "server-port-range": "Port by měl být v rozsahu od 1 do 65535.", "server-public-key": "Veřejný klíč serveru", "server-public-key-required": "Veřejný klíč serveru je povinný.", - "server-public-key-pattern": "Veřejný klíč serveru musí být v hexadecimálním formátu.", "client-hold-off-time": "Čas odložení", "client-hold-off-time-required": "Čas odloženíje povinný.", "client-hold-off-time-pattern": "Čas odložení musí být kladné celé číslo.", diff --git a/ui-ngx/src/assets/locale/locale.constant-en_US.json b/ui-ngx/src/assets/locale/locale.constant-en_US.json index 7bea6e6097..4bbde6c029 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -965,8 +965,6 @@ "identity-required": "Client Identity is required.", "client-key": "Client Key", "client-key-required": "Client Key is required.", - "client-key-pattern": "Client Key must be hexadecimal format.", - "client-key-length": "Client Key must be {{ count }} characters.", "endpoint": "Endpoint Client Name", "endpoint-required": "Endpoint Client Name is required.", "mode": "Security config mode", @@ -977,11 +975,8 @@ "lwm2m-server": "LwM2M Server", "client-publicKey-or-id": "Client Public Key or Id", "client-publicKey-or-id-required": "Client Public Key or Id is required.", - "client-publicKey-or-id-pattern": "Client Public Key or Id must be hexadecimal format.", "client-secret-key": "Client Secret Key", "client-secret-key-required": "Client Secret Key is required.", - "client-secret-key-pattern": "Client Secret Key must be hexadecimal format.", - "client-secret-key-length": "Client Secret Key must be {{ count }} characters.", "client-public-key": "Client public key", "client-public-key-hint": "If client public key is empty, the trusted certificate will be used" }, @@ -1313,7 +1308,6 @@ "server-port-range": "Port should be in a range from 1 to 65535.", "server-public-key": "Server Public Key", "server-public-key-required": "Server Public Key is required.", - "server-public-key-pattern": "Server Public Key must be hex decimal format.", "client-hold-off-time": "Hold Off Time", "client-hold-off-time-required": "Hold Off Time is required.", "client-hold-off-time-pattern": "Hold Off Time must be a positive integer.", diff --git a/ui-ngx/src/assets/locale/locale.constant-tr_TR.json b/ui-ngx/src/assets/locale/locale.constant-tr_TR.json index 087060361b..c600cb0c9a 100644 --- a/ui-ngx/src/assets/locale/locale.constant-tr_TR.json +++ b/ui-ngx/src/assets/locale/locale.constant-tr_TR.json @@ -964,8 +964,6 @@ "identity-required": "İstemci Kimliği gerekli.", "client-key": "İstemci Anahtarı", "client-key-required": "İstemci Anahtarı gerekli.", - "client-key-pattern": "İstemci Anahtarı onaltılık biçimde olmalıdır.", - "client-key-length": "İstemci Anahtarı {{ sayı }} karakter olmalıdır.", "endpoint": "Uç Nokta İstemci Adı", "endpoint-required": "Uç Nokta İstemci Adı gerekli.", "mode": "Güvenlik yapılandırma modu", @@ -976,11 +974,8 @@ "lwm2m-server": "LwM2M Sunucusu", "client-publicKey-or-id": "İstemci Genel Anahtarı veya Kimliği", "client-publicKey-or-id-required": "İstemci Genel Anahtarı veya Kimliği gerekli.", - "client-publicKey-or-id-pattern": "İstemci Genel Anahtarı veya Kimliği onaltılık biçimde olmalıdır.", "client-secret-key": "İstemci Gizli Anahtarı", "client-secret-key-required": "İstemci Gizli Anahtarı gerekli.", - "client-secret-key-pattern": "İstemci Gizli Anahtarı onaltılık biçimde olmalıdır.", - "client-secret-key-length": "İstemci Gizli Anahtarı {{ sayı }} karakter olmalıdır.", "client-public-key": "İstemci açık anahtarı", "client-public-key-hint": "İstemci açık anahtarı boşsa, güvenilen sertifika kullanılacaktır." }, @@ -1312,7 +1307,6 @@ "server-port-range": "Port 1 ila 65535 aralığında olmalıdır.", "server-public-key": "Sunucu Açık Anahtarı", "server-public-key-required": "Sunucu Açık Anahtarı gerekli.", - "server-public-key-pattern": "Sunucu Açık Anahtarı onaltılık biçimde olmalıdır.", "client-hold-off-time": "Bekleme Süresi", "client-hold-off-time-required": "Bekleme Süresi gerekli.", "client-hold-off-time-pattern": "Bekleme Süresi pozitif bir tam sayı olmalıdır.", From 287657ae861bd136e0733aa394b1d7c032faef71 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Mon, 27 Sep 2021 17:54:28 +0300 Subject: [PATCH 047/432] Lwm2m credentials base64 validate back --- ...AbstractLwM2MClientCredentialsWithKey.java | 6 +-- ...bstractLwM2MServerCredentialsWithKeys.java | 4 +- .../lwm2m/X509ClientCredentials.java | 14 ++++++ .../device/DeviceCredentialsServiceImpl.java | 46 +++++++++---------- 4 files changed, 40 insertions(+), 30 deletions(-) diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/AbstractLwM2MClientCredentialsWithKey.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/AbstractLwM2MClientCredentialsWithKey.java index 2a3c0ab434..4279694909 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/AbstractLwM2MClientCredentialsWithKey.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/AbstractLwM2MClientCredentialsWithKey.java @@ -19,7 +19,7 @@ import com.fasterxml.jackson.annotation.JsonIgnore; import lombok.Getter; import lombok.Setter; import lombok.SneakyThrows; -import org.apache.commons.codec.binary.Hex; +import org.apache.commons.codec.binary.Base64; public abstract class AbstractLwM2MClientCredentialsWithKey extends AbstractLwM2MClientCredentials { @Getter @@ -30,9 +30,9 @@ public abstract class AbstractLwM2MClientCredentialsWithKey extends AbstractLwM2 @SneakyThrows @JsonIgnore - public byte[] getDecodedKey() { + public byte[] getDecodedKey() throws IllegalArgumentException { if (keyInBytes == null) { - keyInBytes = Hex.decodeHex(key.toLowerCase().toCharArray()); + keyInBytes = Base64.decodeBase64(key.getBytes()); } return keyInBytes; } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/AbstractLwM2MServerCredentialsWithKeys.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/AbstractLwM2MServerCredentialsWithKeys.java index c45fb3891b..c46962fc91 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/AbstractLwM2MServerCredentialsWithKeys.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/AbstractLwM2MServerCredentialsWithKeys.java @@ -19,7 +19,7 @@ import com.fasterxml.jackson.annotation.JsonIgnore; import lombok.Getter; import lombok.Setter; import lombok.SneakyThrows; -import org.apache.commons.codec.binary.Hex; +import org.apache.commons.codec.binary.Base64; @Getter @Setter @@ -40,6 +40,6 @@ public abstract class AbstractLwM2MServerCredentialsWithKeys implements LwM2MSer @SneakyThrows private static byte[] getDecoded(String key) { - return Hex.decodeHex(key.toLowerCase().toCharArray()); + return Base64.decodeBase64(key.getBytes()); } } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/X509ClientCredentials.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/X509ClientCredentials.java index 712dcab5eb..d91fbf62ea 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/X509ClientCredentials.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/X509ClientCredentials.java @@ -15,16 +15,30 @@ */ package org.thingsboard.server.common.data.device.credentials.lwm2m; +import com.fasterxml.jackson.annotation.JsonIgnore; import lombok.Getter; import lombok.Setter; +import lombok.SneakyThrows; +import org.apache.commons.codec.binary.Base64; @Getter @Setter public class X509ClientCredentials extends AbstractLwM2MClientCredentials { private String cert; + private byte[] certInBytes; + @Override public LwM2MSecurityMode getSecurityConfigClientMode() { return LwM2MSecurityMode.X509; } + + @SneakyThrows + @JsonIgnore + public byte[] getDecodedCert() throws IllegalArgumentException { + if (certInBytes == null) { + certInBytes = Base64.decodeBase64(cert.getBytes()); + } + return certInBytes; + } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsServiceImpl.java index 969745ae31..68370b95e6 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsServiceImpl.java @@ -17,7 +17,6 @@ package org.thingsboard.server.dao.device; import lombok.extern.slf4j.Slf4j; -import org.eclipse.leshan.core.util.Base64; import org.eclipse.leshan.core.util.SecurityUtil; import org.hibernate.exception.ConstraintViolationException; import org.springframework.beans.factory.annotation.Autowired; @@ -231,7 +230,7 @@ public class DeviceCredentialsServiceImpl extends AbstractEntityService implemen } private void validateLwM2MClientCredentials(LwM2MClientCredentials clientCredentials) { - if (StringUtils.isEmpty(clientCredentials.getEndpoint())) { + if (StringUtils.isBlank(clientCredentials.getEndpoint())) { throw new DeviceCredentialsValidationException("LwM2M client endpoint should be specified!"); } @@ -240,43 +239,42 @@ public class DeviceCredentialsServiceImpl extends AbstractEntityService implemen break; case PSK: PSKClientCredentials pskCredentials = (PSKClientCredentials) clientCredentials; - if (StringUtils.isEmpty(pskCredentials.getIdentity())) { + if (StringUtils.isBlank(pskCredentials.getIdentity())) { throw new DeviceCredentialsValidationException("LwM2M client PSK identity should be specified!"); } String pskKey = pskCredentials.getKey(); - if (StringUtils.isEmpty(pskKey)) { + if (StringUtils.isBlank(pskKey)) { throw new DeviceCredentialsValidationException("LwM2M client PSK key should be specified!"); } if (!pskKey.matches("-?[0-9a-fA-F]+")) { - throw new DeviceCredentialsValidationException("LwM2M client PSK key should be HexDecimal format!"); + throw new DeviceCredentialsValidationException("LwM2M client PSK key should be random sequence in hex encoding!"); } - if (pskKey.length() % 32 != 0 || pskKey.length() > 128) { - throw new DeviceCredentialsValidationException("LwM2M client PSK key must be 32, 64, 128 characters!"); + if (pskKey.length()% 32 != 0 || pskKey.length() > 128) { + throw new DeviceCredentialsValidationException("LwM2M client PSK key length = " + pskKey.length() + ". Key should be HexDec format: 32, 64, 128 characters!"); } break; case RPK: RPKClientCredentials rpkCredentials = (RPKClientCredentials) clientCredentials; - - if (StringUtils.isEmpty(rpkCredentials.getKey())) { + if (StringUtils.isBlank(rpkCredentials.getKey())) { throw new DeviceCredentialsValidationException("LwM2M client RPK key should be specified!"); } try { SecurityUtil.publicKey.decode(rpkCredentials.getDecodedKey()); } catch (Exception e) { - throw new DeviceCredentialsValidationException("LwM2M client RPK key should be in RFC7250 standard!"); + throw new DeviceCredentialsValidationException("LwM2M client RPK key should be in RFC7250 standard and support only EC algorithm and encoded to Bas64 format!"); } break; case X509: X509ClientCredentials x509CCredentials = (X509ClientCredentials) clientCredentials; if (StringUtils.isNotBlank(x509CCredentials.getCert())) { try { - SecurityUtil.certificate.decode(Base64.decodeBase64(x509CCredentials.getCert())); + SecurityUtil.certificate.decode(x509CCredentials.getDecodedCert()); } catch (Exception e) { - throw new DeviceCredentialsValidationException("LwM2M client X509 certificate should be in DER-encoded X.509 format!"); + throw new DeviceCredentialsValidationException("LwM2M client X509 certificate should be in DER-encoded X509v3 format and support only EC algorithm and encoded to Bas64 format!"); } } break; @@ -289,34 +287,32 @@ public class DeviceCredentialsServiceImpl extends AbstractEntityService implemen break; case PSK: PSKServerCredentials pskCredentials = (PSKServerCredentials) serverCredentials; - if (StringUtils.isEmpty(pskCredentials.getClientPublicKeyOrId())) { + if (StringUtils.isBlank(pskCredentials.getClientPublicKeyOrId())) { throw new DeviceCredentialsValidationException(server + " client PSK public key or id should be specified!"); } String pskKey = pskCredentials.getClientSecretKey(); - if (StringUtils.isEmpty(pskKey)) { + if (StringUtils.isBlank(pskKey)) { throw new DeviceCredentialsValidationException(server + " client PSK key should be specified!"); } if (!pskKey.matches("-?[0-9a-fA-F]+")) { - throw new DeviceCredentialsValidationException(server + " client PSK key should be HexDecimal format!"); + throw new DeviceCredentialsValidationException(server + " client PSK key should be random sequence in hex encoding!"); } - if (pskKey.length() % 32 != 0 || pskKey.length() > 128) { - throw new DeviceCredentialsValidationException(server + " client PSK key must be 32, 64, 128 characters!"); + if (pskKey.length()% 32 != 0 || pskKey.length() > 128) { + throw new DeviceCredentialsValidationException(server + " client PSK key length = " + pskKey.length() + ". Key should be HexDec format: 32, 64, 128 characters!"); } break; case RPK: RPKServerCredentials rpkCredentials = (RPKServerCredentials) serverCredentials; - if (StringUtils.isEmpty(rpkCredentials.getClientPublicKeyOrId())) { throw new DeviceCredentialsValidationException(server + " client RPK public key or id should be specified!"); } - try { SecurityUtil.publicKey.decode(rpkCredentials.getDecodedClientPublicKeyOrId()); } catch (Exception e) { - throw new DeviceCredentialsValidationException(server + " client RPK public key or id should be in RFC7250 standard!"); + throw new DeviceCredentialsValidationException(server + " client RPK public key or id should be in RFC7250 standard and encoded to Bas64 format!"); } if (StringUtils.isEmpty(rpkCredentials.getClientSecretKey())) { @@ -326,28 +322,28 @@ public class DeviceCredentialsServiceImpl extends AbstractEntityService implemen try { SecurityUtil.privateKey.decode(rpkCredentials.getDecodedClientSecretKey()); } catch (Exception e) { - throw new DeviceCredentialsValidationException(server + " client RPK secret key should be in RFC5958 standard!"); + throw new DeviceCredentialsValidationException(server + " client RPK secret key should be in PKCS#8 format (DER encoding, RFC5958 standard) and encoded to Bas64 format!"); } break; case X509: X509ServerCredentials x509CCredentials = (X509ServerCredentials) serverCredentials; - if (StringUtils.isEmpty(x509CCredentials.getClientPublicKeyOrId())) { + if (StringUtils.isBlank(x509CCredentials.getClientPublicKeyOrId())) { throw new DeviceCredentialsValidationException(server + " client X509 public key or id should be specified!"); } try { SecurityUtil.certificate.decode(x509CCredentials.getDecodedClientPublicKeyOrId()); } catch (Exception e) { - throw new DeviceCredentialsValidationException(server + " client X509 public key or id should be in DER-encoded X.509 format!"); + throw new DeviceCredentialsValidationException(server + " client X509 public key or id should be in DER-encoded X509v3 format and support only EC algorithm and encoded to Bas64 format!"); } - if (StringUtils.isEmpty(x509CCredentials.getClientSecretKey())) { + if (StringUtils.isBlank(x509CCredentials.getClientSecretKey())) { throw new DeviceCredentialsValidationException(server + " client X509 secret key should be specified!"); } try { SecurityUtil.privateKey.decode(x509CCredentials.getDecodedClientSecretKey()); } catch (Exception e) { - throw new DeviceCredentialsValidationException(server + " client X509 secret key should be in RFC5958 standard!"); + throw new DeviceCredentialsValidationException(server + " client X509 secret key should be in PKCS#8 format (DER encoding, RFC5958 standard) and encoded to Bas64 format!"); } break; } From d403afb0e6815bd28da12e8f5e70b5f6fe629341 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Tue, 28 Sep 2021 14:11:32 +0300 Subject: [PATCH 048/432] Lwm2m credentials base64 validate (with /n and "...BEGIN...") back --- .../AbstractCoapProvisionJsonDeviceTest.java | 2 +- .../AbstractCoapProvisionProtoDeviceTest.java | 2 +- .../AbstractMqttProvisionJsonDeviceTest.java | 2 +- .../AbstractMqttProvisionProtoDeviceTest.java | 2 +- .../server/common/msg/EncryptionUtil.java | 23 ++++++-- .../server/common/transport/util/SslUtil.java | 2 +- .../device/DeviceCredentialsServiceImpl.java | 53 +++++++++++-------- 7 files changed, 56 insertions(+), 30 deletions(-) diff --git a/application/src/test/java/org/thingsboard/server/transport/coap/provision/AbstractCoapProvisionJsonDeviceTest.java b/application/src/test/java/org/thingsboard/server/transport/coap/provision/AbstractCoapProvisionJsonDeviceTest.java index eccba64ddc..091900488b 100644 --- a/application/src/test/java/org/thingsboard/server/transport/coap/provision/AbstractCoapProvisionJsonDeviceTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/coap/provision/AbstractCoapProvisionJsonDeviceTest.java @@ -146,7 +146,7 @@ public abstract class AbstractCoapProvisionJsonDeviceTest extends AbstractCoapIn Assert.assertEquals(deviceCredentials.getCredentialsType().name(), response.get("credentialsType").getAsString()); Assert.assertEquals(deviceCredentials.getCredentialsType().name(), "X509_CERTIFICATE"); - String cert = EncryptionUtil.trimNewLines(deviceCredentials.getCredentialsValue()); + String cert = EncryptionUtil.certTrimNewLines(deviceCredentials.getCredentialsValue()); String sha3Hash = EncryptionUtil.getSha3Hash(cert); Assert.assertEquals(deviceCredentials.getCredentialsId(), sha3Hash); diff --git a/application/src/test/java/org/thingsboard/server/transport/coap/provision/AbstractCoapProvisionProtoDeviceTest.java b/application/src/test/java/org/thingsboard/server/transport/coap/provision/AbstractCoapProvisionProtoDeviceTest.java index 14d72297a4..671741c7d0 100644 --- a/application/src/test/java/org/thingsboard/server/transport/coap/provision/AbstractCoapProvisionProtoDeviceTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/coap/provision/AbstractCoapProvisionProtoDeviceTest.java @@ -145,7 +145,7 @@ public abstract class AbstractCoapProvisionProtoDeviceTest extends AbstractCoapI Assert.assertEquals(deviceCredentials.getCredentialsType().name(), response.getCredentialsType().toString()); Assert.assertEquals(deviceCredentials.getCredentialsType(), DeviceCredentialsType.X509_CERTIFICATE); - String cert = EncryptionUtil.trimNewLines(deviceCredentials.getCredentialsValue()); + String cert = EncryptionUtil.certTrimNewLines(deviceCredentials.getCredentialsValue()); String sha3Hash = EncryptionUtil.getSha3Hash(cert); Assert.assertEquals(deviceCredentials.getCredentialsId(), sha3Hash); diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/provision/AbstractMqttProvisionJsonDeviceTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/provision/AbstractMqttProvisionJsonDeviceTest.java index 870b62b195..e1b0269138 100644 --- a/application/src/test/java/org/thingsboard/server/transport/mqtt/provision/AbstractMqttProvisionJsonDeviceTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/provision/AbstractMqttProvisionJsonDeviceTest.java @@ -152,7 +152,7 @@ public abstract class AbstractMqttProvisionJsonDeviceTest extends AbstractMqttIn Assert.assertEquals(deviceCredentials.getCredentialsType().name(), response.get("credentialsType").getAsString()); Assert.assertEquals(deviceCredentials.getCredentialsType().name(), "X509_CERTIFICATE"); - String cert = EncryptionUtil.trimNewLines(deviceCredentials.getCredentialsValue()); + String cert = EncryptionUtil.certTrimNewLines(deviceCredentials.getCredentialsValue()); String sha3Hash = EncryptionUtil.getSha3Hash(cert); Assert.assertEquals(deviceCredentials.getCredentialsId(), sha3Hash); diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/provision/AbstractMqttProvisionProtoDeviceTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/provision/AbstractMqttProvisionProtoDeviceTest.java index 97ebbfe4a7..7816db5de0 100644 --- a/application/src/test/java/org/thingsboard/server/transport/mqtt/provision/AbstractMqttProvisionProtoDeviceTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/provision/AbstractMqttProvisionProtoDeviceTest.java @@ -154,7 +154,7 @@ public abstract class AbstractMqttProvisionProtoDeviceTest extends AbstractMqttI Assert.assertEquals(deviceCredentials.getCredentialsType().name(), response.getCredentialsType().toString()); Assert.assertEquals(deviceCredentials.getCredentialsType(), DeviceCredentialsType.X509_CERTIFICATE); - String cert = EncryptionUtil.trimNewLines(deviceCredentials.getCredentialsValue()); + String cert = EncryptionUtil.certTrimNewLines(deviceCredentials.getCredentialsValue()); String sha3Hash = EncryptionUtil.getSha3Hash(cert); Assert.assertEquals(deviceCredentials.getCredentialsId(), sha3Hash); diff --git a/common/message/src/main/java/org/thingsboard/server/common/msg/EncryptionUtil.java b/common/message/src/main/java/org/thingsboard/server/common/msg/EncryptionUtil.java index d8fbbad543..1421d4c64e 100644 --- a/common/message/src/main/java/org/thingsboard/server/common/msg/EncryptionUtil.java +++ b/common/message/src/main/java/org/thingsboard/server/common/msg/EncryptionUtil.java @@ -28,15 +28,30 @@ public class EncryptionUtil { private EncryptionUtil() { } - public static String trimNewLines(String input) { + public static String certTrimNewLines(String input) { return input.replaceAll("-----BEGIN CERTIFICATE-----", "") - .replaceAll("-----END CERTIFICATE-----", "") .replaceAll("\n", "") - .replaceAll("\r", ""); + .replaceAll("\r", "") + .replaceAll("-----END CERTIFICATE-----", ""); } + public static String pubkTrimNewLines(String input) { + return input.replaceAll("-----BEGIN PUBLIC KEY-----", "") + .replaceAll("\n", "") + .replaceAll("\r", "") + .replaceAll("-----END PUBLIC KEY-----", ""); + } + + public static String prikTrimNewLines(String input) { + return input.replaceAll("-----BEGIN EC PRIVATE KEY-----", "") + .replaceAll("\n", "") + .replaceAll("\r", "") + .replaceAll("-----END EC PRIVATE KEY-----", ""); + } + + public static String getSha3Hash(String data) { - String trimmedData = trimNewLines(data); + String trimmedData = certTrimNewLines(data); byte[] dataBytes = trimmedData.getBytes(); SHA3Digest md = new SHA3Digest(256); md.reset(); diff --git a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/util/SslUtil.java b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/util/SslUtil.java index 77e4045655..2a17a4791d 100644 --- a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/util/SslUtil.java +++ b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/util/SslUtil.java @@ -33,6 +33,6 @@ public class SslUtil { public static String getCertificateString(Certificate cert) throws CertificateEncodingException { - return EncryptionUtil.trimNewLines(Base64Utils.encodeToString(cert.getEncoded())); + return EncryptionUtil.certTrimNewLines(Base64Utils.encodeToString(cert.getEncoded())); } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsServiceImpl.java index 68370b95e6..84db68f4fc 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsServiceImpl.java @@ -154,7 +154,7 @@ public class DeviceCredentialsServiceImpl extends AbstractEntityService implemen } private void formatCertData(DeviceCredentials deviceCredentials) { - String cert = EncryptionUtil.trimNewLines(deviceCredentials.getCredentialsValue()); + String cert = EncryptionUtil.certTrimNewLines(deviceCredentials.getCredentialsValue()); String sha3Hash = EncryptionUtil.getSha3Hash(cert); deviceCredentials.setCredentialsId(sha3Hash); deviceCredentials.setCredentialsValue(cert); @@ -171,26 +171,25 @@ public class DeviceCredentialsServiceImpl extends AbstractEntityService implemen String credentialsId = null; LwM2MClientCredentials clientCredentials = lwM2MCredentials.getClient(); - + LwM2MServerCredentials bootstrapServer = lwM2MCredentials.getBootstrap().getBootstrapServer(); + LwM2MServerCredentials lwm2mServer = lwM2MCredentials.getBootstrap().getLwm2mServer(); switch (clientCredentials.getSecurityConfigClientMode()) { case NO_SEC: case RPK: + deviceCredentials.setCredentialsValue(JacksonUtil.toString(lwM2MCredentials)); credentialsId = clientCredentials.getEndpoint(); break; case PSK: credentialsId = ((PSKClientCredentials) clientCredentials).getIdentity(); break; case X509: - X509ClientCredentials x509Config = (X509ClientCredentials) clientCredentials; - if ((StringUtils.isNotBlank(x509Config.getCert()))) { - String cert = EncryptionUtil.trimNewLines(x509Config.getCert()); - String sha3Hash = EncryptionUtil.getSha3Hash(cert); - x509Config.setCert(cert); - ((X509ClientCredentials) clientCredentials).setCert(cert); - deviceCredentials.setCredentialsValue(JacksonUtil.toString(lwM2MCredentials)); + deviceCredentials.setCredentialsValue(JacksonUtil.toString(lwM2MCredentials)); + X509ClientCredentials x509ClientConfig = (X509ClientCredentials) clientCredentials; + if ((StringUtils.isNotBlank(x509ClientConfig.getCert()))) { + String sha3Hash = EncryptionUtil.getSha3Hash(x509ClientConfig.getCert()); credentialsId = sha3Hash; } else { - credentialsId = x509Config.getEndpoint(); + credentialsId = x509ClientConfig.getEndpoint(); } break; } @@ -263,6 +262,8 @@ public class DeviceCredentialsServiceImpl extends AbstractEntityService implemen } try { + String pubkClient = EncryptionUtil.pubkTrimNewLines(rpkCredentials.getKey()); + rpkCredentials.setKey(pubkClient); SecurityUtil.publicKey.decode(rpkCredentials.getDecodedKey()); } catch (Exception e) { throw new DeviceCredentialsValidationException("LwM2M client RPK key should be in RFC7250 standard and support only EC algorithm and encoded to Bas64 format!"); @@ -272,6 +273,8 @@ public class DeviceCredentialsServiceImpl extends AbstractEntityService implemen X509ClientCredentials x509CCredentials = (X509ClientCredentials) clientCredentials; if (StringUtils.isNotBlank(x509CCredentials.getCert())) { try { + String certClient = EncryptionUtil.certTrimNewLines(x509CCredentials.getCert()); + x509CCredentials.setCert(certClient); SecurityUtil.certificate.decode(x509CCredentials.getDecodedCert()); } catch (Exception e) { throw new DeviceCredentialsValidationException("LwM2M client X509 certificate should be in DER-encoded X509v3 format and support only EC algorithm and encoded to Bas64 format!"); @@ -300,48 +303,56 @@ public class DeviceCredentialsServiceImpl extends AbstractEntityService implemen throw new DeviceCredentialsValidationException(server + " client PSK key should be random sequence in hex encoding!"); } - if (pskKey.length()% 32 != 0 || pskKey.length() > 128) { + if (pskKey.length() % 32 != 0 || pskKey.length() > 128) { throw new DeviceCredentialsValidationException(server + " client PSK key length = " + pskKey.length() + ". Key should be HexDec format: 32, 64, 128 characters!"); } break; case RPK: - RPKServerCredentials rpkCredentials = (RPKServerCredentials) serverCredentials; - if (StringUtils.isEmpty(rpkCredentials.getClientPublicKeyOrId())) { + RPKServerCredentials rpkServerCredentials = (RPKServerCredentials) serverCredentials; + if (StringUtils.isEmpty(rpkServerCredentials.getClientPublicKeyOrId())) { throw new DeviceCredentialsValidationException(server + " client RPK public key or id should be specified!"); } try { - SecurityUtil.publicKey.decode(rpkCredentials.getDecodedClientPublicKeyOrId()); + String pubkRpkSever = EncryptionUtil.pubkTrimNewLines(rpkServerCredentials.getClientPublicKeyOrId()); + rpkServerCredentials.setClientPublicKeyOrId(pubkRpkSever); + SecurityUtil.publicKey.decode(rpkServerCredentials.getDecodedClientPublicKeyOrId()); } catch (Exception e) { throw new DeviceCredentialsValidationException(server + " client RPK public key or id should be in RFC7250 standard and encoded to Bas64 format!"); } - if (StringUtils.isEmpty(rpkCredentials.getClientSecretKey())) { + if (StringUtils.isEmpty(rpkServerCredentials.getClientSecretKey())) { throw new DeviceCredentialsValidationException(server + " client RPK secret key should be specified!"); } try { - SecurityUtil.privateKey.decode(rpkCredentials.getDecodedClientSecretKey()); + String prikRpkSever = EncryptionUtil.prikTrimNewLines(rpkServerCredentials.getClientSecretKey()); + rpkServerCredentials.setClientSecretKey(prikRpkSever); + SecurityUtil.privateKey.decode(rpkServerCredentials.getDecodedClientSecretKey()); } catch (Exception e) { throw new DeviceCredentialsValidationException(server + " client RPK secret key should be in PKCS#8 format (DER encoding, RFC5958 standard) and encoded to Bas64 format!"); } break; case X509: - X509ServerCredentials x509CCredentials = (X509ServerCredentials) serverCredentials; - if (StringUtils.isBlank(x509CCredentials.getClientPublicKeyOrId())) { + X509ServerCredentials x509ServerCredentials = (X509ServerCredentials) serverCredentials; + if (StringUtils.isBlank(x509ServerCredentials.getClientPublicKeyOrId())) { throw new DeviceCredentialsValidationException(server + " client X509 public key or id should be specified!"); } try { - SecurityUtil.certificate.decode(x509CCredentials.getDecodedClientPublicKeyOrId()); + String certServer = EncryptionUtil.certTrimNewLines(x509ServerCredentials.getClientPublicKeyOrId()); + x509ServerCredentials.setClientPublicKeyOrId(certServer); + SecurityUtil.certificate.decode(x509ServerCredentials.getDecodedClientPublicKeyOrId()); } catch (Exception e) { throw new DeviceCredentialsValidationException(server + " client X509 public key or id should be in DER-encoded X509v3 format and support only EC algorithm and encoded to Bas64 format!"); } - if (StringUtils.isBlank(x509CCredentials.getClientSecretKey())) { + if (StringUtils.isBlank(x509ServerCredentials.getClientSecretKey())) { throw new DeviceCredentialsValidationException(server + " client X509 secret key should be specified!"); } try { - SecurityUtil.privateKey.decode(x509CCredentials.getDecodedClientSecretKey()); + String prikX509Sever = EncryptionUtil.prikTrimNewLines(x509ServerCredentials.getClientSecretKey()); + x509ServerCredentials.setClientSecretKey(prikX509Sever); + SecurityUtil.privateKey.decode(x509ServerCredentials.getDecodedClientSecretKey()); } catch (Exception e) { throw new DeviceCredentialsValidationException(server + " client X509 secret key should be in PKCS#8 format (DER encoding, RFC5958 standard) and encoded to Bas64 format!"); } From dba087e949ec04085339710e4fbf253605c450c8 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Tue, 28 Sep 2021 16:48:34 +0300 Subject: [PATCH 049/432] Lwm2m credentials base64 fix bug PSK (hexDec) --- .../lwm2m/AbstractLwM2MClientCredentialsWithKey.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/AbstractLwM2MClientCredentialsWithKey.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/AbstractLwM2MClientCredentialsWithKey.java index 4279694909..26cc55faa6 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/AbstractLwM2MClientCredentialsWithKey.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/AbstractLwM2MClientCredentialsWithKey.java @@ -20,6 +20,7 @@ import lombok.Getter; import lombok.Setter; import lombok.SneakyThrows; import org.apache.commons.codec.binary.Base64; +import org.apache.commons.codec.binary.Hex; public abstract class AbstractLwM2MClientCredentialsWithKey extends AbstractLwM2MClientCredentials { @Getter @@ -32,7 +33,12 @@ public abstract class AbstractLwM2MClientCredentialsWithKey extends AbstractLwM2 @JsonIgnore public byte[] getDecodedKey() throws IllegalArgumentException { if (keyInBytes == null) { - keyInBytes = Base64.decodeBase64(key.getBytes()); + if (this.getSecurityConfigClientMode() == LwM2MSecurityMode.PSK) { + keyInBytes = Hex.decodeHex(key.toLowerCase().toCharArray()); + } + else { + keyInBytes = Base64.decodeBase64(key.getBytes()); + } } return keyInBytes; } From 81ec387c86e28eee7771a21c2ba4882f5ef1aa39 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Tue, 28 Sep 2021 17:21:15 +0300 Subject: [PATCH 050/432] Lwm2m credentials base64 fix bug PSK test --- .../lwm2m/security/sql/RpkLwM2MIntegrationTest.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/RpkLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/RpkLwM2MIntegrationTest.java index fdfa56957c..68479f6fb9 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/RpkLwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/RpkLwM2MIntegrationTest.java @@ -16,11 +16,12 @@ package org.thingsboard.server.transport.lwm2m.security.sql; import org.eclipse.leshan.client.object.Security; -import org.eclipse.leshan.core.util.Hex; import org.junit.Test; import org.thingsboard.server.common.data.device.credentials.lwm2m.RPKClientCredentials; import org.thingsboard.server.transport.lwm2m.security.AbstractSecurityLwM2MIntegrationTest; +import org.apache.commons.codec.binary.Base64;; + import static org.eclipse.leshan.client.object.Security.rpk; import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SECURE_COAP_CONFIG; import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SECURE_URI; @@ -32,7 +33,7 @@ public class RpkLwM2MIntegrationTest extends AbstractSecurityLwM2MIntegrationTes public void testConnectWithRPKAndObserveTelemetry() throws Exception { RPKClientCredentials rpkClientCredentials = new RPKClientCredentials(); rpkClientCredentials.setEndpoint(ENDPOINT); - rpkClientCredentials.setKey(Hex.encodeHexString(clientPublicKey.getEncoded())); + rpkClientCredentials.setKey(new String(Base64.encodeBase64(clientPublicKey.getEncoded()))); Security security = rpk(SECURE_URI, SHORT_SERVER_ID, clientPublicKey.getEncoded(), @@ -40,5 +41,4 @@ public class RpkLwM2MIntegrationTest extends AbstractSecurityLwM2MIntegrationTes serverX509Cert.getPublicKey().getEncoded()); super.basicTestConnectionObserveTelemetry(security, rpkClientCredentials, SECURE_COAP_CONFIG, ENDPOINT); } - } From e8444f8bdc7cf7d96b8b32eccd18797e39d8869d Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Wed, 29 Sep 2021 19:32:19 +0300 Subject: [PATCH 051/432] Lwm2m base64 back fix bug "bas64" and x509 empty --- .../dao/device/DeviceCredentialsServiceImpl.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsServiceImpl.java index 84db68f4fc..4c6031d8bf 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsServiceImpl.java @@ -266,18 +266,18 @@ public class DeviceCredentialsServiceImpl extends AbstractEntityService implemen rpkCredentials.setKey(pubkClient); SecurityUtil.publicKey.decode(rpkCredentials.getDecodedKey()); } catch (Exception e) { - throw new DeviceCredentialsValidationException("LwM2M client RPK key should be in RFC7250 standard and support only EC algorithm and encoded to Bas64 format!"); + throw new DeviceCredentialsValidationException("LwM2M client RPK key should be in RFC7250 standard and support only EC algorithm and encoded to Base64 format!"); } break; case X509: X509ClientCredentials x509CCredentials = (X509ClientCredentials) clientCredentials; - if (StringUtils.isNotBlank(x509CCredentials.getCert())) { + if (StringUtils.isNotEmpty(x509CCredentials.getCert())) { try { String certClient = EncryptionUtil.certTrimNewLines(x509CCredentials.getCert()); x509CCredentials.setCert(certClient); SecurityUtil.certificate.decode(x509CCredentials.getDecodedCert()); } catch (Exception e) { - throw new DeviceCredentialsValidationException("LwM2M client X509 certificate should be in DER-encoded X509v3 format and support only EC algorithm and encoded to Bas64 format!"); + throw new DeviceCredentialsValidationException("LwM2M client X509 certificate should be in DER-encoded X509v3 format and support only EC algorithm and encoded to Base64 format!"); } } break; @@ -317,7 +317,7 @@ public class DeviceCredentialsServiceImpl extends AbstractEntityService implemen rpkServerCredentials.setClientPublicKeyOrId(pubkRpkSever); SecurityUtil.publicKey.decode(rpkServerCredentials.getDecodedClientPublicKeyOrId()); } catch (Exception e) { - throw new DeviceCredentialsValidationException(server + " client RPK public key or id should be in RFC7250 standard and encoded to Bas64 format!"); + throw new DeviceCredentialsValidationException(server + " client RPK public key or id should be in RFC7250 standard and encoded to Base64 format!"); } if (StringUtils.isEmpty(rpkServerCredentials.getClientSecretKey())) { @@ -329,7 +329,7 @@ public class DeviceCredentialsServiceImpl extends AbstractEntityService implemen rpkServerCredentials.setClientSecretKey(prikRpkSever); SecurityUtil.privateKey.decode(rpkServerCredentials.getDecodedClientSecretKey()); } catch (Exception e) { - throw new DeviceCredentialsValidationException(server + " client RPK secret key should be in PKCS#8 format (DER encoding, RFC5958 standard) and encoded to Bas64 format!"); + throw new DeviceCredentialsValidationException(server + " client RPK secret key should be in PKCS#8 format (DER encoding, RFC5958 standard) and encoded to Base64 format!"); } break; case X509: @@ -343,7 +343,7 @@ public class DeviceCredentialsServiceImpl extends AbstractEntityService implemen x509ServerCredentials.setClientPublicKeyOrId(certServer); SecurityUtil.certificate.decode(x509ServerCredentials.getDecodedClientPublicKeyOrId()); } catch (Exception e) { - throw new DeviceCredentialsValidationException(server + " client X509 public key or id should be in DER-encoded X509v3 format and support only EC algorithm and encoded to Bas64 format!"); + throw new DeviceCredentialsValidationException(server + " client X509 public key or id should be in DER-encoded X509v3 format and support only EC algorithm and encoded to Base64 format!"); } if (StringUtils.isBlank(x509ServerCredentials.getClientSecretKey())) { throw new DeviceCredentialsValidationException(server + " client X509 secret key should be specified!"); @@ -354,7 +354,7 @@ public class DeviceCredentialsServiceImpl extends AbstractEntityService implemen x509ServerCredentials.setClientSecretKey(prikX509Sever); SecurityUtil.privateKey.decode(x509ServerCredentials.getDecodedClientSecretKey()); } catch (Exception e) { - throw new DeviceCredentialsValidationException(server + " client X509 secret key should be in PKCS#8 format (DER encoding, RFC5958 standard) and encoded to Bas64 format!"); + throw new DeviceCredentialsValidationException(server + " client X509 secret key should be in PKCS#8 format (DER encoding, RFC5958 standard) and encoded to Base64 format!"); } break; } From 9186377b974fec8809cfb84963a27ca2174823fd Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Thu, 30 Sep 2021 12:24:29 +0300 Subject: [PATCH 052/432] Lwm2m base64 back fix bug "bas64" on review --- ...AbstractLwM2MClientCredentialsWithKey.java | 45 ------------------- ...bstractLwM2MClientSecurityCredentials.java | 30 +++++++++++++ .../lwm2m/PSKClientCredentials.java | 14 +++++- .../lwm2m/RPKClientCredentials.java | 13 +++++- .../lwm2m/X509ClientCredentials.java | 19 ++++---- ...LwM2mCredentialsSecurityInfoValidator.java | 13 +++--- .../device/DeviceCredentialsServiceImpl.java | 10 ++--- 7 files changed, 73 insertions(+), 71 deletions(-) delete mode 100644 common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/AbstractLwM2MClientCredentialsWithKey.java create mode 100644 common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/AbstractLwM2MClientSecurityCredentials.java diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/AbstractLwM2MClientCredentialsWithKey.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/AbstractLwM2MClientCredentialsWithKey.java deleted file mode 100644 index 26cc55faa6..0000000000 --- a/common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/AbstractLwM2MClientCredentialsWithKey.java +++ /dev/null @@ -1,45 +0,0 @@ -/** - * Copyright © 2016-2021 The Thingsboard Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.thingsboard.server.common.data.device.credentials.lwm2m; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import lombok.Getter; -import lombok.Setter; -import lombok.SneakyThrows; -import org.apache.commons.codec.binary.Base64; -import org.apache.commons.codec.binary.Hex; - -public abstract class AbstractLwM2MClientCredentialsWithKey extends AbstractLwM2MClientCredentials { - @Getter - @Setter - private String key; - - private byte[] keyInBytes; - - @SneakyThrows - @JsonIgnore - public byte[] getDecodedKey() throws IllegalArgumentException { - if (keyInBytes == null) { - if (this.getSecurityConfigClientMode() == LwM2MSecurityMode.PSK) { - keyInBytes = Hex.decodeHex(key.toLowerCase().toCharArray()); - } - else { - keyInBytes = Base64.decodeBase64(key.getBytes()); - } - } - return keyInBytes; - } -} diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/AbstractLwM2MClientSecurityCredentials.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/AbstractLwM2MClientSecurityCredentials.java new file mode 100644 index 0000000000..e5e3271c7a --- /dev/null +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/AbstractLwM2MClientSecurityCredentials.java @@ -0,0 +1,30 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.common.data.device.credentials.lwm2m; + +import lombok.Getter; +import lombok.Setter; +import org.apache.commons.codec.DecoderException; + +public abstract class AbstractLwM2MClientSecurityCredentials extends AbstractLwM2MClientCredentials { + @Getter + @Setter + protected String key; + + protected byte[] securityInBytes; + + public abstract byte[] getDecoded() throws IllegalArgumentException, DecoderException; +} diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/PSKClientCredentials.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/PSKClientCredentials.java index f90e85ff4a..03d2ab328c 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/PSKClientCredentials.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/PSKClientCredentials.java @@ -17,14 +17,24 @@ package org.thingsboard.server.common.data.device.credentials.lwm2m; import lombok.Getter; import lombok.Setter; +import org.apache.commons.codec.DecoderException; +import org.apache.commons.codec.binary.Hex; @Getter @Setter -public class PSKClientCredentials extends AbstractLwM2MClientCredentialsWithKey { +public class PSKClientCredentials extends AbstractLwM2MClientSecurityCredentials { private String identity; @Override public LwM2MSecurityMode getSecurityConfigClientMode() { return LwM2MSecurityMode.PSK; } -} + + @Override + public byte[] getDecoded() throws IllegalArgumentException, DecoderException { + if (securityInBytes == null) { + securityInBytes = Hex.decodeHex(key.toLowerCase().toCharArray()); + } + return securityInBytes; + } +} \ No newline at end of file diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/RPKClientCredentials.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/RPKClientCredentials.java index 4ebe2de71a..a05bb438c6 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/RPKClientCredentials.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/RPKClientCredentials.java @@ -15,10 +15,21 @@ */ package org.thingsboard.server.common.data.device.credentials.lwm2m; -public class RPKClientCredentials extends AbstractLwM2MClientCredentialsWithKey { +import org.apache.commons.codec.DecoderException; +import org.apache.commons.codec.binary.Base64; + +public class RPKClientCredentials extends AbstractLwM2MClientSecurityCredentials { @Override public LwM2MSecurityMode getSecurityConfigClientMode() { return LwM2MSecurityMode.RPK; } + + @Override + public byte[] getDecoded() throws IllegalArgumentException, DecoderException { + if (securityInBytes == null) { + securityInBytes = Base64.decodeBase64(key.getBytes()); + } + return securityInBytes; + } } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/X509ClientCredentials.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/X509ClientCredentials.java index d91fbf62ea..dfef57e18e 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/X509ClientCredentials.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/X509ClientCredentials.java @@ -15,30 +15,27 @@ */ package org.thingsboard.server.common.data.device.credentials.lwm2m; -import com.fasterxml.jackson.annotation.JsonIgnore; import lombok.Getter; import lombok.Setter; -import lombok.SneakyThrows; +import org.apache.commons.codec.DecoderException; import org.apache.commons.codec.binary.Base64; @Getter @Setter -public class X509ClientCredentials extends AbstractLwM2MClientCredentials { - private String cert; +public class X509ClientCredentials extends AbstractLwM2MClientSecurityCredentials { - private byte[] certInBytes; + private String cert; @Override public LwM2MSecurityMode getSecurityConfigClientMode() { return LwM2MSecurityMode.X509; } - @SneakyThrows - @JsonIgnore - public byte[] getDecodedCert() throws IllegalArgumentException { - if (certInBytes == null) { - certInBytes = Base64.decodeBase64(cert.getBytes()); + @Override + public byte[] getDecoded() throws IllegalArgumentException, DecoderException { + if (securityInBytes == null && cert != null) { + securityInBytes = Base64.decodeBase64(cert.getBytes()); } - return certInBytes; + return securityInBytes; } } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LwM2mCredentialsSecurityInfoValidator.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LwM2mCredentialsSecurityInfoValidator.java index bf30723ce0..6b7b3a9877 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LwM2mCredentialsSecurityInfoValidator.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LwM2mCredentialsSecurityInfoValidator.java @@ -17,6 +17,7 @@ package org.thingsboard.server.transport.lwm2m.secure; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.codec.DecoderException; import org.eclipse.leshan.core.util.SecurityUtil; import org.eclipse.leshan.server.security.SecurityInfo; import org.springframework.stereotype.Component; @@ -146,14 +147,14 @@ public class LwM2mCredentialsSecurityInfoValidator { PSKClientCredentials pskConfig = (PSKClientCredentials) clientCredentialsConfig; if (StringUtils.isNotEmpty(pskConfig.getIdentity())) { try { - if (pskConfig.getDecodedKey() != null && pskConfig.getDecodedKey().length > 0) { + if (pskConfig.getDecoded() != null && pskConfig.getDecoded().length > 0) { endpoint = StringUtils.isNotEmpty(pskConfig.getEndpoint()) ? pskConfig.getEndpoint() : endpoint; if (endpoint != null && !endpoint.isEmpty()) { - result.setSecurityInfo(SecurityInfo.newPreSharedKeyInfo(endpoint, pskConfig.getIdentity(), pskConfig.getDecodedKey())); + result.setSecurityInfo(SecurityInfo.newPreSharedKeyInfo(endpoint, pskConfig.getIdentity(), pskConfig.getDecoded())); result.setSecurityMode(PSK); } } - } catch (IllegalArgumentException e) { + } catch (IllegalArgumentException | DecoderException e) { log.error("Missing PSK key: " + e.getMessage()); } } else { @@ -164,14 +165,14 @@ public class LwM2mCredentialsSecurityInfoValidator { private void createClientSecurityInfoRPK(TbLwM2MSecurityInfo result, String endpoint, LwM2MClientCredentials clientCredentialsConfig) { RPKClientCredentials rpkConfig = (RPKClientCredentials) clientCredentialsConfig; try { - if (rpkConfig.getDecodedKey() != null) { - PublicKey key = SecurityUtil.publicKey.decode(rpkConfig.getDecodedKey()); + if (rpkConfig.getDecoded() != null) { + PublicKey key = SecurityUtil.publicKey.decode(rpkConfig.getDecoded()); result.setSecurityInfo(SecurityInfo.newRawPublicKeyInfo(endpoint, key)); result.setSecurityMode(RPK); } else { log.error("Missing RPK key"); } - } catch (IllegalArgumentException | IOException | GeneralSecurityException e) { + } catch (IllegalArgumentException | IOException | GeneralSecurityException | DecoderException e) { log.error("RPK: Invalid security info content: " + e.getMessage()); } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsServiceImpl.java index 4c6031d8bf..a5ed9e1e29 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsServiceImpl.java @@ -117,7 +117,7 @@ public class DeviceCredentialsServiceImpl extends AbstractEntityService implemen formatSimpleMqttCredentials(deviceCredentials); break; case LWM2M_CREDENTIALS: - formatSimpleLwm2mCredentials(deviceCredentials); + formatAndValidateSimpleLwm2mCredentials(deviceCredentials); break; } } @@ -160,7 +160,7 @@ public class DeviceCredentialsServiceImpl extends AbstractEntityService implemen deviceCredentials.setCredentialsValue(cert); } - private void formatSimpleLwm2mCredentials(DeviceCredentials deviceCredentials) { + private void formatAndValidateSimpleLwm2mCredentials(DeviceCredentials deviceCredentials) { LwM2MDeviceCredentials lwM2MCredentials; try { lwM2MCredentials = JacksonUtil.fromString(deviceCredentials.getCredentialsValue(), LwM2MDeviceCredentials.class); @@ -171,8 +171,6 @@ public class DeviceCredentialsServiceImpl extends AbstractEntityService implemen String credentialsId = null; LwM2MClientCredentials clientCredentials = lwM2MCredentials.getClient(); - LwM2MServerCredentials bootstrapServer = lwM2MCredentials.getBootstrap().getBootstrapServer(); - LwM2MServerCredentials lwm2mServer = lwM2MCredentials.getBootstrap().getLwm2mServer(); switch (clientCredentials.getSecurityConfigClientMode()) { case NO_SEC: case RPK: @@ -264,7 +262,7 @@ public class DeviceCredentialsServiceImpl extends AbstractEntityService implemen try { String pubkClient = EncryptionUtil.pubkTrimNewLines(rpkCredentials.getKey()); rpkCredentials.setKey(pubkClient); - SecurityUtil.publicKey.decode(rpkCredentials.getDecodedKey()); + SecurityUtil.publicKey.decode(rpkCredentials.getDecoded()); } catch (Exception e) { throw new DeviceCredentialsValidationException("LwM2M client RPK key should be in RFC7250 standard and support only EC algorithm and encoded to Base64 format!"); } @@ -275,7 +273,7 @@ public class DeviceCredentialsServiceImpl extends AbstractEntityService implemen try { String certClient = EncryptionUtil.certTrimNewLines(x509CCredentials.getCert()); x509CCredentials.setCert(certClient); - SecurityUtil.certificate.decode(x509CCredentials.getDecodedCert()); + SecurityUtil.certificate.decode(x509CCredentials.getDecoded()); } catch (Exception e) { throw new DeviceCredentialsValidationException("LwM2M client X509 certificate should be in DER-encoded X509v3 format and support only EC algorithm and encoded to Base64 format!"); } From 973b979900363721c66240e6674fbe32b3b89997 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Fri, 1 Oct 2021 18:24:01 +0300 Subject: [PATCH 053/432] Lwm2m fix bug double log --- .../lwm2m/server/downlink/TbLwM2MTargetedCallback.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MTargetedCallback.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MTargetedCallback.java index e61067b382..cf33a5857f 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MTargetedCallback.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MTargetedCallback.java @@ -18,6 +18,7 @@ package org.thingsboard.server.transport.lwm2m.server.downlink; import lombok.extern.slf4j.Slf4j; import org.eclipse.leshan.core.ResponseCode; import org.eclipse.leshan.core.response.LwM2mResponse; +import org.eclipse.leshan.core.response.ReadResponse; import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService; @@ -47,7 +48,7 @@ public abstract class TbLwM2MTargetedCallback extends AbstractTbLwM2MReque @Override public void onSuccess(R request, T response) { //TODO convert camelCase to "camel case" using .split("(? Date: Wed, 6 Oct 2021 13:02:07 +0300 Subject: [PATCH 054/432] Lwm2m fix bug 19 object --- .../rpc/sql/RpcLwm2mIntegrationWriteTest.java | 2 +- .../DefaultLwM2MAttributesService.java | 21 ++++++------------- .../DefaultLwM2mDownlinkMsgHandler.java | 11 +++++++--- .../lwm2m/utils/LwM2MTransportUtil.java | 16 ++++++++++++++ 4 files changed, 31 insertions(+), 19 deletions(-) diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationWriteTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationWriteTest.java index de0a22756d..3dad6231ad 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationWriteTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationWriteTest.java @@ -121,7 +121,7 @@ public class RpcLwm2mIntegrationWriteTest extends AbstractRpcLwM2MIntegrationTes ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); assertEquals(ResponseCode.BAD_REQUEST.getName(), rpcActualResult.get("result").asText()); String actualValues = rpcActualResult.get("error").asText(); - String expected = "is bad. Value of Multi-Instance Resource must be in Json format!"; + String expected = "Format value is bad. Value for this Multi-Instance Resource must be in Json format!"; assertTrue(actualValues.contains(expected)); } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/attributes/DefaultLwM2MAttributesService.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/attributes/DefaultLwM2MAttributesService.java index a4a4fa58ed..e6fddf430b 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/attributes/DefaultLwM2MAttributesService.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/attributes/DefaultLwM2MAttributesService.java @@ -44,7 +44,6 @@ import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandle import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collection; import java.util.List; import java.util.Map; @@ -52,7 +51,6 @@ import java.util.Optional; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicInteger; -import static org.eclipse.leshan.core.model.ResourceModel.Type.OPAQUE; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportServerHelper.getValueFromKvProto; import static org.thingsboard.server.transport.lwm2m.server.ota.DefaultLwM2MOtaUpdateService.FIRMWARE_TAG; import static org.thingsboard.server.transport.lwm2m.server.ota.DefaultLwM2MOtaUpdateService.FIRMWARE_TITLE; @@ -67,6 +65,7 @@ import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.LO import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.compareAttNameKeyOta; import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.convertMultiResourceValuesFromJson; import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.fromVersionedIdToObjectId; +import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.valueEquals; @Slf4j @Service @@ -220,7 +219,7 @@ public class DefaultLwM2MAttributesService implements LwM2MAttributesService { Object newValProto = getValueFromKvProto(tsKvProto.getKv()); Object oldResourceValue = this.getResourceValueFormatKv(lwM2MClient, pathIdVer); if (!resourceModel.multiple || !(newValProto instanceof JsonElement)) { - this.pushUpdateToClientIfNeeded(lwM2MClient, oldResourceValue, newValProto, pathIdVer, logFailedUpdateOfNonChangedValue, resourceModel.type); + this.pushUpdateToClientIfNeeded(lwM2MClient, oldResourceValue, newValProto, pathIdVer, logFailedUpdateOfNonChangedValue); } else { try { pushUpdateMultiToClientIfNeeded(lwM2MClient, resourceModel, (JsonElement) newValProto, @@ -235,16 +234,14 @@ public class DefaultLwM2MAttributesService implements LwM2MAttributesService { }); } - private void pushUpdateToClientIfNeeded(LwM2mClient lwM2MClient, Object valueOld, Object newValue, - String versionedId, boolean logFailedUpdateOfNonChangedValue, ResourceModel.Type type) { + private void pushUpdateToClientIfNeeded(LwM2mClient lwM2MClient, Object oldValue, Object newValue, + String versionedId, boolean logFailedUpdateOfNonChangedValue) { if (newValue == null) { String logMsg = String.format("%s: Failed update resource versionedId - %s value - %s. New value is bad", LOG_LWM2M_ERROR, versionedId, "null"); logService.log(lwM2MClient, logMsg); log.error("Failed update resource [{}] [{}]", versionedId, "null"); - } else if ((valueOld == null) || - ((OPAQUE.equals(type) && !Arrays.equals((byte[]) newValue, (byte[]) valueOld)) || - !newValue.equals(valueOld))) { + } else if ((oldValue == null) || !valueEquals(newValue, oldValue)) { TbLwM2MWriteReplaceRequest request = TbLwM2MWriteReplaceRequest.builder().versionedId(versionedId).value(newValue).timeout(clientContext.getRequestTimeout(lwM2MClient)).build(); downlinkHandler.sendWriteReplaceRequest(lwM2MClient, request, new TbLwM2MWriteResponseCallback(uplinkHandler, logService, lwM2MClient, versionedId)); } else if (logFailedUpdateOfNonChangedValue) { @@ -262,13 +259,7 @@ public class DefaultLwM2MAttributesService implements LwM2MAttributesService { if (newValues.size() > 0 && valueOld != null && valueOld.size() > 0) { valueOld.values().stream().forEach((v) -> { if (newValues.containsKey(v.getId())) { - boolean isValueEquals; - if (OPAQUE.equals(v.getType())) { - isValueEquals = Arrays.equals((byte[]) newValues.get(v.getId()), (byte[]) v.getValue()); - } else { - isValueEquals = newValues.get(v.getId()).toString().equals(v.getValue().toString()); - } - if (isValueEquals) { + if (valueEquals(newValues.get(v.getId()), v.getValue())) { newValues.remove(v.getId()); } } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2mDownlinkMsgHandler.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2mDownlinkMsgHandler.java index 07acf224c8..3382c8a83b 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2mDownlinkMsgHandler.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2mDownlinkMsgHandler.java @@ -307,11 +307,16 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im value, resourceModelWrite.type); } catch (Exception e) { msgError = "Resource id=" + resultIds.toString() + ", value = " + request.getValue() + - ", class = " + request.getValue().getClass().getSimpleName() + "is bad. Value of Multi-Instance Resource must be in Json format!"; + ", class = " + request.getValue().getClass().getSimpleName() + ". Format value is bad. Value for this Multi-Instance Resource must be in Json format!"; } } else { - downlink = this.getWriteRequestSingleResource(resourceModelWrite.type, contentFormat, - resultIds.getObjectId(), resultIds.getObjectInstanceId(), resultIds.getResourceId(), request.getValue()); + try { + downlink = this.getWriteRequestSingleResource(resourceModelWrite.type, contentFormat, + resultIds.getObjectId(), resultIds.getObjectInstanceId(), resultIds.getResourceId(), request.getValue()); + } catch (Exception e) { + msgError = "Resource id=" + resultIds.toString() + ", value = " + request.getValue() + + ", class = " + request.getValue().getClass().getSimpleName() + ". Format value is bad. Value for this Single Resource must be " + resourceModelWrite.type + "!"; + } } if (downlink != null) { sendSimpleRequest(client, downlink, request.getTimeout(), callback); diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2MTransportUtil.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2MTransportUtil.java index 1a209fd7a3..1531f725c6 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2MTransportUtil.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2MTransportUtil.java @@ -525,4 +525,20 @@ public class LwM2MTransportUtil { } return false; } + + public static boolean valueEquals(Object newValue, Object oldValue) { + String newValueStr; + String oldValueStr; + if (oldValue instanceof byte[]) { + oldValueStr = Hex.encodeHexString((byte[]) oldValue); + } else { + oldValueStr = oldValue.toString(); + } + if (newValue instanceof byte[]) { + newValueStr = Hex.encodeHexString((byte[]) newValue); + } else { + newValueStr = newValue.toString(); + } + return newValueStr.equals(oldValueStr); + } } From f165a1a810b84e99c9dddc3c06651bf32f34835a Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Fri, 15 Oct 2021 16:13:48 +0300 Subject: [PATCH 055/432] dao sql tests: run on postgresql with in-memory disk using testcontainers jdbc (jdbc:tc:postgresql:12.8) --- .../dao/PostgreSqlDaoServiceTestSuite.java | 30 ------------ .../server/dao/SqlDaoServiceTestSuite.java | 36 +------------- .../server/dao/service/DaoPostgreSqlTest.java | 33 ------------- .../EntityServiceSqlTest.java} | 8 ++-- dao/src/test/resources/psql-test.properties | 47 ------------------- dao/src/test/resources/sql-test.properties | 17 +++---- 6 files changed, 15 insertions(+), 156 deletions(-) delete mode 100644 dao/src/test/java/org/thingsboard/server/dao/PostgreSqlDaoServiceTestSuite.java delete mode 100644 dao/src/test/java/org/thingsboard/server/dao/service/DaoPostgreSqlTest.java rename dao/src/test/java/org/thingsboard/server/dao/service/{psql/EntityServicePostgreSqlTest.java => sql/EntityServiceSqlTest.java} (77%) delete mode 100644 dao/src/test/resources/psql-test.properties diff --git a/dao/src/test/java/org/thingsboard/server/dao/PostgreSqlDaoServiceTestSuite.java b/dao/src/test/java/org/thingsboard/server/dao/PostgreSqlDaoServiceTestSuite.java deleted file mode 100644 index b89c70e8f4..0000000000 --- a/dao/src/test/java/org/thingsboard/server/dao/PostgreSqlDaoServiceTestSuite.java +++ /dev/null @@ -1,30 +0,0 @@ -/** - * Copyright © 2016-2021 The Thingsboard Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.thingsboard.server.dao; - -import org.junit.extensions.cpsuite.ClasspathSuite; -import org.junit.extensions.cpsuite.ClasspathSuite.ClassnameFilters; -import org.junit.runner.RunWith; - -@RunWith(ClasspathSuite.class) -@ClassnameFilters({ - "org.thingsboard.server.dao.service.psql.*SqlTest", - "org.thingsboard.server.dao.service.attributes.psql.*SqlTest", - "org.thingsboard.server.dao.service.event.psql.*SqlTest", - "org.thingsboard.server.dao.service.timeseries.psql.*SqlTest" -}) -public class PostgreSqlDaoServiceTestSuite { -} diff --git a/dao/src/test/java/org/thingsboard/server/dao/SqlDaoServiceTestSuite.java b/dao/src/test/java/org/thingsboard/server/dao/SqlDaoServiceTestSuite.java index f110aa2398..163f141f55 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/SqlDaoServiceTestSuite.java +++ b/dao/src/test/java/org/thingsboard/server/dao/SqlDaoServiceTestSuite.java @@ -15,48 +15,16 @@ */ package org.thingsboard.server.dao; -import org.junit.ClassRule; import org.junit.extensions.cpsuite.ClasspathSuite; import org.junit.extensions.cpsuite.ClasspathSuite.ClassnameFilters; import org.junit.runner.RunWith; -import java.util.Arrays; - @RunWith(ClasspathSuite.class) @ClassnameFilters({ - "org.thingsboard.server.dao.service.sql.*SqlTest", "org.thingsboard.server.dao.service.attributes.sql.*SqlTest", "org.thingsboard.server.dao.service.event.sql.*SqlTest", - "org.thingsboard.server.dao.service.timeseries.sql.*SqlTest" - + "org.thingsboard.server.dao.service.sql.*SqlTest", + "org.thingsboard.server.dao.service.timeseries.sql.*SqlTest", }) public class SqlDaoServiceTestSuite { - - @ClassRule - public static CustomSqlUnit sqlUnit = new CustomSqlUnit( - Arrays.asList("sql/schema-types-hsql.sql", "sql/schema-ts-hsql.sql", "sql/schema-entities-hsql.sql", "sql/schema-entities-idx.sql" - , "sql/system-data.sql" - , "sql/system-test.sql" - ), - "sql/hsql/drop-all-tables.sql", - "sql-test.properties" - ); - -// @ClassRule -// public static CustomSqlUnit sqlUnit = new CustomSqlUnit( -// Arrays.asList("sql/schema-ts-psql.sql" -// , "sql/schema-entities.sql", "sql/schema-entities-idx.sql" -// , "sql/system-data.sql", "sql/system-test.sql" -// ), -// "sql/psql/drop-all-tables.sql", -// "sql-test.properties" -// ); - -// @ClassRule -// public static CustomSqlUnit sqlUnit = new CustomSqlUnit( -// Arrays.asList("sql/schema-timescale.sql", "sql/schema-entities.sql", "sql/schema-entities-idx.sql", "sql/system-data.sql", "sql/system-test.sql"), -// "sql/timescale/drop-all-tables.sql", -// "sql-test.properties" -// ); - } diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/DaoPostgreSqlTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/DaoPostgreSqlTest.java deleted file mode 100644 index 43ed1f4d02..0000000000 --- a/dao/src/test/java/org/thingsboard/server/dao/service/DaoPostgreSqlTest.java +++ /dev/null @@ -1,33 +0,0 @@ -/** - * Copyright © 2016-2021 The Thingsboard Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.thingsboard.server.dao.service; - -import org.springframework.test.context.TestPropertySource; - -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Inherited; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -@Target(ElementType.TYPE) -@Retention(RetentionPolicy.RUNTIME) -@Inherited -@Documented -@TestPropertySource(locations = {"classpath:application-test.properties", "classpath:psql-test.properties"}) -public @interface DaoPostgreSqlTest { -} diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/psql/EntityServicePostgreSqlTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/sql/EntityServiceSqlTest.java similarity index 77% rename from dao/src/test/java/org/thingsboard/server/dao/service/psql/EntityServicePostgreSqlTest.java rename to dao/src/test/java/org/thingsboard/server/dao/service/sql/EntityServiceSqlTest.java index 5b8c6d4aca..0c59ae49c8 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/psql/EntityServicePostgreSqlTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/sql/EntityServiceSqlTest.java @@ -13,11 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.dao.service.psql; +package org.thingsboard.server.dao.service.sql; import org.thingsboard.server.dao.service.BaseEntityServiceTest; -import org.thingsboard.server.dao.service.DaoPostgreSqlTest; +import org.thingsboard.server.dao.service.DaoSqlTest; -@DaoPostgreSqlTest -public class EntityServicePostgreSqlTest extends BaseEntityServiceTest { +@DaoSqlTest +public class EntityServiceSqlTest extends BaseEntityServiceTest { } diff --git a/dao/src/test/resources/psql-test.properties b/dao/src/test/resources/psql-test.properties deleted file mode 100644 index fb65966acf..0000000000 --- a/dao/src/test/resources/psql-test.properties +++ /dev/null @@ -1,47 +0,0 @@ -database.ts.type=sql -database.ts_latest.type=sql -sql.ts_inserts_executor_type=fixed -sql.ts_inserts_fixed_thread_pool_size=200 -sql.ts_key_value_partitioning=MONTHS -# -spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=true -spring.jpa.properties.hibernate.order_by.default_null_ordering=last -spring.jpa.properties.hibernate.jdbc.log.warnings=false -spring.jpa.show-sql=false -spring.jpa.hibernate.ddl-auto=none -spring.jpa.database-platform=org.hibernate.dialect.PostgreSQLDialect -spring.datasource.username=postgres -spring.datasource.password=postgres -spring.datasource.url=jdbc:tc:postgresql:12.8:///thingsboard?TC_DAEMON=true&TC_TMPFS=/testtmpfs:rw&?TC_INITFUNCTION=org.thingsboard.server.dao.PostgreSqlInitializer::initDb -spring.datasource.driverClassName=org.testcontainers.jdbc.ContainerDatabaseDriver -#org.postgresql.Driver -spring.datasource.hikari.maximumPoolSize=50 -service.type=monolith -#database.ts.type=timescale -#database.ts.type=sql -#database.entities.type=sql -# -#sql.ts_inserts_executor_type=fixed -#sql.ts_inserts_fixed_thread_pool_size=200 -#sql.ts_key_value_partitioning=MONTHS -# -#spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=true -#spring.jpa.show-sql=false -#spring.jpa.hibernate.ddl-auto=none -#spring.jpa.database-platform=org.hibernate.dialect.PostgreSQLDialect -# -#spring.datasource.username=postgres -#spring.datasource.password=postgres -#spring.datasource.url=jdbc:postgresql://localhost:5432/sqltest -#spring.datasource.driverClassName=org.postgresql.Driver -#spring.datasource.hikari.maximumPoolSize = 50 -queue.core.pack-processing-timeout=3000 -queue.rule-engine.pack-processing-timeout=3000 -queue.rule-engine.queues[0].name=Main -queue.rule-engine.queues[0].topic=tb_rule_engine.main -queue.rule-engine.queues[0].poll-interval=25 -queue.rule-engine.queues[0].partitions=3 -queue.rule-engine.queues[0].pack-processing-timeout=3000 -queue.rule-engine.queues[0].processing-strategy.type=SKIP_ALL_FAILURES -queue.rule-engine.queues[0].submit-strategy.type=BURST -sql.log_entity_queries=true diff --git a/dao/src/test/resources/sql-test.properties b/dao/src/test/resources/sql-test.properties index e81637ac3e..ee14004969 100644 --- a/dao/src/test/resources/sql-test.properties +++ b/dao/src/test/resources/sql-test.properties @@ -10,14 +10,15 @@ spring.jpa.properties.hibernate.order_by.default_null_ordering=last spring.jpa.properties.hibernate.jdbc.log.warnings=false spring.jpa.show-sql=false -spring.jpa.hibernate.ddl-auto=validate -spring.jpa.database-platform=org.hibernate.dialect.HSQLDialect - -spring.datasource.username=sa -spring.datasource.password= -spring.datasource.url=jdbc:hsqldb:file:target/tmp/testDb;sql.enforce_size=false;sql.syntax_pgs=true -spring.datasource.driverClassName=org.hsqldb.jdbc.JDBCDriver -spring.datasource.hikari.maximumPoolSize = 50 + +spring.jpa.hibernate.ddl-auto=none +spring.jpa.database-platform=org.hibernate.dialect.PostgreSQLDialect +spring.datasource.username=postgres +spring.datasource.password=postgres +spring.datasource.url=jdbc:tc:postgresql:12.8:///thingsboard?TC_DAEMON=true&TC_TMPFS=/testtmpfs:rw&?TC_INITFUNCTION=org.thingsboard.server.dao.PostgreSqlInitializer::initDb +spring.datasource.driverClassName=org.testcontainers.jdbc.ContainerDatabaseDriver + +spring.datasource.hikari.maximumPoolSize = 20 service.type=monolith From d52c64ef03b1d9e18d92ecd59dfc841a84f21535 Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Fri, 15 Oct 2021 19:48:49 +0300 Subject: [PATCH 056/432] CustomSqlUnit removed from test suites. dependency added for testcontainers for application test scope. --- application/pom.xml | 9 +++++-- .../controller/ControllerSqlTestSuite.java | 15 +++-------- .../server/edge/EdgeSqlTestSuite.java | 16 +++--------- .../server/rules/RuleEngineSqlTestSuite.java | 16 +++--------- .../server/service/ServiceSqlTestSuite.java | 15 +++-------- .../server/system/SystemSqlTestSuite.java | 16 +++--------- .../transport/TransportNoSqlTestSuite.java | 13 +++------- .../transport/TransportSqlTestSuite.java | 13 ++-------- dao/pom.xml | 5 ---- .../thingsboard/server/dao/CustomSqlUnit.java | 3 +++ .../server/dao/JpaDaoTestSuite.java | 26 +------------------ .../server/dao/NoSqlDaoServiceTestSuite.java | 9 +------ dao/src/test/resources/nosql-test.properties | 12 ++++----- dao/src/test/resources/sql-test.properties | 3 +-- 14 files changed, 43 insertions(+), 128 deletions(-) diff --git a/application/pom.xml b/application/pom.xml index 3378d52459..d21dc7bb2e 100644 --- a/application/pom.xml +++ b/application/pom.xml @@ -311,8 +311,13 @@ test - org.hsqldb - hsqldb + org.testcontainers + postgresql + test + + + org.testcontainers + jdbc test diff --git a/application/src/test/java/org/thingsboard/server/controller/ControllerSqlTestSuite.java b/application/src/test/java/org/thingsboard/server/controller/ControllerSqlTestSuite.java index e30ef07b5b..413955ca22 100644 --- a/application/src/test/java/org/thingsboard/server/controller/ControllerSqlTestSuite.java +++ b/application/src/test/java/org/thingsboard/server/controller/ControllerSqlTestSuite.java @@ -16,14 +16,10 @@ package org.thingsboard.server.controller; import org.junit.BeforeClass; -import org.junit.ClassRule; import org.junit.extensions.cpsuite.ClasspathSuite; import org.junit.runner.RunWith; -import org.thingsboard.server.dao.CustomSqlUnit; import org.thingsboard.server.queue.memory.InMemoryStorage; -import java.util.Arrays; - @RunWith(ClasspathSuite.class) @ClasspathSuite.ClassnameFilters({ // "org.thingsboard.server.controller.sql.WebsocketApiSqlTest", @@ -31,17 +27,12 @@ import java.util.Arrays; // "org.thingsboard.server.controller.sql.TbResourceControllerSqlTest", // "org.thingsboard.server.controller.sql.DeviceProfileControllerSqlTest", "org.thingsboard.server.controller.sql.*Test", - }) +}) public class ControllerSqlTestSuite { - @ClassRule - public static CustomSqlUnit sqlUnit = new CustomSqlUnit( - Arrays.asList("sql/schema-types-hsql.sql", "sql/schema-ts-hsql.sql", "sql/schema-entities-hsql.sql", "sql/schema-entities-idx.sql", "sql/system-data.sql"), - "sql/hsql/drop-all-tables.sql", - "sql-test.properties"); - @BeforeClass - public static void cleanupInMemStorage(){ + public static void cleanupInMemStorage() { InMemoryStorage.getInstance().cleanup(); } + } diff --git a/application/src/test/java/org/thingsboard/server/edge/EdgeSqlTestSuite.java b/application/src/test/java/org/thingsboard/server/edge/EdgeSqlTestSuite.java index 19b6bd7f23..ea7b275cfd 100644 --- a/application/src/test/java/org/thingsboard/server/edge/EdgeSqlTestSuite.java +++ b/application/src/test/java/org/thingsboard/server/edge/EdgeSqlTestSuite.java @@ -16,26 +16,18 @@ package org.thingsboard.server.edge; import org.junit.BeforeClass; -import org.junit.ClassRule; import org.junit.extensions.cpsuite.ClasspathSuite; import org.junit.runner.RunWith; -import org.thingsboard.server.dao.CustomSqlUnit; import org.thingsboard.server.queue.memory.InMemoryStorage; -import java.util.Arrays; - @RunWith(ClasspathSuite.class) -@ClasspathSuite.ClassnameFilters({"org.thingsboard.server.edge.sql.*Test"}) +@ClasspathSuite.ClassnameFilters({ + "org.thingsboard.server.edge.sql.*Test", +}) public class EdgeSqlTestSuite { - @ClassRule - public static CustomSqlUnit sqlUnit = new CustomSqlUnit( - Arrays.asList("sql/schema-types-hsql.sql", "sql/schema-ts-hsql.sql", "sql/schema-entities-hsql.sql", "sql/system-data.sql"), - "sql/hsql/drop-all-tables.sql", - "sql-test.properties"); - @BeforeClass - public static void cleanupInMemStorage(){ + public static void cleanupInMemStorage() { InMemoryStorage.getInstance().cleanup(); } } diff --git a/application/src/test/java/org/thingsboard/server/rules/RuleEngineSqlTestSuite.java b/application/src/test/java/org/thingsboard/server/rules/RuleEngineSqlTestSuite.java index 4eebeaa606..2989d2de7f 100644 --- a/application/src/test/java/org/thingsboard/server/rules/RuleEngineSqlTestSuite.java +++ b/application/src/test/java/org/thingsboard/server/rules/RuleEngineSqlTestSuite.java @@ -16,28 +16,20 @@ package org.thingsboard.server.rules; import org.junit.BeforeClass; -import org.junit.ClassRule; import org.junit.extensions.cpsuite.ClasspathSuite; import org.junit.runner.RunWith; -import org.thingsboard.server.dao.CustomSqlUnit; import org.thingsboard.server.queue.memory.InMemoryStorage; -import java.util.Arrays; - @RunWith(ClasspathSuite.class) @ClasspathSuite.ClassnameFilters({ "org.thingsboard.server.rules.flow.sql.*Test", - "org.thingsboard.server.rules.lifecycle.sql.*Test"}) + "org.thingsboard.server.rules.lifecycle.sql.*Test", +}) public class RuleEngineSqlTestSuite { - @ClassRule - public static CustomSqlUnit sqlUnit = new CustomSqlUnit( - Arrays.asList("sql/schema-types-hsql.sql", "sql/schema-ts-hsql.sql", "sql/schema-entities-hsql.sql", "sql/system-data.sql"), - "sql/hsql/drop-all-tables.sql", - "sql-test.properties"); - @BeforeClass - public static void cleanupInMemStorage(){ + public static void cleanupInMemStorage() { InMemoryStorage.getInstance().cleanup(); } + } diff --git a/application/src/test/java/org/thingsboard/server/service/ServiceSqlTestSuite.java b/application/src/test/java/org/thingsboard/server/service/ServiceSqlTestSuite.java index 7ba11be52e..508272085c 100644 --- a/application/src/test/java/org/thingsboard/server/service/ServiceSqlTestSuite.java +++ b/application/src/test/java/org/thingsboard/server/service/ServiceSqlTestSuite.java @@ -16,28 +16,19 @@ package org.thingsboard.server.service; import org.junit.BeforeClass; -import org.junit.ClassRule; import org.junit.extensions.cpsuite.ClasspathSuite; import org.junit.runner.RunWith; -import org.thingsboard.server.dao.CustomSqlUnit; import org.thingsboard.server.queue.memory.InMemoryStorage; -import java.util.Arrays; - @RunWith(ClasspathSuite.class) @ClasspathSuite.ClassnameFilters({ "org.thingsboard.server.service.resource.sql.*Test", - }) +}) public class ServiceSqlTestSuite { - @ClassRule - public static CustomSqlUnit sqlUnit = new CustomSqlUnit( - Arrays.asList("sql/schema-types-hsql.sql", "sql/schema-ts-hsql.sql", "sql/schema-entities-hsql.sql", "sql/schema-entities-idx.sql", "sql/system-data.sql"), - "sql/hsql/drop-all-tables.sql", - "sql-test.properties"); - @BeforeClass - public static void cleanupInMemStorage(){ + public static void cleanupInMemStorage() { InMemoryStorage.getInstance().cleanup(); } + } diff --git a/application/src/test/java/org/thingsboard/server/system/SystemSqlTestSuite.java b/application/src/test/java/org/thingsboard/server/system/SystemSqlTestSuite.java index 157625f96f..52f7e07f6a 100644 --- a/application/src/test/java/org/thingsboard/server/system/SystemSqlTestSuite.java +++ b/application/src/test/java/org/thingsboard/server/system/SystemSqlTestSuite.java @@ -16,29 +16,21 @@ package org.thingsboard.server.system; import org.junit.BeforeClass; -import org.junit.ClassRule; import org.junit.extensions.cpsuite.ClasspathSuite; import org.junit.runner.RunWith; -import org.thingsboard.server.dao.CustomSqlUnit; import org.thingsboard.server.queue.memory.InMemoryStorage; -import java.util.Arrays; - /** * Created by Valerii Sosliuk on 6/27/2017. */ @RunWith(ClasspathSuite.class) -@ClasspathSuite.ClassnameFilters({"org.thingsboard.server.system.sql.*SqlTest"}) +@ClasspathSuite.ClassnameFilters({ + "org.thingsboard.server.system.sql.*SqlTest", +}) public class SystemSqlTestSuite { - @ClassRule - public static CustomSqlUnit sqlUnit = new CustomSqlUnit( - Arrays.asList("sql/schema-types-hsql.sql", "sql/schema-ts-hsql.sql", "sql/schema-entities-hsql.sql", "sql/system-data.sql"), - "sql/hsql/drop-all-tables.sql", - "sql-test.properties"); - @BeforeClass - public static void cleanupInMemStorage(){ + public static void cleanupInMemStorage() { InMemoryStorage.getInstance().cleanup(); } diff --git a/application/src/test/java/org/thingsboard/server/transport/TransportNoSqlTestSuite.java b/application/src/test/java/org/thingsboard/server/transport/TransportNoSqlTestSuite.java index 539a1da055..f5e02c146d 100644 --- a/application/src/test/java/org/thingsboard/server/transport/TransportNoSqlTestSuite.java +++ b/application/src/test/java/org/thingsboard/server/transport/TransportNoSqlTestSuite.java @@ -21,22 +21,16 @@ import org.junit.ClassRule; import org.junit.extensions.cpsuite.ClasspathSuite; import org.junit.runner.RunWith; import org.thingsboard.server.dao.CustomCassandraCQLUnit; -import org.thingsboard.server.dao.CustomSqlUnit; import org.thingsboard.server.queue.memory.InMemoryStorage; import java.util.Arrays; @RunWith(ClasspathSuite.class) @ClasspathSuite.ClassnameFilters({ - "org.thingsboard.server.transport.*.telemetry.timeseries.nosql.*Test"}) + "org.thingsboard.server.transport.*.telemetry.timeseries.nosql.*Test", +}) public class TransportNoSqlTestSuite { - @ClassRule - public static CustomSqlUnit sqlUnit = new CustomSqlUnit( - Arrays.asList("sql/schema-types-hsql.sql", "sql/schema-entities-hsql.sql", "sql/system-data.sql"), - "sql/hsql/drop-all-tables.sql", - "nosql-test.properties"); - @ClassRule public static CustomCassandraCQLUnit cassandraUnit = new CustomCassandraCQLUnit( @@ -47,7 +41,8 @@ public class TransportNoSqlTestSuite { "cassandra-test.yaml", 30000l); @BeforeClass - public static void cleanupInMemStorage(){ + public static void cleanupInMemStorage() { InMemoryStorage.getInstance().cleanup(); } + } diff --git a/application/src/test/java/org/thingsboard/server/transport/TransportSqlTestSuite.java b/application/src/test/java/org/thingsboard/server/transport/TransportSqlTestSuite.java index 0fa04d0611..7454589a6d 100644 --- a/application/src/test/java/org/thingsboard/server/transport/TransportSqlTestSuite.java +++ b/application/src/test/java/org/thingsboard/server/transport/TransportSqlTestSuite.java @@ -16,14 +16,10 @@ package org.thingsboard.server.transport; import org.junit.BeforeClass; -import org.junit.ClassRule; import org.junit.extensions.cpsuite.ClasspathSuite; import org.junit.runner.RunWith; -import org.thingsboard.server.dao.CustomSqlUnit; import org.thingsboard.server.queue.memory.InMemoryStorage; -import java.util.Arrays; - @RunWith(ClasspathSuite.class) @ClasspathSuite.ClassnameFilters({ "org.thingsboard.server.transport.*.rpc.sql.*Test", @@ -37,14 +33,9 @@ import java.util.Arrays; }) public class TransportSqlTestSuite { - @ClassRule - public static CustomSqlUnit sqlUnit = new CustomSqlUnit( - Arrays.asList("sql/schema-types-hsql.sql", "sql/schema-ts-hsql.sql", "sql/schema-entities-hsql.sql", "sql/system-data.sql"), - "sql/hsql/drop-all-tables.sql", - "sql-test.properties"); - @BeforeClass - public static void cleanupInMemStorage(){ + public static void cleanupInMemStorage() { InMemoryStorage.getInstance().cleanup(); } + } diff --git a/dao/pom.xml b/dao/pom.xml index f490a0e8e5..984ed753d2 100644 --- a/dao/pom.xml +++ b/dao/pom.xml @@ -211,11 +211,6 @@ spring-test test - - org.hsqldb - hsqldb - test - org.testcontainers postgresql diff --git a/dao/src/test/java/org/thingsboard/server/dao/CustomSqlUnit.java b/dao/src/test/java/org/thingsboard/server/dao/CustomSqlUnit.java index da19ae7a93..66d20f704d 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/CustomSqlUnit.java +++ b/dao/src/test/java/org/thingsboard/server/dao/CustomSqlUnit.java @@ -32,8 +32,11 @@ import java.util.Properties; /** * Created by Valerii Sosliuk on 6/24/2017. + * + * Deprecated. Use PostgreSqlInitializer class instead */ @Slf4j +@Deprecated public class CustomSqlUnit extends ExternalResource { private final List sqlFiles; diff --git a/dao/src/test/java/org/thingsboard/server/dao/JpaDaoTestSuite.java b/dao/src/test/java/org/thingsboard/server/dao/JpaDaoTestSuite.java index 23630e4b19..889607cb59 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/JpaDaoTestSuite.java +++ b/dao/src/test/java/org/thingsboard/server/dao/JpaDaoTestSuite.java @@ -15,38 +15,14 @@ */ package org.thingsboard.server.dao; -import org.junit.ClassRule; import org.junit.extensions.cpsuite.ClasspathSuite; import org.junit.extensions.cpsuite.ClasspathSuite.ClassnameFilters; import org.junit.runner.RunWith; -import java.util.Arrays; - @RunWith(ClasspathSuite.class) @ClassnameFilters({ - "org.thingsboard.server.dao.sql.*THIS_MUST_BE_FIXED_Test" + "org.thingsboard.server.dao.sql.*THIS_MUST_BE_FIXED_Test", }) public class JpaDaoTestSuite { - @ClassRule - public static CustomSqlUnit sqlUnit = new CustomSqlUnit( - Arrays.asList("sql/schema-ts-hsql.sql", "sql/schema-entities-hsql.sql", "sql/system-data.sql"), - "sql/hsql/drop-all-tables.sql", - "sql-test.properties" - ); - -// @ClassRule -// public static CustomSqlUnit sqlUnit = new CustomSqlUnit( -// Arrays.asList("sql/schema-ts-psql.sql", "sql/schema-entities.sql", "sql/system-data.sql"), -// "sql/psql/drop-all-tables.sql", -// "sql-test.properties" -// ); - -// @ClassRule -// public static CustomSqlUnit sqlUnit = new CustomSqlUnit( -// Arrays.asList("sql/schema-timescale.sql", "sql/schema-timescale-idx.sql", "sql/schema-entities.sql", "sql/system-data.sql"), -// "sql/timescale/drop-all-tables.sql", -// "sql-test.properties" -// ); - } diff --git a/dao/src/test/java/org/thingsboard/server/dao/NoSqlDaoServiceTestSuite.java b/dao/src/test/java/org/thingsboard/server/dao/NoSqlDaoServiceTestSuite.java index cb6de2fe89..c4bf1a5f77 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/NoSqlDaoServiceTestSuite.java +++ b/dao/src/test/java/org/thingsboard/server/dao/NoSqlDaoServiceTestSuite.java @@ -25,17 +25,10 @@ import java.util.Arrays; @RunWith(ClasspathSuite.class) @ClassnameFilters({ - "org.thingsboard.server.dao.service.nosql.*ServiceNoSqlTest" + "org.thingsboard.server.dao.service.nosql.*ServiceNoSqlTest", }) public class NoSqlDaoServiceTestSuite { - @ClassRule - public static CustomSqlUnit sqlUnit = new CustomSqlUnit( - Arrays.asList("sql/schema-types-hsql.sql", "sql/schema-entities-hsql.sql", "sql/schema-entities-idx.sql", "sql/system-data.sql", "sql/system-test.sql"), - "sql/hsql/drop-all-tables.sql", - "nosql-test.properties" - ); - @ClassRule public static CustomCassandraCQLUnit cassandraUnit = new CustomCassandraCQLUnit( diff --git a/dao/src/test/resources/nosql-test.properties b/dao/src/test/resources/nosql-test.properties index 6fe2dc2112..b81f5db8ac 100644 --- a/dao/src/test/resources/nosql-test.properties +++ b/dao/src/test/resources/nosql-test.properties @@ -9,11 +9,11 @@ spring.jpa.properties.hibernate.order_by.default_null_ordering=last spring.jpa.properties.hibernate.jdbc.log.warnings=false spring.jpa.show-sql=false -spring.jpa.hibernate.ddl-auto=none -spring.jpa.database-platform=org.hibernate.dialect.HSQLDialect -spring.datasource.username=sa -spring.datasource.password= -spring.datasource.url=jdbc:hsqldb:file:/tmp/testDb;sql.enforce_size=false -spring.datasource.driverClassName=org.hsqldb.jdbc.JDBCDriver +spring.jpa.hibernate.ddl-auto=none +spring.jpa.database-platform=org.hibernate.dialect.PostgreSQLDialect +spring.datasource.username=postgres +spring.datasource.password=postgres +spring.datasource.url=jdbc:tc:postgresql:12.8:///thingsboard?TC_DAEMON=true&TC_TMPFS=/testtmpfs:rw&?TC_INITFUNCTION=org.thingsboard.server.dao.PostgreSqlInitializer::initDb +spring.datasource.driverClassName=org.testcontainers.jdbc.ContainerDatabaseDriver spring.datasource.hikari.maximumPoolSize = 50 diff --git a/dao/src/test/resources/sql-test.properties b/dao/src/test/resources/sql-test.properties index ee14004969..d2add71eea 100644 --- a/dao/src/test/resources/sql-test.properties +++ b/dao/src/test/resources/sql-test.properties @@ -17,8 +17,7 @@ spring.datasource.username=postgres spring.datasource.password=postgres spring.datasource.url=jdbc:tc:postgresql:12.8:///thingsboard?TC_DAEMON=true&TC_TMPFS=/testtmpfs:rw&?TC_INITFUNCTION=org.thingsboard.server.dao.PostgreSqlInitializer::initDb spring.datasource.driverClassName=org.testcontainers.jdbc.ContainerDatabaseDriver - -spring.datasource.hikari.maximumPoolSize = 20 +spring.datasource.hikari.maximumPoolSize = 50 service.type=monolith From 6246753b92771c7de64427384699695165b9e71f Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Mon, 18 Oct 2021 16:10:26 +0300 Subject: [PATCH 057/432] test: refactored to clear InMemoryStorage (queues) on before and after each test, delete tenant profiles after each test run, psql specific indexes added --- .../AbstractInMemoryStorageTest.java | 42 +++++++++++++++++++ .../server/controller/AbstractWebTest.java | 24 +++++++---- .../BaseTenantProfileControllerTest.java | 7 ---- .../server/dao/PostgreSqlInitializer.java | 1 + 4 files changed, 60 insertions(+), 14 deletions(-) create mode 100644 application/src/test/java/org/thingsboard/server/controller/AbstractInMemoryStorageTest.java diff --git a/application/src/test/java/org/thingsboard/server/controller/AbstractInMemoryStorageTest.java b/application/src/test/java/org/thingsboard/server/controller/AbstractInMemoryStorageTest.java new file mode 100644 index 0000000000..8daa48722e --- /dev/null +++ b/application/src/test/java/org/thingsboard/server/controller/AbstractInMemoryStorageTest.java @@ -0,0 +1,42 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.controller; + +import lombok.extern.slf4j.Slf4j; +import org.junit.After; +import org.junit.Before; +import org.thingsboard.server.queue.memory.InMemoryStorage; + +@Slf4j +public abstract class AbstractInMemoryStorageTest { + + @Before + public void setUpInMemoryStorage() { + log.info("set up InMemoryStorage"); + cleanupInMemStorage(); + } + + @After + public void tearDownInMemoryStorage() { + log.info("tear down InMemoryStorage"); + cleanupInMemStorage(); + } + + public static void cleanupInMemStorage() { + InMemoryStorage.getInstance().cleanup(); + } + +} diff --git a/application/src/test/java/org/thingsboard/server/controller/AbstractWebTest.java b/application/src/test/java/org/thingsboard/server/controller/AbstractWebTest.java index 7be184e036..1a6027350c 100644 --- a/application/src/test/java/org/thingsboard/server/controller/AbstractWebTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/AbstractWebTest.java @@ -71,6 +71,8 @@ import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.page.TimePageLink; import org.thingsboard.server.common.data.security.Authority; import org.thingsboard.server.config.ThingsboardSecurityConfiguration; +import org.thingsboard.server.dao.tenant.TenantProfileService; +import org.thingsboard.server.queue.memory.InMemoryStorage; import org.thingsboard.server.service.mail.TestMailService; import org.thingsboard.server.service.security.auth.jwt.RefreshTokenRequest; import org.thingsboard.server.service.security.auth.rest.LoginRequest; @@ -93,7 +95,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. import static org.springframework.test.web.servlet.setup.MockMvcBuilders.webAppContextSetup; @Slf4j -public abstract class AbstractWebTest { +public abstract class AbstractWebTest extends AbstractInMemoryStorageTest{ protected ObjectMapper mapper = new ObjectMapper(); @@ -132,6 +134,9 @@ public abstract class AbstractWebTest { @Autowired private WebApplicationContext webApplicationContext; + @Autowired + private TenantProfileService tenantProfileService; + @Rule public TestRule watcher = new TestWatcher() { protected void starting(Description description) { @@ -161,8 +166,9 @@ public abstract class AbstractWebTest { } @Before - public void setup() throws Exception { - log.info("Executing setup"); + public void setupWebTest() throws Exception { + log.info("Executing web test setup"); + if (this.mockMvc == null) { this.mockMvc = webAppContextSetup(webApplicationContext) .apply(springSecurity()).build(); @@ -197,16 +203,20 @@ public abstract class AbstractWebTest { logout(); - log.info("Executed setup"); + log.info("Executed web test setup"); } @After - public void teardown() throws Exception { - log.info("Executing teardown"); + public void teardownWebTest() throws Exception { + log.info("Executing web test teardown"); + loginSysAdmin(); doDelete("/api/tenant/" + tenantId.getId().toString()) .andExpect(status().isOk()); - log.info("Executed teardown"); + + tenantProfileService.deleteTenantProfiles(TenantId.SYS_TENANT_ID); + + log.info("Executed web test teardown"); } protected void loginSysAdmin() throws Exception { diff --git a/application/src/test/java/org/thingsboard/server/controller/BaseTenantProfileControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/BaseTenantProfileControllerTest.java index c70e7d0178..bf8ab3e343 100644 --- a/application/src/test/java/org/thingsboard/server/controller/BaseTenantProfileControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/BaseTenantProfileControllerTest.java @@ -46,13 +46,6 @@ public abstract class BaseTenantProfileControllerTest extends AbstractController @Autowired private TenantProfileService tenantProfileService; - @After - @Override - public void teardown() throws Exception { - super.teardown(); - tenantProfileService.deleteTenantProfiles(TenantId.SYS_TENANT_ID); - } - @Test public void testSaveTenantProfile() throws Exception { loginSysAdmin(); diff --git a/dao/src/test/java/org/thingsboard/server/dao/PostgreSqlInitializer.java b/dao/src/test/java/org/thingsboard/server/dao/PostgreSqlInitializer.java index 429fa1d711..6719f6dfe2 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/PostgreSqlInitializer.java +++ b/dao/src/test/java/org/thingsboard/server/dao/PostgreSqlInitializer.java @@ -32,6 +32,7 @@ public class PostgreSqlInitializer { "sql/schema-ts-psql.sql", "sql/schema-entities.sql", "sql/schema-entities-idx.sql", + "sql/schema-entities-idx-psql-addon.sql", "sql/system-data.sql", "sql/system-test-psql.sql"); private static final String dropAllTablesSqlFile = "sql/psql/drop-all-tables.sql"; From 8feec6f078c42beacd4d70ea451b71ae84cfb486 Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Mon, 18 Oct 2021 16:11:29 +0300 Subject: [PATCH 058/432] CaffeineCacheDefaultConfigurationTest renamed from TestSuite --- ...tSuite.java => CaffeineCacheDefaultConfigurationTest.java} | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename application/src/test/java/org/thingsboard/server/cache/{CaffeineCacheDefaultConfigurationTestSuite.java => CaffeineCacheDefaultConfigurationTest.java} (95%) diff --git a/application/src/test/java/org/thingsboard/server/cache/CaffeineCacheDefaultConfigurationTestSuite.java b/application/src/test/java/org/thingsboard/server/cache/CaffeineCacheDefaultConfigurationTest.java similarity index 95% rename from application/src/test/java/org/thingsboard/server/cache/CaffeineCacheDefaultConfigurationTestSuite.java rename to application/src/test/java/org/thingsboard/server/cache/CaffeineCacheDefaultConfigurationTest.java index cdca5f3af9..eaab5c196e 100644 --- a/application/src/test/java/org/thingsboard/server/cache/CaffeineCacheDefaultConfigurationTestSuite.java +++ b/application/src/test/java/org/thingsboard/server/cache/CaffeineCacheDefaultConfigurationTest.java @@ -29,11 +29,11 @@ import org.springframework.test.context.junit.jupiter.SpringExtension; import static org.assertj.core.api.Assertions.assertThat; @ExtendWith(SpringExtension.class) -@ContextConfiguration(classes = CaffeineCacheDefaultConfigurationTestSuite.class, loader = SpringBootContextLoader.class) +@ContextConfiguration(classes = CaffeineCacheDefaultConfigurationTest.class, loader = SpringBootContextLoader.class) @ComponentScan({"org.thingsboard.server.cache"}) @EnableConfigurationProperties @Slf4j -public class CaffeineCacheDefaultConfigurationTestSuite { +public class CaffeineCacheDefaultConfigurationTest { @Autowired CaffeineCacheConfiguration caffeineCacheConfiguration; From d98419106b7045c2538dff3f92c99ab8e0319053 Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Mon, 18 Oct 2021 16:47:43 +0300 Subject: [PATCH 059/432] InMemoryStorage: added getLagTotal to be able to await while queue have any messages (no guarantee that messages was processed). --- .../server/queue/memory/InMemoryStorage.java | 4 ++ .../queue/memory/InMemoryStorageTest.java | 39 +++++++++++++++++++ 2 files changed, 43 insertions(+) create mode 100644 common/queue/src/test/java/org/thingsboard/server/queue/memory/InMemoryStorageTest.java diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/memory/InMemoryStorage.java b/common/queue/src/main/java/org/thingsboard/server/queue/memory/InMemoryStorage.java index 226ed32682..58a722e77c 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/memory/InMemoryStorage.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/memory/InMemoryStorage.java @@ -42,6 +42,10 @@ public final class InMemoryStorage { }); } + public int getLagTotal() { + return storage.values().stream().map(BlockingQueue::size).reduce(0, Integer::sum); + } + public static InMemoryStorage getInstance() { if (instance == null) { synchronized (InMemoryStorage.class) { diff --git a/common/queue/src/test/java/org/thingsboard/server/queue/memory/InMemoryStorageTest.java b/common/queue/src/test/java/org/thingsboard/server/queue/memory/InMemoryStorageTest.java new file mode 100644 index 0000000000..4e92a46748 --- /dev/null +++ b/common/queue/src/test/java/org/thingsboard/server/queue/memory/InMemoryStorageTest.java @@ -0,0 +1,39 @@ +package org.thingsboard.server.queue.memory; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.thingsboard.server.queue.TbQueueMsg; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; + +public class InMemoryStorageTest { + + InMemoryStorage storage = InMemoryStorage.getInstance(); + + @Before + public void setUp() { + storage.cleanup(); + } + + @After + public void tearDown() { + storage.cleanup(); + } + + @Test + public void givenStorage_whenGetLagTotal_thenReturnInteger() throws InterruptedException { + assertThat(storage.getLagTotal()).isEqualTo(0); + storage.put("main", mock(TbQueueMsg.class)); + assertThat(storage.getLagTotal()).isEqualTo(1); + storage.put("main", mock(TbQueueMsg.class)); + assertThat(storage.getLagTotal()).isEqualTo(2); + storage.put("hp", mock(TbQueueMsg.class)); + assertThat(storage.getLagTotal()).isEqualTo(3); + storage.get("main"); + assertThat(storage.getLagTotal()).isEqualTo(1); + storage.cleanup(); + assertThat(storage.getLagTotal()).isEqualTo(0); + } +} \ No newline at end of file From 78c624ea52f6402719e9f215ff67c7834b56efc2 Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Mon, 18 Oct 2021 16:47:58 +0300 Subject: [PATCH 060/432] AbstractRuleEngineLifecycleIntegrationTest added await getLagTotal == 0 --- .../AbstractRuleEngineLifecycleIntegrationTest.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/application/src/test/java/org/thingsboard/server/rules/lifecycle/AbstractRuleEngineLifecycleIntegrationTest.java b/application/src/test/java/org/thingsboard/server/rules/lifecycle/AbstractRuleEngineLifecycleIntegrationTest.java index cfa546cc11..ccdf788634 100644 --- a/application/src/test/java/org/thingsboard/server/rules/lifecycle/AbstractRuleEngineLifecycleIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/rules/lifecycle/AbstractRuleEngineLifecycleIntegrationTest.java @@ -42,11 +42,14 @@ import org.thingsboard.server.common.msg.queue.QueueToRuleEngineMsg; import org.thingsboard.server.common.msg.queue.TbMsgCallback; import org.thingsboard.server.controller.AbstractRuleEngineControllerTest; import org.thingsboard.server.dao.attributes.AttributesService; +import org.thingsboard.server.queue.memory.InMemoryStorage; import java.util.Collections; import java.util.List; +import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; +import static org.awaitility.Awaitility.await; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; /** @@ -132,6 +135,8 @@ public abstract class AbstractRuleEngineLifecycleIntegrationTest extends Abstrac attributesService.save(device.getTenantId(), device.getId(), DataConstants.SERVER_SCOPE, Collections.singletonList(new BaseAttributeKvEntry(new StringDataEntry("serverAttributeKey", "serverAttributeValue"), System.currentTimeMillis()))); + await("total inMemory queue lag is empty").atMost(30, TimeUnit.SECONDS) + .until(() -> InMemoryStorage.getInstance().getLagTotal() == 0); Thread.sleep(1000); TbMsgCallback tbMsgCallback = Mockito.mock(TbMsgCallback.class); @@ -139,7 +144,7 @@ public abstract class AbstractRuleEngineLifecycleIntegrationTest extends Abstrac QueueToRuleEngineMsg qMsg = new QueueToRuleEngineMsg(savedTenant.getId(), tbMsg, null, null); // Pushing Message to the system actorSystem.tell(qMsg); - Mockito.verify(tbMsgCallback, Mockito.timeout(3000)).onSuccess(); + Mockito.verify(tbMsgCallback, Mockito.timeout(10000)).onSuccess(); PageData eventsPage = getDebugEvents(savedTenant.getId(), ruleChain.getFirstRuleNodeId(), 1000); From 0d6a49aafc24119b3baeb80ad25343c8ffeb2bfb Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Wed, 20 Oct 2021 17:24:40 +0300 Subject: [PATCH 061/432] Lwm2m front base64 tooltip --- .../device-credentials-lwm2m-server.component.html | 7 +++++++ .../device/device-credentials-lwm2m.component.html | 14 +++++++++++--- .../lwm2m-device-config-server.component.html | 7 ++++++- ...-profile-transport-configuration.component.html | 4 ++-- .../src/assets/locale/locale.constant-cs_CZ.json | 1 - .../src/assets/locale/locale.constant-en_US.json | 13 +++++++++---- .../src/assets/locale/locale.constant-tr_TR.json | 1 - 7 files changed, 35 insertions(+), 12 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/device/device-credentials-lwm2m-server.component.html b/ui-ngx/src/app/modules/home/components/device/device-credentials-lwm2m-server.component.html index 3c3806882f..d9f08787b6 100644 --- a/ui-ngx/src/app/modules/home/components/device/device-credentials-lwm2m-server.component.html +++ b/ui-ngx/src/app/modules/home/components/device/device-credentials-lwm2m-server.component.html @@ -32,6 +32,9 @@ cdkAutosizeMinRows="1" cols="1" formControlName="clientPublicKeyOrId" + matTooltip="{{ 'device.lwm2m-security-config.client-publicKey-or-id-tooltip' | translate: + {count: serverFormGroup.get('securityMode').value === securityConfigLwM2MType.PSK? 0 : + serverFormGroup.get('securityMode').value === securityConfigLwM2MType.RPK? 1 : 2} }}" required> @@ -45,6 +48,10 @@ cdkAutosizeMinRows="1" cols="1" formControlName="clientSecretKey" + matTooltip="{{ 'device.lwm2m-security-config.client-secret-key-tooltip' | translate: + {count: serverFormGroup.get('securityMode').value === securityConfigLwM2MType.PSK? 0 : + serverFormGroup.get('securityMode').value === securityConfigLwM2MType.RPK? 1 : 2} }}" + matTooltipPosition="below" required> diff --git a/ui-ngx/src/app/modules/home/components/device/device-credentials-lwm2m.component.html b/ui-ngx/src/app/modules/home/components/device/device-credentials-lwm2m.component.html index b10eaf68ae..5833e33934 100644 --- a/ui-ngx/src/app/modules/home/components/device/device-credentials-lwm2m.component.html +++ b/ui-ngx/src/app/modules/home/components/device/device-credentials-lwm2m.component.html @@ -34,9 +34,12 @@ - + {{ 'device.lwm2m-security-config.identity' | translate }} - + {{ 'device.lwm2m-security-config.identity-required' | translate }} @@ -49,7 +52,10 @@ cdkAutosizeMinRows="1" cols="1" formControlName="key" - required> + required + matTooltip="{{ 'device.lwm2m-security-config.client-key-tooltip' | translate:{count: + lwm2mConfigFormGroup.get('client.securityConfigClientMode').value === securityConfigLwM2MType.PSK?0:1} }}" + matTooltipPosition="below"> {{ 'device.lwm2m-security-config.client-key-required' | translate }} @@ -61,6 +67,8 @@ cdkTextareaAutosize cdkAutosizeMinRows="1" cols="1" + matTooltip="{{ 'device.lwm2m-security-config.client-public-key-tooltip' | translate: {count: lwm2mConfigFormGroup.get('client.cert').value?1:2} }}" + matTooltipPosition="below" formControlName="cert"> device.lwm2m-security-config.client-public-key-hint diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-config-server.component.html b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-config-server.component.html index 9c2ce132d8..9606883368 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-config-server.component.html +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-config-server.component.html @@ -99,7 +99,12 @@ cdkAutosizeMinRows="1" cols="1" required formControlName="serverPublicKey" - > + matTooltip="{{ 'device.lwm2m-security-config.client-publicKey-or-id-tooltip' | translate: + {count: serverFormGroup.get('securityMode').value === securityConfigLwM2MType.RPK? 1 : 2} }}" + matTooltipPosition="below" + required> + + {{ 'device-profile.lwm2m.server-public-key-required' | translate }} diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.html b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.html index 5e444f8ee2..a514891e09 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.html +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.html @@ -31,13 +31,13 @@ - +

- {{ 'device-profile.lwm2m.servers' | translate }} + {{ 'device-profile.lwm2m.security' | translate }}
diff --git a/ui-ngx/src/assets/locale/locale.constant-cs_CZ.json b/ui-ngx/src/assets/locale/locale.constant-cs_CZ.json index 4e1ec64412..97bc94b645 100644 --- a/ui-ngx/src/assets/locale/locale.constant-cs_CZ.json +++ b/ui-ngx/src/assets/locale/locale.constant-cs_CZ.json @@ -1258,7 +1258,6 @@ "view-attribute": "Zobrazit atribut", "remove-attribute": "Odebrat atribut", "mode": "Režim konfigurace bezpečnosti", - "servers": "Servery", "short-id": "Krátké ID", "short-id-required": "Krátké ID je povinné.", "short-id-range": "Krátké ID by mělo být v rozsahu od 1 do 65534.", diff --git a/ui-ngx/src/assets/locale/locale.constant-en_US.json b/ui-ngx/src/assets/locale/locale.constant-en_US.json index 4bbde6c029..91dfca6955 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -963,10 +963,15 @@ "lwm2m-security-config": { "identity": "Client Identity", "identity-required": "Client Identity is required.", + "identity-tooltip": "PSK identity is arbitrary PSK Identities of up to 128 bytes, as mandated in [RFC7925]. \n PSK identity MUST be first converted to a character string, and then encoded to octets using UTF-8 [UTF8].", "client-key": "Client Key", "client-key-required": "Client Key is required.", + "client-key-tooltip": "{ count, plural, 1 {RPK public key or id should be in RFC7250 standard and encoded to Base64 format!} other {PSK key should be in RFC4279 standard and HexDec format: 32, 64, 128 characters!.} }", "endpoint": "Endpoint Client Name", "endpoint-required": "Endpoint Client Name is required.", + "client-public-key": "Client public key", + "client-public-key-hint": "If client public key is empty, the trusted certificate will be used", + "client-public-key-tooltip": "{ count, plural, 1 {X509 public key should be in DER-encoded X509v3 format and support only EC algorithm and encoded to Base64 format!} other {} }", "mode": "Security config mode", "client-tab": "Client Security Config", "client-certificate": "Client certificate", @@ -975,10 +980,10 @@ "lwm2m-server": "LwM2M Server", "client-publicKey-or-id": "Client Public Key or Id", "client-publicKey-or-id-required": "Client Public Key or Id is required.", + "client-publicKey-or-id-tooltip": "{ count, plural, 0 {PSK identity is arbitrary PSK Identities of up to 128 bytes, as mandated in [RFC7925]. \n PSK identity MUST be first converted to a character string, and then encoded to octets using UTF-8 [UTF8].} 1 {RPK public key or id should be in RFC7250 standard and encoded to Base64 format!} other {X509 public key should be in DER-encoded X509v3 format and support only EC algorithm and encoded to Base64 format!} }", "client-secret-key": "Client Secret Key", "client-secret-key-required": "Client Secret Key is required.", - "client-public-key": "Client public key", - "client-public-key-hint": "If client public key is empty, the trusted certificate will be used" + "client-secret-key-tooltip": "{ count, plural, 0 {PSK key should be in RFC4279 standard and HexDec format: 32, 64, 128 characters!.} 1 {RPK secret key should be in PKCS_8 format (DER encoding, RFC5958 standard) and encoded to Base64 format!} other {X509 secret key should be in PKCS_8 format (DER encoding, RFC5958 standard) and encoded to Base64 format!} }" }, "client-id": "Client ID", "client-id-pattern": "Contains invalid character.", @@ -1272,7 +1277,8 @@ "view-attribute": "View attribute", "remove-attribute": "Remove attribute", "mode": "Security config mode", - "servers": "Servers", + "security": "Securities", + "bootstrap-tab": "Bootstrap", "short-id": "Short ID", "short-id-required": "Short ID is required.", "short-id-range": "Short ID should be in a range from 1 to 65534.", @@ -1297,7 +1303,6 @@ "s": "S: SMS connection in standard mode", "sq": "SQ: SMS connection in queue mode" }, - "bootstrap-tab": "Bootstrap", "bootstrap-server": "Bootstrap Server", "lwm2m-server": "LwM2M Server", "server-host": "Host", diff --git a/ui-ngx/src/assets/locale/locale.constant-tr_TR.json b/ui-ngx/src/assets/locale/locale.constant-tr_TR.json index c600cb0c9a..3bca05e458 100644 --- a/ui-ngx/src/assets/locale/locale.constant-tr_TR.json +++ b/ui-ngx/src/assets/locale/locale.constant-tr_TR.json @@ -1271,7 +1271,6 @@ "view-attribute": "Öznitelik görüntüle", "remove-attribute": "Öznitelik kaldır", "mode": "Güvenlik yapılandırma modu", - "servers": "Sunucular", "short-id": "Kısa ID", "short-id-required": "Kısa ID gerekli.", "short-id-range": "Kısa ID 1 ile 65534 aralığında olmalıdır.", From c78c46c8ec7abfe6a322157928dd4e8e30aae0d1 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Mon, 25 Oct 2021 10:58:11 +0300 Subject: [PATCH 062/432] Lwm2m fix bug validate credentials per each update registration --- .../transport/lwm2m/secure/TbLwM2MAuthorizer.java | 8 ++++++++ .../lwm2m/server/store/TbInMemorySecurityStore.java | 13 ++++++++++--- .../server/store/TbLwM2mRedisSecurityStore.java | 9 ++++++++- .../lwm2m/server/store/TbLwM2mSecurityStore.java | 12 ++++++++++++ 4 files changed, 38 insertions(+), 4 deletions(-) diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MAuthorizer.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MAuthorizer.java index 04c6a2b160..5cb8390ef9 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MAuthorizer.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MAuthorizer.java @@ -17,6 +17,7 @@ package org.thingsboard.server.transport.lwm2m.secure; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.eclipse.leshan.core.SecurityMode; import org.eclipse.leshan.core.request.Identity; import org.eclipse.leshan.core.request.UplinkRequest; import org.eclipse.leshan.server.registration.Registration; @@ -30,6 +31,8 @@ import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientContext; import org.thingsboard.server.transport.lwm2m.server.store.TbLwM2MDtlsSessionStore; import org.thingsboard.server.transport.lwm2m.server.store.TbSecurityStore; +import java.util.Arrays; + @Component @RequiredArgsConstructor @TbLwM2mTransportComponent @@ -61,6 +64,11 @@ public class TbLwM2MAuthorizer implements Authorizer { if (securityStore != null) { try { expectedSecurityInfo = securityStore.getByEndpoint(registration.getEndpoint()); + if (expectedSecurityInfo != null && expectedSecurityInfo.usePSK() && expectedSecurityInfo.getEndpoint().equals(SecurityMode.NO_SEC.toString()) + && expectedSecurityInfo.getIdentity().equals(SecurityMode.NO_SEC.toString()) + && Arrays.equals(SecurityMode.NO_SEC.toString().getBytes(), expectedSecurityInfo.getPreSharedKey())) { + expectedSecurityInfo = null; + } } catch (LwM2MAuthException e) { log.info("Registration failed: FORBIDDEN, endpointId: [{}]", registration.getEndpoint()); return null; diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbInMemorySecurityStore.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbInMemorySecurityStore.java index 9c0b109082..0286e1556f 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbInMemorySecurityStore.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbInMemorySecurityStore.java @@ -15,6 +15,7 @@ */ package org.thingsboard.server.transport.lwm2m.server.store; +import org.eclipse.leshan.core.SecurityMode; import org.eclipse.leshan.server.security.NonUniqueSecurityInfoException; import org.eclipse.leshan.server.security.SecurityInfo; import org.thingsboard.server.transport.lwm2m.secure.TbLwM2MSecurityInfo; @@ -48,9 +49,15 @@ public class TbInMemorySecurityStore implements TbEditableSecurityStore { readLock.lock(); try { TbLwM2MSecurityInfo securityInfo = securityByEp.get(endpoint); - if (securityInfo != null) { - return securityInfo.getSecurityInfo(); - } else { + if (securityInfo != null ) { + if (SecurityMode.NO_SEC.equals(securityInfo.getSecurityMode())) { + return SecurityInfo.newPreSharedKeyInfo(SecurityMode.NO_SEC.toString(), SecurityMode.NO_SEC.toString(), + SecurityMode.NO_SEC.toString().getBytes()); + } else { + return securityInfo.getSecurityInfo(); + } + } + else { return null; } } finally { diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mRedisSecurityStore.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mRedisSecurityStore.java index 54200be434..4990923ce8 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mRedisSecurityStore.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mRedisSecurityStore.java @@ -15,6 +15,7 @@ */ package org.thingsboard.server.transport.lwm2m.server.store; +import org.eclipse.leshan.core.SecurityMode; import org.eclipse.leshan.server.security.NonUniqueSecurityInfoException; import org.eclipse.leshan.server.security.SecurityInfo; import org.nustaq.serialization.FSTConfiguration; @@ -49,7 +50,13 @@ public class TbLwM2mRedisSecurityStore implements TbEditableSecurityStore { if (data == null || data.length == 0) { return null; } else { - return ((TbLwM2MSecurityInfo) serializer.asObject(data)).getSecurityInfo(); + if (SecurityMode.NO_SEC.equals(((TbLwM2MSecurityInfo) serializer.asObject(data)).getSecurityMode())) { + return SecurityInfo.newPreSharedKeyInfo(SecurityMode.NO_SEC.toString(), SecurityMode.NO_SEC.toString(), + SecurityMode.NO_SEC.toString().getBytes()); + } + else { + return ((TbLwM2MSecurityInfo) serializer.asObject(data)).getSecurityInfo(); + } } } finally { if (lock != null) { diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mSecurityStore.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mSecurityStore.java index ac0d3d0e68..a289391dbf 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mSecurityStore.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mSecurityStore.java @@ -16,12 +16,14 @@ package org.thingsboard.server.transport.lwm2m.server.store; import lombok.extern.slf4j.Slf4j; +import org.eclipse.leshan.core.SecurityMode; import org.eclipse.leshan.server.security.NonUniqueSecurityInfoException; import org.eclipse.leshan.server.security.SecurityInfo; import org.jetbrains.annotations.Nullable; import org.thingsboard.server.transport.lwm2m.secure.LwM2mCredentialsSecurityInfoValidator; import org.thingsboard.server.transport.lwm2m.secure.TbLwM2MSecurityInfo; +import java.util.Arrays; import java.util.HashSet; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; @@ -46,11 +48,21 @@ public class TbLwM2mSecurityStore implements TbMainSecurityStore { return securityStore.getTbLwM2MSecurityInfoByEndpoint(endpoint); } + /** + * @param endpoint + * @return : If SecurityMode == NO_SEC: + * return SecurityInfo.newPreSharedKeyInfo(SecurityMode.NO_SEC.toString(), SecurityMode.NO_SEC.toString(), + * SecurityMode.NO_SEC.toString().getBytes()); + */ @Override public SecurityInfo getByEndpoint(String endpoint) { SecurityInfo securityInfo = securityStore.getByEndpoint(endpoint); if (securityInfo == null) { securityInfo = fetchAndPutSecurityInfo(endpoint); + } else if (securityInfo.usePSK() && securityInfo.getEndpoint().equals(SecurityMode.NO_SEC.toString()) + && securityInfo.getIdentity().equals(SecurityMode.NO_SEC.toString()) + && Arrays.equals(SecurityMode.NO_SEC.toString().getBytes(), securityInfo.getPreSharedKey())) { + return null; } return securityInfo; } From b2a93e834b043f9c514e0f2b0ae0a62105244fad Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Tue, 26 Oct 2021 19:35:36 +0300 Subject: [PATCH 063/432] Improved tests --- .../lwm2m/AbstractLwM2MIntegrationTest.java | 3 +-- .../lwm2m/rpc/AbstractRpcLwM2MIntegrationTest.java | 13 ++++--------- .../lwm2m/rpc/sql/RpcLwm2mIntegrationWriteTest.java | 2 +- 3 files changed, 6 insertions(+), 12 deletions(-) diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/AbstractLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/AbstractLwM2MIntegrationTest.java index 0bdc221b1b..1a49807374 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/AbstractLwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/AbstractLwM2MIntegrationTest.java @@ -123,7 +123,7 @@ public abstract class AbstractLwM2MIntegrationTest extends AbstractWebsocketTest protected LwM2MTestClient client; private final LwM2MBootstrapCredentials defaultBootstrapCredentials; private String[] resources; - private String endpoint; + protected String endpoint; public AbstractLwM2MIntegrationTest() { this.defaultBootstrapCredentials = new LwM2MBootstrapCredentials(); @@ -238,7 +238,6 @@ public abstract class AbstractLwM2MIntegrationTest extends AbstractWebsocketTest deviceCredentials.setCredentialsValue(JacksonUtil.toString(credentials)); doPost("/api/device/credentials", deviceCredentials).andExpect(status().isOk()); - Thread.sleep(1000); return device; } diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/AbstractRpcLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/AbstractRpcLwM2MIntegrationTest.java index ab08379389..93f9ffb1ae 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/AbstractRpcLwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/AbstractRpcLwM2MIntegrationTest.java @@ -24,6 +24,7 @@ import org.thingsboard.server.transport.lwm2m.AbstractLwM2MIntegrationTest; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Predicate; import static org.eclipse.leshan.core.LwM2mId.ACCESS_CONTROL; @@ -52,7 +53,6 @@ public abstract class AbstractRpcLwM2MIntegrationTest extends AbstractLwM2MInteg protected String RPC_TRANSPORT_CONFIGURATION; - protected static final String ENDPOINT_RPC = "deviceEndpointRpc"; protected ScheduledExecutorService executor; protected TbTestWebSocketClient wsClient; protected String deviceId; @@ -72,19 +72,18 @@ public abstract class AbstractRpcLwM2MIntegrationTest extends AbstractLwM2MInteg protected String objectIdVer_19; protected String objectIdVer_50 = "/50"; protected String objectIdVer_3303; + protected static AtomicInteger endpointSequence = new AtomicInteger(); public AbstractRpcLwM2MIntegrationTest(){ setResources(resources); - setEndpoint(ENDPOINT_RPC); } @Before public void beforeTest() throws Exception { + setEndpoint("deviceEndpointRpc" + endpointSequence.incrementAndGet()); init(); createNewClient (SECURITY, COAP_CONFIG, true); - Thread.sleep(1000); - expectedObjects = ConcurrentHashMap.newKeySet(); expectedObjectIdVers = ConcurrentHashMap.newKeySet(); expectedInstances = ConcurrentHashMap.newKeySet(); @@ -179,14 +178,10 @@ public abstract class AbstractRpcLwM2MIntegrationTest extends AbstractLwM2MInteg "}"; createDeviceProfile(RPC_TRANSPORT_CONFIGURATION); - Thread.sleep(1000); - - NoSecClientCredentials credentials = createNoSecClientCredentials(ENDPOINT_RPC); + NoSecClientCredentials credentials = createNoSecClientCredentials(endpoint); final Device device = createDevice(credentials); deviceId = device.getId().getId().toString(); - Thread.sleep(1000); - client.start(); } diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationWriteTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationWriteTest.java index 3dad6231ad..e039efa8eb 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationWriteTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationWriteTest.java @@ -121,7 +121,7 @@ public class RpcLwm2mIntegrationWriteTest extends AbstractRpcLwM2MIntegrationTes ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); assertEquals(ResponseCode.BAD_REQUEST.getName(), rpcActualResult.get("result").asText()); String actualValues = rpcActualResult.get("error").asText(); - String expected = "Format value is bad. Value for this Multi-Instance Resource must be in Json format!"; + String expected = "Value of Multi-Instance Resource must be in Json format!"; assertTrue(actualValues.contains(expected)); } From 0341c25d1a97ac7b5f3e2f7284403109ba2ec982 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Wed, 27 Oct 2021 12:35:38 +0300 Subject: [PATCH 064/432] Lwm2m update text PSK identity --- ui-ngx/src/assets/locale/locale.constant-en_US.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui-ngx/src/assets/locale/locale.constant-en_US.json b/ui-ngx/src/assets/locale/locale.constant-en_US.json index 91dfca6955..716be68599 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -963,7 +963,7 @@ "lwm2m-security-config": { "identity": "Client Identity", "identity-required": "Client Identity is required.", - "identity-tooltip": "PSK identity is arbitrary PSK Identities of up to 128 bytes, as mandated in [RFC7925]. \n PSK identity MUST be first converted to a character string, and then encoded to octets using UTF-8 [UTF8].", + "identity-tooltip": "The PSK identifier is an arbitrary PSK identifier up to 128 bytes, as described in the standart [RFC7925].\nThe PSK identifier MUST first be converted to a character string and then encoded into octets using UTF-8.", "client-key": "Client Key", "client-key-required": "Client Key is required.", "client-key-tooltip": "{ count, plural, 1 {RPK public key or id should be in RFC7250 standard and encoded to Base64 format!} other {PSK key should be in RFC4279 standard and HexDec format: 32, 64, 128 characters!.} }", From 4b6f7963cf3c6e2ec33ba0f017d4f8140b7b802d Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Wed, 27 Oct 2021 16:27:13 +0300 Subject: [PATCH 065/432] Lwm2m update text RPK and x509 --- ui-ngx/src/assets/locale/locale.constant-en_US.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ui-ngx/src/assets/locale/locale.constant-en_US.json b/ui-ngx/src/assets/locale/locale.constant-en_US.json index 716be68599..5c4333f76c 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -963,15 +963,15 @@ "lwm2m-security-config": { "identity": "Client Identity", "identity-required": "Client Identity is required.", - "identity-tooltip": "The PSK identifier is an arbitrary PSK identifier up to 128 bytes, as described in the standart [RFC7925].\nThe PSK identifier MUST first be converted to a character string and then encoded into octets using UTF-8.", + "identity-tooltip": "The PSK identifier is an arbitrary PSK identifier up to 128 bytes, as described in the standard [RFC7925].\nThe PSK identifier MUST first be converted to a character string and then encoded into octets using UTF-8.", "client-key": "Client Key", "client-key-required": "Client Key is required.", - "client-key-tooltip": "{ count, plural, 1 {RPK public key or id should be in RFC7250 standard and encoded to Base64 format!} other {PSK key should be in RFC4279 standard and HexDec format: 32, 64, 128 characters!.} }", + "client-key-tooltip": "{ count, plural, 1 {RPK public key or id must be in the standard [RFC7250] and encoded to Base64 format!} other {PSK key must be in the standard [RFC4279] and HexDec format: 32, 64, 128 characters!} }", "endpoint": "Endpoint Client Name", "endpoint-required": "Endpoint Client Name is required.", "client-public-key": "Client public key", "client-public-key-hint": "If client public key is empty, the trusted certificate will be used", - "client-public-key-tooltip": "{ count, plural, 1 {X509 public key should be in DER-encoded X509v3 format and support only EC algorithm and encoded to Base64 format!} other {} }", + "client-public-key-tooltip": "{ count, plural, 1 {X509 public key must be in DER-encoded X509v3 format and support exclusively EC algorithm and then encoded to Base64 format!} other {} }", "mode": "Security config mode", "client-tab": "Client Security Config", "client-certificate": "Client certificate", @@ -980,10 +980,10 @@ "lwm2m-server": "LwM2M Server", "client-publicKey-or-id": "Client Public Key or Id", "client-publicKey-or-id-required": "Client Public Key or Id is required.", - "client-publicKey-or-id-tooltip": "{ count, plural, 0 {PSK identity is arbitrary PSK Identities of up to 128 bytes, as mandated in [RFC7925]. \n PSK identity MUST be first converted to a character string, and then encoded to octets using UTF-8 [UTF8].} 1 {RPK public key or id should be in RFC7250 standard and encoded to Base64 format!} other {X509 public key should be in DER-encoded X509v3 format and support only EC algorithm and encoded to Base64 format!} }", + "client-publicKey-or-id-tooltip": "{ count, plural, 0 {The PSK identifier is an arbitrary PSK identifier up to 128 bytes, as described in the standard [RFC7925].\nThe PSK identifier MUST first be converted to a character string and then encoded into octets using UTF-8.} 1 {RPK public key or id must be in the standard [RFC7250] and encoded to Base64 format!} other {X509 public key must be in DER-encoded X509v3 format and support exclusively EC algorithm and then encoded to Base64 format!} }", "client-secret-key": "Client Secret Key", "client-secret-key-required": "Client Secret Key is required.", - "client-secret-key-tooltip": "{ count, plural, 0 {PSK key should be in RFC4279 standard and HexDec format: 32, 64, 128 characters!.} 1 {RPK secret key should be in PKCS_8 format (DER encoding, RFC5958 standard) and encoded to Base64 format!} other {X509 secret key should be in PKCS_8 format (DER encoding, RFC5958 standard) and encoded to Base64 format!} }" + "client-secret-key-tooltip": "{ count, plural, 0 {PSK key must be in the standard [RFC4279] and HexDec format: 32, 64, 128 characters!} 1 {RPK secret key must be in PKCS_8 format (DER encoding, standard [RFC5958]) and then encoded to Base64 format!} other {X509 secret key must be in PKCS_8 format (DER encoding, standard [RFC5958]) and then encoded to Base64 format!} }" }, "client-id": "Client ID", "client-id-pattern": "Contains invalid character.", From 883d58c155a41c12e10271e119cc3ba1ff6b0342 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Wed, 27 Oct 2021 17:46:46 +0300 Subject: [PATCH 066/432] Lwm2m validate PSK --- .../device/DeviceCredentialsServiceImpl.java | 63 +++++++++++-------- 1 file changed, 37 insertions(+), 26 deletions(-) diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsServiceImpl.java index 7a778762b8..3e4d49b21b 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsServiceImpl.java @@ -17,6 +17,7 @@ package org.thingsboard.server.dao.device; import lombok.extern.slf4j.Slf4j; +import org.eclipse.leshan.core.SecurityMode; import org.eclipse.leshan.core.util.SecurityUtil; import org.hibernate.exception.ConstraintViolationException; import org.springframework.beans.factory.annotation.Autowired; @@ -89,7 +90,7 @@ public class DeviceCredentialsServiceImpl extends AbstractEntityService implemen private DeviceCredentials saveOrUpdate(TenantId tenantId, DeviceCredentials deviceCredentials) { if (deviceCredentials.getCredentialsType() == null) { - throw new DataValidationException("Device credentials type should be specified"); + throw new DataValidationException("Device credentials type must be specified"); } formatCredentials(deviceCredentials); log.trace("Executing updateDeviceCredentials [{}]", deviceCredentials); @@ -199,36 +200,36 @@ public class DeviceCredentialsServiceImpl extends AbstractEntityService implemen private void validateLwM2MDeviceCredentials(LwM2MDeviceCredentials lwM2MCredentials) { if (lwM2MCredentials == null) { - throw new DeviceCredentialsValidationException("LwM2M credentials should be specified!"); + throw new DeviceCredentialsValidationException("LwM2M credentials must be specified!"); } LwM2MClientCredentials clientCredentials = lwM2MCredentials.getClient(); if (clientCredentials == null) { - throw new DeviceCredentialsValidationException("LwM2M client credentials should be specified!"); + throw new DeviceCredentialsValidationException("LwM2M client credentials must be specified!"); } validateLwM2MClientCredentials(clientCredentials); LwM2MBootstrapCredentials bootstrapCredentials = lwM2MCredentials.getBootstrap(); if (bootstrapCredentials == null) { - throw new DeviceCredentialsValidationException("LwM2M bootstrap credentials should be specified!"); + throw new DeviceCredentialsValidationException("LwM2M bootstrap credentials must be specified!"); } LwM2MServerCredentials bootstrapServerCredentials = bootstrapCredentials.getBootstrapServer(); if (bootstrapServerCredentials == null) { - throw new DeviceCredentialsValidationException("LwM2M bootstrap server credentials should be specified!"); + throw new DeviceCredentialsValidationException("LwM2M bootstrap server credentials must be specified!"); } validateServerCredentials(bootstrapServerCredentials, "Bootstrap server"); LwM2MServerCredentials lwm2mServerCredentials = bootstrapCredentials.getLwm2mServer(); if (lwm2mServerCredentials == null) { - throw new DeviceCredentialsValidationException("LwM2M lwm2m server credentials should be specified!"); + throw new DeviceCredentialsValidationException("LwM2M lwm2m server credentials must be specified!"); } validateServerCredentials(lwm2mServerCredentials, "LwM2M server"); } private void validateLwM2MClientCredentials(LwM2MClientCredentials clientCredentials) { if (StringUtils.isBlank(clientCredentials.getEndpoint())) { - throw new DeviceCredentialsValidationException("LwM2M client endpoint should be specified!"); + throw new DeviceCredentialsValidationException("LwM2M client endpoint must be specified!"); } switch (clientCredentials.getSecurityConfigClientMode()) { @@ -237,26 +238,31 @@ public class DeviceCredentialsServiceImpl extends AbstractEntityService implemen case PSK: PSKClientCredentials pskCredentials = (PSKClientCredentials) clientCredentials; if (StringUtils.isBlank(pskCredentials.getIdentity())) { - throw new DeviceCredentialsValidationException("LwM2M client PSK identity should be specified!"); + throw new DeviceCredentialsValidationException("LwM2M client PSK identity must be specified!"); + } + // SecurityMode.NO_SEC.toString() == "NO_SEC"; + if (pskCredentials.getIdentity().equals(SecurityMode.NO_SEC.toString())) { + throw new DeviceCredentialsValidationException("The PSK ID of the LwM2M client must not be '" + SecurityMode.NO_SEC + "'!"); } String pskKey = pskCredentials.getKey(); if (StringUtils.isBlank(pskKey)) { - throw new DeviceCredentialsValidationException("LwM2M client PSK key should be specified!"); + throw new DeviceCredentialsValidationException("LwM2M client PSK key must be specified!"); } if (!pskKey.matches("-?[0-9a-fA-F]+")) { - throw new DeviceCredentialsValidationException("LwM2M client PSK key should be random sequence in hex encoding!"); + throw new DeviceCredentialsValidationException("LwM2M client PSK key must be random sequence in hex encoding!"); } if (pskKey.length()% 32 != 0 || pskKey.length() > 128) { - throw new DeviceCredentialsValidationException("LwM2M client PSK key length = " + pskKey.length() + ". Key should be HexDec format: 32, 64, 128 characters!"); + throw new DeviceCredentialsValidationException("LwM2M client PSK key length = " + pskKey.length() + ". Key must be HexDec format: 32, 64, 128 characters!"); } + break; case RPK: RPKClientCredentials rpkCredentials = (RPKClientCredentials) clientCredentials; if (StringUtils.isBlank(rpkCredentials.getKey())) { - throw new DeviceCredentialsValidationException("LwM2M client RPK key should be specified!"); + throw new DeviceCredentialsValidationException("LwM2M client RPK key must be specified!"); } try { @@ -264,7 +270,7 @@ public class DeviceCredentialsServiceImpl extends AbstractEntityService implemen rpkCredentials.setKey(pubkClient); SecurityUtil.publicKey.decode(rpkCredentials.getDecoded()); } catch (Exception e) { - throw new DeviceCredentialsValidationException("LwM2M client RPK key should be in RFC7250 standard and support only EC algorithm and encoded to Base64 format!"); + throw new DeviceCredentialsValidationException("LwM2M client RPK key must be in standard [RFC7250] and support only EC algorithm and then encoded to Base64 format!"); } break; case X509: @@ -275,7 +281,7 @@ public class DeviceCredentialsServiceImpl extends AbstractEntityService implemen x509CCredentials.setCert(certClient); SecurityUtil.certificate.decode(x509CCredentials.getDecoded()); } catch (Exception e) { - throw new DeviceCredentialsValidationException("LwM2M client X509 certificate should be in DER-encoded X509v3 format and support only EC algorithm and encoded to Base64 format!"); + throw new DeviceCredentialsValidationException("LwM2M client X509 certificate must be in DER-encoded X509v3 format and support only EC algorithm and then encoded to Base64 format!"); } } break; @@ -289,37 +295,42 @@ public class DeviceCredentialsServiceImpl extends AbstractEntityService implemen case PSK: PSKServerCredentials pskCredentials = (PSKServerCredentials) serverCredentials; if (StringUtils.isBlank(pskCredentials.getClientPublicKeyOrId())) { - throw new DeviceCredentialsValidationException(server + " client PSK public key or id should be specified!"); + throw new DeviceCredentialsValidationException(server + " client PSK public key or id must be specified!"); + } + + // SecurityMode.NO_SEC.toString() == "NO_SEC"; + if (pskCredentials.getClientPublicKeyOrId().equals(SecurityMode.NO_SEC.toString())) { + throw new DeviceCredentialsValidationException(server + " client PSK public key or id must not be '" + SecurityMode.NO_SEC + "'!"); } String pskKey = pskCredentials.getClientSecretKey(); if (StringUtils.isBlank(pskKey)) { - throw new DeviceCredentialsValidationException(server + " client PSK key should be specified!"); + throw new DeviceCredentialsValidationException(server + " client PSK key must be specified!"); } if (!pskKey.matches("-?[0-9a-fA-F]+")) { - throw new DeviceCredentialsValidationException(server + " client PSK key should be random sequence in hex encoding!"); + throw new DeviceCredentialsValidationException(server + " client PSK key must be random sequence in hex encoding!"); } if (pskKey.length() % 32 != 0 || pskKey.length() > 128) { - throw new DeviceCredentialsValidationException(server + " client PSK key length = " + pskKey.length() + ". Key should be HexDec format: 32, 64, 128 characters!"); + throw new DeviceCredentialsValidationException(server + " client PSK key length = " + pskKey.length() + ". Key must be HexDec format: 32, 64, 128 characters!"); } break; case RPK: RPKServerCredentials rpkServerCredentials = (RPKServerCredentials) serverCredentials; if (StringUtils.isEmpty(rpkServerCredentials.getClientPublicKeyOrId())) { - throw new DeviceCredentialsValidationException(server + " client RPK public key or id should be specified!"); + throw new DeviceCredentialsValidationException(server + " client RPK public key or id must be specified!"); } try { String pubkRpkSever = EncryptionUtil.pubkTrimNewLines(rpkServerCredentials.getClientPublicKeyOrId()); rpkServerCredentials.setClientPublicKeyOrId(pubkRpkSever); SecurityUtil.publicKey.decode(rpkServerCredentials.getDecodedClientPublicKeyOrId()); } catch (Exception e) { - throw new DeviceCredentialsValidationException(server + " client RPK public key or id should be in RFC7250 standard and encoded to Base64 format!"); + throw new DeviceCredentialsValidationException(server + " client RPK public key or id must be in standard [RFC7250 ] and then encoded to Base64 format!"); } if (StringUtils.isEmpty(rpkServerCredentials.getClientSecretKey())) { - throw new DeviceCredentialsValidationException(server + " client RPK secret key should be specified!"); + throw new DeviceCredentialsValidationException(server + " client RPK secret key must be specified!"); } try { @@ -327,13 +338,13 @@ public class DeviceCredentialsServiceImpl extends AbstractEntityService implemen rpkServerCredentials.setClientSecretKey(prikRpkSever); SecurityUtil.privateKey.decode(rpkServerCredentials.getDecodedClientSecretKey()); } catch (Exception e) { - throw new DeviceCredentialsValidationException(server + " client RPK secret key should be in PKCS#8 format (DER encoding, RFC5958 standard) and encoded to Base64 format!"); + throw new DeviceCredentialsValidationException(server + " client RPK secret key must be in PKCS#8 format (DER encoding, standard [RFC5958]) and then encoded to Base64 format!"); } break; case X509: X509ServerCredentials x509ServerCredentials = (X509ServerCredentials) serverCredentials; if (StringUtils.isBlank(x509ServerCredentials.getClientPublicKeyOrId())) { - throw new DeviceCredentialsValidationException(server + " client X509 public key or id should be specified!"); + throw new DeviceCredentialsValidationException(server + " client X509 public key or id must be specified!"); } try { @@ -341,10 +352,10 @@ public class DeviceCredentialsServiceImpl extends AbstractEntityService implemen x509ServerCredentials.setClientPublicKeyOrId(certServer); SecurityUtil.certificate.decode(x509ServerCredentials.getDecodedClientPublicKeyOrId()); } catch (Exception e) { - throw new DeviceCredentialsValidationException(server + " client X509 public key or id should be in DER-encoded X509v3 format and support only EC algorithm and encoded to Base64 format!"); + throw new DeviceCredentialsValidationException(server + " client X509 public key or id must be in DER-encoded X509v3 format and support only EC algorithm and then encoded to Base64 format!"); } if (StringUtils.isBlank(x509ServerCredentials.getClientSecretKey())) { - throw new DeviceCredentialsValidationException(server + " client X509 secret key should be specified!"); + throw new DeviceCredentialsValidationException(server + " client X509 secret key must be specified!"); } try { @@ -352,7 +363,7 @@ public class DeviceCredentialsServiceImpl extends AbstractEntityService implemen x509ServerCredentials.setClientSecretKey(prikX509Sever); SecurityUtil.privateKey.decode(x509ServerCredentials.getDecodedClientSecretKey()); } catch (Exception e) { - throw new DeviceCredentialsValidationException(server + " client X509 secret key should be in PKCS#8 format (DER encoding, RFC5958 standard) and encoded to Base64 format!"); + throw new DeviceCredentialsValidationException(server + " client X509 secret key must be in PKCS#8 format (DER encoding, standard [RFC5958]) and then encoded to Base64 format!"); } break; } From 8908d7d8f51ad090b96d58dcee52bf21744ce38c Mon Sep 17 00:00:00 2001 From: Andrew Shvayka Date: Wed, 27 Oct 2021 17:37:33 +0300 Subject: [PATCH 067/432] Merge pull request #5453 from YevhenBondarenko/lwm2m-improvements --- .../device/DeviceActorMessageProcessor.java | 4 +- .../lwm2m/secure/TbLwM2MAuthorizer.java | 9 ++- .../server/DefaultLwM2mTransportService.java | 2 - .../lwm2m/server/LwM2mSessionMsgListener.java | 8 ++- .../server/client/LwM2mClientContext.java | 2 - .../server/client/LwM2mClientContextImpl.java | 5 -- .../uplink/DefaultLwM2mUplinkMsgHandler.java | 72 +++++++++++++------ .../server/uplink/LwM2mUplinkMsgHandler.java | 3 + 8 files changed, 65 insertions(+), 40 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/actors/device/DeviceActorMessageProcessor.java b/application/src/main/java/org/thingsboard/server/actors/device/DeviceActorMessageProcessor.java index a12887db81..41d99a682b 100644 --- a/application/src/main/java/org/thingsboard/server/actors/device/DeviceActorMessageProcessor.java +++ b/application/src/main/java/org/thingsboard/server/actors/device/DeviceActorMessageProcessor.java @@ -719,7 +719,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { void processCredentialsUpdate(TbActorMsg msg) { if (((DeviceCredentialsUpdateNotificationMsg) msg).getDeviceCredentials().getCredentialsType() == DeviceCredentialsType.LWM2M_CREDENTIALS) { sessions.forEach((k, v) -> { - notifyTransportAboutProfileUpdate(k, v, ((DeviceCredentialsUpdateNotificationMsg) msg).getDeviceCredentials()); + notifyTransportAboutDeviceCredentialsUpdate(k, v, ((DeviceCredentialsUpdateNotificationMsg) msg).getDeviceCredentials()); }); } else { sessions.forEach((sessionId, sessionMd) -> notifyTransportAboutClosedSession(sessionId, sessionMd, "device credentials updated!")); @@ -747,7 +747,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { systemContext.getTbCoreToTransportService().process(sessionMd.getSessionInfo().getNodeId(), msg); } - void notifyTransportAboutProfileUpdate(UUID sessionId, SessionInfoMetaData sessionMd, DeviceCredentials deviceCredentials) { + void notifyTransportAboutDeviceCredentialsUpdate(UUID sessionId, SessionInfoMetaData sessionMd, DeviceCredentials deviceCredentials) { ToTransportUpdateCredentialsProto.Builder notification = ToTransportUpdateCredentialsProto.newBuilder(); notification.addCredentialsId(deviceCredentials.getCredentialsId()); notification.addCredentialsValue(deviceCredentials.getCredentialsValue()); diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MAuthorizer.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MAuthorizer.java index 5cb8390ef9..a836eae27e 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MAuthorizer.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MAuthorizer.java @@ -29,7 +29,7 @@ import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; import org.thingsboard.server.transport.lwm2m.server.client.LwM2MAuthException; import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientContext; import org.thingsboard.server.transport.lwm2m.server.store.TbLwM2MDtlsSessionStore; -import org.thingsboard.server.transport.lwm2m.server.store.TbSecurityStore; +import org.thingsboard.server.transport.lwm2m.server.store.TbMainSecurityStore; import java.util.Arrays; @@ -40,7 +40,7 @@ import java.util.Arrays; public class TbLwM2MAuthorizer implements Authorizer { private final TbLwM2MDtlsSessionStore sessionStorage; - private final TbSecurityStore securityStore; + private final TbMainSecurityStore securityStore; private final SecurityChecker securityChecker = new SecurityChecker(); private final LwM2mClientContext clientContext; @@ -60,8 +60,7 @@ public class TbLwM2MAuthorizer implements Authorizer { } // If session info is not found, this may be the trusted certificate, so we still need to check all other options below. } - SecurityInfo expectedSecurityInfo = null; - if (securityStore != null) { + SecurityInfo expectedSecurityInfo; try { expectedSecurityInfo = securityStore.getByEndpoint(registration.getEndpoint()); if (expectedSecurityInfo != null && expectedSecurityInfo.usePSK() && expectedSecurityInfo.getEndpoint().equals(SecurityMode.NO_SEC.toString()) @@ -73,10 +72,10 @@ public class TbLwM2MAuthorizer implements Authorizer { log.info("Registration failed: FORBIDDEN, endpointId: [{}]", registration.getEndpoint()); return null; } - } if (securityChecker.checkSecurityInfo(registration.getEndpoint(), senderIdentity, expectedSecurityInfo)) { return registration; } else { + securityStore.remove(registration.getEndpoint(), registration.getId()); return null; } } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2mTransportService.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2mTransportService.java index c4b9ea3f27..b5b682ed0d 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2mTransportService.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2mTransportService.java @@ -25,7 +25,6 @@ import org.eclipse.leshan.core.node.codec.DefaultLwM2mEncoder; import org.eclipse.leshan.server.californium.LeshanServer; import org.eclipse.leshan.server.californium.LeshanServerBuilder; import org.eclipse.leshan.server.californium.registration.CaliforniumRegistrationStore; -import org.eclipse.leshan.server.model.LwM2mModelProvider; import org.springframework.stereotype.Component; import org.thingsboard.server.cache.ota.OtaPackageDataCache; import org.thingsboard.server.common.data.DataConstants; @@ -33,7 +32,6 @@ import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; import org.thingsboard.server.transport.lwm2m.secure.TbLwM2MAuthorizer; import org.thingsboard.server.transport.lwm2m.secure.TbLwM2MDtlsCertificateVerifier; -import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientContext; import org.thingsboard.server.transport.lwm2m.server.store.TbSecurityStore; import org.thingsboard.server.transport.lwm2m.server.uplink.DefaultLwM2mUplinkMsgHandler; import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl; diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mSessionMsgListener.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mSessionMsgListener.java index b3c07c91b9..3e0ad17925 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mSessionMsgListener.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mSessionMsgListener.java @@ -19,10 +19,10 @@ import io.netty.util.concurrent.Future; import io.netty.util.concurrent.GenericFutureListener; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.jetbrains.annotations.NotNull; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.ResourceType; +import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.transport.SessionMsgListener; import org.thingsboard.server.common.transport.TransportService; import org.thingsboard.server.gen.transport.TransportProtos; @@ -108,4 +108,10 @@ public class LwM2mSessionMsgListener implements GenericFutureListener observations) { - executor.submit(() -> { - LwM2mClient client = clientContext.getClientByEndpoint(registration.getEndpoint()); - try { - logService.log(client, LOG_LWM2M_INFO + ": Client unRegistration"); - clientContext.unregister(client, registration); - SessionInfoProto sessionInfo = client.getSession(); - if (sessionInfo != null) { - sessionManager.deregister(sessionInfo); - sessionStore.remove(registration.getEndpoint()); - log.info("Client close session: [{}] unReg [{}] name [{}] profile ", registration.getId(), registration.getEndpoint(), sessionInfo.getDeviceType()); - } else { - log.error("Client close session: [{}] unReg [{}] name [{}] sessionInfo ", registration.getId(), registration.getEndpoint(), null); - } - } catch (LwM2MClientStateException stateException) { - log.info("[{}] delete registration: [{}] {}.", registration.getEndpoint(), stateException.getState(), stateException.getMessage()); - } catch (Throwable t) { - log.error("[{}] endpoint [{}] error Unable un registration.", registration.getEndpoint(), t); - logService.log(client, LOG_LWM2M_ERROR + String.format(": Client Unable un Registration, %s", t.getMessage())); + executor.submit(() -> doUnReg(registration, clientContext.getClientByEndpoint(registration.getEndpoint()))); + } + + private void doUnReg(Registration registration, LwM2mClient client) { + try { + logService.log(client, LOG_LWM2M_INFO + ": Client unRegistration"); + clientContext.unregister(client, registration); + SessionInfoProto sessionInfo = client.getSession(); + if (sessionInfo != null) { + sessionManager.deregister(sessionInfo); + sessionStore.remove(registration.getEndpoint()); + log.info("Client close session: [{}] unReg [{}] name [{}] profile ", registration.getId(), registration.getEndpoint(), sessionInfo.getDeviceType()); + } else { + log.error("Client close session: [{}] unReg [{}] name [{}] sessionInfo ", registration.getId(), registration.getEndpoint(), null); } - }); + } catch (LwM2MClientStateException stateException) { + log.info("[{}] delete registration: [{}] {}.", registration.getEndpoint(), stateException.getState(), stateException.getMessage()); + } catch (Throwable t) { + log.error("[{}] endpoint [{}] error Unable un registration.", registration.getEndpoint(), t); + logService.log(client, LOG_LWM2M_ERROR + String.format(": Client Unable un Registration, %s", t.getMessage())); + } } @Override @@ -394,6 +403,11 @@ public class DefaultLwM2mUplinkMsgHandler extends LwM2MExecutorAwareService impl } } + @Override + public void onDeviceDelete(DeviceId deviceId) { + clearAndUnregister(clientContext.getClientByDeviceId(deviceId.getId())); + } + @Override public void onResourceUpdate(TransportProtos.ResourceUpdateMsg resourceUpdateMsgOpt) { String idVer = resourceUpdateMsgOpt.getResourceKey(); @@ -902,8 +916,8 @@ public class DefaultLwM2mUplinkMsgHandler extends LwM2MExecutorAwareService impl */ @Override public void onToTransportUpdateCredentials(SessionInfoProto sessionInfo, TransportProtos.ToTransportUpdateCredentialsProto updateCredentials) { - log.info("[{}] idList [{}] valueList updateCredentials", updateCredentials.getCredentialsIdList(), updateCredentials.getCredentialsValueList()); - this.clientContext.removeCredentials(sessionInfo); + log.info("[{}] updateCredentials", sessionInfo); + clearAndUnregister(clientContext.getClientBySessionInfo(sessionInfo)); } /** @@ -980,4 +994,16 @@ public class DefaultLwM2mUplinkMsgHandler extends LwM2MExecutorAwareService impl .setLastActivityTime(System.currentTimeMillis()) .build(), TransportServiceCallback.EMPTY); } + + private void clearAndUnregister(LwM2mClient client) { + client.lock(); + try { + Registration registration = client.getRegistration(); + doUnReg(registration, client); + securityStore.remove(registration.getEndpoint(), registration.getId()); + registrationStore.removeRegistration(registration.getId()); + } finally { + client.unlock(); + } + } } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/LwM2mUplinkMsgHandler.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/LwM2mUplinkMsgHandler.java index 2d8139bf9b..ca706c8138 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/LwM2mUplinkMsgHandler.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/LwM2mUplinkMsgHandler.java @@ -24,6 +24,7 @@ import org.eclipse.leshan.core.response.ReadResponse; import org.eclipse.leshan.server.registration.Registration; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.DeviceProfile; +import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; @@ -49,6 +50,8 @@ public interface LwM2mUplinkMsgHandler { void onDeviceUpdate(TransportProtos.SessionInfoProto sessionInfo, Device device, Optional deviceProfileOpt); + void onDeviceDelete(DeviceId deviceId); + void onResourceUpdate(TransportProtos.ResourceUpdateMsg resourceUpdateMsgOpt); void onResourceDelete(TransportProtos.ResourceDeleteMsg resourceDeleteMsgOpt); From 25c669f420b008204e42a39db8693449642cabd4 Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Thu, 28 Oct 2021 14:26:22 +0300 Subject: [PATCH 068/432] dao test dependency: removed duplicated spring-boot-starter-test --- dao/pom.xml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/dao/pom.xml b/dao/pom.xml index 984ed753d2..9384417a76 100644 --- a/dao/pom.xml +++ b/dao/pom.xml @@ -201,11 +201,6 @@ org.springframework.boot spring-boot-starter-data-jpa - - org.springframework.boot - spring-boot-starter-test - test - org.springframework spring-test From eab54435eb8784a7a5600c5e7cd9bc5ed5c602d2 Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Thu, 28 Oct 2021 15:03:13 +0300 Subject: [PATCH 069/432] fixed license header for InMemoryStorageTest --- .../server/queue/memory/InMemoryStorageTest.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/common/queue/src/test/java/org/thingsboard/server/queue/memory/InMemoryStorageTest.java b/common/queue/src/test/java/org/thingsboard/server/queue/memory/InMemoryStorageTest.java index 4e92a46748..2ae4f78e07 100644 --- a/common/queue/src/test/java/org/thingsboard/server/queue/memory/InMemoryStorageTest.java +++ b/common/queue/src/test/java/org/thingsboard/server/queue/memory/InMemoryStorageTest.java @@ -1,3 +1,18 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.thingsboard.server.queue.memory; import org.junit.After; From fa0e1966b32b3b0d47aae2196094a2f5dbb6d4de Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Fri, 29 Oct 2021 14:00:58 +0300 Subject: [PATCH 070/432] lwm2m - fix bug info if first update Fw/Sw - failed --- .../transport/lwm2m/server/LwM2mTransportCoapResource.java | 6 ++++-- .../lwm2m/server/ota/DefaultLwM2MOtaUpdateService.java | 6 ++++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportCoapResource.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportCoapResource.java index bde1725807..d3002d196b 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportCoapResource.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportCoapResource.java @@ -138,8 +138,8 @@ public class LwM2mTransportCoapResource extends AbstractLwM2mTransportResource { UUID currentId = UUID.fromString(idStr); Response response = new Response(CoAP.ResponseCode.CONTENT); byte[] otaData = this.getOtaData(currentId); - log.debug("Read ota data (length): [{}]", otaData.length); - if (otaData.length > 0) { + if (otaData != null && otaData.length > 0) { + log.debug("Read ota data (length): [{}]", otaData.length); response.setPayload(otaData); if (exchange.getRequestOptions().getBlock2() != null) { int chunkSize = exchange.getRequestOptions().getBlock2().getSzx(); @@ -150,6 +150,8 @@ public class LwM2mTransportCoapResource extends AbstractLwM2mTransportResource { log.trace("With block1 Send currentId: [{}], length: [{}], ", currentId.toString(), otaData.length); } exchange.respond(response); + } else { + log.trace("Ota packaged currentId: [{}], is not in this session.", currentId.toString()); } } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/DefaultLwM2MOtaUpdateService.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/DefaultLwM2MOtaUpdateService.java index 0a30f2df72..34ab841c74 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/DefaultLwM2MOtaUpdateService.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/DefaultLwM2MOtaUpdateService.java @@ -399,6 +399,9 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl log.debug("[{}] Starting update to [{}{}] using binary", client.getEndpoint(), fwInfo.getTargetName(), fwInfo.getTargetVersion()); startUpdateUsingBinary(client, fwInfo); } + } else { + log.debug("[{}] failed to update client: [{}], previous update failed.", client.getEndpoint(), fwInfo); + logService.log(client, "Failed to process firmware update: " + fwInfo + ". Previous update failed."); } } catch (Exception e) { log.info("[{}] failed to update client: {}", client.getEndpoint(), fwInfo, e); @@ -424,6 +427,9 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl startUpdateUsingBinary(client, swInfo); } } + } else { + log.debug("[{}] failed to update client: [{}], previous update failed.", client.getEndpoint(), swInfo); + logService.log(client, "Failed to process software update: " + swInfo + ". Previous update failed."); } } catch (Exception e) { log.info("[{}] failed to update client: {}", client.getEndpoint(), swInfo, e); From c978d9441a29e4806a1ed34bfb657646be3fb3d5 Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Fri, 29 Oct 2021 15:54:54 +0300 Subject: [PATCH 071/432] Fix UUID link --- .../org/thingsboard/server/controller/AlarmController.java | 3 ++- .../org/thingsboard/server/controller/AssetController.java | 7 ++++--- .../thingsboard/server/controller/ControllerConstants.java | 1 + .../thingsboard/server/controller/DeviceController.java | 5 +++-- .../server/controller/DeviceProfileController.java | 3 ++- .../org/thingsboard/server/controller/EdgeController.java | 3 ++- .../server/controller/OtaPackageController.java | 3 ++- .../thingsboard/server/controller/RuleChainController.java | 3 ++- .../server/controller/TbResourceController.java | 3 ++- .../thingsboard/server/controller/TenantController.java | 3 ++- .../server/controller/TenantProfileController.java | 3 ++- .../org/thingsboard/server/controller/UserController.java | 3 ++- .../server/controller/WidgetTypeController.java | 3 ++- .../server/controller/WidgetsBundleController.java | 3 ++- 14 files changed, 30 insertions(+), 16 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/AlarmController.java b/application/src/main/java/org/thingsboard/server/controller/AlarmController.java index d376f5984f..9920e232de 100644 --- a/application/src/main/java/org/thingsboard/server/controller/AlarmController.java +++ b/application/src/main/java/org/thingsboard/server/controller/AlarmController.java @@ -66,6 +66,7 @@ import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_A import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_DESCRIPTION; import static org.thingsboard.server.controller.ControllerConstants.SORT_PROPERTY_DESCRIPTION; import static org.thingsboard.server.controller.ControllerConstants.TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH; +import static org.thingsboard.server.controller.ControllerConstants.UUID_WIKI_LINK; @RestController @TbCoreComponent @@ -120,7 +121,7 @@ public class AlarmController extends BaseController { @ApiOperation(value = "Create or update Alarm (saveAlarm)", notes = "Creates or Updates the Alarm. " + - "When creating alarm, platform generates Alarm Id as [time-based UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_1_(date-time_and_MAC_address). " + + "When creating alarm, platform generates Alarm Id as " + UUID_WIKI_LINK + "The newly created Alarm id will be present in the response. Specify existing Alarm id to update the alarm. " + "Referencing non-existing Alarm Id will cause 'Not Found' error. " + "\n\nPlatform also deduplicate the alarms based on the entity id of originator and alarm 'type'. " + diff --git a/application/src/main/java/org/thingsboard/server/controller/AssetController.java b/application/src/main/java/org/thingsboard/server/controller/AssetController.java index f7098868d8..3623d49aee 100644 --- a/application/src/main/java/org/thingsboard/server/controller/AssetController.java +++ b/application/src/main/java/org/thingsboard/server/controller/AssetController.java @@ -84,6 +84,7 @@ import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_D import static org.thingsboard.server.controller.ControllerConstants.SORT_PROPERTY_DESCRIPTION; import static org.thingsboard.server.controller.ControllerConstants.TENANT_AUTHORITY_PARAGRAPH; import static org.thingsboard.server.controller.ControllerConstants.TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH; +import static org.thingsboard.server.controller.ControllerConstants.UUID_WIKI_LINK; import static org.thingsboard.server.controller.EdgeController.EDGE_ID; import static org.thingsboard.server.dao.asset.BaseAssetService.TB_SERVICE_QUEUE; @@ -136,7 +137,7 @@ public class AssetController extends BaseController { } @ApiOperation(value = "Create Or Update Asset (saveAsset)", - notes = "Creates or Updates the Asset. When creating asset, platform generates Asset Id as [time-based UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_1_(date-time_and_MAC_address) " + + notes = "Creates or Updates the Asset. When creating asset, platform generates Asset Id as " + UUID_WIKI_LINK + "The newly created Asset id will be present in the response. " + "Specify existing Asset id to update the asset. " + "Referencing non-existing Asset Id will cause 'Not Found' error." + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH, produces = MediaType.APPLICATION_JSON_VALUE) @@ -378,9 +379,9 @@ public class AssetController extends BaseController { notes = "Requested asset must be owned by tenant that the user belongs to. " + "Asset name is an unique property of asset. So it can be used to identify the asset." + TENANT_AUTHORITY_PARAGRAPH, produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAuthority('TENANT_ADMIN')") - @RequestMapping(value = "/tenant/assets", params = {"assetName"}, method = RequestMethod.GET) + @RequestMapping(value = "/tenant/assets/name", method = RequestMethod.GET) @ResponseBody - public Asset getTenantAsset( + public Asset getTenantAssetByName( @ApiParam(value = ASSET_NAME_DESCRIPTION) @RequestParam String assetName) throws ThingsboardException { try { diff --git a/application/src/main/java/org/thingsboard/server/controller/ControllerConstants.java b/application/src/main/java/org/thingsboard/server/controller/ControllerConstants.java index 7c881e8b67..593126332c 100644 --- a/application/src/main/java/org/thingsboard/server/controller/ControllerConstants.java +++ b/application/src/main/java/org/thingsboard/server/controller/ControllerConstants.java @@ -18,6 +18,7 @@ package org.thingsboard.server.controller; public class ControllerConstants { protected static final String NEW_LINE = "\n\n"; + protected static final String UUID_WIKI_LINK = "[time-based UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_1_(date-time_and_MAC_address%29) "; protected static final int DEFAULT_PAGE_SIZE = 1000; protected static final String ENTITY_TYPE = "entityType"; protected static final String CUSTOMER_ID = "customerId"; diff --git a/application/src/main/java/org/thingsboard/server/controller/DeviceController.java b/application/src/main/java/org/thingsboard/server/controller/DeviceController.java index 07d6bf06c1..ad0a77cddd 100644 --- a/application/src/main/java/org/thingsboard/server/controller/DeviceController.java +++ b/application/src/main/java/org/thingsboard/server/controller/DeviceController.java @@ -112,6 +112,7 @@ import static org.thingsboard.server.controller.ControllerConstants.SORT_PROPERT import static org.thingsboard.server.controller.ControllerConstants.TENANT_AUTHORITY_PARAGRAPH; import static org.thingsboard.server.controller.ControllerConstants.TENANT_ID_PARAM_DESCRIPTION; import static org.thingsboard.server.controller.ControllerConstants.TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH; +import static org.thingsboard.server.controller.ControllerConstants.UUID_WIKI_LINK; import static org.thingsboard.server.controller.EdgeController.EDGE_ID; @RestController @@ -166,7 +167,7 @@ public class DeviceController extends BaseController { } @ApiOperation(value = "Create Or Update Device (saveDevice)", - notes = "Create or update the Device. When creating device, platform generates Device Id as [time-based UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_1_(date-time_and_MAC_address). " + + notes = "Create or update the Device. When creating device, platform generates Device Id as " + UUID_WIKI_LINK + "Device credentials are also generated if not provided in the 'accessToken' request parameter. " + "The newly created device id will be present in the response. " + "Specify existing Device id to update the device. " + @@ -203,7 +204,7 @@ public class DeviceController extends BaseController { } @ApiOperation(value = "Create Device (saveDevice) with credentials ", - notes = "Create or update the Device. When creating device, platform generates Device Id as [time-based UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_1_(date-time_and_MAC_address). " + + notes = "Create or update the Device. When creating device, platform generates Device Id as " + UUID_WIKI_LINK + "Requires to provide the Device Credentials object as well. Useful to create device and credentials in one request. " + "You may find the example of LwM2M device and RPK credentials below: \n\n" + DEVICE_WITH_DEVICE_CREDENTIALS_PARAM_DESCRIPTION_MARKDOWN + diff --git a/application/src/main/java/org/thingsboard/server/controller/DeviceProfileController.java b/application/src/main/java/org/thingsboard/server/controller/DeviceProfileController.java index ccd3237e18..5aacfbb5ce 100644 --- a/application/src/main/java/org/thingsboard/server/controller/DeviceProfileController.java +++ b/application/src/main/java/org/thingsboard/server/controller/DeviceProfileController.java @@ -65,6 +65,7 @@ import static org.thingsboard.server.controller.ControllerConstants.SORT_PROPERT import static org.thingsboard.server.controller.ControllerConstants.TENANT_AUTHORITY_PARAGRAPH; import static org.thingsboard.server.controller.ControllerConstants.TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH; import static org.thingsboard.server.controller.ControllerConstants.TRANSPORT_TYPE_ALLOWABLE_VALUES; +import static org.thingsboard.server.controller.ControllerConstants.UUID_WIKI_LINK; @RestController @TbCoreComponent @@ -186,7 +187,7 @@ public class DeviceProfileController extends BaseController { } @ApiOperation(value = "Create Or Update Device Profile (saveDeviceProfile)", - notes = "Create or update the Device Profile. When creating device profile, platform generates device profile id as [time-based UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_1_(date-time_and_MAC_address). " + + notes = "Create or update the Device Profile. When creating device profile, platform generates device profile id as " + UUID_WIKI_LINK + "The newly created device profile id will be present in the response. " + "Specify existing device profile id to update the device profile. " + "Referencing non-existing device profile Id will cause 'Not Found' error. " + NEW_LINE + diff --git a/application/src/main/java/org/thingsboard/server/controller/EdgeController.java b/application/src/main/java/org/thingsboard/server/controller/EdgeController.java index 219041e82c..177658e8cd 100644 --- a/application/src/main/java/org/thingsboard/server/controller/EdgeController.java +++ b/application/src/main/java/org/thingsboard/server/controller/EdgeController.java @@ -84,6 +84,7 @@ import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_D import static org.thingsboard.server.controller.ControllerConstants.SORT_PROPERTY_DESCRIPTION; import static org.thingsboard.server.controller.ControllerConstants.TENANT_AUTHORITY_PARAGRAPH; import static org.thingsboard.server.controller.ControllerConstants.TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH; +import static org.thingsboard.server.controller.ControllerConstants.UUID_WIKI_LINK; @RestController @TbCoreComponent @@ -149,7 +150,7 @@ public class EdgeController extends BaseController { } @ApiOperation(value = "Create Or Update Edge (saveEdge)", - notes = "Create or update the Edge. When creating edge, platform generates Edge Id as [time-based UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_1_(date-time_and_MAC_address). " + + notes = "Create or update the Edge. When creating edge, platform generates Edge Id as " + UUID_WIKI_LINK + "The newly created edge id will be present in the response. " + "Specify existing Edge id to update the edge. " + "Referencing non-existing Edge Id will cause 'Not Found' error." + diff --git a/application/src/main/java/org/thingsboard/server/controller/OtaPackageController.java b/application/src/main/java/org/thingsboard/server/controller/OtaPackageController.java index 593914bc4c..71fdcae1c8 100644 --- a/application/src/main/java/org/thingsboard/server/controller/OtaPackageController.java +++ b/application/src/main/java/org/thingsboard/server/controller/OtaPackageController.java @@ -64,6 +64,7 @@ import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_D import static org.thingsboard.server.controller.ControllerConstants.SORT_PROPERTY_DESCRIPTION; import static org.thingsboard.server.controller.ControllerConstants.TENANT_AUTHORITY_PARAGRAPH; import static org.thingsboard.server.controller.ControllerConstants.TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH; +import static org.thingsboard.server.controller.ControllerConstants.UUID_WIKI_LINK; @Slf4j @RestController @@ -138,7 +139,7 @@ public class OtaPackageController extends BaseController { } @ApiOperation(value = "Create Or Update OTA Package Info (saveOtaPackageInfo)", - notes = "Create or update the OTA Package Info. When creating OTA Package Info, platform generates OTA Package id as [time-based UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_1_(date-time_and_MAC_address). " + + notes = "Create or update the OTA Package Info. When creating OTA Package Info, platform generates OTA Package id as " + UUID_WIKI_LINK + "The newly created OTA Package id will be present in the response. " + "Specify existing OTA Package id to update the OTA Package Info. " + "Referencing non-existing OTA Package Id will cause 'Not Found' error. " + diff --git a/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java b/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java index 8996367c36..823044bcf5 100644 --- a/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java +++ b/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java @@ -99,6 +99,7 @@ import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_A import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_DESCRIPTION; import static org.thingsboard.server.controller.ControllerConstants.SORT_PROPERTY_DESCRIPTION; import static org.thingsboard.server.controller.ControllerConstants.TENANT_AUTHORITY_PARAGRAPH; +import static org.thingsboard.server.controller.ControllerConstants.UUID_WIKI_LINK; @Slf4j @RestController @@ -184,7 +185,7 @@ public class RuleChainController extends BaseController { } @ApiOperation(value = "Create Or Update Rule Chain (saveRuleChain)", - notes = "Create or update the Rule Chain. When creating Rule Chain, platform generates Rule Chain Id as [time-based UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_1_(date-time_and_MAC_address). " + + notes = "Create or update the Rule Chain. When creating Rule Chain, platform generates Rule Chain Id as " + UUID_WIKI_LINK + "The newly created Rule Chain Id will be present in the response. " + "Specify existing Rule Chain id to update the rule chain. " + "Referencing non-existing rule chain Id will cause 'Not Found' error." + diff --git a/application/src/main/java/org/thingsboard/server/controller/TbResourceController.java b/application/src/main/java/org/thingsboard/server/controller/TbResourceController.java index 3f083c3572..4d0c088194 100644 --- a/application/src/main/java/org/thingsboard/server/controller/TbResourceController.java +++ b/application/src/main/java/org/thingsboard/server/controller/TbResourceController.java @@ -62,6 +62,7 @@ import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_D import static org.thingsboard.server.controller.ControllerConstants.SORT_PROPERTY_DESCRIPTION; import static org.thingsboard.server.controller.ControllerConstants.SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH; import static org.thingsboard.server.controller.ControllerConstants.TENANT_AUTHORITY_PARAGRAPH; +import static org.thingsboard.server.controller.ControllerConstants.UUID_WIKI_LINK; @Slf4j @RestController @@ -131,7 +132,7 @@ public class TbResourceController extends BaseController { } @ApiOperation(value = "Create Or Update Resource (saveResource)", - notes = "Create or update the Resource. When creating the Resource, platform generates Resource id as [time-based UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_1_(date-time_and_MAC_address). " + + notes = "Create or update the Resource. When creating the Resource, platform generates Resource id as " + UUID_WIKI_LINK + "The newly created Resource id will be present in the response. " + "Specify existing Resource id to update the Resource. " + "Referencing non-existing Resource Id will cause 'Not Found' error. " + diff --git a/application/src/main/java/org/thingsboard/server/controller/TenantController.java b/application/src/main/java/org/thingsboard/server/controller/TenantController.java index edde16d6e5..0cfc8f3865 100644 --- a/application/src/main/java/org/thingsboard/server/controller/TenantController.java +++ b/application/src/main/java/org/thingsboard/server/controller/TenantController.java @@ -57,6 +57,7 @@ import static org.thingsboard.server.controller.ControllerConstants.TENANT_ID_PA import static org.thingsboard.server.controller.ControllerConstants.TENANT_INFO_SORT_PROPERTY_ALLOWABLE_VALUES; import static org.thingsboard.server.controller.ControllerConstants.TENANT_SORT_PROPERTY_ALLOWABLE_VALUES; import static org.thingsboard.server.controller.ControllerConstants.TENANT_TEXT_SEARCH_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.UUID_WIKI_LINK; @RestController @TbCoreComponent @@ -111,7 +112,7 @@ public class TenantController extends BaseController { } @ApiOperation(value = "Create Or update Tenant (saveTenant)", - notes = "Create or update the Tenant. When creating tenant, platform generates Tenant Id as [time-based UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_1_(date-time_and_MAC_address). " + + notes = "Create or update the Tenant. When creating tenant, platform generates Tenant Id as " + UUID_WIKI_LINK + "Default Rule Chain and Device profile are also generated for the new tenants automatically. " + "The newly created Tenant Id will be present in the response. " + "Specify existing Tenant Id id to update the Tenant. " + diff --git a/application/src/main/java/org/thingsboard/server/controller/TenantProfileController.java b/application/src/main/java/org/thingsboard/server/controller/TenantProfileController.java index ab52e8ebd4..01023edf6d 100644 --- a/application/src/main/java/org/thingsboard/server/controller/TenantProfileController.java +++ b/application/src/main/java/org/thingsboard/server/controller/TenantProfileController.java @@ -53,6 +53,7 @@ import static org.thingsboard.server.controller.ControllerConstants.TENANT_PROFI import static org.thingsboard.server.controller.ControllerConstants.TENANT_PROFILE_INFO_SORT_PROPERTY_ALLOWABLE_VALUES; import static org.thingsboard.server.controller.ControllerConstants.TENANT_PROFILE_SORT_PROPERTY_ALLOWABLE_VALUES; import static org.thingsboard.server.controller.ControllerConstants.TENANT_PROFILE_TEXT_SEARCH_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.UUID_WIKI_LINK; @RestController @TbCoreComponent @@ -110,7 +111,7 @@ public class TenantProfileController extends BaseController { } @ApiOperation(value = "Create Or update Tenant Profile (saveTenantProfile)", - notes = "Create or update the Tenant Profile. When creating tenant profile, platform generates Tenant Profile Id as [time-based UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_1_(date-time_and_MAC_address). " + + notes = "Create or update the Tenant Profile. When creating tenant profile, platform generates Tenant Profile Id as " + UUID_WIKI_LINK + "The newly created Tenant Profile Id will be present in the response. " + "Specify existing Tenant Profile Id id to update the Tenant Profile. " + "Referencing non-existing Tenant Profile Id will cause 'Not Found' error. " + diff --git a/application/src/main/java/org/thingsboard/server/controller/UserController.java b/application/src/main/java/org/thingsboard/server/controller/UserController.java index d768a42e16..e83bc8970c 100644 --- a/application/src/main/java/org/thingsboard/server/controller/UserController.java +++ b/application/src/main/java/org/thingsboard/server/controller/UserController.java @@ -81,6 +81,7 @@ import static org.thingsboard.server.controller.ControllerConstants.TENANT_OR_CU import static org.thingsboard.server.controller.ControllerConstants.USER_ID_PARAM_DESCRIPTION; import static org.thingsboard.server.controller.ControllerConstants.USER_SORT_PROPERTY_ALLOWABLE_VALUES; import static org.thingsboard.server.controller.ControllerConstants.USER_TEXT_SEARCH_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.UUID_WIKI_LINK; @RequiredArgsConstructor @RestController @@ -174,7 +175,7 @@ public class UserController extends BaseController { } @ApiOperation(value = "Save Or update User (saveUser)", - notes = "Create or update the User. When creating user, platform generates User Id as [time-based UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_1_(date-time_and_MAC_address). " + + notes = "Create or update the User. When creating user, platform generates User Id as " + UUID_WIKI_LINK + "The newly created User Id will be present in the response. " + "Specify existing User Id to update the device. " + "Referencing non-existing User Id will cause 'Not Found' error." + diff --git a/application/src/main/java/org/thingsboard/server/controller/WidgetTypeController.java b/application/src/main/java/org/thingsboard/server/controller/WidgetTypeController.java index a899f4cce2..b7f8b28b28 100644 --- a/application/src/main/java/org/thingsboard/server/controller/WidgetTypeController.java +++ b/application/src/main/java/org/thingsboard/server/controller/WidgetTypeController.java @@ -45,6 +45,7 @@ import java.util.List; import static org.thingsboard.server.controller.ControllerConstants.AVAILABLE_FOR_ANY_AUTHORIZED_USER; import static org.thingsboard.server.controller.ControllerConstants.SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH; +import static org.thingsboard.server.controller.ControllerConstants.UUID_WIKI_LINK; import static org.thingsboard.server.controller.ControllerConstants.WIDGET_TYPE_ID_PARAM_DESCRIPTION; @Slf4j @@ -78,7 +79,7 @@ public class WidgetTypeController extends BaseController { @ApiOperation(value = "Create Or Update Widget Type (saveWidgetType)", notes = "Create or update the Widget Type. " + WIDGET_TYPE_DESCRIPTION + " " + - "When creating the Widget Type, platform generates Widget Type Id as [time-based UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_1_(date-time_and_MAC_address). " + + "When creating the Widget Type, platform generates Widget Type Id as " + UUID_WIKI_LINK + "The newly created Widget Type Id will be present in the response. " + "Specify existing Widget Type id to update the Widget Type. " + "Referencing non-existing Widget Type Id will cause 'Not Found' error." + diff --git a/application/src/main/java/org/thingsboard/server/controller/WidgetsBundleController.java b/application/src/main/java/org/thingsboard/server/controller/WidgetsBundleController.java index a6cc14dce1..36999950c1 100644 --- a/application/src/main/java/org/thingsboard/server/controller/WidgetsBundleController.java +++ b/application/src/main/java/org/thingsboard/server/controller/WidgetsBundleController.java @@ -49,6 +49,7 @@ import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_A import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_DESCRIPTION; import static org.thingsboard.server.controller.ControllerConstants.SORT_PROPERTY_DESCRIPTION; import static org.thingsboard.server.controller.ControllerConstants.SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH; +import static org.thingsboard.server.controller.ControllerConstants.UUID_WIKI_LINK; import static org.thingsboard.server.controller.ControllerConstants.WIDGET_BUNDLE_ID_PARAM_DESCRIPTION; import static org.thingsboard.server.controller.ControllerConstants.WIDGET_BUNDLE_SORT_PROPERTY_ALLOWABLE_VALUES; import static org.thingsboard.server.controller.ControllerConstants.WIDGET_BUNDLE_TEXT_SEARCH_DESCRIPTION; @@ -79,7 +80,7 @@ public class WidgetsBundleController extends BaseController { @ApiOperation(value = "Create Or Update Widget Bundle (saveWidgetsBundle)", notes = "Create or update the Widget Bundle. " + WIDGET_BUNDLE_DESCRIPTION + " " + - "When creating the bundle, platform generates Widget Bundle Id as [time-based UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_1_(date-time_and_MAC_address). " + + "When creating the bundle, platform generates Widget Bundle Id as " + UUID_WIKI_LINK + "The newly created Widget Bundle Id will be present in the response. " + "Specify existing Widget Bundle id to update the Widget Bundle. " + "Referencing non-existing Widget Bundle Id will cause 'Not Found' error." + From 5daeb0a12cd5ea36af30eba2b045a3cdbe98d087 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Mon, 1 Nov 2021 13:10:12 +0200 Subject: [PATCH 072/432] lwm2m - fix bug info if first update Fw/Sw - failed (change text msg) --- .../transport/lwm2m/server/LwM2mTransportCoapResource.java | 2 +- .../lwm2m/server/ota/DefaultLwM2MOtaUpdateService.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportCoapResource.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportCoapResource.java index d3002d196b..4182a5ecf5 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportCoapResource.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportCoapResource.java @@ -151,7 +151,7 @@ public class LwM2mTransportCoapResource extends AbstractLwM2mTransportResource { } exchange.respond(response); } else { - log.trace("Ota packaged currentId: [{}], is not in this session.", currentId.toString()); + log.trace("Ota packaged currentId: [{}] is not found.", currentId.toString()); } } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/DefaultLwM2MOtaUpdateService.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/DefaultLwM2MOtaUpdateService.java index 34ab841c74..0b253ecc20 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/DefaultLwM2MOtaUpdateService.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/DefaultLwM2MOtaUpdateService.java @@ -400,7 +400,7 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl startUpdateUsingBinary(client, fwInfo); } } else { - log.debug("[{}] failed to update client: [{}], previous update failed.", client.getEndpoint(), fwInfo); + log.debug("[{}] failed to process firmware update: [{}]. Previous update failed.", client.getEndpoint(), fwInfo); logService.log(client, "Failed to process firmware update: " + fwInfo + ". Previous update failed."); } } catch (Exception e) { From 2d10409042aa372de0f34c5a75476b880ca38866 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Tue, 2 Nov 2021 13:31:17 +0200 Subject: [PATCH 073/432] lwm2m - authorization in Bootstrap session --- .../LwM2mDefaultBootstrapSessionManager.java | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2mDefaultBootstrapSessionManager.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2mDefaultBootstrapSessionManager.java index 0e6d2933e4..b12ae1c91f 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2mDefaultBootstrapSessionManager.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2mDefaultBootstrapSessionManager.java @@ -34,6 +34,7 @@ import org.eclipse.leshan.server.security.BootstrapSecurityStore; import org.eclipse.leshan.server.security.SecurityChecker; import org.eclipse.leshan.server.security.SecurityInfo; import org.thingsboard.server.common.transport.TransportService; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2MAuthException; import java.util.ArrayList; import java.util.Iterator; @@ -81,15 +82,19 @@ public class LwM2mDefaultBootstrapSessionManager extends DefaultBootstrapSession public BootstrapSession begin(BootstrapRequest request, Identity clientIdentity) { boolean authorized; Iterator securityInfos; - if (bsSecurityStore != null && securityChecker != null) { - if (clientIdentity.isSecure() && clientIdentity.isPSK()) { - securityInfos = bsSecurityStore.getAllByEndpoint(clientIdentity.getPskIdentity()); + try { + if (bsSecurityStore != null && securityChecker != null) { + if (clientIdentity.isSecure() && clientIdentity.isPSK()) { + securityInfos = bsSecurityStore.getAllByEndpoint(clientIdentity.getPskIdentity()); + } else { + securityInfos = bsSecurityStore.getAllByEndpoint(request.getEndpointName()); + } + authorized = securityChecker.checkSecurityInfos(request.getEndpointName(), clientIdentity, securityInfos); } else { - securityInfos = bsSecurityStore.getAllByEndpoint(request.getEndpointName()); + authorized = true; } - authorized = securityChecker.checkSecurityInfos(request.getEndpointName(), clientIdentity, securityInfos); - } else { - authorized = true; + } catch (LwM2MAuthException e) { + authorized = false; } DefaultBootstrapSession session = new DefaultBootstrapSession(request, clientIdentity, authorized); if (authorized) { From 934a03ea79c721b8b9a4fcf87bbbd97cb6b11316 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Tue, 2 Nov 2021 14:54:40 +0200 Subject: [PATCH 074/432] lwm2m - authorization in Bootstrap session default true --- .../bootstrap/secure/LwM2mDefaultBootstrapSessionManager.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2mDefaultBootstrapSessionManager.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2mDefaultBootstrapSessionManager.java index b12ae1c91f..097b69f806 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2mDefaultBootstrapSessionManager.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2mDefaultBootstrapSessionManager.java @@ -80,7 +80,7 @@ public class LwM2mDefaultBootstrapSessionManager extends DefaultBootstrapSession @Override public BootstrapSession begin(BootstrapRequest request, Identity clientIdentity) { - boolean authorized; + boolean authorized = true; Iterator securityInfos; try { if (bsSecurityStore != null && securityChecker != null) { @@ -90,8 +90,6 @@ public class LwM2mDefaultBootstrapSessionManager extends DefaultBootstrapSession securityInfos = bsSecurityStore.getAllByEndpoint(request.getEndpointName()); } authorized = securityChecker.checkSecurityInfos(request.getEndpointName(), clientIdentity, securityInfos); - } else { - authorized = true; } } catch (LwM2MAuthException e) { authorized = false; From f14a966cc6a6c05297d30c6294a8a64ded13575e Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Wed, 3 Nov 2021 13:52:42 +0200 Subject: [PATCH 075/432] lwm2m - Biding mode for lwm2m V_1.1 --- .../lwm2m-device-config-server.component.html | 3 +- ...ile-transport-configuration.component.html | 217 ++++++++++++------ .../lwm2m/lwm2m-profile-config.models.ts | 22 +- .../assets/locale/locale.constant-cs_CZ.json | 14 -- .../assets/locale/locale.constant-en_US.json | 31 +-- .../assets/locale/locale.constant-tr_TR.json | 12 - 6 files changed, 173 insertions(+), 126 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-config-server.component.html b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-config-server.component.html index 9606883368..b481c9a24a 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-config-server.component.html +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-config-server.component.html @@ -51,7 +51,8 @@
{{ 'device-profile.lwm2m.short-id' | translate }} - + {{ 'device-profile.lwm2m.short-id-required' | translate }} diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.html b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.html index a514891e09..b58546cf70 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.html +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.html @@ -35,84 +35,149 @@
- - - {{ 'device-profile.lwm2m.security' | translate }} - - -
- - {{ 'device-profile.lwm2m.short-id' | translate }} - - - {{ 'device-profile.lwm2m.short-id-required' | translate }} - - - {{ 'device-profile.lwm2m.short-id-range' | translate }} - - - {{ 'device-profile.lwm2m.short-id-pattern' | translate }} - +
+ device-profile.lwm2m.bootstrap-server-legend + + + {{ 'device-profile.lwm2m.server' | translate }} + + +
+ + {{ 'device-profile.lwm2m.short-id' | translate }} + + + {{ 'device-profile.lwm2m.short-id-required' | translate }} + + + {{ 'device-profile.lwm2m.short-id-range' | translate }} + + + {{ 'device-profile.lwm2m.short-id-pattern' | translate }} + + + + {{ 'device-profile.lwm2m.lifetime' | translate }} + + + {{ 'device-profile.lwm2m.lifetime-required' | translate }} + + + {{ 'device-profile.lwm2m.lifetime-pattern' | translate }} + + + + {{ 'device-profile.lwm2m.default-min-period' | translate }} + + + {{ 'device-profile.lwm2m.default-min-period-required' | translate }} + + + {{ 'device-profile.lwm2m.default-min-period-pattern' | translate }} + + +
+ + {{ 'device-profile.lwm2m.binding' | translate }} + + + {{ bindingModeTypeNamesMap.get(bindingMode) | translate }} + + - - {{ 'device-profile.lwm2m.lifetime' | translate }} - - - {{ 'device-profile.lwm2m.lifetime-required' | translate }} - - - {{ 'device-profile.lwm2m.lifetime-pattern' | translate }} - + + {{ 'device-profile.lwm2m.notification-storing' | translate }} + +
+
+ + + {{ 'device-profile.lwm2m.security' | translate }} + + + + + + +
+
+ device-profile.lwm2m.lwm2m-server-legend + + + {{ 'device-profile.lwm2m.server' | translate }} + + +
+ + {{ 'device-profile.lwm2m.short-id' | translate }} + + + {{ 'device-profile.lwm2m.short-id-required' | translate }} + + + {{ 'device-profile.lwm2m.short-id-range' | translate }} + + + {{ 'device-profile.lwm2m.short-id-pattern' | translate }} + + + + {{ 'device-profile.lwm2m.lifetime' | translate }} + + + {{ 'device-profile.lwm2m.lifetime-required' | translate }} + + + {{ 'device-profile.lwm2m.lifetime-pattern' | translate }} + + + + {{ 'device-profile.lwm2m.default-min-period' | translate }} + + + {{ 'device-profile.lwm2m.default-min-period-required' | translate }} + + + {{ 'device-profile.lwm2m.default-min-period-pattern' | translate }} + + +
+ + {{ 'device-profile.lwm2m.binding' | translate }} + + + {{ bindingModeTypeNamesMap.get(bindingMode) | translate }} + + - - {{ 'device-profile.lwm2m.default-min-period' | translate }} - - - {{ 'device-profile.lwm2m.default-min-period-required' | translate }} - - - {{ 'device-profile.lwm2m.default-min-period-pattern' | translate }} - - -
- - {{ 'device-profile.lwm2m.binding' | translate }} - - - {{ bindingModeTypeNamesMap.get(bindingMode) | translate }} - - - - - {{ 'device-profile.lwm2m.notification-storing' | translate }} - -
-
- - - {{ 'device-profile.lwm2m.bootstrap-server' | translate }} - - - - - - - - - {{ 'device-profile.lwm2m.lwm2m-server' | translate }} - - - - - - + + {{ 'device-profile.lwm2m.notification-storing' | translate }} + + + + + + {{ 'device-profile.lwm2m.security' | translate }} + + + + + + +
diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-profile-config.models.ts b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-profile-config.models.ts index 2845ad75b3..7025415ab8 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-profile-config.models.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-profile-config.models.ts @@ -45,28 +45,30 @@ export const DEFAULT_PAGING_TRANSMISSION_WINDOW = 10000; export enum BingingMode { U = 'U', - UQ = 'UQ', + M = 'M', + H = 'H', T = 'T', - TQ = 'TQ', S = 'S', - SQ = 'SQ', - US = 'US', - TS = 'TS', + N = 'N', + UQ = 'UQ', UQS = 'UQS', - TQS = 'TQS' + TQ = 'TQ', + TQS = 'TQS', + SQ = 'SQ' } export const BingingModeTranslationsMap = new Map( [ [BingingMode.U, 'device-profile.lwm2m.binding-type.u'], + [BingingMode.M, 'device-profile.lwm2m.binding-type.m'], + [BingingMode.H, 'device-profile.lwm2m.binding-type.h'], + [BingingMode.T, 'device-profile.lwm2m.binding-type.t'], + [BingingMode.S, 'device-profile.lwm2m.binding-type.s'], + [BingingMode.N, 'device-profile.lwm2m.binding-type.n'], [BingingMode.UQ, 'device-profile.lwm2m.binding-type.uq'], - [BingingMode.US, 'device-profile.lwm2m.binding-type.us'], [BingingMode.UQS, 'device-profile.lwm2m.binding-type.uqs'], - [BingingMode.T, 'device-profile.lwm2m.binding-type.t'], [BingingMode.TQ, 'device-profile.lwm2m.binding-type.tq'], - [BingingMode.TS, 'device-profile.lwm2m.binding-type.ts'], [BingingMode.TQS, 'device-profile.lwm2m.binding-type.tqs'], - [BingingMode.S, 'device-profile.lwm2m.binding-type.s'], [BingingMode.SQ, 'device-profile.lwm2m.binding-type.sq'] ] ); diff --git a/ui-ngx/src/assets/locale/locale.constant-cs_CZ.json b/ui-ngx/src/assets/locale/locale.constant-cs_CZ.json index 97bc94b645..0d872dc003 100644 --- a/ui-ngx/src/assets/locale/locale.constant-cs_CZ.json +++ b/ui-ngx/src/assets/locale/locale.constant-cs_CZ.json @@ -1270,21 +1270,7 @@ "default-min-period-pattern": "Minimální interval musí být kladné celé číslo.", "notification-storing": "Ukládání notifikací v případě nedostupnosti", "binding": "Binding", - "binding-type": { - "u": "U: UDP spojení ve standardním režimu", - "uq": "UQ: UDP spojení v queue režimu", - "us": "US: UDP i SMS spojení aktivní, obojí ve standardním režimu", - "uqs": "UQS: UDP i SMS spojení aktivní; UDP v queue režimu, SMS ve standardním režimu", - "t": "T: TCP spojení ve standardním režimu", - "tq": "TQ: TCP spojení v queue režimu", - "ts": "TS: TCP i SMS spojení aktivní, obojí ve standardním režimu", - "tqs": "TQS: TCP i SMS spojení aktivní; TCP v queue režimu, SMS ve standardním režimu", - "s": "S: SMS spojení ve standardním režimu", - "sq": "SQ: SMS spojení v queue režimu" - }, "bootstrap-tab": "Bootstrap", - "bootstrap-server": "Bootstrap server", - "lwm2m-server": "LwM2M server", "server-host": "Host", "server-host-required": "Host je povinný.", "server-port": "Port", diff --git a/ui-ngx/src/assets/locale/locale.constant-en_US.json b/ui-ngx/src/assets/locale/locale.constant-en_US.json index 5c4333f76c..a46b64384a 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -1277,9 +1277,12 @@ "view-attribute": "View attribute", "remove-attribute": "Remove attribute", "mode": "Security config mode", - "security": "Securities", "bootstrap-tab": "Bootstrap", + "bootstrap-server-legend": "Bootstrap Server (ShortId...)", + "lwm2m-server-legend": "LwM2M Server (ShortId...)", + "server": "Server", "short-id": "Short ID", + "short-id-tooltip": "Server ShortID must be equal Security ShortID ", "short-id-required": "Short ID is required.", "short-id-range": "Short ID should be in a range from 1 to 65534.", "short-id-pattern": "Short ID must be a positive integer.", @@ -1287,24 +1290,26 @@ "lifetime-required": "Client registration lifetime is required.", "lifetime-pattern": "Client registration lifetime must be a positive integer.", "default-min-period": "Minimum period between two notifications (s)", + "default-min-period-tooltip": "The default value the LwM2M Client should use for the Minimum Period of an Observation in the absence of this parameter being included in an Observation.", "default-min-period-required": "Minimum period is required.", "default-min-period-pattern": "Minimum period must be a positive integer.", "notification-storing": "Notification storing when disabled or offline", "binding": "Binding", "binding-type": { - "u": "U: UDP connection in standard mode", - "uq": "UQ: UDP connection in queue mode", - "us": "US: both UDP and SMS connections active, both in standard mode", - "uqs": "UQS: both UDP and SMS connections active; UDP in queue mode, SMS in standard mode", - "t": "T: TCP connection in standard mode", - "tq": "TQ: TCP connection in queue mode", - "ts": "TS: both TCP and SMS connections active, both in standard mode", - "tqs": "TQS: both TCP and SMS connections active; TCP in queue mode, SMS in standard mode", - "s": "S: SMS connection in standard mode", - "sq": "SQ: SMS connection in queue mode" + "u": "U: Client is reachable via the UDP binding at any time.", + "m": "M: Client is reachable via the MQTT binding at any time.", + "h": "H: Client is reachable via the HTTP binding at any time.", + "t": "T: Client is reachable via the TCP binding at any time.", + "s": "S: Client is reachable via the SMS binding at any time.", + "n": "N: Client MUST send the response to such a request over the Non-IP binding (is supported since LWM2M 1.1).", + "uq": "UQ: UDP connection in queue mode (is not supported since LWM2M 1.1)", + "uqs": "UQS: both UDP and SMS connections active; UDP in queue mode, SMS in standard mode (is not supported since LWM2M 1.1)", + "tq": "TQ: TCP connection in queue mode (is not supported since LWM2M 1.1)", + "tqs": "TQS: both TCP and SMS connections active; TCP in queue mode, SMS in standard mode (is not supported since LWM2M 1.1)", + "sq": "SQ: SMS connection in queue mode (is not supported since LWM2M 1.1)" }, - "bootstrap-server": "Bootstrap Server", - "lwm2m-server": "LwM2M Server", + "binding-tooltip": "Tis is the list in the\"binding\" resource of the LwM2M server object - /1/x/7.\nIndicates the supported binding modes in the LwM2M Client.\nThis value SHOULD be the same as the value in the “Supported Binding and Modes” resource in the Device Object (/3/0/16).\nWhile multiple transports are supported, only one transport binding can be used during the entire Transport\nSession. As an example, when UDP and SMS are both supported, the LwM2M Client and the LwM2M Server can\nchoose to communicate either over UDP or SMS during the entire Transport Session.", + "security": "Security", "server-host": "Host", "server-host-required": "Host is required.", "server-port": "Port", diff --git a/ui-ngx/src/assets/locale/locale.constant-tr_TR.json b/ui-ngx/src/assets/locale/locale.constant-tr_TR.json index 3bca05e458..432644ae56 100644 --- a/ui-ngx/src/assets/locale/locale.constant-tr_TR.json +++ b/ui-ngx/src/assets/locale/locale.constant-tr_TR.json @@ -1283,18 +1283,6 @@ "default-min-period-pattern": "Minimum süre pozitif bir tam sayı olmalıdır.", "notification-storing": "Devre dışı bırakıldığında veya çevrimdışı olduğunda bildirim depolama", "binding": "Bağlama", - "binding-type": { - "u": "U: UDP connection in standard mode", - "uq": "UQ: UDP connection in queue mode", - "us": "US: both UDP and SMS connections active, both in standard mode", - "uqs": "UQS: both UDP and SMS connections active; UDP in queue mode, SMS in standard mode", - "t": "T: TCP connection in standard mode", - "tq": "TQ: TCP connection in queue mode", - "ts": "TS: both TCP and SMS connections active, both in standard mode", - "tqs": "TQS: both TCP and SMS connections active; TCP in queue mode, SMS in standard mode", - "s": "S: SMS connection in standard mode", - "sq": "SQ: SMS connection in queue mode" - }, "bootstrap-tab": "Bootstrap", "bootstrap-server": "Bootstrap Sunucusu", "lwm2m-server": "LwM2M Sunucusu", From b095922aa8c4e6e6a00414c8c94c3d9e0c383f58 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Wed, 3 Nov 2021 15:22:15 +0200 Subject: [PATCH 076/432] lwm2m - Biding mode default --- .../profile/device/lwm2m/lwm2m-profile-config.models.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-profile-config.models.ts b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-profile-config.models.ts index 7025415ab8..070d0b703d 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-profile-config.models.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-profile-config.models.ts @@ -32,7 +32,7 @@ export const DEFAULT_CLIENT_HOLD_OFF_TIME = 1; export const DEFAULT_LIFE_TIME = 300; export const DEFAULT_MIN_PERIOD = 1; export const DEFAULT_NOTIF_IF_DESIBLED = true; -export const DEFAULT_BINDING = 'UQ'; +export const DEFAULT_BINDING = 'U'; export const DEFAULT_BOOTSTRAP_SERVER_ACCOUNT_TIME_OUT = 0; export const INSTANCES_ID_VALUE_MIN = 0; export const INSTANCES_ID_VALUE_MAX = 65535; From bad6653a50fd9623e497e2ab4ec22fffae2c908c Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Wed, 3 Nov 2021 23:28:28 +0200 Subject: [PATCH 077/432] lwm2m - update lwm2mController by base64 and createte BootstrpServerCredentials by Profile (Base64 validate) --- .../service/lwm2m/LwM2MServiceImpl.java | 15 ++++--- .../data/lwm2m/BootstrapConfiguration.java | 5 ++- .../bootstrap/AbstractServerCredentials.java | 38 +++++++++++++++++ .../bootstrap/NoSecServerCredentials.java | 25 +++++++++++ .../lwm2m/bootstrap/PSKServerCredentials.java | 25 +++++++++++ .../lwm2m/bootstrap/RPKServerCredentials.java | 25 +++++++++++ .../profile/lwm2m/bootstrap/ServerConfig.java | 27 ++++++++++++ .../lwm2m/bootstrap/ServerCredentials.java | 37 ++++++++++++++++ .../bootstrap/X509ServerCredentials.java | 25 +++++++++++ .../data/lwm2m/ServerSecurityConfig.java | 30 ++++++------- .../dao/device/DeviceProfileServiceImpl.java | 42 +++++++++++++++++++ 11 files changed, 272 insertions(+), 22 deletions(-) create mode 100644 common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/AbstractServerCredentials.java create mode 100644 common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/NoSecServerCredentials.java create mode 100644 common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/PSKServerCredentials.java create mode 100644 common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/RPKServerCredentials.java create mode 100644 common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/ServerConfig.java create mode 100644 common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/ServerCredentials.java create mode 100644 common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/X509ServerCredentials.java diff --git a/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MServiceImpl.java b/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MServiceImpl.java index 3a85a94f2d..34f8c54300 100644 --- a/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MServiceImpl.java +++ b/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MServiceImpl.java @@ -17,6 +17,7 @@ package org.thingsboard.server.service.lwm2m; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.codec.binary.Base64; import org.eclipse.leshan.core.util.Hex; import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.stereotype.Service; @@ -50,22 +51,26 @@ public class LwM2MServiceImpl implements LwM2MService { bsServ.setPort(serverConfig.getPort()); bsServ.setSecurityHost(serverConfig.getSecureHost()); bsServ.setSecurityPort(serverConfig.getSecurePort()); - bsServ.setServerPublicKey(getPublicKey(serverConfig)); + byte[] publicKeyBase64 = getPublicKey(serverConfig); + if (publicKeyBase64 == null) { + bsServ.setServerPublicKey(""); + } else { + bsServ.setServerPublicKey(Base64.encodeBase64String(getPublicKey(serverConfig))); + } return bsServ; } - private String getPublicKey(LwM2MSecureServerConfig config) { + private byte[] getPublicKey(LwM2MSecureServerConfig config) { try { KeyStore keyStore = serverConfig.getKeyStoreValue(); if (keyStore != null) { X509Certificate serverCertificate = (X509Certificate) serverConfig.getKeyStoreValue().getCertificate(config.getCertificateAlias()); - return Hex.encodeHexString(serverCertificate.getPublicKey().getEncoded()); + return serverCertificate.getPublicKey().getEncoded(); } } catch (Exception e) { log.trace("Failed to fetch public key from key store!", e); - } - return ""; + return null; } } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/data/lwm2m/BootstrapConfiguration.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/data/lwm2m/BootstrapConfiguration.java index 66bdfd1f4c..4b3901d655 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/device/data/lwm2m/BootstrapConfiguration.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/data/lwm2m/BootstrapConfiguration.java @@ -16,6 +16,7 @@ package org.thingsboard.server.common.data.device.data.lwm2m; import lombok.Data; +import org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap.ServerCredentials; import java.util.Map; @@ -24,7 +25,7 @@ public class BootstrapConfiguration { //TODO: define the objects; private Map servers; - private Map lwm2mServer; - private Map bootstrapServer; + private ServerCredentials lwm2mServer; + private ServerCredentials bootstrapServer; } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/AbstractServerCredentials.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/AbstractServerCredentials.java new file mode 100644 index 0000000000..030b40946f --- /dev/null +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/AbstractServerCredentials.java @@ -0,0 +1,38 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import lombok.Getter; +import lombok.Setter; +import lombok.SneakyThrows; +import org.apache.commons.codec.binary.Base64; +import org.thingsboard.server.common.data.lwm2m.ServerSecurityConfig; + +@Getter +@Setter +public abstract class AbstractServerCredentials extends ServerSecurityConfig implements ServerCredentials { + + @JsonIgnore + public byte[] getDecodedCServerPublicKey() { + return getDecoded(serverPublicKey); + } + + @SneakyThrows + private static byte[] getDecoded(String key) { + return Base64.decodeBase64(key.getBytes()); + } +} diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/NoSecServerCredentials.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/NoSecServerCredentials.java new file mode 100644 index 0000000000..432066b1ff --- /dev/null +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/NoSecServerCredentials.java @@ -0,0 +1,25 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap; + +import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MSecurityMode; + +public class NoSecServerCredentials extends AbstractServerCredentials{ + @Override + public LwM2MSecurityMode getSecurityMode() { + return LwM2MSecurityMode.NO_SEC; + } +} diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/PSKServerCredentials.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/PSKServerCredentials.java new file mode 100644 index 0000000000..2e21e34145 --- /dev/null +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/PSKServerCredentials.java @@ -0,0 +1,25 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap; + +import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MSecurityMode; + +public class PSKServerCredentials extends AbstractServerCredentials{ + @Override + public LwM2MSecurityMode getSecurityMode() { + return LwM2MSecurityMode.PSK; + } +} diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/RPKServerCredentials.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/RPKServerCredentials.java new file mode 100644 index 0000000000..42d7ab2981 --- /dev/null +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/RPKServerCredentials.java @@ -0,0 +1,25 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap; + +import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MSecurityMode; + +public class RPKServerCredentials extends AbstractServerCredentials{ + @Override + public LwM2MSecurityMode getSecurityMode() { + return LwM2MSecurityMode.RPK; + } +} diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/ServerConfig.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/ServerConfig.java new file mode 100644 index 0000000000..ab05fb6b75 --- /dev/null +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/ServerConfig.java @@ -0,0 +1,27 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap; + +import lombok.Data; + +@Data +public class ServerConfig { + private Integer shortId = 123; + private Integer lifetime = 300; + private Integer defaultMinPeriod = 1; + private boolean notifIfDisabled = true; + private String binding = "U"; +} diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/ServerCredentials.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/ServerCredentials.java new file mode 100644 index 0000000000..146e2cf125 --- /dev/null +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/ServerCredentials.java @@ -0,0 +1,37 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonSubTypes; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MSecurityMode; + +@JsonTypeInfo( + use = JsonTypeInfo.Id.NAME, + property = "securityMode") +@JsonSubTypes({ + @JsonSubTypes.Type(value = NoSecServerCredentials.class, name = "NO_SEC"), + @JsonSubTypes.Type(value = PSKServerCredentials.class, name = "PSK"), + @JsonSubTypes.Type(value = RPKServerCredentials.class, name = "RPK"), + @JsonSubTypes.Type(value = X509ServerCredentials.class, name = "X509") +}) +@JsonIgnoreProperties(ignoreUnknown = true) +public interface ServerCredentials { + @JsonIgnore + LwM2MSecurityMode getSecurityMode(); +} diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/X509ServerCredentials.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/X509ServerCredentials.java new file mode 100644 index 0000000000..f56cb12e80 --- /dev/null +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/X509ServerCredentials.java @@ -0,0 +1,25 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap; + +import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MSecurityMode; + +public class X509ServerCredentials extends AbstractServerCredentials{ + @Override + public LwM2MSecurityMode getSecurityMode() { + return LwM2MSecurityMode.X509; + } +} diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/lwm2m/ServerSecurityConfig.java b/common/data/src/main/java/org/thingsboard/server/common/data/lwm2m/ServerSecurityConfig.java index 79b3ef40b6..83b56a2661 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/lwm2m/ServerSecurityConfig.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/lwm2m/ServerSecurityConfig.java @@ -22,23 +22,23 @@ import lombok.Data; @ApiModel @Data public class ServerSecurityConfig { - @ApiModelProperty(position = 1, value = "Is Bootstrap Server", example = "true", readOnly = true) - boolean bootstrapServerIs = true; + @ApiModelProperty(position = 1, value = "Is Bootstrap Server or Lwm2m Server", example = "true or false", readOnly = true) + protected boolean bootstrapServerIs = true; @ApiModelProperty(position = 2, value = "Host for 'No Security' mode", example = "0.0.0.0", readOnly = true) - String host; - @ApiModelProperty(position = 3, value = "Port for 'No Security' mode", example = "5687", readOnly = true) - Integer port; + protected String host; + @ApiModelProperty(position = 3, value = "Port for Lwm2m Server: 'No Security' mode: Lwm2m Server or Bootstrap Server", example = "'5685' or '5687'", readOnly = true) + protected Integer port; @ApiModelProperty(position = 4, value = "Host for 'Security' mode (DTLS)", example = "0.0.0.0", readOnly = true) - String securityHost; - @ApiModelProperty(position = 5, value = "Port for 'Security' mode (DTLS)", example = "5688", readOnly = true) - Integer securityPort; - @ApiModelProperty(position = 5, value = "Server short Id", example = "111", readOnly = true) - Integer serverId = 111; - @ApiModelProperty(position = 7, value = "Client Hold Off Time", example = "1", readOnly = true) - Integer clientHoldOffTime = 1; - @ApiModelProperty(position = 8, value = "Server Public Key (base64 encoded)", example = "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEAZ0pSaGKHk/GrDaUDnQZpeEdGwX7m3Ws+U/kiVat\n" + + protected String securityHost; + @ApiModelProperty(position = 5, value = "Port for 'Security' mode (DTLS): Lwm2m Server or Bootstrap Server", example = "5686 or 5688", readOnly = true) + protected Integer securityPort; + @ApiModelProperty(position = 6, value = "Server short Id", example = "111", readOnly = true) + protected Integer serverId = 111; + @ApiModelProperty(position = 7, value = "Client Hold Off Time. The number of seconds to wait before initiating a Client Initiated Bootstrap once the LwM2M Client has determined it should initiate this bootstrap mode. (This information is relevant for use with a Bootstrap-Server only.)", example = "1", readOnly = true) + protected Integer clientHoldOffTime = 1; + @ApiModelProperty(position = 8, value = "Server Public Key for 'Security' mode (DTLS): RPK or X509. Format: base64 encoded", example = "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEAZ0pSaGKHk/GrDaUDnQZpeEdGwX7m3Ws+U/kiVat\n" + "+44sgk3c8g0LotfMpLlZJPhPwJ6ipXV+O1r7IZUjBs3LNA==", readOnly = true) - String serverPublicKey; - @ApiModelProperty(position = 9, value = "Bootstrap Server Account Timeout", example = "0", readOnly = true) + protected String serverPublicKey; + @ApiModelProperty(position = 9, value = "Bootstrap Server Account Timeout (If the value is set to 0, or if this resource is not instantiated, the Bootstrap-Server Account lifetime is infinite.)", example = "0", readOnly = true) Integer bootstrapServerAccountTimeout = 0; } diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java index f3e2f6599f..c7ebbb11bc 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java @@ -28,6 +28,7 @@ import com.squareup.wire.schema.internal.parser.ProtoFileElement; import com.squareup.wire.schema.internal.parser.ProtoParser; import com.squareup.wire.schema.internal.parser.TypeElement; import lombok.extern.slf4j.Slf4j; +import org.eclipse.leshan.core.util.SecurityUtil; import org.thingsboard.server.common.data.StringUtils; import org.hibernate.exception.ConstraintViolationException; import org.springframework.beans.factory.annotation.Autowired; @@ -58,16 +59,21 @@ import org.thingsboard.server.common.data.device.profile.Lwm2mDeviceProfileTrans import org.thingsboard.server.common.data.device.profile.MqttDeviceProfileTransportConfiguration; import org.thingsboard.server.common.data.device.profile.ProtoTransportPayloadConfiguration; import org.thingsboard.server.common.data.device.profile.TransportPayloadTypeConfiguration; +import org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap.RPKServerCredentials; +import org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap.ServerCredentials; +import org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap.X509ServerCredentials; import org.thingsboard.server.common.data.ota.OtaPackageType; import org.thingsboard.server.common.data.id.DeviceProfileId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.rule.RuleChain; +import org.thingsboard.server.common.msg.EncryptionUtil; import org.thingsboard.server.common.msg.queue.ServiceType; import org.thingsboard.server.dao.dashboard.DashboardService; import org.thingsboard.server.dao.entity.AbstractEntityService; import org.thingsboard.server.dao.exception.DataValidationException; +import org.thingsboard.server.dao.exception.DeviceCredentialsValidationException; import org.thingsboard.server.dao.ota.OtaPackageService; import org.thingsboard.server.dao.rule.RuleChainService; import org.thingsboard.server.dao.service.DataValidator; @@ -695,6 +701,42 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D } } + private void validateLwm2mServersCredentialOfBootstrapForClient(ServerCredentials bootstrapServerConfig, String server) { + switch (bootstrapServerConfig.getSecurityMode()) { + case NO_SEC: + case PSK: + break; + case RPK: + RPKServerCredentials rpkServerCredentials = (RPKServerCredentials) bootstrapServerConfig; + if (StringUtils.isEmpty(rpkServerCredentials.getServerPublicKey())) { + throw new DeviceCredentialsValidationException(server + " RPK public key must be specified!"); + } + try { + String pubkRpkSever = EncryptionUtil.pubkTrimNewLines(rpkServerCredentials.getServerPublicKey()); + rpkServerCredentials.setServerPublicKey(pubkRpkSever); + SecurityUtil.publicKey.decode(rpkServerCredentials.getDecodedCServerPublicKey()); + } catch (Exception e) { + throw new DeviceCredentialsValidationException(server + " RPK public key must be in standard [RFC7250] and then encoded to Base64 format!"); + } + break; + case X509: + X509ServerCredentials x509ServerCredentials = (X509ServerCredentials) bootstrapServerConfig; +// X509BootstrapServerCredentials x509ServerCredentials = (X509BootstrapServerCredentials) bootstrapServerConfig; + if (StringUtils.isEmpty(x509ServerCredentials.getServerPublicKey())) { + throw new DeviceCredentialsValidationException(server + " X509 public key must be specified!"); + } + + try { + String certServer = EncryptionUtil.certTrimNewLines(x509ServerCredentials.getServerPublicKey()); + x509ServerCredentials.setServerPublicKey(certServer); + SecurityUtil.publicKey.decode(x509ServerCredentials.getDecodedCServerPublicKey()); + } catch (Exception e) { + throw new DeviceCredentialsValidationException(server + " X509 public key must be in standard [RFC7250] and then encoded to Base64 format!"); + } + break; + } + } + private PaginatedRemover tenantDeviceProfilesRemover = new PaginatedRemover() { From 82704d54d0c26bcbfa4f9dfbfaa35ffd6d4a0974 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Thu, 4 Nov 2021 07:58:58 +0200 Subject: [PATCH 078/432] lwm2m - profile (Base64 validate) --- .../server/dao/device/DeviceProfileServiceImpl.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java index c7ebbb11bc..e4e394d7e7 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java @@ -46,6 +46,7 @@ import org.thingsboard.server.common.data.DeviceProfileType; import org.thingsboard.server.common.data.DeviceTransportType; import org.thingsboard.server.common.data.OtaPackage; import org.thingsboard.server.common.data.Tenant; +import org.thingsboard.server.common.data.device.data.lwm2m.BootstrapConfiguration; import org.thingsboard.server.common.data.device.profile.CoapDeviceProfileTransportConfiguration; import org.thingsboard.server.common.data.device.profile.CoapDeviceTypeConfiguration; import org.thingsboard.server.common.data.device.profile.DefaultCoapDeviceTypeConfiguration; @@ -417,7 +418,9 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D } } } else if (transportConfiguration instanceof Lwm2mDeviceProfileTransportConfiguration) { -// deviceCredentialsService.verifyLwm2mSecurityKeyDeviceProfile((Lwm2mDeviceProfileTransportConfiguration) transportConfiguration); + BootstrapConfiguration bootstrapConfiguration = ((Lwm2mDeviceProfileTransportConfiguration) transportConfiguration).getBootstrap(); + validateLwm2mServersCredentialOfBootstrapForClient(bootstrapConfiguration.getBootstrapServer(), "Bootstrap Server"); + validateLwm2mServersCredentialOfBootstrapForClient(bootstrapConfiguration.getLwm2mServer(), "LwM2M Server"); } List profileAlarms = deviceProfile.getProfileData().getAlarms(); From 9e71c0b9fe6be13c3a31973fa92a1d586843c919 Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Thu, 4 Nov 2021 14:50:11 +0200 Subject: [PATCH 079/432] EntityDataAdapterTest added to verify convertValue method --- .../dao/sql/query/EntityDataAdapter.java | 2 +- .../dao/sql/query/EntityDataAdapterTest.java | 29 +++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 dao/src/test/java/org/thingsboard/server/dao/sql/query/EntityDataAdapterTest.java diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/query/EntityDataAdapter.java b/dao/src/main/java/org/thingsboard/server/dao/sql/query/EntityDataAdapter.java index 785ba69c7e..5450c43287 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/query/EntityDataAdapter.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/query/EntityDataAdapter.java @@ -79,7 +79,7 @@ public class EntityDataAdapter { return entityData; } - private static String convertValue(Object value) { + static String convertValue(Object value) { if (value != null) { String strVal = value.toString(); // check number diff --git a/dao/src/test/java/org/thingsboard/server/dao/sql/query/EntityDataAdapterTest.java b/dao/src/test/java/org/thingsboard/server/dao/sql/query/EntityDataAdapterTest.java new file mode 100644 index 0000000000..abbcb61d3b --- /dev/null +++ b/dao/src/test/java/org/thingsboard/server/dao/sql/query/EntityDataAdapterTest.java @@ -0,0 +1,29 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.dao.sql.query; + +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +class EntityDataAdapterTest { + + @Test + void testConvertValue() { + assertThat(EntityDataAdapter.convertValue("500")).isEqualTo("500"); + assertThat(EntityDataAdapter.convertValue("500D")).isEqualTo("500D"); //do not convert to Double !!! + } +} From 4efa360f5ca73a52b1e43cde842658f473d5bb54 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Thu, 4 Nov 2021 16:26:44 +0200 Subject: [PATCH 080/432] lwm2m - profile fix bug server config --- .../thingsboard/server/service/lwm2m/LwM2MServiceImpl.java | 2 +- .../data/device/data/lwm2m/BootstrapConfiguration.java | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MServiceImpl.java b/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MServiceImpl.java index 34f8c54300..06e772c52d 100644 --- a/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MServiceImpl.java +++ b/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MServiceImpl.java @@ -55,7 +55,7 @@ public class LwM2MServiceImpl implements LwM2MService { if (publicKeyBase64 == null) { bsServ.setServerPublicKey(""); } else { - bsServ.setServerPublicKey(Base64.encodeBase64String(getPublicKey(serverConfig))); + bsServ.setServerPublicKey(Base64.encodeBase64String(publicKeyBase64)); } return bsServ; } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/data/lwm2m/BootstrapConfiguration.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/data/lwm2m/BootstrapConfiguration.java index 4b3901d655..007fd81c07 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/device/data/lwm2m/BootstrapConfiguration.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/data/lwm2m/BootstrapConfiguration.java @@ -16,15 +16,13 @@ package org.thingsboard.server.common.data.device.data.lwm2m; import lombok.Data; +import org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap.ServerConfig; import org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap.ServerCredentials; -import java.util.Map; - @Data public class BootstrapConfiguration { - //TODO: define the objects; - private Map servers; + private ServerConfig servers; private ServerCredentials lwm2mServer; private ServerCredentials bootstrapServer; From 8f93f6dd06d72abfce2130f33f06a1a5cbf48d17 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Thu, 4 Nov 2021 17:37:19 +0200 Subject: [PATCH 081/432] lwm2m - profile&device rename --- .../device/DeviceBulkImportService.java | 6 +-- .../lwm2m/AbstractLwM2MIntegrationTest.java | 22 ++++---- .../ota/sql/OtaLwM2MIntegrationTest.java | 8 +-- .../rpc/AbstractRpcLwM2MIntegrationTest.java | 4 +- .../AbstractSecurityLwM2MIntegrationTest.java | 10 ++-- .../sql/NoSecLwM2MIntegrationTest.java | 4 +- .../security/sql/PskLwm2mIntegrationTest.java | 4 +- .../security/sql/RpkLwM2MIntegrationTest.java | 4 +- .../sql/X509_NoTrustLwM2MIntegrationTest.java | 4 +- .../sql/X509_TrustLwM2MIntegrationTest.java | 4 +- ...M2MBootstrapClientCredentialWithKeys.java} | 2 +- ...ava => AbstractLwM2MClientCredential.java} | 2 +- ...bstractLwM2MClientSecurityCredential.java} | 2 +- ...va => LwM2MBootstrapClientCredential.java} | 10 ++-- ...a => LwM2MBootstrapClientCredentials.java} | 6 +-- ...ntials.java => LwM2MClientCredential.java} | 10 ++-- .../lwm2m/LwM2MDeviceCredentials.java | 4 +- ...va => NoSecBootstrapClientCredential.java} | 2 +- ...ntials.java => NoSecClientCredential.java} | 2 +- ...java => PSKBootstrapClientCredential.java} | 2 +- ...dentials.java => PSKClientCredential.java} | 2 +- ...java => RPKBootstrapClientCredential.java} | 2 +- ...dentials.java => RPKClientCredential.java} | 2 +- ...ava => X509BootstrapClientCredential.java} | 2 +- ...entials.java => X509ClientCredential.java} | 2 +- .../data/lwm2m/BootstrapConfiguration.java | 29 ----------- ...2mDeviceProfileTransportConfiguration.java | 8 +-- .../lwm2m/ObjectAttributes.java | 2 +- .../lwm2m/OtherConfiguration.java | 2 +- .../lwm2m/TelemetryMappingConfiguration.java | 3 +- ...stractLwM2MBootstrapServerCredential.java} | 2 +- ...g.java => LwM2MBootstrapServerConfig.java} | 2 +- ...va => LwM2MBootstrapServerCredential.java} | 10 ++-- .../LwM2MBootstrapServersConfiguration.java | 31 +++++++++++ ... NoSecLwM2MBootstrapServerCredential.java} | 2 +- ...=> PSKLwM2MBootstrapServerCredential.java} | 2 +- ...=> RPKLwM2MBootstrapServerCredential.java} | 2 +- ...> X509LwM2MBootstrapServerCredential.java} | 2 +- .../secure/LwM2MBootstrapSecurityStore.java | 4 +- ...LwM2mCredentialsSecurityInfoValidator.java | 18 +++---- .../TbLwM2MDtlsCertificateVerifier.java | 4 +- .../secure/credentials/LwM2MCredentials.java | 4 +- .../server/client/LwM2mClientContextImpl.java | 3 +- .../DefaultLwM2mDownlinkMsgHandler.java | 2 +- .../TbLwM2MWriteAttributesRequest.java | 2 +- .../ota/DefaultLwM2MOtaUpdateService.java | 2 +- .../server/ota/LwM2MOtaUpdateService.java | 2 +- .../server/rpc/RpcWriteAttributesRequest.java | 2 +- .../uplink/DefaultLwM2mUplinkMsgHandler.java | 6 +-- .../lwm2m/utils/LwM2MTransportUtil.java | 4 +- .../device/DeviceCredentialsServiceImpl.java | 52 +++++++++---------- .../dao/device/DeviceProfileServiceImpl.java | 21 ++++---- 52 files changed, 173 insertions(+), 172 deletions(-) rename common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/{AbstractLwM2MServerCredentialsWithKeys.java => AbstractLwM2MBootstrapClientCredentialWithKeys.java} (92%) rename common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/{AbstractLwM2MClientCredentials.java => AbstractLwM2MClientCredential.java} (90%) rename common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/{AbstractLwM2MClientSecurityCredentials.java => AbstractLwM2MClientSecurityCredential.java} (90%) rename common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/{LwM2MServerCredentials.java => LwM2MBootstrapClientCredential.java} (73%) rename common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/{LwM2MBootstrapCredentials.java => LwM2MBootstrapClientCredentials.java} (82%) rename common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/{LwM2MClientCredentials.java => LwM2MClientCredential.java} (76%) rename common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/{NoSecServerCredentials.java => NoSecBootstrapClientCredential.java} (90%) rename common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/{NoSecClientCredentials.java => NoSecClientCredential.java} (91%) rename common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/{PSKServerCredentials.java => PSKBootstrapClientCredential.java} (88%) rename common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/{PSKClientCredentials.java => PSKClientCredential.java} (93%) rename common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/{RPKServerCredentials.java => RPKBootstrapClientCredential.java} (88%) rename common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/{RPKClientCredentials.java => RPKClientCredential.java} (93%) rename common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/{X509ServerCredentials.java => X509BootstrapClientCredential.java} (88%) rename common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/{X509ClientCredentials.java => X509ClientCredential.java} (93%) delete mode 100644 common/data/src/main/java/org/thingsboard/server/common/data/device/data/lwm2m/BootstrapConfiguration.java rename common/data/src/main/java/org/thingsboard/server/common/data/device/{data => profile}/lwm2m/ObjectAttributes.java (93%) rename common/data/src/main/java/org/thingsboard/server/common/data/device/{data => profile}/lwm2m/OtherConfiguration.java (95%) rename common/data/src/main/java/org/thingsboard/server/common/data/device/{data => profile}/lwm2m/TelemetryMappingConfiguration.java (86%) rename common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/{AbstractServerCredentials.java => AbstractLwM2MBootstrapServerCredential.java} (89%) rename common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/{ServerConfig.java => LwM2MBootstrapServerConfig.java} (95%) rename common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/{ServerCredentials.java => LwM2MBootstrapServerCredential.java} (74%) create mode 100644 common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/LwM2MBootstrapServersConfiguration.java rename common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/{NoSecServerCredentials.java => NoSecLwM2MBootstrapServerCredential.java} (90%) rename common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/{PSKServerCredentials.java => PSKLwM2MBootstrapServerCredential.java} (90%) rename common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/{RPKServerCredentials.java => RPKLwM2MBootstrapServerCredential.java} (90%) rename common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/{X509ServerCredentials.java => X509LwM2MBootstrapServerCredential.java} (90%) diff --git a/application/src/main/java/org/thingsboard/server/service/device/DeviceBulkImportService.java b/application/src/main/java/org/thingsboard/server/service/device/DeviceBulkImportService.java index 6e31fa1d73..4beb072a7b 100644 --- a/application/src/main/java/org/thingsboard/server/service/device/DeviceBulkImportService.java +++ b/application/src/main/java/org/thingsboard/server/service/device/DeviceBulkImportService.java @@ -31,7 +31,7 @@ import org.thingsboard.server.common.data.DeviceProfileProvisionType; import org.thingsboard.server.common.data.DeviceProfileType; import org.thingsboard.server.common.data.DeviceTransportType; import org.thingsboard.server.common.data.device.credentials.BasicMqttCredentials; -import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MClientCredentials; +import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MClientCredential; import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MSecurityMode; import org.thingsboard.server.common.data.device.profile.DefaultDeviceProfileConfiguration; import org.thingsboard.server.common.data.device.profile.DeviceProfileData; @@ -205,9 +205,9 @@ public class DeviceBulkImportService extends AbstractBulkImportService { setValues(client, fields, Set.of(BulkImportColumnType.LWM2M_CLIENT_SECURITY_CONFIG_MODE, BulkImportColumnType.LWM2M_CLIENT_ENDPOINT, BulkImportColumnType.LWM2M_CLIENT_IDENTITY, BulkImportColumnType.LWM2M_CLIENT_KEY, BulkImportColumnType.LWM2M_CLIENT_CERT)); - LwM2MClientCredentials lwM2MClientCredentials = JacksonUtil.treeToValue(client, LwM2MClientCredentials.class); + LwM2MClientCredential lwM2MClientCredential = JacksonUtil.treeToValue(client, LwM2MClientCredential.class); // so that only fields needed for specific type of lwM2MClientCredentials were saved in json - lwm2mCredentials.set("client", JacksonUtil.valueToTree(lwM2MClientCredentials)); + lwm2mCredentials.set("client", JacksonUtil.valueToTree(lwM2MClientCredential)); ObjectNode bootstrapServer = JacksonUtil.newObjectNode(); setValues(bootstrapServer, fields, Set.of(BulkImportColumnType.LWM2M_BOOTSTRAP_SERVER_SECURITY_MODE, diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/AbstractLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/AbstractLwM2MIntegrationTest.java index 1a49807374..37e174d09c 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/AbstractLwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/AbstractLwM2MIntegrationTest.java @@ -32,11 +32,11 @@ import org.thingsboard.server.common.data.DeviceProfileType; import org.thingsboard.server.common.data.DeviceTransportType; import org.thingsboard.server.common.data.ResourceType; import org.thingsboard.server.common.data.TbResource; -import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MBootstrapCredentials; -import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MClientCredentials; +import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MBootstrapClientCredentials; +import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MClientCredential; import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MDeviceCredentials; -import org.thingsboard.server.common.data.device.credentials.lwm2m.NoSecClientCredentials; -import org.thingsboard.server.common.data.device.credentials.lwm2m.NoSecServerCredentials; +import org.thingsboard.server.common.data.device.credentials.lwm2m.NoSecClientCredential; +import org.thingsboard.server.common.data.device.credentials.lwm2m.NoSecBootstrapClientCredential; import org.thingsboard.server.common.data.device.profile.DefaultDeviceProfileConfiguration; import org.thingsboard.server.common.data.device.profile.DeviceProfileData; import org.thingsboard.server.common.data.device.profile.DisabledDeviceProfileProvisionConfiguration; @@ -121,13 +121,13 @@ public abstract class AbstractLwM2MIntegrationTest extends AbstractWebsocketTest protected ScheduledExecutorService executor; protected TbTestWebSocketClient wsClient; protected LwM2MTestClient client; - private final LwM2MBootstrapCredentials defaultBootstrapCredentials; + private final LwM2MBootstrapClientCredentials defaultBootstrapCredentials; private String[] resources; protected String endpoint; public AbstractLwM2MIntegrationTest() { - this.defaultBootstrapCredentials = new LwM2MBootstrapCredentials(); - NoSecServerCredentials serverCredentials = new NoSecServerCredentials(); + this.defaultBootstrapCredentials = new LwM2MBootstrapClientCredentials(); + NoSecBootstrapClientCredential serverCredentials = new NoSecBootstrapClientCredential(); this.defaultBootstrapCredentials.setBootstrapServer(serverCredentials); this.defaultBootstrapCredentials.setLwm2mServer(serverCredentials); } @@ -164,7 +164,7 @@ public abstract class AbstractLwM2MIntegrationTest extends AbstractWebsocketTest } public void basicTestConnectionObserveTelemetry(Security security, - LwM2MClientCredentials credentials, + LwM2MClientCredential credentials, NetworkConfig coapConfig, String endpoint) throws Exception { createDeviceProfile(transportConfiguration); @@ -219,7 +219,7 @@ public abstract class AbstractLwM2MIntegrationTest extends AbstractWebsocketTest Assert.assertNotNull(deviceProfile); } - protected Device createDevice(LwM2MClientCredentials clientCredentials) throws Exception { + protected Device createDevice(LwM2MClientCredential clientCredentials) throws Exception { Device device = new Device(); device.setName("Device A"); device.setDeviceProfileId(deviceProfile.getId()); @@ -241,8 +241,8 @@ public abstract class AbstractLwM2MIntegrationTest extends AbstractWebsocketTest return device; } - public NoSecClientCredentials createNoSecClientCredentials(String endpoint) { - NoSecClientCredentials clientCredentials = new NoSecClientCredentials(); + public NoSecClientCredential createNoSecClientCredentials(String endpoint) { + NoSecClientCredential clientCredentials = new NoSecClientCredential(); clientCredentials.setEndpoint(endpoint); return clientCredentials; } diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/ota/sql/OtaLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/ota/sql/OtaLwM2MIntegrationTest.java index 68f8c98d6f..440a8a8532 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/ota/sql/OtaLwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/ota/sql/OtaLwM2MIntegrationTest.java @@ -20,7 +20,7 @@ import lombok.extern.slf4j.Slf4j; import org.junit.Assert; import org.junit.Test; import org.thingsboard.server.common.data.Device; -import org.thingsboard.server.common.data.device.credentials.lwm2m.NoSecClientCredentials; +import org.thingsboard.server.common.data.device.credentials.lwm2m.NoSecClientCredential; import org.thingsboard.server.common.data.kv.KvEntry; import org.thingsboard.server.common.data.kv.TsKvEntry; import org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus; @@ -135,7 +135,7 @@ public class OtaLwM2MIntegrationTest extends AbstractOtaLwM2MIntegrationTest { String endpoint = "WithoutFirmwareInfoDevice"; setEndpoint(endpoint); createDeviceProfile(transportConfiguration); - NoSecClientCredentials credentials = createNoSecClientCredentials(endpoint); + NoSecClientCredential credentials = createNoSecClientCredentials(endpoint); final Device device = createDevice(credentials); createNewClient(SECURITY, COAP_CONFIG, false); @@ -162,7 +162,7 @@ public class OtaLwM2MIntegrationTest extends AbstractOtaLwM2MIntegrationTest { String endpoint = "Ota5_Device"; setEndpoint(endpoint); createDeviceProfile(OTA_TRANSPORT_CONFIGURATION); - NoSecClientCredentials credentials = createNoSecClientCredentials(endpoint); + NoSecClientCredential credentials = createNoSecClientCredentials(endpoint); final Device device = createDevice(credentials); createNewClient(SECURITY, COAP_CONFIG, false); @@ -201,7 +201,7 @@ public class OtaLwM2MIntegrationTest extends AbstractOtaLwM2MIntegrationTest { String endpoint = "Ota9_Device"; setEndpoint(endpoint); createDeviceProfile(OTA_TRANSPORT_CONFIGURATION); - NoSecClientCredentials credentials = createNoSecClientCredentials(endpoint); + NoSecClientCredential credentials = createNoSecClientCredentials(endpoint); final Device device = createDevice(credentials); createNewClient(SECURITY, COAP_CONFIG, false); diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/AbstractRpcLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/AbstractRpcLwM2MIntegrationTest.java index 93f9ffb1ae..2906fb0215 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/AbstractRpcLwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/AbstractRpcLwM2MIntegrationTest.java @@ -17,7 +17,7 @@ package org.thingsboard.server.transport.lwm2m.rpc; import org.junit.Before; import org.thingsboard.server.common.data.Device; -import org.thingsboard.server.common.data.device.credentials.lwm2m.NoSecClientCredentials; +import org.thingsboard.server.common.data.device.credentials.lwm2m.NoSecClientCredential; import org.thingsboard.server.controller.TbTestWebSocketClient; import org.thingsboard.server.dao.service.DaoSqlTest; import org.thingsboard.server.transport.lwm2m.AbstractLwM2MIntegrationTest; @@ -178,7 +178,7 @@ public abstract class AbstractRpcLwM2MIntegrationTest extends AbstractLwM2MInteg "}"; createDeviceProfile(RPC_TRANSPORT_CONFIGURATION); - NoSecClientCredentials credentials = createNoSecClientCredentials(endpoint); + NoSecClientCredential credentials = createNoSecClientCredentials(endpoint); final Device device = createDevice(credentials); deviceId = device.getId().getId().toString(); diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/AbstractSecurityLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/AbstractSecurityLwM2MIntegrationTest.java index 491c39a9f9..046f0558cb 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/AbstractSecurityLwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/AbstractSecurityLwM2MIntegrationTest.java @@ -16,8 +16,8 @@ package org.thingsboard.server.transport.lwm2m.security; import org.eclipse.leshan.core.util.Hex; -import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MBootstrapCredentials; -import org.thingsboard.server.common.data.device.credentials.lwm2m.NoSecServerCredentials; +import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MBootstrapClientCredentials; +import org.thingsboard.server.common.data.device.credentials.lwm2m.NoSecBootstrapClientCredential; import org.thingsboard.server.dao.service.DaoSqlTest; import org.thingsboard.server.transport.lwm2m.AbstractLwM2MIntegrationTest; import org.thingsboard.server.transport.lwm2m.client.LwM2MTestClient; @@ -75,7 +75,7 @@ public abstract class AbstractSecurityLwM2MIntegrationTest extends AbstractLwM2M protected LwM2MTestClient client; - private final LwM2MBootstrapCredentials defaultBootstrapCredentials; + private final LwM2MBootstrapClientCredentials defaultBootstrapCredentials; private final String[] resources = new String[]{"1.xml", "2.xml", "3.xml", "5.xml", "9.xml"}; @@ -166,9 +166,9 @@ public abstract class AbstractSecurityLwM2MIntegrationTest extends AbstractLwM2M throw new RuntimeException(e); } - defaultBootstrapCredentials = new LwM2MBootstrapCredentials(); + defaultBootstrapCredentials = new LwM2MBootstrapClientCredentials(); - NoSecServerCredentials serverCredentials = new NoSecServerCredentials(); + NoSecBootstrapClientCredential serverCredentials = new NoSecBootstrapClientCredential(); defaultBootstrapCredentials.setBootstrapServer(serverCredentials); defaultBootstrapCredentials.setLwm2mServer(serverCredentials); diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/NoSecLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/NoSecLwM2MIntegrationTest.java index 1d278354b5..0e86c6a438 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/NoSecLwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/NoSecLwM2MIntegrationTest.java @@ -17,7 +17,7 @@ package org.thingsboard.server.transport.lwm2m.security.sql; import lombok.extern.slf4j.Slf4j; import org.junit.Test; -import org.thingsboard.server.common.data.device.credentials.lwm2m.NoSecClientCredentials; +import org.thingsboard.server.common.data.device.credentials.lwm2m.NoSecClientCredential; import org.thingsboard.server.transport.lwm2m.security.AbstractSecurityLwM2MIntegrationTest; import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.COAP_CONFIG; @@ -28,7 +28,7 @@ public class NoSecLwM2MIntegrationTest extends AbstractSecurityLwM2MIntegrationT @Test public void testConnectAndObserveTelemetry() throws Exception { - NoSecClientCredentials clientCredentials = createNoSecClientCredentials(ENDPOINT); + NoSecClientCredential clientCredentials = createNoSecClientCredentials(ENDPOINT); super.basicTestConnectionObserveTelemetry(SECURITY, clientCredentials, COAP_CONFIG, ENDPOINT); } diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/PskLwm2mIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/PskLwm2mIntegrationTest.java index 23b60482f0..af9a668376 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/PskLwm2mIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/PskLwm2mIntegrationTest.java @@ -18,7 +18,7 @@ package org.thingsboard.server.transport.lwm2m.security.sql; import org.eclipse.leshan.client.object.Security; import org.eclipse.leshan.core.util.Hex; import org.junit.Test; -import org.thingsboard.server.common.data.device.credentials.lwm2m.PSKClientCredentials; +import org.thingsboard.server.common.data.device.credentials.lwm2m.PSKClientCredential; import org.thingsboard.server.transport.lwm2m.security.AbstractSecurityLwM2MIntegrationTest; import java.nio.charset.StandardCharsets; @@ -32,7 +32,7 @@ public class PskLwm2mIntegrationTest extends AbstractSecurityLwM2MIntegrationTes @Test public void testConnectWithPSKAndObserveTelemetry() throws Exception { - PSKClientCredentials clientCredentials = new PSKClientCredentials(); + PSKClientCredential clientCredentials = new PSKClientCredential(); clientCredentials.setEndpoint(ENDPOINT); clientCredentials.setKey(pskKey); clientCredentials.setIdentity(pskIdentity); diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/RpkLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/RpkLwM2MIntegrationTest.java index 68479f6fb9..9e74beaa6b 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/RpkLwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/RpkLwM2MIntegrationTest.java @@ -17,7 +17,7 @@ package org.thingsboard.server.transport.lwm2m.security.sql; import org.eclipse.leshan.client.object.Security; import org.junit.Test; -import org.thingsboard.server.common.data.device.credentials.lwm2m.RPKClientCredentials; +import org.thingsboard.server.common.data.device.credentials.lwm2m.RPKClientCredential; import org.thingsboard.server.transport.lwm2m.security.AbstractSecurityLwM2MIntegrationTest; import org.apache.commons.codec.binary.Base64;; @@ -31,7 +31,7 @@ public class RpkLwM2MIntegrationTest extends AbstractSecurityLwM2MIntegrationTes @Test public void testConnectWithRPKAndObserveTelemetry() throws Exception { - RPKClientCredentials rpkClientCredentials = new RPKClientCredentials(); + RPKClientCredential rpkClientCredentials = new RPKClientCredential(); rpkClientCredentials.setEndpoint(ENDPOINT); rpkClientCredentials.setKey(new String(Base64.encodeBase64(clientPublicKey.getEncoded()))); Security security = rpk(SECURE_URI, diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/X509_NoTrustLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/X509_NoTrustLwM2MIntegrationTest.java index f6e08f0e3d..f55c21dcc2 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/X509_NoTrustLwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/X509_NoTrustLwM2MIntegrationTest.java @@ -17,7 +17,7 @@ package org.thingsboard.server.transport.lwm2m.security.sql; import org.eclipse.leshan.client.object.Security; import org.junit.Test; -import org.thingsboard.server.common.data.device.credentials.lwm2m.X509ClientCredentials; +import org.thingsboard.server.common.data.device.credentials.lwm2m.X509ClientCredential; import org.thingsboard.server.common.transport.util.SslUtil; import org.thingsboard.server.transport.lwm2m.security.AbstractSecurityLwM2MIntegrationTest; @@ -30,7 +30,7 @@ public class X509_NoTrustLwM2MIntegrationTest extends AbstractSecurityLwM2MInteg @Test public void testConnectWithCertAndObserveTelemetry() throws Exception { - X509ClientCredentials credentials = new X509ClientCredentials(); + X509ClientCredential credentials = new X509ClientCredential(); credentials.setEndpoint(ENDPOINT); credentials.setCert(SslUtil.getCertificateString(clientX509CertNotTrusted)); Security security = x509(SECURE_URI, diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/X509_TrustLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/X509_TrustLwM2MIntegrationTest.java index 28289b32bf..32d176d598 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/X509_TrustLwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/X509_TrustLwM2MIntegrationTest.java @@ -17,7 +17,7 @@ package org.thingsboard.server.transport.lwm2m.security.sql; import org.eclipse.leshan.client.object.Security; import org.junit.Test; -import org.thingsboard.server.common.data.device.credentials.lwm2m.X509ClientCredentials; +import org.thingsboard.server.common.data.device.credentials.lwm2m.X509ClientCredential; import org.thingsboard.server.transport.lwm2m.security.AbstractSecurityLwM2MIntegrationTest; import static org.eclipse.leshan.client.object.Security.x509; @@ -29,7 +29,7 @@ public class X509_TrustLwM2MIntegrationTest extends AbstractSecurityLwM2MIntegra @Test public void testConnectAndObserveTelemetry() throws Exception { - X509ClientCredentials credentials = new X509ClientCredentials(); + X509ClientCredential credentials = new X509ClientCredential(); credentials.setEndpoint(ENDPOINT); Security security = x509(SECURE_URI, SHORT_SERVER_ID, diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/AbstractLwM2MServerCredentialsWithKeys.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/AbstractLwM2MBootstrapClientCredentialWithKeys.java similarity index 92% rename from common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/AbstractLwM2MServerCredentialsWithKeys.java rename to common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/AbstractLwM2MBootstrapClientCredentialWithKeys.java index c46962fc91..e0712c4728 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/AbstractLwM2MServerCredentialsWithKeys.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/AbstractLwM2MBootstrapClientCredentialWithKeys.java @@ -23,7 +23,7 @@ import org.apache.commons.codec.binary.Base64; @Getter @Setter -public abstract class AbstractLwM2MServerCredentialsWithKeys implements LwM2MServerCredentials { +public abstract class AbstractLwM2MBootstrapClientCredentialWithKeys implements LwM2MBootstrapClientCredential { private String clientPublicKeyOrId; private String clientSecretKey; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/AbstractLwM2MClientCredentials.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/AbstractLwM2MClientCredential.java similarity index 90% rename from common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/AbstractLwM2MClientCredentials.java rename to common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/AbstractLwM2MClientCredential.java index 66eb523209..70cdc1545b 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/AbstractLwM2MClientCredentials.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/AbstractLwM2MClientCredential.java @@ -22,6 +22,6 @@ import lombok.Setter; @Getter @Setter @NoArgsConstructor -public abstract class AbstractLwM2MClientCredentials implements LwM2MClientCredentials { +public abstract class AbstractLwM2MClientCredential implements LwM2MClientCredential { private String endpoint; } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/AbstractLwM2MClientSecurityCredentials.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/AbstractLwM2MClientSecurityCredential.java similarity index 90% rename from common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/AbstractLwM2MClientSecurityCredentials.java rename to common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/AbstractLwM2MClientSecurityCredential.java index e5e3271c7a..27f0f79511 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/AbstractLwM2MClientSecurityCredentials.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/AbstractLwM2MClientSecurityCredential.java @@ -19,7 +19,7 @@ import lombok.Getter; import lombok.Setter; import org.apache.commons.codec.DecoderException; -public abstract class AbstractLwM2MClientSecurityCredentials extends AbstractLwM2MClientCredentials { +public abstract class AbstractLwM2MClientSecurityCredential extends AbstractLwM2MClientCredential { @Getter @Setter protected String key; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/LwM2MServerCredentials.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/LwM2MBootstrapClientCredential.java similarity index 73% rename from common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/LwM2MServerCredentials.java rename to common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/LwM2MBootstrapClientCredential.java index 82e2b6feae..f27a7ceb4b 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/LwM2MServerCredentials.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/LwM2MBootstrapClientCredential.java @@ -24,13 +24,13 @@ import com.fasterxml.jackson.annotation.JsonTypeInfo; use = JsonTypeInfo.Id.NAME, property = "securityMode") @JsonSubTypes({ - @JsonSubTypes.Type(value = NoSecServerCredentials.class, name = "NO_SEC"), - @JsonSubTypes.Type(value = PSKServerCredentials.class, name = "PSK"), - @JsonSubTypes.Type(value = RPKServerCredentials.class, name = "RPK"), - @JsonSubTypes.Type(value = X509ServerCredentials.class, name = "X509") + @JsonSubTypes.Type(value = NoSecBootstrapClientCredential.class, name = "NO_SEC"), + @JsonSubTypes.Type(value = PSKBootstrapClientCredential.class, name = "PSK"), + @JsonSubTypes.Type(value = RPKBootstrapClientCredential.class, name = "RPK"), + @JsonSubTypes.Type(value = X509BootstrapClientCredential.class, name = "X509") }) @JsonIgnoreProperties(ignoreUnknown = true) -public interface LwM2MServerCredentials { +public interface LwM2MBootstrapClientCredential { @JsonIgnore LwM2MSecurityMode getSecurityMode(); diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/LwM2MBootstrapCredentials.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/LwM2MBootstrapClientCredentials.java similarity index 82% rename from common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/LwM2MBootstrapCredentials.java rename to common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/LwM2MBootstrapClientCredentials.java index 70a4846e86..fe46b77541 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/LwM2MBootstrapCredentials.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/LwM2MBootstrapClientCredentials.java @@ -20,7 +20,7 @@ import lombok.Setter; @Getter @Setter -public class LwM2MBootstrapCredentials { - private LwM2MServerCredentials bootstrapServer; - private LwM2MServerCredentials lwm2mServer; +public class LwM2MBootstrapClientCredentials { + private LwM2MBootstrapClientCredential bootstrapServer; + private LwM2MBootstrapClientCredential lwm2mServer; } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/LwM2MClientCredentials.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/LwM2MClientCredential.java similarity index 76% rename from common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/LwM2MClientCredentials.java rename to common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/LwM2MClientCredential.java index 7322c80359..f53e3885fe 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/LwM2MClientCredentials.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/LwM2MClientCredential.java @@ -24,13 +24,13 @@ import com.fasterxml.jackson.annotation.JsonTypeInfo; use = JsonTypeInfo.Id.NAME, property = "securityConfigClientMode") @JsonSubTypes({ - @JsonSubTypes.Type(value = NoSecClientCredentials.class, name = "NO_SEC"), - @JsonSubTypes.Type(value = PSKClientCredentials.class, name = "PSK"), - @JsonSubTypes.Type(value = RPKClientCredentials.class, name = "RPK"), - @JsonSubTypes.Type(value = X509ClientCredentials.class, name = "X509") + @JsonSubTypes.Type(value = NoSecClientCredential.class, name = "NO_SEC"), + @JsonSubTypes.Type(value = PSKClientCredential.class, name = "PSK"), + @JsonSubTypes.Type(value = RPKClientCredential.class, name = "RPK"), + @JsonSubTypes.Type(value = X509ClientCredential.class, name = "X509") }) @JsonIgnoreProperties(ignoreUnknown = true) -public interface LwM2MClientCredentials { +public interface LwM2MClientCredential { @JsonIgnore LwM2MSecurityMode getSecurityConfigClientMode(); diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/LwM2MDeviceCredentials.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/LwM2MDeviceCredentials.java index 3275b4313e..cd73484a51 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/LwM2MDeviceCredentials.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/LwM2MDeviceCredentials.java @@ -21,6 +21,6 @@ import lombok.Setter; @Getter @Setter public class LwM2MDeviceCredentials { - private LwM2MClientCredentials client; - private LwM2MBootstrapCredentials bootstrap; + private LwM2MClientCredential client; + private LwM2MBootstrapClientCredentials bootstrap; } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/NoSecServerCredentials.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/NoSecBootstrapClientCredential.java similarity index 90% rename from common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/NoSecServerCredentials.java rename to common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/NoSecBootstrapClientCredential.java index a7a76e5192..12a28f062d 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/NoSecServerCredentials.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/NoSecBootstrapClientCredential.java @@ -15,7 +15,7 @@ */ package org.thingsboard.server.common.data.device.credentials.lwm2m; -public class NoSecServerCredentials implements LwM2MServerCredentials { +public class NoSecBootstrapClientCredential implements LwM2MBootstrapClientCredential { @Override public LwM2MSecurityMode getSecurityMode() { diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/NoSecClientCredentials.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/NoSecClientCredential.java similarity index 91% rename from common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/NoSecClientCredentials.java rename to common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/NoSecClientCredential.java index 7e54a9b63d..fe40eef78f 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/NoSecClientCredentials.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/NoSecClientCredential.java @@ -15,7 +15,7 @@ */ package org.thingsboard.server.common.data.device.credentials.lwm2m; -public class NoSecClientCredentials extends AbstractLwM2MClientCredentials { +public class NoSecClientCredential extends AbstractLwM2MClientCredential { @Override public LwM2MSecurityMode getSecurityConfigClientMode() { diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/PSKServerCredentials.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/PSKBootstrapClientCredential.java similarity index 88% rename from common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/PSKServerCredentials.java rename to common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/PSKBootstrapClientCredential.java index ab9e515482..6a4cc7f35e 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/PSKServerCredentials.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/PSKBootstrapClientCredential.java @@ -15,7 +15,7 @@ */ package org.thingsboard.server.common.data.device.credentials.lwm2m; -public class PSKServerCredentials extends AbstractLwM2MServerCredentialsWithKeys { +public class PSKBootstrapClientCredential extends AbstractLwM2MBootstrapClientCredentialWithKeys { @Override public LwM2MSecurityMode getSecurityMode() { diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/PSKClientCredentials.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/PSKClientCredential.java similarity index 93% rename from common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/PSKClientCredentials.java rename to common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/PSKClientCredential.java index 03d2ab328c..abb7931b52 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/PSKClientCredentials.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/PSKClientCredential.java @@ -22,7 +22,7 @@ import org.apache.commons.codec.binary.Hex; @Getter @Setter -public class PSKClientCredentials extends AbstractLwM2MClientSecurityCredentials { +public class PSKClientCredential extends AbstractLwM2MClientSecurityCredential { private String identity; @Override diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/RPKServerCredentials.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/RPKBootstrapClientCredential.java similarity index 88% rename from common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/RPKServerCredentials.java rename to common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/RPKBootstrapClientCredential.java index f18e74f46c..c93db49eb1 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/RPKServerCredentials.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/RPKBootstrapClientCredential.java @@ -15,7 +15,7 @@ */ package org.thingsboard.server.common.data.device.credentials.lwm2m; -public class RPKServerCredentials extends AbstractLwM2MServerCredentialsWithKeys { +public class RPKBootstrapClientCredential extends AbstractLwM2MBootstrapClientCredentialWithKeys { @Override public LwM2MSecurityMode getSecurityMode() { diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/RPKClientCredentials.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/RPKClientCredential.java similarity index 93% rename from common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/RPKClientCredentials.java rename to common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/RPKClientCredential.java index a05bb438c6..13869aa15d 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/RPKClientCredentials.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/RPKClientCredential.java @@ -18,7 +18,7 @@ package org.thingsboard.server.common.data.device.credentials.lwm2m; import org.apache.commons.codec.DecoderException; import org.apache.commons.codec.binary.Base64; -public class RPKClientCredentials extends AbstractLwM2MClientSecurityCredentials { +public class RPKClientCredential extends AbstractLwM2MClientSecurityCredential { @Override public LwM2MSecurityMode getSecurityConfigClientMode() { diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/X509ServerCredentials.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/X509BootstrapClientCredential.java similarity index 88% rename from common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/X509ServerCredentials.java rename to common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/X509BootstrapClientCredential.java index a7b98608e2..53eda29e60 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/X509ServerCredentials.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/X509BootstrapClientCredential.java @@ -15,7 +15,7 @@ */ package org.thingsboard.server.common.data.device.credentials.lwm2m; -public class X509ServerCredentials extends AbstractLwM2MServerCredentialsWithKeys { +public class X509BootstrapClientCredential extends AbstractLwM2MBootstrapClientCredentialWithKeys { @Override public LwM2MSecurityMode getSecurityMode() { diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/X509ClientCredentials.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/X509ClientCredential.java similarity index 93% rename from common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/X509ClientCredentials.java rename to common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/X509ClientCredential.java index dfef57e18e..1d52e22a33 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/X509ClientCredentials.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/X509ClientCredential.java @@ -22,7 +22,7 @@ import org.apache.commons.codec.binary.Base64; @Getter @Setter -public class X509ClientCredentials extends AbstractLwM2MClientSecurityCredentials { +public class X509ClientCredential extends AbstractLwM2MClientSecurityCredential { private String cert; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/data/lwm2m/BootstrapConfiguration.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/data/lwm2m/BootstrapConfiguration.java deleted file mode 100644 index 007fd81c07..0000000000 --- a/common/data/src/main/java/org/thingsboard/server/common/data/device/data/lwm2m/BootstrapConfiguration.java +++ /dev/null @@ -1,29 +0,0 @@ -/** - * Copyright © 2016-2021 The Thingsboard Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.thingsboard.server.common.data.device.data.lwm2m; - -import lombok.Data; -import org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap.ServerConfig; -import org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap.ServerCredentials; - -@Data -public class BootstrapConfiguration { - - private ServerConfig servers; - private ServerCredentials lwm2mServer; - private ServerCredentials bootstrapServer; - -} diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/Lwm2mDeviceProfileTransportConfiguration.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/Lwm2mDeviceProfileTransportConfiguration.java index 31ae4594ea..1bc6ce8004 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/Lwm2mDeviceProfileTransportConfiguration.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/Lwm2mDeviceProfileTransportConfiguration.java @@ -17,9 +17,9 @@ package org.thingsboard.server.common.data.device.profile; import lombok.Data; import org.thingsboard.server.common.data.DeviceTransportType; -import org.thingsboard.server.common.data.device.data.lwm2m.BootstrapConfiguration; -import org.thingsboard.server.common.data.device.data.lwm2m.OtherConfiguration; -import org.thingsboard.server.common.data.device.data.lwm2m.TelemetryMappingConfiguration; +import org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap.LwM2MBootstrapServersConfiguration; +import org.thingsboard.server.common.data.device.profile.lwm2m.OtherConfiguration; +import org.thingsboard.server.common.data.device.profile.lwm2m.TelemetryMappingConfiguration; @Data public class Lwm2mDeviceProfileTransportConfiguration implements DeviceProfileTransportConfiguration { @@ -27,7 +27,7 @@ public class Lwm2mDeviceProfileTransportConfiguration implements DeviceProfileTr private static final long serialVersionUID = 6257277825459600068L; private TelemetryMappingConfiguration observeAttr; - private BootstrapConfiguration bootstrap; + private LwM2MBootstrapServersConfiguration bootstrap; private OtherConfiguration clientLwM2mSettings; @Override diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/data/lwm2m/ObjectAttributes.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/ObjectAttributes.java similarity index 93% rename from common/data/src/main/java/org/thingsboard/server/common/data/device/data/lwm2m/ObjectAttributes.java rename to common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/ObjectAttributes.java index ee54a23a07..e0fcc7499c 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/device/data/lwm2m/ObjectAttributes.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/ObjectAttributes.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.common.data.device.data.lwm2m; +package org.thingsboard.server.common.data.device.profile.lwm2m; import com.fasterxml.jackson.annotation.JsonInclude; import lombok.Data; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/data/lwm2m/OtherConfiguration.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/OtherConfiguration.java similarity index 95% rename from common/data/src/main/java/org/thingsboard/server/common/data/device/data/lwm2m/OtherConfiguration.java rename to common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/OtherConfiguration.java index cf841d6204..ae4f04c10b 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/device/data/lwm2m/OtherConfiguration.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/OtherConfiguration.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.common.data.device.data.lwm2m; +package org.thingsboard.server.common.data.device.profile.lwm2m; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import lombok.Data; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/data/lwm2m/TelemetryMappingConfiguration.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/TelemetryMappingConfiguration.java similarity index 86% rename from common/data/src/main/java/org/thingsboard/server/common/data/device/data/lwm2m/TelemetryMappingConfiguration.java rename to common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/TelemetryMappingConfiguration.java index 2f2683998d..4bdcee6b3f 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/device/data/lwm2m/TelemetryMappingConfiguration.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/TelemetryMappingConfiguration.java @@ -13,9 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.common.data.device.data.lwm2m; +package org.thingsboard.server.common.data.device.profile.lwm2m; import lombok.Data; +import org.thingsboard.server.common.data.device.profile.lwm2m.ObjectAttributes; import java.util.Map; import java.util.Set; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/AbstractServerCredentials.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/AbstractLwM2MBootstrapServerCredential.java similarity index 89% rename from common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/AbstractServerCredentials.java rename to common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/AbstractLwM2MBootstrapServerCredential.java index 030b40946f..87eeb3a1e1 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/AbstractServerCredentials.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/AbstractLwM2MBootstrapServerCredential.java @@ -24,7 +24,7 @@ import org.thingsboard.server.common.data.lwm2m.ServerSecurityConfig; @Getter @Setter -public abstract class AbstractServerCredentials extends ServerSecurityConfig implements ServerCredentials { +public abstract class AbstractLwM2MBootstrapServerCredential extends ServerSecurityConfig implements LwM2MBootstrapServerCredential { @JsonIgnore public byte[] getDecodedCServerPublicKey() { diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/ServerConfig.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/LwM2MBootstrapServerConfig.java similarity index 95% rename from common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/ServerConfig.java rename to common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/LwM2MBootstrapServerConfig.java index ab05fb6b75..f27f01978f 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/ServerConfig.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/LwM2MBootstrapServerConfig.java @@ -18,7 +18,7 @@ package org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap; import lombok.Data; @Data -public class ServerConfig { +public class LwM2MBootstrapServerConfig { private Integer shortId = 123; private Integer lifetime = 300; private Integer defaultMinPeriod = 1; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/ServerCredentials.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/LwM2MBootstrapServerCredential.java similarity index 74% rename from common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/ServerCredentials.java rename to common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/LwM2MBootstrapServerCredential.java index 146e2cf125..b22e80d81f 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/ServerCredentials.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/LwM2MBootstrapServerCredential.java @@ -25,13 +25,13 @@ import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MSecurity use = JsonTypeInfo.Id.NAME, property = "securityMode") @JsonSubTypes({ - @JsonSubTypes.Type(value = NoSecServerCredentials.class, name = "NO_SEC"), - @JsonSubTypes.Type(value = PSKServerCredentials.class, name = "PSK"), - @JsonSubTypes.Type(value = RPKServerCredentials.class, name = "RPK"), - @JsonSubTypes.Type(value = X509ServerCredentials.class, name = "X509") + @JsonSubTypes.Type(value = NoSecLwM2MBootstrapServerCredential.class, name = "NO_SEC"), + @JsonSubTypes.Type(value = PSKLwM2MBootstrapServerCredential.class, name = "PSK"), + @JsonSubTypes.Type(value = RPKLwM2MBootstrapServerCredential.class, name = "RPK"), + @JsonSubTypes.Type(value = X509LwM2MBootstrapServerCredential.class, name = "X509") }) @JsonIgnoreProperties(ignoreUnknown = true) -public interface ServerCredentials { +public interface LwM2MBootstrapServerCredential { @JsonIgnore LwM2MSecurityMode getSecurityMode(); } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/LwM2MBootstrapServersConfiguration.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/LwM2MBootstrapServersConfiguration.java new file mode 100644 index 0000000000..6347ecc06c --- /dev/null +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/LwM2MBootstrapServersConfiguration.java @@ -0,0 +1,31 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap; + +import lombok.Data; + +@Data +public class LwM2MBootstrapServersConfiguration { + + //TODO + // List LwM2MBootstrapServersConfigurations; + // LwM2MBootstrapServersConfiguration: Integer shortId, LwM2MBootstrapServerConfig serverConfig; LwM2MBootstrapServerCredential serverSecurity. + + private LwM2MBootstrapServerConfig servers; + private LwM2MBootstrapServerCredential lwm2mServer; + private LwM2MBootstrapServerCredential bootstrapServer; + +} diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/NoSecServerCredentials.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/NoSecLwM2MBootstrapServerCredential.java similarity index 90% rename from common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/NoSecServerCredentials.java rename to common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/NoSecLwM2MBootstrapServerCredential.java index 432066b1ff..7730c79ee9 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/NoSecServerCredentials.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/NoSecLwM2MBootstrapServerCredential.java @@ -17,7 +17,7 @@ package org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap; import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MSecurityMode; -public class NoSecServerCredentials extends AbstractServerCredentials{ +public class NoSecLwM2MBootstrapServerCredential extends AbstractLwM2MBootstrapServerCredential { @Override public LwM2MSecurityMode getSecurityMode() { return LwM2MSecurityMode.NO_SEC; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/PSKServerCredentials.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/PSKLwM2MBootstrapServerCredential.java similarity index 90% rename from common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/PSKServerCredentials.java rename to common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/PSKLwM2MBootstrapServerCredential.java index 2e21e34145..30f7f8c472 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/PSKServerCredentials.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/PSKLwM2MBootstrapServerCredential.java @@ -17,7 +17,7 @@ package org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap; import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MSecurityMode; -public class PSKServerCredentials extends AbstractServerCredentials{ +public class PSKLwM2MBootstrapServerCredential extends AbstractLwM2MBootstrapServerCredential { @Override public LwM2MSecurityMode getSecurityMode() { return LwM2MSecurityMode.PSK; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/RPKServerCredentials.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/RPKLwM2MBootstrapServerCredential.java similarity index 90% rename from common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/RPKServerCredentials.java rename to common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/RPKLwM2MBootstrapServerCredential.java index 42d7ab2981..c529820709 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/RPKServerCredentials.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/RPKLwM2MBootstrapServerCredential.java @@ -17,7 +17,7 @@ package org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap; import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MSecurityMode; -public class RPKServerCredentials extends AbstractServerCredentials{ +public class RPKLwM2MBootstrapServerCredential extends AbstractLwM2MBootstrapServerCredential { @Override public LwM2MSecurityMode getSecurityMode() { return LwM2MSecurityMode.RPK; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/X509ServerCredentials.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/X509LwM2MBootstrapServerCredential.java similarity index 90% rename from common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/X509ServerCredentials.java rename to common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/X509LwM2MBootstrapServerCredential.java index f56cb12e80..e95bf7742d 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/X509ServerCredentials.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/X509LwM2MBootstrapServerCredential.java @@ -17,7 +17,7 @@ package org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap; import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MSecurityMode; -public class X509ServerCredentials extends AbstractServerCredentials{ +public class X509LwM2MBootstrapServerCredential extends AbstractLwM2MBootstrapServerCredential { @Override public LwM2MSecurityMode getSecurityMode() { return LwM2MSecurityMode.X509; diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapSecurityStore.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapSecurityStore.java index e15520406f..2731c22d52 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapSecurityStore.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapSecurityStore.java @@ -27,7 +27,7 @@ import org.eclipse.leshan.server.security.SecurityInfo; import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.stereotype.Service; import org.thingsboard.common.util.JacksonUtil; -import org.thingsboard.server.common.data.device.data.lwm2m.BootstrapConfiguration; +import org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap.LwM2MBootstrapServersConfiguration; import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.transport.lwm2m.secure.LwM2mCredentialsSecurityInfoValidator; import org.thingsboard.server.transport.lwm2m.secure.TbLwM2MSecurityInfo; @@ -157,7 +157,7 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore { private LwM2MBootstrapConfig getParametersBootstrap(TbLwM2MSecurityInfo store) { LwM2MBootstrapConfig lwM2MBootstrapConfig = store.getBootstrapCredentialConfig(); if (lwM2MBootstrapConfig != null) { - BootstrapConfiguration bootstrapObject = getBootstrapParametersFromThingsboard(store.getDeviceProfile()); + LwM2MBootstrapServersConfiguration bootstrapObject = getBootstrapParametersFromThingsboard(store.getDeviceProfile()); lwM2MBootstrapConfig.setServers(JacksonUtil.fromString(JacksonUtil.toString(bootstrapObject.getServers()), LwM2MBootstrapServers.class)); LwM2MServerBootstrap bootstrapServerProfile = JacksonUtil.fromString(JacksonUtil.toString(bootstrapObject.getBootstrapServer()), LwM2MServerBootstrap.class); if (SecurityMode.NO_SEC != bootstrapServerProfile.getSecurityMode() && bootstrapServerProfile != null) { diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LwM2mCredentialsSecurityInfoValidator.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LwM2mCredentialsSecurityInfoValidator.java index 6b7b3a9877..64498645c8 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LwM2mCredentialsSecurityInfoValidator.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LwM2mCredentialsSecurityInfoValidator.java @@ -23,10 +23,10 @@ import org.eclipse.leshan.server.security.SecurityInfo; import org.springframework.stereotype.Component; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.StringUtils; -import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MClientCredentials; +import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MClientCredential; import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MSecurityMode; -import org.thingsboard.server.common.data.device.credentials.lwm2m.PSKClientCredentials; -import org.thingsboard.server.common.data.device.credentials.lwm2m.RPKClientCredentials; +import org.thingsboard.server.common.data.device.credentials.lwm2m.PSKClientCredential; +import org.thingsboard.server.common.data.device.credentials.lwm2m.RPKClientCredential; import org.thingsboard.server.common.transport.TransportServiceCallback; import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse; import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceLwM2MCredentialsRequestMsg; @@ -110,7 +110,7 @@ public class LwM2mCredentialsSecurityInfoValidator { if (keyValue.equals(BOOTSTRAP)) { result.setBootstrapCredentialConfig(credentials.getBootstrap()); if (LwM2MSecurityMode.PSK.equals(credentials.getClient().getSecurityConfigClientMode())) { - PSKClientCredentials pskClientConfig = (PSKClientCredentials) credentials.getClient(); + PSKClientCredential pskClientConfig = (PSKClientCredential) credentials.getClient(); endpoint = StringUtils.isNotEmpty(pskClientConfig.getEndpoint()) ? pskClientConfig.getEndpoint() : endpoint; } result.setEndpoint(endpoint); @@ -143,8 +143,8 @@ public class LwM2mCredentialsSecurityInfoValidator { result.setSecurityMode(NO_SEC); } - private void createClientSecurityInfoPSK(TbLwM2MSecurityInfo result, String endpoint, LwM2MClientCredentials clientCredentialsConfig) { - PSKClientCredentials pskConfig = (PSKClientCredentials) clientCredentialsConfig; + private void createClientSecurityInfoPSK(TbLwM2MSecurityInfo result, String endpoint, LwM2MClientCredential clientCredentialsConfig) { + PSKClientCredential pskConfig = (PSKClientCredential) clientCredentialsConfig; if (StringUtils.isNotEmpty(pskConfig.getIdentity())) { try { if (pskConfig.getDecoded() != null && pskConfig.getDecoded().length > 0) { @@ -162,8 +162,8 @@ public class LwM2mCredentialsSecurityInfoValidator { } } - private void createClientSecurityInfoRPK(TbLwM2MSecurityInfo result, String endpoint, LwM2MClientCredentials clientCredentialsConfig) { - RPKClientCredentials rpkConfig = (RPKClientCredentials) clientCredentialsConfig; + private void createClientSecurityInfoRPK(TbLwM2MSecurityInfo result, String endpoint, LwM2MClientCredential clientCredentialsConfig) { + RPKClientCredential rpkConfig = (RPKClientCredential) clientCredentialsConfig; try { if (rpkConfig.getDecoded() != null) { PublicKey key = SecurityUtil.publicKey.decode(rpkConfig.getDecoded()); @@ -177,7 +177,7 @@ public class LwM2mCredentialsSecurityInfoValidator { } } - private void createClientSecurityInfoX509(TbLwM2MSecurityInfo result, String endpoint, LwM2MClientCredentials clientCredentialsConfig) { + private void createClientSecurityInfoX509(TbLwM2MSecurityInfo result, String endpoint, LwM2MClientCredential clientCredentialsConfig) { result.setSecurityInfo(SecurityInfo.newX509CertInfo(endpoint)); result.setSecurityMode(X509); } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MDtlsCertificateVerifier.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MDtlsCertificateVerifier.java index fe04410c17..e286bd0ae6 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MDtlsCertificateVerifier.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MDtlsCertificateVerifier.java @@ -35,7 +35,7 @@ import org.springframework.stereotype.Component; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MSecurityMode; -import org.thingsboard.server.common.data.device.credentials.lwm2m.X509ClientCredentials; +import org.thingsboard.server.common.data.device.credentials.lwm2m.X509ClientCredential; import org.thingsboard.server.common.msg.EncryptionUtil; import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse; import org.thingsboard.server.common.transport.util.SslUtil; @@ -132,7 +132,7 @@ public class TbLwM2MDtlsCertificateVerifier implements NewAdvancedCertificateVer if (!credentials.getClient().getSecurityConfigClientMode().equals(LwM2MSecurityMode.X509)) { continue; } - X509ClientCredentials config = (X509ClientCredentials) credentials.getClient(); + X509ClientCredential config = (X509ClientCredential) credentials.getClient(); String certBody = config.getCert(); String endpoint = config.getEndpoint(); if (strCert.equals(certBody)) { diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/credentials/LwM2MCredentials.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/credentials/LwM2MCredentials.java index bbc733b40b..878188bffc 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/credentials/LwM2MCredentials.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/credentials/LwM2MCredentials.java @@ -16,11 +16,11 @@ package org.thingsboard.server.transport.lwm2m.secure.credentials; import lombok.Data; -import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MClientCredentials; +import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MClientCredential; import org.thingsboard.server.transport.lwm2m.bootstrap.secure.LwM2MBootstrapConfig; @Data public class LwM2MCredentials { - private LwM2MClientCredentials client; + private LwM2MClientCredential client; private LwM2MBootstrapConfig bootstrap; } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java index b0fea97205..9c57a4b955 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java @@ -18,7 +18,6 @@ package org.thingsboard.server.transport.lwm2m.server.client; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.eclipse.leshan.core.SecurityMode; -import org.eclipse.leshan.core.model.ResourceModel; import org.eclipse.leshan.core.node.LwM2mPath; import org.eclipse.leshan.server.registration.Registration; import org.springframework.beans.factory.annotation.Autowired; @@ -26,7 +25,7 @@ import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.device.data.PowerMode; -import org.thingsboard.server.common.data.device.data.lwm2m.OtherConfiguration; +import org.thingsboard.server.common.data.device.profile.lwm2m.OtherConfiguration; import org.thingsboard.server.common.data.device.profile.Lwm2mDeviceProfileTransportConfiguration; import org.thingsboard.server.common.data.id.DeviceProfileId; import org.thingsboard.server.common.transport.TransportDeviceProfileCache; diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2mDownlinkMsgHandler.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2mDownlinkMsgHandler.java index 037474aa1c..354e7f8abd 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2mDownlinkMsgHandler.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2mDownlinkMsgHandler.java @@ -61,7 +61,7 @@ import org.eclipse.leshan.core.util.Hex; import org.eclipse.leshan.server.model.LwM2mModelProvider; import org.eclipse.leshan.server.registration.Registration; import org.springframework.stereotype.Service; -import org.thingsboard.server.common.data.device.data.lwm2m.ObjectAttributes; +import org.thingsboard.server.common.data.device.profile.lwm2m.ObjectAttributes; import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportContext; diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MWriteAttributesRequest.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MWriteAttributesRequest.java index 1c56574b0f..7d0436b1b8 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MWriteAttributesRequest.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MWriteAttributesRequest.java @@ -18,7 +18,7 @@ package org.thingsboard.server.transport.lwm2m.server.downlink; import lombok.Builder; import lombok.Getter; import org.eclipse.leshan.core.response.WriteAttributesResponse; -import org.thingsboard.server.common.data.device.data.lwm2m.ObjectAttributes; +import org.thingsboard.server.common.data.device.profile.lwm2m.ObjectAttributes; import org.thingsboard.server.transport.lwm2m.server.LwM2MOperationType; public class TbLwM2MWriteAttributesRequest extends AbstractTbLwM2MTargetedDownlinkRequest { diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/DefaultLwM2MOtaUpdateService.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/DefaultLwM2MOtaUpdateService.java index 0b253ecc20..a368d74ded 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/DefaultLwM2MOtaUpdateService.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/DefaultLwM2MOtaUpdateService.java @@ -25,7 +25,7 @@ import org.springframework.stereotype.Service; import org.thingsboard.common.util.DonAsynchron; import org.thingsboard.server.cache.ota.OtaPackageDataCache; import org.thingsboard.server.common.data.StringUtils; -import org.thingsboard.server.common.data.device.data.lwm2m.OtherConfiguration; +import org.thingsboard.server.common.data.device.profile.lwm2m.OtherConfiguration; import org.thingsboard.server.common.data.ota.OtaPackageKey; import org.thingsboard.server.common.data.ota.OtaPackageType; import org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus; diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/LwM2MOtaUpdateService.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/LwM2MOtaUpdateService.java index b03fe81d28..b23924b906 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/LwM2MOtaUpdateService.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/LwM2MOtaUpdateService.java @@ -15,7 +15,7 @@ */ package org.thingsboard.server.transport.lwm2m.server.ota; -import org.thingsboard.server.common.data.device.data.lwm2m.OtherConfiguration; +import org.thingsboard.server.common.data.device.profile.lwm2m.OtherConfiguration; import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; import java.util.Optional; diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcWriteAttributesRequest.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcWriteAttributesRequest.java index bfe3b3cb90..1dd3a4fd18 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcWriteAttributesRequest.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcWriteAttributesRequest.java @@ -17,7 +17,7 @@ package org.thingsboard.server.transport.lwm2m.server.rpc; import lombok.Data; import lombok.EqualsAndHashCode; -import org.thingsboard.server.common.data.device.data.lwm2m.ObjectAttributes; +import org.thingsboard.server.common.data.device.profile.lwm2m.ObjectAttributes; @Data @EqualsAndHashCode(callSuper = true) diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/DefaultLwM2mUplinkMsgHandler.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/DefaultLwM2mUplinkMsgHandler.java index 7732948c27..df50d20cdf 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/DefaultLwM2mUplinkMsgHandler.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/DefaultLwM2mUplinkMsgHandler.java @@ -49,9 +49,9 @@ import org.thingsboard.common.util.DonAsynchron; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.StringUtils; -import org.thingsboard.server.common.data.device.data.lwm2m.ObjectAttributes; -import org.thingsboard.server.common.data.device.data.lwm2m.OtherConfiguration; -import org.thingsboard.server.common.data.device.data.lwm2m.TelemetryMappingConfiguration; +import org.thingsboard.server.common.data.device.profile.lwm2m.ObjectAttributes; +import org.thingsboard.server.common.data.device.profile.lwm2m.OtherConfiguration; +import org.thingsboard.server.common.data.device.profile.lwm2m.TelemetryMappingConfiguration; import org.thingsboard.server.common.data.device.profile.Lwm2mDeviceProfileTransportConfiguration; import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.TenantId; diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2MTransportUtil.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2MTransportUtil.java index 1531f725c6..daa521abc3 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2MTransportUtil.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2MTransportUtil.java @@ -39,7 +39,7 @@ import org.eclipse.leshan.server.registration.Registration; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.DeviceTransportType; -import org.thingsboard.server.common.data.device.data.lwm2m.BootstrapConfiguration; +import org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap.LwM2MBootstrapServersConfiguration; import org.thingsboard.server.common.data.device.profile.DeviceProfileTransportConfiguration; import org.thingsboard.server.common.data.device.profile.Lwm2mDeviceProfileTransportConfiguration; import org.thingsboard.server.common.data.ota.OtaPackageKey; @@ -181,7 +181,7 @@ public class LwM2MTransportUtil { } } - public static BootstrapConfiguration getBootstrapParametersFromThingsboard(DeviceProfile deviceProfile) { + public static LwM2MBootstrapServersConfiguration getBootstrapParametersFromThingsboard(DeviceProfile deviceProfile) { return toLwM2MClientProfile(deviceProfile).getBootstrap(); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsServiceImpl.java index 3e4d49b21b..c8431da85c 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsServiceImpl.java @@ -28,16 +28,16 @@ import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.data.device.credentials.BasicMqttCredentials; -import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MBootstrapCredentials; -import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MClientCredentials; +import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MBootstrapClientCredentials; +import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MClientCredential; import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MDeviceCredentials; -import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MServerCredentials; -import org.thingsboard.server.common.data.device.credentials.lwm2m.PSKClientCredentials; -import org.thingsboard.server.common.data.device.credentials.lwm2m.PSKServerCredentials; -import org.thingsboard.server.common.data.device.credentials.lwm2m.RPKClientCredentials; -import org.thingsboard.server.common.data.device.credentials.lwm2m.RPKServerCredentials; -import org.thingsboard.server.common.data.device.credentials.lwm2m.X509ClientCredentials; -import org.thingsboard.server.common.data.device.credentials.lwm2m.X509ServerCredentials; +import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MBootstrapClientCredential; +import org.thingsboard.server.common.data.device.credentials.lwm2m.PSKClientCredential; +import org.thingsboard.server.common.data.device.credentials.lwm2m.PSKBootstrapClientCredential; +import org.thingsboard.server.common.data.device.credentials.lwm2m.RPKClientCredential; +import org.thingsboard.server.common.data.device.credentials.lwm2m.RPKBootstrapClientCredential; +import org.thingsboard.server.common.data.device.credentials.lwm2m.X509ClientCredential; +import org.thingsboard.server.common.data.device.credentials.lwm2m.X509BootstrapClientCredential; import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; @@ -171,7 +171,7 @@ public class DeviceCredentialsServiceImpl extends AbstractEntityService implemen } String credentialsId = null; - LwM2MClientCredentials clientCredentials = lwM2MCredentials.getClient(); + LwM2MClientCredential clientCredentials = lwM2MCredentials.getClient(); switch (clientCredentials.getSecurityConfigClientMode()) { case NO_SEC: case RPK: @@ -179,11 +179,11 @@ public class DeviceCredentialsServiceImpl extends AbstractEntityService implemen credentialsId = clientCredentials.getEndpoint(); break; case PSK: - credentialsId = ((PSKClientCredentials) clientCredentials).getIdentity(); + credentialsId = ((PSKClientCredential) clientCredentials).getIdentity(); break; case X509: deviceCredentials.setCredentialsValue(JacksonUtil.toString(lwM2MCredentials)); - X509ClientCredentials x509ClientConfig = (X509ClientCredentials) clientCredentials; + X509ClientCredential x509ClientConfig = (X509ClientCredential) clientCredentials; if ((StringUtils.isNotBlank(x509ClientConfig.getCert()))) { String sha3Hash = EncryptionUtil.getSha3Hash(x509ClientConfig.getCert()); credentialsId = sha3Hash; @@ -203,31 +203,31 @@ public class DeviceCredentialsServiceImpl extends AbstractEntityService implemen throw new DeviceCredentialsValidationException("LwM2M credentials must be specified!"); } - LwM2MClientCredentials clientCredentials = lwM2MCredentials.getClient(); + LwM2MClientCredential clientCredentials = lwM2MCredentials.getClient(); if (clientCredentials == null) { throw new DeviceCredentialsValidationException("LwM2M client credentials must be specified!"); } validateLwM2MClientCredentials(clientCredentials); - LwM2MBootstrapCredentials bootstrapCredentials = lwM2MCredentials.getBootstrap(); + LwM2MBootstrapClientCredentials bootstrapCredentials = lwM2MCredentials.getBootstrap(); if (bootstrapCredentials == null) { throw new DeviceCredentialsValidationException("LwM2M bootstrap credentials must be specified!"); } - LwM2MServerCredentials bootstrapServerCredentials = bootstrapCredentials.getBootstrapServer(); + LwM2MBootstrapClientCredential bootstrapServerCredentials = bootstrapCredentials.getBootstrapServer(); if (bootstrapServerCredentials == null) { throw new DeviceCredentialsValidationException("LwM2M bootstrap server credentials must be specified!"); } validateServerCredentials(bootstrapServerCredentials, "Bootstrap server"); - LwM2MServerCredentials lwm2mServerCredentials = bootstrapCredentials.getLwm2mServer(); - if (lwm2mServerCredentials == null) { + LwM2MBootstrapClientCredential lwm2MBootstrapClientCredential = bootstrapCredentials.getLwm2mServer(); + if (lwm2MBootstrapClientCredential == null) { throw new DeviceCredentialsValidationException("LwM2M lwm2m server credentials must be specified!"); } - validateServerCredentials(lwm2mServerCredentials, "LwM2M server"); + validateServerCredentials(lwm2MBootstrapClientCredential, "LwM2M server"); } - private void validateLwM2MClientCredentials(LwM2MClientCredentials clientCredentials) { + private void validateLwM2MClientCredentials(LwM2MClientCredential clientCredentials) { if (StringUtils.isBlank(clientCredentials.getEndpoint())) { throw new DeviceCredentialsValidationException("LwM2M client endpoint must be specified!"); } @@ -236,7 +236,7 @@ public class DeviceCredentialsServiceImpl extends AbstractEntityService implemen case NO_SEC: break; case PSK: - PSKClientCredentials pskCredentials = (PSKClientCredentials) clientCredentials; + PSKClientCredential pskCredentials = (PSKClientCredential) clientCredentials; if (StringUtils.isBlank(pskCredentials.getIdentity())) { throw new DeviceCredentialsValidationException("LwM2M client PSK identity must be specified!"); } @@ -260,7 +260,7 @@ public class DeviceCredentialsServiceImpl extends AbstractEntityService implemen break; case RPK: - RPKClientCredentials rpkCredentials = (RPKClientCredentials) clientCredentials; + RPKClientCredential rpkCredentials = (RPKClientCredential) clientCredentials; if (StringUtils.isBlank(rpkCredentials.getKey())) { throw new DeviceCredentialsValidationException("LwM2M client RPK key must be specified!"); } @@ -274,7 +274,7 @@ public class DeviceCredentialsServiceImpl extends AbstractEntityService implemen } break; case X509: - X509ClientCredentials x509CCredentials = (X509ClientCredentials) clientCredentials; + X509ClientCredential x509CCredentials = (X509ClientCredential) clientCredentials; if (StringUtils.isNotEmpty(x509CCredentials.getCert())) { try { String certClient = EncryptionUtil.certTrimNewLines(x509CCredentials.getCert()); @@ -288,12 +288,12 @@ public class DeviceCredentialsServiceImpl extends AbstractEntityService implemen } } - private void validateServerCredentials(LwM2MServerCredentials serverCredentials, String server) { + private void validateServerCredentials(LwM2MBootstrapClientCredential serverCredentials, String server) { switch (serverCredentials.getSecurityMode()) { case NO_SEC: break; case PSK: - PSKServerCredentials pskCredentials = (PSKServerCredentials) serverCredentials; + PSKBootstrapClientCredential pskCredentials = (PSKBootstrapClientCredential) serverCredentials; if (StringUtils.isBlank(pskCredentials.getClientPublicKeyOrId())) { throw new DeviceCredentialsValidationException(server + " client PSK public key or id must be specified!"); } @@ -317,7 +317,7 @@ public class DeviceCredentialsServiceImpl extends AbstractEntityService implemen } break; case RPK: - RPKServerCredentials rpkServerCredentials = (RPKServerCredentials) serverCredentials; + RPKBootstrapClientCredential rpkServerCredentials = (RPKBootstrapClientCredential) serverCredentials; if (StringUtils.isEmpty(rpkServerCredentials.getClientPublicKeyOrId())) { throw new DeviceCredentialsValidationException(server + " client RPK public key or id must be specified!"); } @@ -342,7 +342,7 @@ public class DeviceCredentialsServiceImpl extends AbstractEntityService implemen } break; case X509: - X509ServerCredentials x509ServerCredentials = (X509ServerCredentials) serverCredentials; + X509BootstrapClientCredential x509ServerCredentials = (X509BootstrapClientCredential) serverCredentials; if (StringUtils.isBlank(x509ServerCredentials.getClientPublicKeyOrId())) { throw new DeviceCredentialsValidationException(server + " client X509 public key or id must be specified!"); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java index e4e394d7e7..3430e5774e 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java @@ -46,7 +46,7 @@ import org.thingsboard.server.common.data.DeviceProfileType; import org.thingsboard.server.common.data.DeviceTransportType; import org.thingsboard.server.common.data.OtaPackage; import org.thingsboard.server.common.data.Tenant; -import org.thingsboard.server.common.data.device.data.lwm2m.BootstrapConfiguration; +import org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap.LwM2MBootstrapServersConfiguration; import org.thingsboard.server.common.data.device.profile.CoapDeviceProfileTransportConfiguration; import org.thingsboard.server.common.data.device.profile.CoapDeviceTypeConfiguration; import org.thingsboard.server.common.data.device.profile.DefaultCoapDeviceTypeConfiguration; @@ -60,9 +60,9 @@ import org.thingsboard.server.common.data.device.profile.Lwm2mDeviceProfileTrans import org.thingsboard.server.common.data.device.profile.MqttDeviceProfileTransportConfiguration; import org.thingsboard.server.common.data.device.profile.ProtoTransportPayloadConfiguration; import org.thingsboard.server.common.data.device.profile.TransportPayloadTypeConfiguration; -import org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap.RPKServerCredentials; -import org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap.ServerCredentials; -import org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap.X509ServerCredentials; +import org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap.RPKLwM2MBootstrapServerCredential; +import org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap.LwM2MBootstrapServerCredential; +import org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap.X509LwM2MBootstrapServerCredential; import org.thingsboard.server.common.data.ota.OtaPackageType; import org.thingsboard.server.common.data.id.DeviceProfileId; import org.thingsboard.server.common.data.id.TenantId; @@ -418,9 +418,9 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D } } } else if (transportConfiguration instanceof Lwm2mDeviceProfileTransportConfiguration) { - BootstrapConfiguration bootstrapConfiguration = ((Lwm2mDeviceProfileTransportConfiguration) transportConfiguration).getBootstrap(); - validateLwm2mServersCredentialOfBootstrapForClient(bootstrapConfiguration.getBootstrapServer(), "Bootstrap Server"); - validateLwm2mServersCredentialOfBootstrapForClient(bootstrapConfiguration.getLwm2mServer(), "LwM2M Server"); + LwM2MBootstrapServersConfiguration lwM2MBootstrapServersConfiguration = ((Lwm2mDeviceProfileTransportConfiguration) transportConfiguration).getBootstrap(); + validateLwm2mServersCredentialOfBootstrapForClient(lwM2MBootstrapServersConfiguration.getBootstrapServer(), "Bootstrap Server"); + validateLwm2mServersCredentialOfBootstrapForClient(lwM2MBootstrapServersConfiguration.getLwm2mServer(), "LwM2M Server"); } List profileAlarms = deviceProfile.getProfileData().getAlarms(); @@ -704,13 +704,13 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D } } - private void validateLwm2mServersCredentialOfBootstrapForClient(ServerCredentials bootstrapServerConfig, String server) { + private void validateLwm2mServersCredentialOfBootstrapForClient(LwM2MBootstrapServerCredential bootstrapServerConfig, String server) { switch (bootstrapServerConfig.getSecurityMode()) { case NO_SEC: case PSK: break; case RPK: - RPKServerCredentials rpkServerCredentials = (RPKServerCredentials) bootstrapServerConfig; + RPKLwM2MBootstrapServerCredential rpkServerCredentials = (RPKLwM2MBootstrapServerCredential) bootstrapServerConfig; if (StringUtils.isEmpty(rpkServerCredentials.getServerPublicKey())) { throw new DeviceCredentialsValidationException(server + " RPK public key must be specified!"); } @@ -723,8 +723,7 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D } break; case X509: - X509ServerCredentials x509ServerCredentials = (X509ServerCredentials) bootstrapServerConfig; -// X509BootstrapServerCredentials x509ServerCredentials = (X509BootstrapServerCredentials) bootstrapServerConfig; + X509LwM2MBootstrapServerCredential x509ServerCredentials = (X509LwM2MBootstrapServerCredential) bootstrapServerConfig; if (StringUtils.isEmpty(x509ServerCredentials.getServerPublicKey())) { throw new DeviceCredentialsValidationException(server + " X509 public key must be specified!"); } From c197f27d8e16b6b27009daa974f1b823ef3454b4 Mon Sep 17 00:00:00 2001 From: van-vanich Date: Fri, 5 Nov 2021 12:16:52 +0200 Subject: [PATCH 082/432] remove replace quote to method with a meaningful name. Also, remove split values to list to this method. --- .../server/dao/sql/query/EntityKeyMapping.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/query/EntityKeyMapping.java b/dao/src/main/java/org/thingsboard/server/dao/sql/query/EntityKeyMapping.java index 3328ceb4fa..7a86431da0 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/query/EntityKeyMapping.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/query/EntityKeyMapping.java @@ -561,18 +561,16 @@ public class EntityKeyMapping { stringOperationQuery = String.format("%s not like :%s or %s is null)", operationField, paramName, operationField); break; case IN: - value = value.replaceAll("'","").replaceAll("\"", ""); stringOperationQuery = String.format("%s in (:%s))", operationField, paramName); break; case NOT_IN: - value = value.replaceAll("'","").replaceAll("\"", ""); stringOperationQuery = String.format("%s not in (:%s))", operationField, paramName); break; } switch (stringFilterPredicate.getOperation()) { case IN: case NOT_IN: - ctx.addStringListParameter(paramName, List.of(value.trim().split("\\s*,\\s*"))); + ctx.addStringListParameter(paramName, getListValuesWithoutQuote(value)); break; default: ctx.addStringParameter(paramName, value); @@ -580,6 +578,10 @@ public class EntityKeyMapping { return String.format("((%s is not null and %s)", field, stringOperationQuery); } + private List getListValuesWithoutQuote(String value) { + return List.of(value.replaceAll("'", "").replaceAll("\"", "").trim().split("\\s*,\\s*")); + } + private String buildNumericPredicateQuery(QueryContext ctx, String field, NumericFilterPredicate numericFilterPredicate) { String paramName = getNextParameterName(field); ctx.addDoubleParameter(paramName, numericFilterPredicate.getValue().getValue()); From 4bdc93f33ecad95869970538d159834e13228a21 Mon Sep 17 00:00:00 2001 From: van-vanich Date: Fri, 5 Nov 2021 17:51:05 +0200 Subject: [PATCH 083/432] removed quote and double quote when all values have the same way. Also, fix the delete quote, when the value has a quote. Also, added a test to check this method. --- .../dao/sql/query/EntityKeyMapping.java | 23 ++++- .../dao/sql/query/EntityKeyMappingTest.java | 88 +++++++++++++++++++ 2 files changed, 109 insertions(+), 2 deletions(-) create mode 100644 dao/src/test/java/org/thingsboard/server/dao/sql/query/EntityKeyMappingTest.java diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/query/EntityKeyMapping.java b/dao/src/main/java/org/thingsboard/server/dao/sql/query/EntityKeyMapping.java index 7a86431da0..c653d77004 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/query/EntityKeyMapping.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/query/EntityKeyMapping.java @@ -578,8 +578,27 @@ public class EntityKeyMapping { return String.format("((%s is not null and %s)", field, stringOperationQuery); } - private List getListValuesWithoutQuote(String value) { - return List.of(value.replaceAll("'", "").replaceAll("\"", "").trim().split("\\s*,\\s*")); + protected List getListValuesWithoutQuote(String value) { + List splitValues = List.of(value.trim().split("\\s*,\\s*")); + List result = new ArrayList<>(); + char lastWayInputValue = '#'; + for (String str : splitValues) { + char startWith = str.charAt(0); + char endWith = str.charAt(str.length() - 1); + + // if first value is not quote, so we return values after split + if (startWith != '\'' && startWith != '"') return splitValues; + + // if value is not in quote, so we return values after split + if (startWith != endWith) return splitValues; + + // if different way values, so don't replace quote and return values after split + if (lastWayInputValue != '#' && startWith != lastWayInputValue) return splitValues; + + result.add(str.substring(1, str.length() - 1)); + lastWayInputValue = startWith; + } + return result; } private String buildNumericPredicateQuery(QueryContext ctx, String field, NumericFilterPredicate numericFilterPredicate) { diff --git a/dao/src/test/java/org/thingsboard/server/dao/sql/query/EntityKeyMappingTest.java b/dao/src/test/java/org/thingsboard/server/dao/sql/query/EntityKeyMappingTest.java new file mode 100644 index 0000000000..c914bce1c1 --- /dev/null +++ b/dao/src/test/java/org/thingsboard/server/dao/sql/query/EntityKeyMappingTest.java @@ -0,0 +1,88 @@ +package org.thingsboard.server.dao.sql.query; + +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +import java.util.List; + +@RunWith(SpringRunner.class ) +@SpringBootTest(classes = EntityKeyMapping.class) +public class EntityKeyMappingTest { + + @Autowired + private EntityKeyMapping entityKeyMapping; + + private static final List result = List.of("device1", "device2", "device3"); + + @Test + public void testSplitToList() { + String value = "device1, device2, device3"; + Assert.assertEquals(entityKeyMapping.getListValuesWithoutQuote(value), result); + } + + @Test + public void testReplaceSingleQuote() { + String value = "'device1', 'device2', 'device3'"; + Assert.assertEquals(entityKeyMapping.getListValuesWithoutQuote(value), result); + } + + @Test + public void testReplaceDoubleQuote() { + String value = "\"device1\", \"device2\", \"device3\""; + Assert.assertEquals(entityKeyMapping.getListValuesWithoutQuote(value), result); + } + + @Test + public void testSplitWithoutSpace() { + String value = "\"device1\" , \"device2\" , \"device3\""; + Assert.assertEquals(entityKeyMapping.getListValuesWithoutQuote(value), result); + } + + @Test + public void testSaveSpacesBetweenString() { + String value = "device 1 , device 2 , device 3"; + List result = List.of("device 1", "device 2", "device 3"); + Assert.assertEquals(entityKeyMapping.getListValuesWithoutQuote(value), result); + } + + @Test + public void testSaveQuoteInString() { + String value = "device ''1 , device \"\"2 , device \"'3"; + List result = List.of("device ''1", "device \"\"2", "device \"'3"); + Assert.assertEquals(entityKeyMapping.getListValuesWithoutQuote(value), result); + } + + @Test + public void testNotDeleteQuoteWhenDifferentStyle() { + + String value = "\"device1\", 'device2', \"device3\""; + List result = List.of("\"device1\"", "'device2'", "\"device3\""); + Assert.assertEquals(entityKeyMapping.getListValuesWithoutQuote(value), result); + + value = "'device1', \"device2\", \"device3\""; + result = List.of("'device1'", "\"device2\"", "\"device3\""); + Assert.assertEquals(entityKeyMapping.getListValuesWithoutQuote(value), result); + + value = "device1, 'device2', \"device3\""; + result = List.of("device1", "'device2'", "\"device3\""); + Assert.assertEquals(entityKeyMapping.getListValuesWithoutQuote(value), result); + + + value = "'device1', device2, \"device3\""; + result = List.of("'device1'", "device2", "\"device3\""); + Assert.assertEquals(entityKeyMapping.getListValuesWithoutQuote(value), result); + + value = "device1, \"device2\", \"device3\""; + result = List.of("device1", "\"device2\"", "\"device3\""); + Assert.assertEquals(entityKeyMapping.getListValuesWithoutQuote(value), result); + + + value = "\"device1\", device2, \"device3\""; + result = List.of("\"device1\"", "device2", "\"device3\""); + Assert.assertEquals(entityKeyMapping.getListValuesWithoutQuote(value), result); + } +} \ No newline at end of file From 4ad4b904847e3106e19e0acc23914deed899ce0d Mon Sep 17 00:00:00 2001 From: Sergey Tarnavskiy Date: Mon, 8 Nov 2021 11:31:50 +0200 Subject: [PATCH 084/432] Reafctoring of helping-tooltips for Lwm2m form-configs --- .../app/core/http/device-profile.service.ts | 12 +- ...ce-credentials-lwm2m-server.component.html | 11 +- ...vice-credentials-lwm2m-server.component.ts | 4 + .../device-credentials-lwm2m.component.html | 17 +- .../device-credentials-lwm2m.component.ts | 3 +- .../lwm2m-device-config-server.component.html | 23 +- .../lwm2m-device-config-server.component.ts | 30 ++- ...ile-transport-configuration.component.html | 225 +++++++----------- ...ofile-transport-configuration.component.ts | 2 +- .../lwm2m/lwm2m-profile-config.models.ts | 21 +- .../models/lwm2m-security-config.models.ts | 23 ++ .../assets/locale/locale.constant-en_US.json | 20 +- 12 files changed, 175 insertions(+), 216 deletions(-) diff --git a/ui-ngx/src/app/core/http/device-profile.service.ts b/ui-ngx/src/app/core/http/device-profile.service.ts index 26e68a2e88..1514b262aa 100644 --- a/ui-ngx/src/app/core/http/device-profile.service.ts +++ b/ui-ngx/src/app/core/http/device-profile.service.ts @@ -24,13 +24,13 @@ import { DeviceProfile, DeviceProfileInfo, DeviceTransportType } from '@shared/m import { deepClone, isDefinedAndNotNull, isEmptyStr } from '@core/utils'; import { ObjectLwM2M, - securityConfigMode, ServerSecurityConfig, ServerSecurityConfigInfo } from '@home/components/profile/device/lwm2m/lwm2m-profile-config.models'; import { SortOrder } from '@shared/models/page/sort-order'; import { OtaPackageService } from '@core/http/ota-package.service'; import { map, mergeMap, tap } from 'rxjs/operators'; +import { Lwm2mSecurityType } from '@shared/models/lwm2m-security-config.models'; @Injectable({ providedIn: 'root' @@ -79,23 +79,23 @@ export class DeviceProfileService { } } - public getLwm2mBootstrapSecurityInfoBySecurityType(isBootstrapServer: boolean, securityMode = securityConfigMode.NO_SEC, + public getLwm2mBootstrapSecurityInfoBySecurityType(isBootstrapServer: boolean, securityMode = Lwm2mSecurityType.NO_SEC, config?: RequestConfig): Observable { return this.getLwm2mBootstrapSecurityInfo(isBootstrapServer, config).pipe( map(securityConfig => { const serverSecurityConfigInfo = deepClone(securityConfig); switch (securityMode) { - case securityConfigMode.PSK: + case Lwm2mSecurityType.PSK: serverSecurityConfigInfo.port = serverSecurityConfigInfo.securityPort; serverSecurityConfigInfo.host = serverSecurityConfigInfo.securityHost; serverSecurityConfigInfo.serverPublicKey = ''; break; - case securityConfigMode.RPK: - case securityConfigMode.X509: + case Lwm2mSecurityType.RPK: + case Lwm2mSecurityType.X509: serverSecurityConfigInfo.port = serverSecurityConfigInfo.securityPort; serverSecurityConfigInfo.host = serverSecurityConfigInfo.securityHost; break; - case securityConfigMode.NO_SEC: + case Lwm2mSecurityType.NO_SEC: serverSecurityConfigInfo.serverPublicKey = ''; break; } diff --git a/ui-ngx/src/app/modules/home/components/device/device-credentials-lwm2m-server.component.html b/ui-ngx/src/app/modules/home/components/device/device-credentials-lwm2m-server.component.html index d9f08787b6..9694faa9ca 100644 --- a/ui-ngx/src/app/modules/home/components/device/device-credentials-lwm2m-server.component.html +++ b/ui-ngx/src/app/modules/home/components/device/device-credentials-lwm2m-server.component.html @@ -27,14 +27,13 @@
{{ 'device.lwm2m-security-config.client-publicKey-or-id' | translate }} + help @@ -43,15 +42,13 @@ {{ 'device.lwm2m-security-config.client-secret-key' | translate }} + help diff --git a/ui-ngx/src/app/modules/home/components/device/device-credentials-lwm2m-server.component.ts b/ui-ngx/src/app/modules/home/components/device/device-credentials-lwm2m-server.component.ts index 96b1e74fb9..9967280a60 100644 --- a/ui-ngx/src/app/modules/home/components/device/device-credentials-lwm2m-server.component.ts +++ b/ui-ngx/src/app/modules/home/components/device/device-credentials-lwm2m-server.component.ts @@ -26,6 +26,8 @@ import { Validators } from '@angular/forms'; import { + Lwm2mClientSecretKeyTooltipTranslationsMap, + Lwm2mPublicKeyOrIdTooltipTranslationsMap, Lwm2mSecurityType, Lwm2mSecurityTypeTranslationMap, ServerSecurityConfig @@ -57,6 +59,8 @@ export class DeviceCredentialsLwm2mServerComponent implements OnDestroy, Control securityConfigLwM2MType = Lwm2mSecurityType; securityConfigLwM2MTypes = Object.values(Lwm2mSecurityType); lwm2mSecurityTypeTranslationMap = Lwm2mSecurityTypeTranslationMap; + publicKeyOrIdTooltipNamesMap = Lwm2mPublicKeyOrIdTooltipTranslationsMap; + clientSecretKeyTooltipNamesMap = Lwm2mClientSecretKeyTooltipTranslationsMap; private destroy$ = new Subject(); private propagateChange = (v: any) => {}; diff --git a/ui-ngx/src/app/modules/home/components/device/device-credentials-lwm2m.component.html b/ui-ngx/src/app/modules/home/components/device/device-credentials-lwm2m.component.html index 5833e33934..8ffa4ab1e6 100644 --- a/ui-ngx/src/app/modules/home/components/device/device-credentials-lwm2m.component.html +++ b/ui-ngx/src/app/modules/home/components/device/device-credentials-lwm2m.component.html @@ -37,9 +37,9 @@ {{ 'device.lwm2m-security-config.identity' | translate }} - + help + {{ 'device.lwm2m-security-config.identity-required' | translate }} @@ -47,15 +47,14 @@ {{ 'device.lwm2m-security-config.client-key' | translate }} + help {{ 'device.lwm2m-security-config.client-key-required' | translate }} @@ -63,12 +62,12 @@ device.lwm2m-security-config.client-public-key + help device.lwm2m-security-config.client-public-key-hint diff --git a/ui-ngx/src/app/modules/home/components/device/device-credentials-lwm2m.component.ts b/ui-ngx/src/app/modules/home/components/device/device-credentials-lwm2m.component.ts index 1645d3317d..10f5124352 100644 --- a/ui-ngx/src/app/modules/home/components/device/device-credentials-lwm2m.component.ts +++ b/ui-ngx/src/app/modules/home/components/device/device-credentials-lwm2m.component.ts @@ -27,7 +27,7 @@ import { } from '@angular/forms'; import { getDefaultClientSecurityConfig, - getDefaultServerSecurityConfig, + getDefaultServerSecurityConfig, Lwm2mClientKeyTooltipTranslationsMap, Lwm2mSecurityConfigModels, Lwm2mSecurityType, Lwm2mSecurityTypeTranslationMap @@ -60,6 +60,7 @@ export class DeviceCredentialsLwm2mComponent implements ControlValueAccessor, Va securityConfigLwM2MType = Lwm2mSecurityType; securityConfigLwM2MTypes = Object.keys(Lwm2mSecurityType); credentialTypeLwM2MNamesMap = Lwm2mSecurityTypeTranslationMap; + clientKeyTooltipNamesMap = Lwm2mClientKeyTooltipTranslationsMap; private destroy$ = new Subject(); private propagateChange = (v: any) => {}; diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-config-server.component.html b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-config-server.component.html index b481c9a24a..3fe4e7cda8 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-config-server.component.html +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-config-server.component.html @@ -51,8 +51,9 @@
{{ 'device-profile.lwm2m.short-id' | translate }} - + help + {{ 'device-profile.lwm2m.short-id-required' | translate }} @@ -66,9 +67,9 @@ {{ 'device-profile.lwm2m.client-hold-off-time' | translate }} - + help + {{ 'device-profile.lwm2m.client-hold-off-time-required' | translate }} @@ -79,9 +80,9 @@ {{ 'device-profile.lwm2m.account-after-timeout' | translate }} - + help + {{ 'device-profile.lwm2m.account-after-timeout-required' | translate }} @@ -95,16 +96,14 @@ serverFormGroup.get('securityMode').value === securityConfigLwM2MType.X509"> {{ 'device-profile.lwm2m.server-public-key' | translate }} + help {{ 'device-profile.lwm2m.server-public-key-required' | translate }} diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-config-server.component.ts b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-config-server.component.ts index 93c22d44b1..9492b18114 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-config-server.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-config-server.component.ts @@ -28,14 +28,17 @@ import { import { DEFAULT_PORT_BOOTSTRAP_NO_SEC, DEFAULT_PORT_SERVER_NO_SEC, - securityConfigMode, - securityConfigModeNames, ServerSecurityConfig } from './lwm2m-profile-config.models'; import { DeviceProfileService } from '@core/http/device-profile.service'; import { Subject } from 'rxjs'; import { mergeMap, takeUntil, tap } from 'rxjs/operators'; import { Observable } from 'rxjs/internal/Observable'; +import { + Lwm2mPublicKeyOrIdTooltipTranslationsMap, + Lwm2mSecurityType, + Lwm2mSecurityTypeTranslationMap +} from '@shared/models/lwm2m-security-config.models'; @Component({ selector: 'tb-profile-lwm2m-device-config-server', @@ -56,15 +59,16 @@ import { Observable } from 'rxjs/internal/Observable'; export class Lwm2mDeviceConfigServerComponent implements OnInit, ControlValueAccessor, Validator, OnDestroy { - private disabled = false; + public disabled = false; private destroy$ = new Subject(); private isDataLoadedIntoCache = false; serverFormGroup: FormGroup; - securityConfigLwM2MType = securityConfigMode; - securityConfigLwM2MTypes = Object.keys(securityConfigMode); - credentialTypeLwM2MNamesMap = securityConfigModeNames; + securityConfigLwM2MType = Lwm2mSecurityType; + securityConfigLwM2MTypes = Object.keys(Lwm2mSecurityType); + credentialTypeLwM2MNamesMap = Lwm2mSecurityTypeTranslationMap; + publicKeyOrIdTooltipNamesMap = Lwm2mPublicKeyOrIdTooltipTranslationsMap; currentSecurityMode = null; @Input() @@ -81,7 +85,7 @@ export class Lwm2mDeviceConfigServerComponent implements OnInit, ControlValueAcc host: ['', Validators.required], port: [this.isBootstrapServer ? DEFAULT_PORT_BOOTSTRAP_NO_SEC : DEFAULT_PORT_SERVER_NO_SEC, [Validators.required, Validators.min(1), Validators.max(65535), Validators.pattern('[0-9]*')]], - securityMode: [securityConfigMode.NO_SEC], + securityMode: [Lwm2mSecurityType.NO_SEC], serverPublicKey: [''], clientHoldOffTime: ['', [Validators.required, Validators.min(0), Validators.pattern('[0-9]*')]], serverId: ['', [Validators.required, Validators.min(1), Validators.max(65534), Validators.pattern('[0-9]*')]], @@ -136,16 +140,16 @@ export class Lwm2mDeviceConfigServerComponent implements OnInit, ControlValueAcc registerOnTouched(fn: any): void { } - private updateValidate(securityMode: securityConfigMode): void { + private updateValidate(securityMode: Lwm2mSecurityType): void { switch (securityMode) { - case securityConfigMode.NO_SEC: - case securityConfigMode.PSK: + case Lwm2mSecurityType.NO_SEC: + case Lwm2mSecurityType.PSK: this.clearValidators(); break; - case securityConfigMode.RPK: + case Lwm2mSecurityType.RPK: this.setValidators(); break; - case securityConfigMode.X509: + case Lwm2mSecurityType.X509: this.setValidators(); break; } @@ -166,7 +170,7 @@ export class Lwm2mDeviceConfigServerComponent implements OnInit, ControlValueAcc } } - private getLwm2mBootstrapSecurityInfo(securityMode = securityConfigMode.NO_SEC): Observable { + private getLwm2mBootstrapSecurityInfo(securityMode = Lwm2mSecurityType.NO_SEC): Observable { return this.deviceProfileService.getLwm2mBootstrapSecurityInfoBySecurityType(this.isBootstrapServer, securityMode).pipe( tap(() => this.isDataLoadedIntoCache = true) ); diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.html b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.html index b58546cf70..a042ba5ea3 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.html +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.html @@ -33,151 +33,92 @@
-
+
-
- device-profile.lwm2m.bootstrap-server-legend - - - {{ 'device-profile.lwm2m.server' | translate }} - - -
- - {{ 'device-profile.lwm2m.short-id' | translate }} - - - {{ 'device-profile.lwm2m.short-id-required' | translate }} - - - {{ 'device-profile.lwm2m.short-id-range' | translate }} - - - {{ 'device-profile.lwm2m.short-id-pattern' | translate }} - - - - {{ 'device-profile.lwm2m.lifetime' | translate }} - - - {{ 'device-profile.lwm2m.lifetime-required' | translate }} - - - {{ 'device-profile.lwm2m.lifetime-pattern' | translate }} - - - - {{ 'device-profile.lwm2m.default-min-period' | translate }} - - - {{ 'device-profile.lwm2m.default-min-period-required' | translate }} - - - {{ 'device-profile.lwm2m.default-min-period-pattern' | translate }} - - -
- - {{ 'device-profile.lwm2m.binding' | translate }} - - - {{ bindingModeTypeNamesMap.get(bindingMode) | translate }} - - + + + {{ 'device-profile.lwm2m.server' | translate }} + + +
+ + {{ 'device-profile.lwm2m.short-id' | translate }} + help + + + {{ 'device-profile.lwm2m.short-id-required' | translate }} + + + {{ 'device-profile.lwm2m.short-id-range' | translate }} + + + {{ 'device-profile.lwm2m.short-id-pattern' | translate }} + - - {{ 'device-profile.lwm2m.notification-storing' | translate }} - - - - - - {{ 'device-profile.lwm2m.security' | translate }} - - - - - - -
-
- device-profile.lwm2m.lwm2m-server-legend - - - {{ 'device-profile.lwm2m.server' | translate }} - - -
- - {{ 'device-profile.lwm2m.short-id' | translate }} - - - {{ 'device-profile.lwm2m.short-id-required' | translate }} - - - {{ 'device-profile.lwm2m.short-id-range' | translate }} - - - {{ 'device-profile.lwm2m.short-id-pattern' | translate }} - - - - {{ 'device-profile.lwm2m.lifetime' | translate }} - - - {{ 'device-profile.lwm2m.lifetime-required' | translate }} - - - {{ 'device-profile.lwm2m.lifetime-pattern' | translate }} - - - - {{ 'device-profile.lwm2m.default-min-period' | translate }} - - - {{ 'device-profile.lwm2m.default-min-period-required' | translate }} - - - {{ 'device-profile.lwm2m.default-min-period-pattern' | translate }} - - -
- - {{ 'device-profile.lwm2m.binding' | translate }} - - - {{ bindingModeTypeNamesMap.get(bindingMode) | translate }} - - + + {{ 'device-profile.lwm2m.lifetime' | translate }} + + + {{ 'device-profile.lwm2m.lifetime-required' | translate }} + + + {{ 'device-profile.lwm2m.lifetime-pattern' | translate }} + - - {{ 'device-profile.lwm2m.notification-storing' | translate }} - -
-
- - - {{ 'device-profile.lwm2m.security' | translate }} - - - - - - -
+ + {{ 'device-profile.lwm2m.default-min-period' | translate }} + help + + + {{ 'device-profile.lwm2m.default-min-period-required' | translate }} + + + {{ 'device-profile.lwm2m.default-min-period-pattern' | translate }} + + +
+ + {{ 'device-profile.lwm2m.binding' | translate }} + help + + + {{ bindingModeTypeNamesMap.get(bindingMode) | translate }} + + + + + {{ 'device-profile.lwm2m.notification-storing' | translate }} + + + + + + {{ 'device-profile.lwm2m.bootstrap-server' | translate }} + + + + + + + + + {{ 'device-profile.lwm2m.lwm2m-server' | translate }} + + + + + +
diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts index 2495a16eff..792aa3c315 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts @@ -79,8 +79,8 @@ import { takeUntil } from 'rxjs/operators'; }) export class Lwm2mDeviceProfileTransportConfigurationComponent implements ControlValueAccessor, Validator, OnDestroy { + public disabled = false; private requiredValue: boolean; - private disabled = false; private destroy$ = new Subject(); bindingModeTypes = Object.values(BingingMode); diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-profile-config.models.ts b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-profile-config.models.ts index 070d0b703d..e95d1d22d2 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-profile-config.models.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-profile-config.models.ts @@ -15,6 +15,7 @@ /// import { ValidatorFn, Validators } from '@angular/forms'; +import { Lwm2mSecurityType } from '@shared/models/lwm2m-security-config.models'; export const PAGE_SIZE_LIMIT = 50; export const INSTANCES = 'instances'; @@ -95,22 +96,6 @@ export const AttributeNameTranslationMap = new Map( ] ); -export enum securityConfigMode { - PSK = 'PSK', - RPK = 'RPK', - X509 = 'X509', - NO_SEC = 'NO_SEC' -} - -export const securityConfigModeNames = new Map( - [ - [securityConfigMode.PSK, 'Pre-Shared Key'], - [securityConfigMode.RPK, 'Raw Public Key'], - [securityConfigMode.X509, 'X.509 Certificate'], - [securityConfigMode.NO_SEC, 'No Security'] - ] -); - export enum PowerMode { PSM = 'PSM', DRX = 'DRX', @@ -136,7 +121,7 @@ export interface BootstrapServersSecurityConfig { export interface ServerSecurityConfig { host?: string; port?: number; - securityMode: securityConfigMode; + securityMode: Lwm2mSecurityType; serverPublicKey?: string; clientHoldOffTime?: number; serverId?: number; @@ -198,7 +183,7 @@ export function getDefaultBootstrapServerSecurityConfig(): ServerSecurityConfig clientHoldOffTime: DEFAULT_CLIENT_HOLD_OFF_TIME, host: DEFAULT_LOCAL_HOST_NAME, port: DEFAULT_PORT_BOOTSTRAP_NO_SEC, - securityMode: securityConfigMode.NO_SEC, + securityMode: Lwm2mSecurityType.NO_SEC, serverId: DEFAULT_ID_BOOTSTRAP, serverPublicKey: '' }; diff --git a/ui-ngx/src/app/shared/models/lwm2m-security-config.models.ts b/ui-ngx/src/app/shared/models/lwm2m-security-config.models.ts index d3b4171b80..024433b0c7 100644 --- a/ui-ngx/src/app/shared/models/lwm2m-security-config.models.ts +++ b/ui-ngx/src/app/shared/models/lwm2m-security-config.models.ts @@ -30,6 +30,29 @@ export const Lwm2mSecurityTypeTranslationMap = new Map( + [ + [Lwm2mSecurityType.PSK, 'device.lwm2m-security-config.client-publicKey-or-id-tooltip-psk'], + [Lwm2mSecurityType.RPK, 'device.lwm2m-security-config.client-publicKey-or-id-tooltip-rpk'], + [Lwm2mSecurityType.X509, 'device.lwm2m-security-config.client-publicKey-or-id-tooltip-x509'] + ] +); + +export const Lwm2mClientSecretKeyTooltipTranslationsMap = new Map( + [ + [Lwm2mSecurityType.PSK, 'device.lwm2m-security-config.client-secret-key-tooltip-psk'], + [Lwm2mSecurityType.RPK, 'device.lwm2m-security-config.client-secret-key-tooltip-prk'], + [Lwm2mSecurityType.X509, 'device.lwm2m-security-config.client-secret-key-tooltip-x509'] + ] +); + +export const Lwm2mClientKeyTooltipTranslationsMap = new Map( + [ + [Lwm2mSecurityType.PSK, 'device.lwm2m-security-config.client-secret-key-tooltip-psk'], + [Lwm2mSecurityType.RPK, 'device.lwm2m-security-config.client-secret-key-tooltip-prk'] + ] +); + export interface ClientSecurityConfig { securityConfigClientMode: Lwm2mSecurityType; endpoint: string; diff --git a/ui-ngx/src/assets/locale/locale.constant-en_US.json b/ui-ngx/src/assets/locale/locale.constant-en_US.json index a46b64384a..2080a44d45 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -966,12 +966,13 @@ "identity-tooltip": "The PSK identifier is an arbitrary PSK identifier up to 128 bytes, as described in the standard [RFC7925].\nThe PSK identifier MUST first be converted to a character string and then encoded into octets using UTF-8.", "client-key": "Client Key", "client-key-required": "Client Key is required.", - "client-key-tooltip": "{ count, plural, 1 {RPK public key or id must be in the standard [RFC7250] and encoded to Base64 format!} other {PSK key must be in the standard [RFC4279] and HexDec format: 32, 64, 128 characters!} }", + "client-key-tooltip-prk": "RPK public key or id must be in the standard [RFC7250] and encoded to Base64 format!", + "client-key-tooltip-psk": "PSK key must be in the standard [RFC4279] and HexDec format: 32, 64, 128 characters!", "endpoint": "Endpoint Client Name", "endpoint-required": "Endpoint Client Name is required.", "client-public-key": "Client public key", "client-public-key-hint": "If client public key is empty, the trusted certificate will be used", - "client-public-key-tooltip": "{ count, plural, 1 {X509 public key must be in DER-encoded X509v3 format and support exclusively EC algorithm and then encoded to Base64 format!} other {} }", + "client-public-key-tooltip": "X509 public key must be in DER-encoded X509v3 format and support exclusively EC algorithm and then encoded to Base64 format!", "mode": "Security config mode", "client-tab": "Client Security Config", "client-certificate": "Client certificate", @@ -980,10 +981,14 @@ "lwm2m-server": "LwM2M Server", "client-publicKey-or-id": "Client Public Key or Id", "client-publicKey-or-id-required": "Client Public Key or Id is required.", - "client-publicKey-or-id-tooltip": "{ count, plural, 0 {The PSK identifier is an arbitrary PSK identifier up to 128 bytes, as described in the standard [RFC7925].\nThe PSK identifier MUST first be converted to a character string and then encoded into octets using UTF-8.} 1 {RPK public key or id must be in the standard [RFC7250] and encoded to Base64 format!} other {X509 public key must be in DER-encoded X509v3 format and support exclusively EC algorithm and then encoded to Base64 format!} }", + "client-publicKey-or-id-tooltip-psk": "The PSK identifier is an arbitrary PSK identifier up to 128 bytes, as described in the standard [RFC7925].\nThe PSK identifier MUST first be converted to a character string and then encoded into octets using UTF-8.", + "client-publicKey-or-id-tooltip-rpk": "RPK public key or id must be in the standard [RFC7250] and encoded to Base64 format!", + "client-publicKey-or-id-tooltip-x509": "X509 public key must be in DER-encoded X509v3 format and support exclusively EC algorithm and then encoded to Base64 format", "client-secret-key": "Client Secret Key", "client-secret-key-required": "Client Secret Key is required.", - "client-secret-key-tooltip": "{ count, plural, 0 {PSK key must be in the standard [RFC4279] and HexDec format: 32, 64, 128 characters!} 1 {RPK secret key must be in PKCS_8 format (DER encoding, standard [RFC5958]) and then encoded to Base64 format!} other {X509 secret key must be in PKCS_8 format (DER encoding, standard [RFC5958]) and then encoded to Base64 format!} }" + "client-secret-key-tooltip-psk": "PSK key must be in the standard [RFC4279] and HexDec format: 32, 64, 128 characters!", + "client-secret-key-tooltip-prk": "RPK secret key must be in PKCS_8 format (DER encoding, standard [RFC5958]) and then encoded to Base64 format!", + "client-secret-key-tooltip-x509": "X509 secret key must be in PKCS_8 format (DER encoding, standard [RFC5958]) and then encoded to Base64 format!" }, "client-id": "Client ID", "client-id-pattern": "Contains invalid character.", @@ -1289,7 +1294,7 @@ "lifetime": "Client registration lifetime", "lifetime-required": "Client registration lifetime is required.", "lifetime-pattern": "Client registration lifetime must be a positive integer.", - "default-min-period": "Minimum period between two notifications (s)", + "default-min-period": "Min period between two notifications (s)", "default-min-period-tooltip": "The default value the LwM2M Client should use for the Minimum Period of an Observation in the absence of this parameter being included in an Observation.", "default-min-period-required": "Minimum period is required.", "default-min-period-pattern": "Minimum period must be a positive integer.", @@ -1308,8 +1313,9 @@ "tqs": "TQS: both TCP and SMS connections active; TCP in queue mode, SMS in standard mode (is not supported since LWM2M 1.1)", "sq": "SQ: SMS connection in queue mode (is not supported since LWM2M 1.1)" }, - "binding-tooltip": "Tis is the list in the\"binding\" resource of the LwM2M server object - /1/x/7.\nIndicates the supported binding modes in the LwM2M Client.\nThis value SHOULD be the same as the value in the “Supported Binding and Modes” resource in the Device Object (/3/0/16).\nWhile multiple transports are supported, only one transport binding can be used during the entire Transport\nSession. As an example, when UDP and SMS are both supported, the LwM2M Client and the LwM2M Server can\nchoose to communicate either over UDP or SMS during the entire Transport Session.", - "security": "Security", + "binding-tooltip": "Tis is the list in the\"binding\" resource of the LwM2M server object - /1/x/7.\nIndicates the supported binding modes in the LwM2M Client.\nThis value SHOULD be the same as the value in the “Supported Binding and Modes” resource in the Device Object (/3/0/16).\nWhile multiple transports are supported, only one transport binding can be used during the entire Transport Session.\nAs an example, when UDP and SMS are both supported, the LwM2M Client and the LwM2M Server can choose to communicate either over UDP or SMS during the entire Transport Session.", + "bootstrap-server": "Bootstrap Server", + "lwm2m-server": "LwM2M Server", "server-host": "Host", "server-host-required": "Host is required.", "server-port": "Port", From 3c340dc7d2a3c9cf1ecc73cd643c0de833a6a863 Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Mon, 8 Nov 2021 13:51:37 +0200 Subject: [PATCH 085/432] tests added for update service for convertDeviceProfileAlarmRulesForVersion330 --- dao/pom.xml | 2 +- .../server/dao/sql/query/EntityDataAdapterTest.java | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/dao/pom.xml b/dao/pom.xml index f490a0e8e5..b8be6e3439 100644 --- a/dao/pom.xml +++ b/dao/pom.xml @@ -256,7 +256,7 @@ **/sql/*Test.java - **/sql/*/*Test.java + **/sql/*/*DaoTest.java **/psql/*Test.java **/nosql/*Test.java diff --git a/dao/src/test/java/org/thingsboard/server/dao/sql/query/EntityDataAdapterTest.java b/dao/src/test/java/org/thingsboard/server/dao/sql/query/EntityDataAdapterTest.java index abbcb61d3b..ede58da57d 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/sql/query/EntityDataAdapterTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/sql/query/EntityDataAdapterTest.java @@ -15,14 +15,14 @@ */ package org.thingsboard.server.dao.sql.query; -import org.junit.jupiter.api.Test; +import org.junit.Test; import static org.assertj.core.api.Assertions.assertThat; -class EntityDataAdapterTest { +public class EntityDataAdapterTest { @Test - void testConvertValue() { + public void testConvertValue() { assertThat(EntityDataAdapter.convertValue("500")).isEqualTo("500"); assertThat(EntityDataAdapter.convertValue("500D")).isEqualTo("500D"); //do not convert to Double !!! } From 23c6144c20a4c451568dec65ca526a6476af9090 Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Mon, 8 Nov 2021 17:41:03 +0200 Subject: [PATCH 086/432] Develop 3.3.3 --- application/pom.xml | 2 +- application/src/main/resources/thingsboard.yml | 2 +- common/actor/pom.xml | 2 +- common/cache/pom.xml | 2 +- common/cluster-api/pom.xml | 2 +- common/coap-server/pom.xml | 2 +- common/dao-api/pom.xml | 2 +- common/data/pom.xml | 2 +- common/edge-api/pom.xml | 2 +- common/message/pom.xml | 2 +- common/pom.xml | 2 +- common/queue/pom.xml | 2 +- common/stats/pom.xml | 2 +- common/transport/coap/pom.xml | 2 +- common/transport/http/pom.xml | 2 +- common/transport/lwm2m/pom.xml | 2 +- common/transport/mqtt/pom.xml | 2 +- common/transport/pom.xml | 2 +- common/transport/snmp/pom.xml | 2 +- common/transport/transport-api/pom.xml | 2 +- common/util/pom.xml | 2 +- dao/pom.xml | 2 +- msa/black-box-tests/pom.xml | 2 +- msa/js-executor/pom.xml | 2 +- msa/pom.xml | 2 +- msa/tb-node/pom.xml | 2 +- msa/tb/pom.xml | 2 +- msa/transport/coap/pom.xml | 2 +- msa/transport/http/pom.xml | 2 +- msa/transport/lwm2m/pom.xml | 2 +- msa/transport/mqtt/pom.xml | 2 +- msa/transport/pom.xml | 2 +- msa/transport/snmp/pom.xml | 2 +- msa/web-ui/package.json | 2 +- msa/web-ui/pom.xml | 2 +- netty-mqtt/pom.xml | 4 ++-- pom.xml | 2 +- rest-client/pom.xml | 2 +- rule-engine/pom.xml | 2 +- rule-engine/rule-engine-api/pom.xml | 2 +- rule-engine/rule-engine-components/pom.xml | 2 +- tools/pom.xml | 2 +- transport/coap/pom.xml | 2 +- transport/http/pom.xml | 2 +- transport/lwm2m/pom.xml | 2 +- transport/mqtt/pom.xml | 2 +- transport/pom.xml | 2 +- transport/snmp/pom.xml | 2 +- ui-ngx/package.json | 2 +- ui-ngx/pom.xml | 2 +- 50 files changed, 51 insertions(+), 51 deletions(-) diff --git a/application/pom.xml b/application/pom.xml index cc3bcef183..beb931d9b0 100644 --- a/application/pom.xml +++ b/application/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT thingsboard application diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index 3cf5230e7c..34348a1152 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -163,7 +163,7 @@ ui: # Help parameters help: # Base url for UI help assets - base-url: "${UI_HELP_BASE_URL:https://raw.githubusercontent.com/thingsboard/thingsboard-ui-help/release-3.3.2}" + base-url: "${UI_HELP_BASE_URL:https://raw.githubusercontent.com/thingsboard/thingsboard-ui-help/release-3.3.3}" database: ts_max_intervals: "${DATABASE_TS_MAX_INTERVALS:700}" # Max number of DB queries generated by single API call to fetch telemetry records diff --git a/common/actor/pom.xml b/common/actor/pom.xml index 90e7bf22d0..16bd96eedb 100644 --- a/common/actor/pom.xml +++ b/common/actor/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT common org.thingsboard.common diff --git a/common/cache/pom.xml b/common/cache/pom.xml index 1637621273..f5bf91c9f0 100644 --- a/common/cache/pom.xml +++ b/common/cache/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT common org.thingsboard.common diff --git a/common/cluster-api/pom.xml b/common/cluster-api/pom.xml index 4c59e022d4..6a337c414d 100644 --- a/common/cluster-api/pom.xml +++ b/common/cluster-api/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT common org.thingsboard.common diff --git a/common/coap-server/pom.xml b/common/coap-server/pom.xml index 945556c188..a8762a81d2 100644 --- a/common/coap-server/pom.xml +++ b/common/coap-server/pom.xml @@ -22,7 +22,7 @@ 4.0.0 org.thingsboard - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT common org.thingsboard.common diff --git a/common/dao-api/pom.xml b/common/dao-api/pom.xml index b5d26b8781..f861d2fb63 100644 --- a/common/dao-api/pom.xml +++ b/common/dao-api/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT common org.thingsboard.common diff --git a/common/data/pom.xml b/common/data/pom.xml index 1b5c78bcd6..80be41e6a0 100644 --- a/common/data/pom.xml +++ b/common/data/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT common org.thingsboard.common diff --git a/common/edge-api/pom.xml b/common/edge-api/pom.xml index 4223b92d70..482e9d77d8 100644 --- a/common/edge-api/pom.xml +++ b/common/edge-api/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT common org.thingsboard.common diff --git a/common/message/pom.xml b/common/message/pom.xml index 1916aeb254..92c216d7b0 100644 --- a/common/message/pom.xml +++ b/common/message/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT common org.thingsboard.common diff --git a/common/pom.xml b/common/pom.xml index 233046824d..b318d57a4e 100644 --- a/common/pom.xml +++ b/common/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT thingsboard common diff --git a/common/queue/pom.xml b/common/queue/pom.xml index 41937ac079..a43e5c0188 100644 --- a/common/queue/pom.xml +++ b/common/queue/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT common org.thingsboard.common diff --git a/common/stats/pom.xml b/common/stats/pom.xml index 8501fea19a..2af921b251 100644 --- a/common/stats/pom.xml +++ b/common/stats/pom.xml @@ -22,7 +22,7 @@ 4.0.0 org.thingsboard - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT common org.thingsboard.common diff --git a/common/transport/coap/pom.xml b/common/transport/coap/pom.xml index a1e1aaa2b0..26f1f45a0f 100644 --- a/common/transport/coap/pom.xml +++ b/common/transport/coap/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard.common - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT transport org.thingsboard.common.transport diff --git a/common/transport/http/pom.xml b/common/transport/http/pom.xml index 24e3ce2337..2164a5c58e 100644 --- a/common/transport/http/pom.xml +++ b/common/transport/http/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard.common - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT transport org.thingsboard.common.transport diff --git a/common/transport/lwm2m/pom.xml b/common/transport/lwm2m/pom.xml index 6ae5747501..33e7138e33 100644 --- a/common/transport/lwm2m/pom.xml +++ b/common/transport/lwm2m/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard.common - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT transport org.thingsboard.common.transport diff --git a/common/transport/mqtt/pom.xml b/common/transport/mqtt/pom.xml index 5d93b95615..0136730eb3 100644 --- a/common/transport/mqtt/pom.xml +++ b/common/transport/mqtt/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard.common - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT transport org.thingsboard.common.transport diff --git a/common/transport/pom.xml b/common/transport/pom.xml index 113e7b46a9..d82fac0264 100644 --- a/common/transport/pom.xml +++ b/common/transport/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT common org.thingsboard.common diff --git a/common/transport/snmp/pom.xml b/common/transport/snmp/pom.xml index 12576e9a54..7b3535db82 100644 --- a/common/transport/snmp/pom.xml +++ b/common/transport/snmp/pom.xml @@ -21,7 +21,7 @@ org.thingsboard.common - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT transport diff --git a/common/transport/transport-api/pom.xml b/common/transport/transport-api/pom.xml index b66676e61c..df14a28436 100644 --- a/common/transport/transport-api/pom.xml +++ b/common/transport/transport-api/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard.common - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT transport org.thingsboard.common.transport diff --git a/common/util/pom.xml b/common/util/pom.xml index a49b602c19..2109d090b1 100644 --- a/common/util/pom.xml +++ b/common/util/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT common org.thingsboard.common diff --git a/dao/pom.xml b/dao/pom.xml index f490a0e8e5..6a01c08822 100644 --- a/dao/pom.xml +++ b/dao/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT thingsboard dao diff --git a/msa/black-box-tests/pom.xml b/msa/black-box-tests/pom.xml index b642f5a2c5..5a0645c03a 100644 --- a/msa/black-box-tests/pom.xml +++ b/msa/black-box-tests/pom.xml @@ -21,7 +21,7 @@ org.thingsboard - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT msa org.thingsboard.msa diff --git a/msa/js-executor/pom.xml b/msa/js-executor/pom.xml index f08a17987a..5cabaed58a 100644 --- a/msa/js-executor/pom.xml +++ b/msa/js-executor/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT msa org.thingsboard.msa diff --git a/msa/pom.xml b/msa/pom.xml index af70451a1e..024607378c 100644 --- a/msa/pom.xml +++ b/msa/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT thingsboard msa diff --git a/msa/tb-node/pom.xml b/msa/tb-node/pom.xml index 90b8e4ede6..9cf97b4906 100644 --- a/msa/tb-node/pom.xml +++ b/msa/tb-node/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT msa org.thingsboard.msa diff --git a/msa/tb/pom.xml b/msa/tb/pom.xml index f55f5b12e5..841a4edbdf 100644 --- a/msa/tb/pom.xml +++ b/msa/tb/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT msa org.thingsboard.msa diff --git a/msa/transport/coap/pom.xml b/msa/transport/coap/pom.xml index f6e226802a..34b37c6334 100644 --- a/msa/transport/coap/pom.xml +++ b/msa/transport/coap/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard.msa - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT transport org.thingsboard.msa.transport diff --git a/msa/transport/http/pom.xml b/msa/transport/http/pom.xml index b14fa3b82f..0cc5320250 100644 --- a/msa/transport/http/pom.xml +++ b/msa/transport/http/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard.msa - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT transport org.thingsboard.msa.transport diff --git a/msa/transport/lwm2m/pom.xml b/msa/transport/lwm2m/pom.xml index c02dc88e7e..2dd44c4386 100644 --- a/msa/transport/lwm2m/pom.xml +++ b/msa/transport/lwm2m/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard.msa - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT transport org.thingsboard.msa.transport diff --git a/msa/transport/mqtt/pom.xml b/msa/transport/mqtt/pom.xml index 9258221754..d483ef42eb 100644 --- a/msa/transport/mqtt/pom.xml +++ b/msa/transport/mqtt/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard.msa - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT transport org.thingsboard.msa.transport diff --git a/msa/transport/pom.xml b/msa/transport/pom.xml index 3a19267950..06c1d17939 100644 --- a/msa/transport/pom.xml +++ b/msa/transport/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT msa org.thingsboard.msa diff --git a/msa/transport/snmp/pom.xml b/msa/transport/snmp/pom.xml index 7be1e011a2..a30942fe4c 100644 --- a/msa/transport/snmp/pom.xml +++ b/msa/transport/snmp/pom.xml @@ -21,7 +21,7 @@ org.thingsboard.msa transport - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT org.thingsboard.msa.transport diff --git a/msa/web-ui/package.json b/msa/web-ui/package.json index b984118482..cc98e5f457 100644 --- a/msa/web-ui/package.json +++ b/msa/web-ui/package.json @@ -1,7 +1,7 @@ { "name": "thingsboard-web-ui", "private": true, - "version": "3.3.2", + "version": "3.3.3", "description": "ThingsBoard Web UI Microservice", "main": "server.js", "bin": "server.js", diff --git a/msa/web-ui/pom.xml b/msa/web-ui/pom.xml index 0a231344de..2b973afaba 100644 --- a/msa/web-ui/pom.xml +++ b/msa/web-ui/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT msa org.thingsboard.msa diff --git a/netty-mqtt/pom.xml b/netty-mqtt/pom.xml index 93ccb59913..e6c2843b14 100644 --- a/netty-mqtt/pom.xml +++ b/netty-mqtt/pom.xml @@ -19,11 +19,11 @@ 4.0.0 org.thingsboard - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT thingsboard netty-mqtt - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT jar Netty MQTT Client diff --git a/pom.xml b/pom.xml index 221525e852..ca3631aba8 100755 --- a/pom.xml +++ b/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard thingsboard - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT pom Thingsboard diff --git a/rest-client/pom.xml b/rest-client/pom.xml index 87d3b6fa9d..36ec99fab6 100644 --- a/rest-client/pom.xml +++ b/rest-client/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT thingsboard rest-client diff --git a/rule-engine/pom.xml b/rule-engine/pom.xml index 941188b24a..986ac17cae 100644 --- a/rule-engine/pom.xml +++ b/rule-engine/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT thingsboard rule-engine diff --git a/rule-engine/rule-engine-api/pom.xml b/rule-engine/rule-engine-api/pom.xml index 1465ac1fd8..03510ab9ce 100644 --- a/rule-engine/rule-engine-api/pom.xml +++ b/rule-engine/rule-engine-api/pom.xml @@ -22,7 +22,7 @@ 4.0.0 org.thingsboard - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT rule-engine org.thingsboard.rule-engine diff --git a/rule-engine/rule-engine-components/pom.xml b/rule-engine/rule-engine-components/pom.xml index c34d6b3df6..2be6f0cdba 100644 --- a/rule-engine/rule-engine-components/pom.xml +++ b/rule-engine/rule-engine-components/pom.xml @@ -22,7 +22,7 @@ 4.0.0 org.thingsboard - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT rule-engine org.thingsboard.rule-engine diff --git a/tools/pom.xml b/tools/pom.xml index 51c4dd689b..b68e4b94a3 100644 --- a/tools/pom.xml +++ b/tools/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT thingsboard tools diff --git a/transport/coap/pom.xml b/transport/coap/pom.xml index cf54bcb496..cb0bb5e5ee 100644 --- a/transport/coap/pom.xml +++ b/transport/coap/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT transport org.thingsboard.transport diff --git a/transport/http/pom.xml b/transport/http/pom.xml index 4dd04c1932..7b92d5135f 100644 --- a/transport/http/pom.xml +++ b/transport/http/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT transport org.thingsboard.transport diff --git a/transport/lwm2m/pom.xml b/transport/lwm2m/pom.xml index 4730be97bd..1b7ed8f6ca 100644 --- a/transport/lwm2m/pom.xml +++ b/transport/lwm2m/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT transport org.thingsboard.transport diff --git a/transport/mqtt/pom.xml b/transport/mqtt/pom.xml index dc2310f62e..1eac98020b 100644 --- a/transport/mqtt/pom.xml +++ b/transport/mqtt/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT transport org.thingsboard.transport diff --git a/transport/pom.xml b/transport/pom.xml index 9347afe94f..8b19669740 100644 --- a/transport/pom.xml +++ b/transport/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT thingsboard transport diff --git a/transport/snmp/pom.xml b/transport/snmp/pom.xml index 72201e25dd..520c651c32 100644 --- a/transport/snmp/pom.xml +++ b/transport/snmp/pom.xml @@ -21,7 +21,7 @@ org.thingsboard - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT transport diff --git a/ui-ngx/package.json b/ui-ngx/package.json index 519d31b66c..73d8e8e7b7 100644 --- a/ui-ngx/package.json +++ b/ui-ngx/package.json @@ -1,6 +1,6 @@ { "name": "thingsboard", - "version": "3.3.2", + "version": "3.3.3", "scripts": { "ng": "ng", "start": "node --max_old_space_size=8048 ./node_modules/@angular/cli/bin/ng serve --host 0.0.0.0 --open", diff --git a/ui-ngx/pom.xml b/ui-ngx/pom.xml index 59e85024fd..d071908001 100644 --- a/ui-ngx/pom.xml +++ b/ui-ngx/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT thingsboard org.thingsboard From e1442c38bb18e34d76b157d27763b9b77fc88703 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Mon, 8 Nov 2021 21:56:26 +0200 Subject: [PATCH 087/432] lwm2m - profile&device bootstrap M4 --- .../server/controller/Lwm2mController.java | 9 ++++----- .../server/service/lwm2m/LwM2MService.java | 2 +- .../server/service/lwm2m/LwM2MServiceImpl.java | 12 ++++++++---- .../lwm2m/bootstrap/LwM2MBootstrapServerConfig.java | 3 +++ .../LwM2MBootstrapServersConfiguration.java | 3 +++ .../common/data/lwm2m/ServerSecurityConfig.java | 6 +++++- .../lwm2m/bootstrap/secure/LwM2MBootstrapConfig.java | 11 +++++++++++ 7 files changed, 35 insertions(+), 11 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/Lwm2mController.java b/application/src/main/java/org/thingsboard/server/controller/Lwm2mController.java index 7a772a69cc..72f91e11eb 100644 --- a/application/src/main/java/org/thingsboard/server/controller/Lwm2mController.java +++ b/application/src/main/java/org/thingsboard/server/controller/Lwm2mController.java @@ -37,6 +37,7 @@ import org.thingsboard.server.service.lwm2m.LwM2MService; import org.thingsboard.server.service.lwm2m.LwM2MServiceImpl; import org.thingsboard.server.service.security.permission.Resource; +import java.util.List; import java.util.Map; import static org.thingsboard.server.controller.ControllerConstants.IS_BOOTSTRAP_SERVER_PARAM_DESCRIPTION; @@ -61,13 +62,11 @@ public class Lwm2mController extends BaseController { TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH, produces = "application/json") @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") - @RequestMapping(value = "/lwm2m/deviceProfile/bootstrap/{isBootstrapServer}", method = RequestMethod.GET) + @RequestMapping(value = "/lwm2m/deviceProfile/bootstrap", method = RequestMethod.GET) @ResponseBody - public ServerSecurityConfig getLwm2mBootstrapSecurityInfo( - @ApiParam(value = IS_BOOTSTRAP_SERVER_PARAM_DESCRIPTION) - @PathVariable(IS_BOOTSTRAP_SERVER) boolean bootstrapServer) throws ThingsboardException { + public ServerSecurityConfig [] getLwm2mBootstrapSecurityInfo() throws ThingsboardException { try { - return lwM2MService.getServerSecurityInfo(bootstrapServer); + return lwM2MService.getServerSecurityInfo(); } catch (Exception e) { throw handleException(e); } diff --git a/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MService.java b/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MService.java index 7d1a69d270..2dc2827317 100644 --- a/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MService.java +++ b/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MService.java @@ -19,6 +19,6 @@ import org.thingsboard.server.common.data.lwm2m.ServerSecurityConfig; public interface LwM2MService { - ServerSecurityConfig getServerSecurityInfo(boolean bootstrapServer); + ServerSecurityConfig [] getServerSecurityInfo(); } diff --git a/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MServiceImpl.java b/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MServiceImpl.java index c846c60d14..46a56909cf 100644 --- a/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MServiceImpl.java +++ b/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MServiceImpl.java @@ -26,6 +26,8 @@ import org.thingsboard.server.transport.lwm2m.config.LwM2MSecureServerConfig; import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportBootstrapConfig; import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; +import java.util.List; + @Slf4j @Service @RequiredArgsConstructor @@ -36,10 +38,12 @@ public class LwM2MServiceImpl implements LwM2MService { private final LwM2MTransportBootstrapConfig bootstrapConfig; @Override - public ServerSecurityConfig getServerSecurityInfo(boolean bootstrapServer) { - ServerSecurityConfig result = getServerSecurityConfig(bootstrapServer ? bootstrapConfig : serverConfig); - result.setBootstrapServerIs(bootstrapServer); - return result; + public ServerSecurityConfig [] getServerSecurityInfo() { + ServerSecurityConfig bootstrapServer = getServerSecurityConfig(bootstrapConfig); + bootstrapServer.setBootstrapServerIs(true); + ServerSecurityConfig lwm2mServer = getServerSecurityConfig(serverConfig); + lwm2mServer.setBootstrapServerIs(false); + return new ServerSecurityConfig[] {bootstrapServer, lwm2mServer}; } private ServerSecurityConfig getServerSecurityConfig(LwM2MSecureServerConfig serverConfig) { diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/LwM2MBootstrapServerConfig.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/LwM2MBootstrapServerConfig.java index f27f01978f..35adce1187 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/LwM2MBootstrapServerConfig.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/LwM2MBootstrapServerConfig.java @@ -19,6 +19,9 @@ import lombok.Data; @Data public class LwM2MBootstrapServerConfig { + + protected Integer shortServerId = 123; + private Integer shortId = 123; private Integer lifetime = 300; private Integer defaultMinPeriod = 1; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/LwM2MBootstrapServersConfiguration.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/LwM2MBootstrapServersConfiguration.java index 6347ecc06c..fd3cfad5a5 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/LwM2MBootstrapServersConfiguration.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/LwM2MBootstrapServersConfiguration.java @@ -17,10 +17,13 @@ package org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap; import lombok.Data; +import java.util.List; + @Data public class LwM2MBootstrapServersConfiguration { //TODO + List serversConfiguration; // List LwM2MBootstrapServersConfigurations; // LwM2MBootstrapServersConfiguration: Integer shortId, LwM2MBootstrapServerConfig serverConfig; LwM2MBootstrapServerCredential serverSecurity. diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/lwm2m/ServerSecurityConfig.java b/common/data/src/main/java/org/thingsboard/server/common/data/lwm2m/ServerSecurityConfig.java index 83b56a2661..a98f9c52ee 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/lwm2m/ServerSecurityConfig.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/lwm2m/ServerSecurityConfig.java @@ -18,10 +18,14 @@ package org.thingsboard.server.common.data.lwm2m; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; +import org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap.LwM2MBootstrapServerConfig; @ApiModel @Data -public class ServerSecurityConfig { +public class ServerSecurityConfig extends LwM2MBootstrapServerConfig { + + protected Integer shortServerId = 123; + @ApiModelProperty(position = 1, value = "Is Bootstrap Server or Lwm2m Server", example = "true or false", readOnly = true) protected boolean bootstrapServerIs = true; @ApiModelProperty(position = 2, value = "Host for 'No Security' mode", example = "0.0.0.0", readOnly = true) diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapConfig.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapConfig.java index f2ba39dcfa..29024d8f8f 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapConfig.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapConfig.java @@ -23,12 +23,18 @@ import org.eclipse.leshan.core.SecurityMode; import org.eclipse.leshan.core.request.BindingMode; import org.eclipse.leshan.core.util.Hex; import org.eclipse.leshan.server.bootstrap.BootstrapConfig; +import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MBootstrapClientCredential; +import org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap.LwM2MBootstrapServerCredential; import java.io.Serializable; import java.nio.charset.StandardCharsets; +import java.util.List; @Data public class LwM2MBootstrapConfig implements Serializable { + + List serversConfiguration; + LwM2MBootstrapClientCredential bootstrapClientCredential; /* interface BootstrapSecurityConfig servers: BootstrapServersSecurityConfig, @@ -68,6 +74,11 @@ public class LwM2MBootstrapConfig implements Serializable { @Setter private LwM2MServerBootstrap lwm2mServer; + public LwM2MBootstrapConfig(List serversConfiguration, LwM2MBootstrapClientCredential bootstrapClientCredential) { + this.serversConfiguration = serversConfiguration; + this.bootstrapClientCredential = bootstrapClientCredential; + } + @JsonIgnore public BootstrapConfig getLwM2MBootstrapConfig() { BootstrapConfig configBs = new BootstrapConfig(); From 0ac80664e410ee6d8a8dd0f18bff0517ce5740ab Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Tue, 9 Nov 2021 12:35:05 +0200 Subject: [PATCH 088/432] lwm2m - profile bootstrap config --- .../server/controller/Lwm2mController.java | 21 +++---- .../server/service/lwm2m/LwM2MService.java | 4 +- .../service/lwm2m/LwM2MServiceImpl.java | 20 +++--- .../dao/device/DeviceCredentialsService.java | 2 - ...tLwM2MBootstrapLwM2MServerCredential.java} | 3 +- .../bootstrap/LwM2MBootstrapServerConfig.java | 30 --------- .../LwM2MBootstrapServerCredential.java | 8 +-- .../LwM2MBootstrapServersConfiguration.java | 9 +-- .../bootstrap/LwM2MServerSecurityConfig.java | 63 +++++++++++++++++++ ...cLwM2MBootstrapLwM2MServerCredential.java} | 2 +- ...KLwM2MBootstrapLwM2MServerCredential.java} | 2 +- ...KLwM2MBootstrapLwM2MServerCredential.java} | 2 +- ...9LwM2MBootstrapLwM2MServerCredential.java} | 2 +- .../data/lwm2m/ServerSecurityConfig.java | 48 -------------- .../dao/device/DeviceProfileServiceImpl.java | 8 +-- 15 files changed, 97 insertions(+), 127 deletions(-) rename common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/{AbstractLwM2MBootstrapServerCredential.java => AbstractLwM2MBootstrapLwM2MServerCredential.java} (84%) delete mode 100644 common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/LwM2MBootstrapServerConfig.java create mode 100644 common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/LwM2MServerSecurityConfig.java rename common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/{NoSecLwM2MBootstrapServerCredential.java => NoSecLwM2MBootstrapLwM2MServerCredential.java} (89%) rename common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/{PSKLwM2MBootstrapServerCredential.java => PSKLwM2MBootstrapLwM2MServerCredential.java} (89%) rename common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/{RPKLwM2MBootstrapServerCredential.java => RPKLwM2MBootstrapLwM2MServerCredential.java} (89%) rename common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/{X509LwM2MBootstrapServerCredential.java => X509LwM2MBootstrapLwM2MServerCredential.java} (89%) delete mode 100644 common/data/src/main/java/org/thingsboard/server/common/data/lwm2m/ServerSecurityConfig.java diff --git a/application/src/main/java/org/thingsboard/server/controller/Lwm2mController.java b/application/src/main/java/org/thingsboard/server/controller/Lwm2mController.java index 72f91e11eb..86ef420192 100644 --- a/application/src/main/java/org/thingsboard/server/controller/Lwm2mController.java +++ b/application/src/main/java/org/thingsboard/server/controller/Lwm2mController.java @@ -30,14 +30,11 @@ import org.springframework.web.bind.annotation.RestController; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.SaveDeviceWithCredentialsRequest; import org.thingsboard.server.common.data.exception.ThingsboardException; -import org.thingsboard.server.common.data.lwm2m.ServerSecurityConfig; +import org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap.LwM2MServerSecurityConfig; import org.thingsboard.server.common.data.security.DeviceCredentials; import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.service.lwm2m.LwM2MService; -import org.thingsboard.server.service.lwm2m.LwM2MServiceImpl; -import org.thingsboard.server.service.security.permission.Resource; -import java.util.List; import java.util.Map; import static org.thingsboard.server.controller.ControllerConstants.IS_BOOTSTRAP_SERVER_PARAM_DESCRIPTION; @@ -62,14 +59,16 @@ public class Lwm2mController extends BaseController { TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH, produces = "application/json") @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") - @RequestMapping(value = "/lwm2m/deviceProfile/bootstrap", method = RequestMethod.GET) + @RequestMapping(value = "/lwm2m/deviceProfile/bootstrap/{isBootstrapServer}", method = RequestMethod.GET) @ResponseBody - public ServerSecurityConfig [] getLwm2mBootstrapSecurityInfo() throws ThingsboardException { - try { - return lwM2MService.getServerSecurityInfo(); - } catch (Exception e) { - throw handleException(e); - } + public LwM2MServerSecurityConfig getLwm2mBootstrapSecurityInfo( + @ApiParam(value = IS_BOOTSTRAP_SERVER_PARAM_DESCRIPTION) + @PathVariable(IS_BOOTSTRAP_SERVER) boolean bootstrapServer) throws ThingsboardException { + try { + return lwM2MService.getServerSecurityInfo(bootstrapServer); + } catch (Exception e) { + throw handleException(e); + } } @ApiOperation(hidden = true, value = "Save device with credentials (Deprecated)") diff --git a/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MService.java b/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MService.java index 2dc2827317..e63f66f0bf 100644 --- a/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MService.java +++ b/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MService.java @@ -15,10 +15,10 @@ */ package org.thingsboard.server.service.lwm2m; -import org.thingsboard.server.common.data.lwm2m.ServerSecurityConfig; +import org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap.LwM2MServerSecurityConfig; public interface LwM2MService { - ServerSecurityConfig [] getServerSecurityInfo(); + LwM2MServerSecurityConfig getServerSecurityInfo(boolean bootstrapServer); } diff --git a/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MServiceImpl.java b/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MServiceImpl.java index 46a56909cf..0ba57cbc00 100644 --- a/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MServiceImpl.java +++ b/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MServiceImpl.java @@ -20,14 +20,12 @@ import lombok.extern.slf4j.Slf4j; import org.apache.commons.codec.binary.Base64; import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.stereotype.Service; -import org.thingsboard.server.common.data.lwm2m.ServerSecurityConfig; +import org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap.LwM2MServerSecurityConfig; import org.thingsboard.server.common.transport.config.ssl.SslCredentials; import org.thingsboard.server.transport.lwm2m.config.LwM2MSecureServerConfig; import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportBootstrapConfig; import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; -import java.util.List; - @Slf4j @Service @RequiredArgsConstructor @@ -38,17 +36,15 @@ public class LwM2MServiceImpl implements LwM2MService { private final LwM2MTransportBootstrapConfig bootstrapConfig; @Override - public ServerSecurityConfig [] getServerSecurityInfo() { - ServerSecurityConfig bootstrapServer = getServerSecurityConfig(bootstrapConfig); - bootstrapServer.setBootstrapServerIs(true); - ServerSecurityConfig lwm2mServer = getServerSecurityConfig(serverConfig); - lwm2mServer.setBootstrapServerIs(false); - return new ServerSecurityConfig[] {bootstrapServer, lwm2mServer}; + public LwM2MServerSecurityConfig getServerSecurityInfo(boolean bootstrapServer) { + LwM2MServerSecurityConfig result = getServerSecurityConfig(bootstrapServer ? bootstrapConfig : serverConfig); + result.setBootstrapServerIs(bootstrapServer); + return result; } - private ServerSecurityConfig getServerSecurityConfig(LwM2MSecureServerConfig serverConfig) { - ServerSecurityConfig bsServ = new ServerSecurityConfig(); - bsServ.setServerId(serverConfig.getId()); + private LwM2MServerSecurityConfig getServerSecurityConfig(LwM2MSecureServerConfig serverConfig) { + LwM2MServerSecurityConfig bsServ = new LwM2MServerSecurityConfig(); + bsServ.setShortServerId(serverConfig.getId()); bsServ.setHost(serverConfig.getHost()); bsServ.setPort(serverConfig.getPort()); bsServ.setSecurityHost(serverConfig.getSecureHost()); diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsService.java index a57d39776f..01d1baebb3 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsService.java @@ -15,10 +15,8 @@ */ package org.thingsboard.server.dao.device; -import org.thingsboard.server.common.data.device.profile.Lwm2mDeviceProfileTransportConfiguration; import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.TenantId; -import org.thingsboard.server.common.data.lwm2m.ServerSecurityConfig; import org.thingsboard.server.common.data.security.DeviceCredentials; public interface DeviceCredentialsService { diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/AbstractLwM2MBootstrapServerCredential.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/AbstractLwM2MBootstrapLwM2MServerCredential.java similarity index 84% rename from common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/AbstractLwM2MBootstrapServerCredential.java rename to common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/AbstractLwM2MBootstrapLwM2MServerCredential.java index 87eeb3a1e1..c92a2ed0eb 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/AbstractLwM2MBootstrapServerCredential.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/AbstractLwM2MBootstrapLwM2MServerCredential.java @@ -20,11 +20,10 @@ import lombok.Getter; import lombok.Setter; import lombok.SneakyThrows; import org.apache.commons.codec.binary.Base64; -import org.thingsboard.server.common.data.lwm2m.ServerSecurityConfig; @Getter @Setter -public abstract class AbstractLwM2MBootstrapServerCredential extends ServerSecurityConfig implements LwM2MBootstrapServerCredential { +public abstract class AbstractLwM2MBootstrapLwM2MServerCredential extends LwM2MServerSecurityConfig implements LwM2MBootstrapServerCredential { @JsonIgnore public byte[] getDecodedCServerPublicKey() { diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/LwM2MBootstrapServerConfig.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/LwM2MBootstrapServerConfig.java deleted file mode 100644 index 35adce1187..0000000000 --- a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/LwM2MBootstrapServerConfig.java +++ /dev/null @@ -1,30 +0,0 @@ -/** - * Copyright © 2016-2021 The Thingsboard Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap; - -import lombok.Data; - -@Data -public class LwM2MBootstrapServerConfig { - - protected Integer shortServerId = 123; - - private Integer shortId = 123; - private Integer lifetime = 300; - private Integer defaultMinPeriod = 1; - private boolean notifIfDisabled = true; - private String binding = "U"; -} diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/LwM2MBootstrapServerCredential.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/LwM2MBootstrapServerCredential.java index b22e80d81f..a8967c0674 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/LwM2MBootstrapServerCredential.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/LwM2MBootstrapServerCredential.java @@ -25,10 +25,10 @@ import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MSecurity use = JsonTypeInfo.Id.NAME, property = "securityMode") @JsonSubTypes({ - @JsonSubTypes.Type(value = NoSecLwM2MBootstrapServerCredential.class, name = "NO_SEC"), - @JsonSubTypes.Type(value = PSKLwM2MBootstrapServerCredential.class, name = "PSK"), - @JsonSubTypes.Type(value = RPKLwM2MBootstrapServerCredential.class, name = "RPK"), - @JsonSubTypes.Type(value = X509LwM2MBootstrapServerCredential.class, name = "X509") + @JsonSubTypes.Type(value = NoSecLwM2MBootstrapLwM2MServerCredential.class, name = "NO_SEC"), + @JsonSubTypes.Type(value = PSKLwM2MBootstrapLwM2MServerCredential.class, name = "PSK"), + @JsonSubTypes.Type(value = RPKLwM2MBootstrapLwM2MServerCredential.class, name = "RPK"), + @JsonSubTypes.Type(value = X509LwM2MBootstrapLwM2MServerCredential.class, name = "X509") }) @JsonIgnoreProperties(ignoreUnknown = true) public interface LwM2MBootstrapServerCredential { diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/LwM2MBootstrapServersConfiguration.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/LwM2MBootstrapServersConfiguration.java index fd3cfad5a5..15d573b50e 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/LwM2MBootstrapServersConfiguration.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/LwM2MBootstrapServersConfiguration.java @@ -22,13 +22,6 @@ import java.util.List; @Data public class LwM2MBootstrapServersConfiguration { - //TODO - List serversConfiguration; - // List LwM2MBootstrapServersConfigurations; - // LwM2MBootstrapServersConfiguration: Integer shortId, LwM2MBootstrapServerConfig serverConfig; LwM2MBootstrapServerCredential serverSecurity. - - private LwM2MBootstrapServerConfig servers; - private LwM2MBootstrapServerCredential lwm2mServer; - private LwM2MBootstrapServerCredential bootstrapServer; + List serverConfiguration; } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/LwM2MServerSecurityConfig.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/LwM2MServerSecurityConfig.java new file mode 100644 index 0000000000..7a43bd60ca --- /dev/null +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/LwM2MServerSecurityConfig.java @@ -0,0 +1,63 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +@ApiModel +@Data +public class LwM2MServerSecurityConfig { + + @ApiModelProperty(position = 1, value = "Server short Id. Used as link to associate server Object Instance.\nThis identifier uniquely identifies each LwM2M Server configured for the LwM2M Client.\n" + + "This Resource MUST be set when the Bootstrap-Server Resource has a value of 'false'. \n" + + "The values ID:0 and ID:65535 values MUST NOT be used for identifying the LwM2M Server.", example = "123", readOnly = true) + protected Integer shortServerId = 123; + /** Security -> ObjectId = 0 'LWM2M Security' */ + @ApiModelProperty(position = 2, value = "Is Bootstrap Server or Lwm2m Server", example = "true or false", readOnly = true) + protected boolean bootstrapServerIs = false; + @ApiModelProperty(position = 3, value = "Host for 'No Security' mode", example = "0.0.0.0", readOnly = true) + protected String host; + @ApiModelProperty(position = 4, value = "Port for Lwm2m Server: 'No Security' mode: Lwm2m Server or Bootstrap Server", example = "'5685' or '5687'", readOnly = true) + protected Integer port; + @ApiModelProperty(position = 5, value = "Host for 'Security' mode (DTLS)", example = "0.0.0.0", readOnly = true) + protected String securityHost; + @ApiModelProperty(position = 6, value = "Port for 'Security' mode (DTLS): Lwm2m Server or Bootstrap Server", example = "5686 or 5688", readOnly = true) + protected Integer securityPort; + @ApiModelProperty(position = 7, value = "Client Hold Off Time. The number of seconds to wait before initiating a Client Initiated Bootstrap once the LwM2M Client has determined it should initiate this bootstrap mode. (This information is relevant for use with a Bootstrap-Server only.)", example = "1", readOnly = true) + protected Integer clientHoldOffTime = 1; + @ApiModelProperty(position = 8, value = "Server Public Key for 'Security' mode (DTLS): RPK or X509. Format: base64 encoded", example = "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEAZ0pSaGKHk/GrDaUDnQZpeEdGwX7m3Ws+U/kiVat\n" + + "+44sgk3c8g0LotfMpLlZJPhPwJ6ipXV+O1r7IZUjBs3LNA==", readOnly = true) + protected String serverPublicKey; + @ApiModelProperty(position = 9, value = "Bootstrap Server Account Timeout (If the value is set to 0, or if this resource is not instantiated, the Bootstrap-Server Account lifetime is infinite.)", example = "0", readOnly = true) + Integer bootstrapServerAccountTimeout = 0; + + /** Config -> ObjectId = 1 'LwM2M Server' */ + @ApiModelProperty(position = 10, value = "Specify the lifetime of the registration in seconds.", example = "300", readOnly = true) + private Integer lifetime = 300; + @ApiModelProperty(position = 11, value = "The default value the LwM2M Client should use for the Minimum Period of an Observation in the absence of this parameter being included in an Observation.\n" + + "If this Resource doesn’t exist, the default value is 0.", example = "1", readOnly = true) + private Integer defaultMinPeriod = 1; + /** ResourceID=6 'Notification Storing When Disabled or Offline' */ + @ApiModelProperty(position = 12, value = "If true, the LwM2M Client stores “Notify” operations to the LwM2M Server while the LwM2M Server account is disabled or the LwM2M Client is offline. After the LwM2M Server account is enabled or the LwM2M Client is online, the LwM2M Client reports the stored “Notify” operations to the Server.\n" + + "If false, the LwM2M Client discards all the “Notify” operations or temporarily disables the Observe function while the LwM2M Server is disabled or the LwM2M Client is offline.\n" + + "The default value is true.", example = "true", readOnly = true) + private boolean notifIfDisabled = true; + @ApiModelProperty(position = 14, value = "This Resource defines the transport binding configured for the LwM2M Client.\n" + + "If the LwM2M Client supports the binding specified in this Resource, the LwM2M Client MUST use that transport for the Current Binding Mode.", example = "U", readOnly = true) + private String binding = "U"; +} diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/NoSecLwM2MBootstrapServerCredential.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/NoSecLwM2MBootstrapLwM2MServerCredential.java similarity index 89% rename from common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/NoSecLwM2MBootstrapServerCredential.java rename to common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/NoSecLwM2MBootstrapLwM2MServerCredential.java index 7730c79ee9..8973232b9a 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/NoSecLwM2MBootstrapServerCredential.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/NoSecLwM2MBootstrapLwM2MServerCredential.java @@ -17,7 +17,7 @@ package org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap; import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MSecurityMode; -public class NoSecLwM2MBootstrapServerCredential extends AbstractLwM2MBootstrapServerCredential { +public class NoSecLwM2MBootstrapLwM2MServerCredential extends AbstractLwM2MBootstrapLwM2MServerCredential { @Override public LwM2MSecurityMode getSecurityMode() { return LwM2MSecurityMode.NO_SEC; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/PSKLwM2MBootstrapServerCredential.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/PSKLwM2MBootstrapLwM2MServerCredential.java similarity index 89% rename from common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/PSKLwM2MBootstrapServerCredential.java rename to common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/PSKLwM2MBootstrapLwM2MServerCredential.java index 30f7f8c472..9adf566eb0 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/PSKLwM2MBootstrapServerCredential.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/PSKLwM2MBootstrapLwM2MServerCredential.java @@ -17,7 +17,7 @@ package org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap; import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MSecurityMode; -public class PSKLwM2MBootstrapServerCredential extends AbstractLwM2MBootstrapServerCredential { +public class PSKLwM2MBootstrapLwM2MServerCredential extends AbstractLwM2MBootstrapLwM2MServerCredential { @Override public LwM2MSecurityMode getSecurityMode() { return LwM2MSecurityMode.PSK; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/RPKLwM2MBootstrapServerCredential.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/RPKLwM2MBootstrapLwM2MServerCredential.java similarity index 89% rename from common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/RPKLwM2MBootstrapServerCredential.java rename to common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/RPKLwM2MBootstrapLwM2MServerCredential.java index c529820709..bf595a394b 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/RPKLwM2MBootstrapServerCredential.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/RPKLwM2MBootstrapLwM2MServerCredential.java @@ -17,7 +17,7 @@ package org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap; import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MSecurityMode; -public class RPKLwM2MBootstrapServerCredential extends AbstractLwM2MBootstrapServerCredential { +public class RPKLwM2MBootstrapLwM2MServerCredential extends AbstractLwM2MBootstrapLwM2MServerCredential { @Override public LwM2MSecurityMode getSecurityMode() { return LwM2MSecurityMode.RPK; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/X509LwM2MBootstrapServerCredential.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/X509LwM2MBootstrapLwM2MServerCredential.java similarity index 89% rename from common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/X509LwM2MBootstrapServerCredential.java rename to common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/X509LwM2MBootstrapLwM2MServerCredential.java index e95bf7742d..1c2d83ba8e 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/X509LwM2MBootstrapServerCredential.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/X509LwM2MBootstrapLwM2MServerCredential.java @@ -17,7 +17,7 @@ package org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap; import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MSecurityMode; -public class X509LwM2MBootstrapServerCredential extends AbstractLwM2MBootstrapServerCredential { +public class X509LwM2MBootstrapLwM2MServerCredential extends AbstractLwM2MBootstrapLwM2MServerCredential { @Override public LwM2MSecurityMode getSecurityMode() { return LwM2MSecurityMode.X509; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/lwm2m/ServerSecurityConfig.java b/common/data/src/main/java/org/thingsboard/server/common/data/lwm2m/ServerSecurityConfig.java deleted file mode 100644 index a98f9c52ee..0000000000 --- a/common/data/src/main/java/org/thingsboard/server/common/data/lwm2m/ServerSecurityConfig.java +++ /dev/null @@ -1,48 +0,0 @@ -/** - * Copyright © 2016-2021 The Thingsboard Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.thingsboard.server.common.data.lwm2m; - -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; -import lombok.Data; -import org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap.LwM2MBootstrapServerConfig; - -@ApiModel -@Data -public class ServerSecurityConfig extends LwM2MBootstrapServerConfig { - - protected Integer shortServerId = 123; - - @ApiModelProperty(position = 1, value = "Is Bootstrap Server or Lwm2m Server", example = "true or false", readOnly = true) - protected boolean bootstrapServerIs = true; - @ApiModelProperty(position = 2, value = "Host for 'No Security' mode", example = "0.0.0.0", readOnly = true) - protected String host; - @ApiModelProperty(position = 3, value = "Port for Lwm2m Server: 'No Security' mode: Lwm2m Server or Bootstrap Server", example = "'5685' or '5687'", readOnly = true) - protected Integer port; - @ApiModelProperty(position = 4, value = "Host for 'Security' mode (DTLS)", example = "0.0.0.0", readOnly = true) - protected String securityHost; - @ApiModelProperty(position = 5, value = "Port for 'Security' mode (DTLS): Lwm2m Server or Bootstrap Server", example = "5686 or 5688", readOnly = true) - protected Integer securityPort; - @ApiModelProperty(position = 6, value = "Server short Id", example = "111", readOnly = true) - protected Integer serverId = 111; - @ApiModelProperty(position = 7, value = "Client Hold Off Time. The number of seconds to wait before initiating a Client Initiated Bootstrap once the LwM2M Client has determined it should initiate this bootstrap mode. (This information is relevant for use with a Bootstrap-Server only.)", example = "1", readOnly = true) - protected Integer clientHoldOffTime = 1; - @ApiModelProperty(position = 8, value = "Server Public Key for 'Security' mode (DTLS): RPK or X509. Format: base64 encoded", example = "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEAZ0pSaGKHk/GrDaUDnQZpeEdGwX7m3Ws+U/kiVat\n" + - "+44sgk3c8g0LotfMpLlZJPhPwJ6ipXV+O1r7IZUjBs3LNA==", readOnly = true) - protected String serverPublicKey; - @ApiModelProperty(position = 9, value = "Bootstrap Server Account Timeout (If the value is set to 0, or if this resource is not instantiated, the Bootstrap-Server Account lifetime is infinite.)", example = "0", readOnly = true) - Integer bootstrapServerAccountTimeout = 0; -} diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java index 3430e5774e..6552bcf1f8 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java @@ -60,9 +60,9 @@ import org.thingsboard.server.common.data.device.profile.Lwm2mDeviceProfileTrans import org.thingsboard.server.common.data.device.profile.MqttDeviceProfileTransportConfiguration; import org.thingsboard.server.common.data.device.profile.ProtoTransportPayloadConfiguration; import org.thingsboard.server.common.data.device.profile.TransportPayloadTypeConfiguration; -import org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap.RPKLwM2MBootstrapServerCredential; +import org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap.RPKLwM2MBootstrapLwM2MServerCredential; import org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap.LwM2MBootstrapServerCredential; -import org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap.X509LwM2MBootstrapServerCredential; +import org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap.X509LwM2MBootstrapLwM2MServerCredential; import org.thingsboard.server.common.data.ota.OtaPackageType; import org.thingsboard.server.common.data.id.DeviceProfileId; import org.thingsboard.server.common.data.id.TenantId; @@ -710,7 +710,7 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D case PSK: break; case RPK: - RPKLwM2MBootstrapServerCredential rpkServerCredentials = (RPKLwM2MBootstrapServerCredential) bootstrapServerConfig; + RPKLwM2MBootstrapLwM2MServerCredential rpkServerCredentials = (RPKLwM2MBootstrapLwM2MServerCredential) bootstrapServerConfig; if (StringUtils.isEmpty(rpkServerCredentials.getServerPublicKey())) { throw new DeviceCredentialsValidationException(server + " RPK public key must be specified!"); } @@ -723,7 +723,7 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D } break; case X509: - X509LwM2MBootstrapServerCredential x509ServerCredentials = (X509LwM2MBootstrapServerCredential) bootstrapServerConfig; + X509LwM2MBootstrapLwM2MServerCredential x509ServerCredentials = (X509LwM2MBootstrapLwM2MServerCredential) bootstrapServerConfig; if (StringUtils.isEmpty(x509ServerCredentials.getServerPublicKey())) { throw new DeviceCredentialsValidationException(server + " X509 public key must be specified!"); } From de71dd24b8ec41c6bf62bbf4f15d06939060e742 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Tue, 9 Nov 2021 13:12:21 +0200 Subject: [PATCH 089/432] lwm2m - rename file --- ...bstractLwM2MBootstrapServerCredential.java} | 2 +- .../LwM2MBootstrapServerCredential.java | 8 ++++---- ...> NoSecLwM2MBootstrapServerCredential.java} | 2 +- ... => PSKLwM2MBootstrapServerCredential.java} | 2 +- ... => RPKLwM2MBootstrapServerCredential.java} | 2 +- ...=> X509LwM2MBootstrapServerCredential.java} | 2 +- .../dao/device/DeviceProfileServiceImpl.java | 18 +++++++++++------- 7 files changed, 20 insertions(+), 16 deletions(-) rename common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/{AbstractLwM2MBootstrapLwM2MServerCredential.java => AbstractLwM2MBootstrapServerCredential.java} (88%) rename common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/{NoSecLwM2MBootstrapLwM2MServerCredential.java => NoSecLwM2MBootstrapServerCredential.java} (89%) rename common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/{PSKLwM2MBootstrapLwM2MServerCredential.java => PSKLwM2MBootstrapServerCredential.java} (89%) rename common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/{RPKLwM2MBootstrapLwM2MServerCredential.java => RPKLwM2MBootstrapServerCredential.java} (89%) rename common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/{X509LwM2MBootstrapLwM2MServerCredential.java => X509LwM2MBootstrapServerCredential.java} (89%) diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/AbstractLwM2MBootstrapLwM2MServerCredential.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/AbstractLwM2MBootstrapServerCredential.java similarity index 88% rename from common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/AbstractLwM2MBootstrapLwM2MServerCredential.java rename to common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/AbstractLwM2MBootstrapServerCredential.java index c92a2ed0eb..ed0330c60b 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/AbstractLwM2MBootstrapLwM2MServerCredential.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/AbstractLwM2MBootstrapServerCredential.java @@ -23,7 +23,7 @@ import org.apache.commons.codec.binary.Base64; @Getter @Setter -public abstract class AbstractLwM2MBootstrapLwM2MServerCredential extends LwM2MServerSecurityConfig implements LwM2MBootstrapServerCredential { +public abstract class AbstractLwM2MBootstrapServerCredential extends LwM2MServerSecurityConfig implements LwM2MBootstrapServerCredential { @JsonIgnore public byte[] getDecodedCServerPublicKey() { diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/LwM2MBootstrapServerCredential.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/LwM2MBootstrapServerCredential.java index a8967c0674..b22e80d81f 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/LwM2MBootstrapServerCredential.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/LwM2MBootstrapServerCredential.java @@ -25,10 +25,10 @@ import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MSecurity use = JsonTypeInfo.Id.NAME, property = "securityMode") @JsonSubTypes({ - @JsonSubTypes.Type(value = NoSecLwM2MBootstrapLwM2MServerCredential.class, name = "NO_SEC"), - @JsonSubTypes.Type(value = PSKLwM2MBootstrapLwM2MServerCredential.class, name = "PSK"), - @JsonSubTypes.Type(value = RPKLwM2MBootstrapLwM2MServerCredential.class, name = "RPK"), - @JsonSubTypes.Type(value = X509LwM2MBootstrapLwM2MServerCredential.class, name = "X509") + @JsonSubTypes.Type(value = NoSecLwM2MBootstrapServerCredential.class, name = "NO_SEC"), + @JsonSubTypes.Type(value = PSKLwM2MBootstrapServerCredential.class, name = "PSK"), + @JsonSubTypes.Type(value = RPKLwM2MBootstrapServerCredential.class, name = "RPK"), + @JsonSubTypes.Type(value = X509LwM2MBootstrapServerCredential.class, name = "X509") }) @JsonIgnoreProperties(ignoreUnknown = true) public interface LwM2MBootstrapServerCredential { diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/NoSecLwM2MBootstrapLwM2MServerCredential.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/NoSecLwM2MBootstrapServerCredential.java similarity index 89% rename from common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/NoSecLwM2MBootstrapLwM2MServerCredential.java rename to common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/NoSecLwM2MBootstrapServerCredential.java index 8973232b9a..7730c79ee9 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/NoSecLwM2MBootstrapLwM2MServerCredential.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/NoSecLwM2MBootstrapServerCredential.java @@ -17,7 +17,7 @@ package org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap; import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MSecurityMode; -public class NoSecLwM2MBootstrapLwM2MServerCredential extends AbstractLwM2MBootstrapLwM2MServerCredential { +public class NoSecLwM2MBootstrapServerCredential extends AbstractLwM2MBootstrapServerCredential { @Override public LwM2MSecurityMode getSecurityMode() { return LwM2MSecurityMode.NO_SEC; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/PSKLwM2MBootstrapLwM2MServerCredential.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/PSKLwM2MBootstrapServerCredential.java similarity index 89% rename from common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/PSKLwM2MBootstrapLwM2MServerCredential.java rename to common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/PSKLwM2MBootstrapServerCredential.java index 9adf566eb0..30f7f8c472 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/PSKLwM2MBootstrapLwM2MServerCredential.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/PSKLwM2MBootstrapServerCredential.java @@ -17,7 +17,7 @@ package org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap; import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MSecurityMode; -public class PSKLwM2MBootstrapLwM2MServerCredential extends AbstractLwM2MBootstrapLwM2MServerCredential { +public class PSKLwM2MBootstrapServerCredential extends AbstractLwM2MBootstrapServerCredential { @Override public LwM2MSecurityMode getSecurityMode() { return LwM2MSecurityMode.PSK; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/RPKLwM2MBootstrapLwM2MServerCredential.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/RPKLwM2MBootstrapServerCredential.java similarity index 89% rename from common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/RPKLwM2MBootstrapLwM2MServerCredential.java rename to common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/RPKLwM2MBootstrapServerCredential.java index bf595a394b..c529820709 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/RPKLwM2MBootstrapLwM2MServerCredential.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/RPKLwM2MBootstrapServerCredential.java @@ -17,7 +17,7 @@ package org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap; import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MSecurityMode; -public class RPKLwM2MBootstrapLwM2MServerCredential extends AbstractLwM2MBootstrapLwM2MServerCredential { +public class RPKLwM2MBootstrapServerCredential extends AbstractLwM2MBootstrapServerCredential { @Override public LwM2MSecurityMode getSecurityMode() { return LwM2MSecurityMode.RPK; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/X509LwM2MBootstrapLwM2MServerCredential.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/X509LwM2MBootstrapServerCredential.java similarity index 89% rename from common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/X509LwM2MBootstrapLwM2MServerCredential.java rename to common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/X509LwM2MBootstrapServerCredential.java index 1c2d83ba8e..e95bf7742d 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/X509LwM2MBootstrapLwM2MServerCredential.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/X509LwM2MBootstrapServerCredential.java @@ -17,7 +17,7 @@ package org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap; import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MSecurityMode; -public class X509LwM2MBootstrapLwM2MServerCredential extends AbstractLwM2MBootstrapLwM2MServerCredential { +public class X509LwM2MBootstrapServerCredential extends AbstractLwM2MBootstrapServerCredential { @Override public LwM2MSecurityMode getSecurityMode() { return LwM2MSecurityMode.X509; diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java index 6552bcf1f8..5a7bf32518 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java @@ -60,9 +60,9 @@ import org.thingsboard.server.common.data.device.profile.Lwm2mDeviceProfileTrans import org.thingsboard.server.common.data.device.profile.MqttDeviceProfileTransportConfiguration; import org.thingsboard.server.common.data.device.profile.ProtoTransportPayloadConfiguration; import org.thingsboard.server.common.data.device.profile.TransportPayloadTypeConfiguration; -import org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap.RPKLwM2MBootstrapLwM2MServerCredential; +import org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap.RPKLwM2MBootstrapServerCredential; import org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap.LwM2MBootstrapServerCredential; -import org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap.X509LwM2MBootstrapLwM2MServerCredential; +import org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap.X509LwM2MBootstrapServerCredential; import org.thingsboard.server.common.data.ota.OtaPackageType; import org.thingsboard.server.common.data.id.DeviceProfileId; import org.thingsboard.server.common.data.id.TenantId; @@ -419,8 +419,9 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D } } else if (transportConfiguration instanceof Lwm2mDeviceProfileTransportConfiguration) { LwM2MBootstrapServersConfiguration lwM2MBootstrapServersConfiguration = ((Lwm2mDeviceProfileTransportConfiguration) transportConfiguration).getBootstrap(); - validateLwm2mServersCredentialOfBootstrapForClient(lwM2MBootstrapServersConfiguration.getBootstrapServer(), "Bootstrap Server"); - validateLwm2mServersCredentialOfBootstrapForClient(lwM2MBootstrapServersConfiguration.getLwm2mServer(), "LwM2M Server"); + for (LwM2MBootstrapServerCredential bootstrapServerCredential : lwM2MBootstrapServersConfiguration.getServerConfiguration()) { + validateLwm2mServersCredentialOfBootstrapForClient(bootstrapServerCredential); + } } List profileAlarms = deviceProfile.getProfileData().getAlarms(); @@ -704,13 +705,15 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D } } - private void validateLwm2mServersCredentialOfBootstrapForClient(LwM2MBootstrapServerCredential bootstrapServerConfig, String server) { + private void validateLwm2mServersCredentialOfBootstrapForClient(LwM2MBootstrapServerCredential bootstrapServerConfig) { + String server; switch (bootstrapServerConfig.getSecurityMode()) { case NO_SEC: case PSK: break; case RPK: - RPKLwM2MBootstrapLwM2MServerCredential rpkServerCredentials = (RPKLwM2MBootstrapLwM2MServerCredential) bootstrapServerConfig; + RPKLwM2MBootstrapServerCredential rpkServerCredentials = (RPKLwM2MBootstrapServerCredential) bootstrapServerConfig; + server = rpkServerCredentials.isBootstrapServerIs() ? "Bootstrap Server" : "LwM2M Server"; if (StringUtils.isEmpty(rpkServerCredentials.getServerPublicKey())) { throw new DeviceCredentialsValidationException(server + " RPK public key must be specified!"); } @@ -723,7 +726,8 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D } break; case X509: - X509LwM2MBootstrapLwM2MServerCredential x509ServerCredentials = (X509LwM2MBootstrapLwM2MServerCredential) bootstrapServerConfig; + X509LwM2MBootstrapServerCredential x509ServerCredentials = (X509LwM2MBootstrapServerCredential) bootstrapServerConfig; + server = x509ServerCredentials.isBootstrapServerIs() ? "Bootstrap Server" : "LwM2M Server"; if (StringUtils.isEmpty(x509ServerCredentials.getServerPublicKey())) { throw new DeviceCredentialsValidationException(server + " X509 public key must be specified!"); } From 9ec919f175a7f74fe5f924f90bda7d144e4d3eb1 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Tue, 9 Nov 2021 15:26:42 +0200 Subject: [PATCH 090/432] lwm2m - start refactoring --- .../secure/LwM2MBootstrapSecurityStore.java | 56 +++++++++---------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapSecurityStore.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapSecurityStore.java index 2731c22d52..935e95c546 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapSecurityStore.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapSecurityStore.java @@ -158,34 +158,34 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore { LwM2MBootstrapConfig lwM2MBootstrapConfig = store.getBootstrapCredentialConfig(); if (lwM2MBootstrapConfig != null) { LwM2MBootstrapServersConfiguration bootstrapObject = getBootstrapParametersFromThingsboard(store.getDeviceProfile()); - lwM2MBootstrapConfig.setServers(JacksonUtil.fromString(JacksonUtil.toString(bootstrapObject.getServers()), LwM2MBootstrapServers.class)); - LwM2MServerBootstrap bootstrapServerProfile = JacksonUtil.fromString(JacksonUtil.toString(bootstrapObject.getBootstrapServer()), LwM2MServerBootstrap.class); - if (SecurityMode.NO_SEC != bootstrapServerProfile.getSecurityMode() && bootstrapServerProfile != null) { - bootstrapServerProfile.setSecurityHost(bootstrapServerProfile.getHost()); - bootstrapServerProfile.setSecurityPort(bootstrapServerProfile.getPort()); - } - LwM2MServerBootstrap profileLwm2mServer = JacksonUtil.fromString(JacksonUtil.toString(bootstrapObject.getLwm2mServer()), LwM2MServerBootstrap.class); - if (SecurityMode.NO_SEC != profileLwm2mServer.getSecurityMode() && profileLwm2mServer != null) { - profileLwm2mServer.setSecurityHost(profileLwm2mServer.getHost()); - profileLwm2mServer.setSecurityPort(profileLwm2mServer.getPort()); - } - UUID sessionUUiD = UUID.randomUUID(); - TransportProtos.SessionInfoProto sessionInfo = helper.getValidateSessionInfo(store.getMsg(), sessionUUiD.getMostSignificantBits(), sessionUUiD.getLeastSignificantBits()); - bsSessions.put(store.getEndpoint(), sessionInfo); - context.getTransportService().registerAsyncSession(sessionInfo, new LwM2mSessionMsgListener(null, null, null, sessionInfo, context.getTransportService())); - if (this.getValidatedSecurityMode(lwM2MBootstrapConfig.getBootstrapServer(), bootstrapServerProfile, lwM2MBootstrapConfig.getLwm2mServer(), profileLwm2mServer)) { - lwM2MBootstrapConfig.setBootstrapServer(new LwM2MServerBootstrap(lwM2MBootstrapConfig.getBootstrapServer(), bootstrapServerProfile)); - lwM2MBootstrapConfig.setLwm2mServer(new LwM2MServerBootstrap(lwM2MBootstrapConfig.getLwm2mServer(), profileLwm2mServer)); - String logMsg = String.format("%s: getParametersBootstrap: %s Access connect client with bootstrap server.", LOG_LWM2M_INFO, store.getEndpoint()); - helper.sendParametersOnThingsboardTelemetry(helper.getKvStringtoThingsboard(LOG_LWM2M_TELEMETRY, logMsg), sessionInfo); - return lwM2MBootstrapConfig; - } else { - log.error(" [{}] Different values SecurityMode between of client and profile.", store.getEndpoint()); - log.error("{} getParametersBootstrap: [{}] Different values SecurityMode between of client and profile.", LOG_LWM2M_ERROR, store.getEndpoint()); - String logMsg = String.format("%s: getParametersBootstrap: %s Different values SecurityMode between of client and profile.", LOG_LWM2M_ERROR, store.getEndpoint()); - helper.sendParametersOnThingsboardTelemetry(helper.getKvStringtoThingsboard(LOG_LWM2M_TELEMETRY, logMsg), sessionInfo); - return null; - } +// lwM2MBootstrapConfig.setServers(JacksonUtil.fromString(JacksonUtil.toString(bootstrapObject.getServers()), LwM2MBootstrapServers.class)); +// LwM2MServerBootstrap bootstrapServerProfile = JacksonUtil.fromString(JacksonUtil.toString(bootstrapObject.getBootstrapServer()), LwM2MServerBootstrap.class); +// if (SecurityMode.NO_SEC != bootstrapServerProfile.getSecurityMode() && bootstrapServerProfile != null) { +// bootstrapServerProfile.setSecurityHost(bootstrapServerProfile.getHost()); +// bootstrapServerProfile.setSecurityPort(bootstrapServerProfile.getPort()); +// } +// LwM2MServerBootstrap profileLwm2mServer = JacksonUtil.fromString(JacksonUtil.toString(bootstrapObject.getLwm2mServer()), LwM2MServerBootstrap.class); +// if (SecurityMode.NO_SEC != profileLwm2mServer.getSecurityMode() && profileLwm2mServer != null) { +// profileLwm2mServer.setSecurityHost(profileLwm2mServer.getHost()); +// profileLwm2mServer.setSecurityPort(profileLwm2mServer.getPort()); +// } +// UUID sessionUUiD = UUID.randomUUID(); +// TransportProtos.SessionInfoProto sessionInfo = helper.getValidateSessionInfo(store.getMsg(), sessionUUiD.getMostSignificantBits(), sessionUUiD.getLeastSignificantBits()); +// bsSessions.put(store.getEndpoint(), sessionInfo); +// context.getTransportService().registerAsyncSession(sessionInfo, new LwM2mSessionMsgListener(null, null, null, sessionInfo, context.getTransportService())); +// if (this.getValidatedSecurityMode(lwM2MBootstrapConfig.getBootstrapServer(), bootstrapServerProfile, lwM2MBootstrapConfig.getLwm2mServer(), profileLwm2mServer)) { +// lwM2MBootstrapConfig.setBootstrapServer(new LwM2MServerBootstrap(lwM2MBootstrapConfig.getBootstrapServer(), bootstrapServerProfile)); +// lwM2MBootstrapConfig.setLwm2mServer(new LwM2MServerBootstrap(lwM2MBootstrapConfig.getLwm2mServer(), profileLwm2mServer)); +// String logMsg = String.format("%s: getParametersBootstrap: %s Access connect client with bootstrap server.", LOG_LWM2M_INFO, store.getEndpoint()); +// helper.sendParametersOnThingsboardTelemetry(helper.getKvStringtoThingsboard(LOG_LWM2M_TELEMETRY, logMsg), sessionInfo); +// return lwM2MBootstrapConfig; +// } else { +// log.error(" [{}] Different values SecurityMode between of client and profile.", store.getEndpoint()); +// log.error("{} getParametersBootstrap: [{}] Different values SecurityMode between of client and profile.", LOG_LWM2M_ERROR, store.getEndpoint()); +// String logMsg = String.format("%s: getParametersBootstrap: %s Different values SecurityMode between of client and profile.", LOG_LWM2M_ERROR, store.getEndpoint()); +// helper.sendParametersOnThingsboardTelemetry(helper.getKvStringtoThingsboard(LOG_LWM2M_TELEMETRY, logMsg), sessionInfo); +// return null; +// } } log.error("Unable to decode Json or Certificate for [{}]", store.getEndpoint()); return null; From 0344b61ed3bd8f3ee8b4bf5e6f9a4390fe768d24 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Wed, 10 Nov 2021 08:38:04 +0200 Subject: [PATCH 091/432] lwm2m - change bootstrapConfig --- .../secure/LwM2MBootstrapConfig.java | 39 ++++++++++--------- .../secure/LwM2MBootstrapSecurityStore.java | 23 +++++------ ...LwM2mCredentialsSecurityInfoValidator.java | 23 ++++++----- .../TbLwM2MDtlsCertificateVerifier.java | 4 +- .../lwm2m/secure/TbLwM2MSecurityInfo.java | 2 +- ...tials.java => LwM2MClientCredentials.java} | 2 +- 6 files changed, 47 insertions(+), 46 deletions(-) rename common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/credentials/{LwM2MCredentials.java => LwM2MClientCredentials.java} (96%) diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapConfig.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapConfig.java index 29024d8f8f..2340267926 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapConfig.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapConfig.java @@ -16,6 +16,7 @@ package org.thingsboard.server.transport.lwm2m.bootstrap.secure; import com.fasterxml.jackson.annotation.JsonIgnore; +import lombok.AllArgsConstructor; import lombok.Data; import lombok.Getter; import lombok.Setter; @@ -31,10 +32,10 @@ import java.nio.charset.StandardCharsets; import java.util.List; @Data +@AllArgsConstructor public class LwM2MBootstrapConfig implements Serializable { - List serversConfiguration; - LwM2MBootstrapClientCredential bootstrapClientCredential; + List serverConfiguration; /* interface BootstrapSecurityConfig servers: BootstrapServersSecurityConfig, @@ -49,9 +50,9 @@ public class LwM2MBootstrapConfig implements Serializable { * notifIfDisabled: boolean, * binding: string * */ - @Getter - @Setter - private LwM2MBootstrapServers servers; +// @Getter +// @Setter +// private LwM2MBootstrapServers servers; /** -bootstrapServer, lwm2mServer * interface ServerSecurityConfig @@ -68,15 +69,15 @@ public class LwM2MBootstrapConfig implements Serializable { * */ @Getter @Setter - private LwM2MServerBootstrap bootstrapServer; + private LwM2MBootstrapClientCredential bootstrapServer; @Getter @Setter - private LwM2MServerBootstrap lwm2mServer; + private LwM2MBootstrapClientCredential lwm2mServer; + + public LwM2MBootstrapConfig(List serverConfiguration, LwM2MBootstrapClientCredential bootstrapClientCredential) { + this.serverConfiguration = serverConfiguration; - public LwM2MBootstrapConfig(List serversConfiguration, LwM2MBootstrapClientCredential bootstrapClientCredential) { - this.serversConfiguration = serversConfiguration; - this.bootstrapClientCredential = bootstrapClientCredential; } @JsonIgnore @@ -87,17 +88,17 @@ public class LwM2MBootstrapConfig implements Serializable { configBs.toDelete.add("/1"); /* Server Configuration (object 1) as defined in LWM2M 1.0.x TS. */ BootstrapConfig.ServerConfig server0 = new BootstrapConfig.ServerConfig(); - server0.shortId = servers.getShortId(); - server0.lifetime = servers.getLifetime(); - server0.defaultMinPeriod = servers.getDefaultMinPeriod(); - server0.notifIfDisabled = servers.isNotifIfDisabled(); - server0.binding = BindingMode.parse(servers.getBinding()); +// server0.shortId = servers.getShortId(); +// server0.lifetime = servers.getLifetime(); +// server0.defaultMinPeriod = servers.getDefaultMinPeriod(); +// server0.notifIfDisabled = servers.isNotifIfDisabled(); +// server0.binding = BindingMode.parse(servers.getBinding()); configBs.servers.put(0, server0); /* Security Configuration (object 0) as defined in LWM2M 1.0.x TS. Bootstrap instance = 0 */ - this.bootstrapServer.setBootstrapServerIs(true); - configBs.security.put(0, setServerSecurity(this.lwm2mServer.getHost(), this.lwm2mServer.getPort(), this.lwm2mServer.getSecurityHost(), this.lwm2mServer.getSecurityPort(), this.bootstrapServer.isBootstrapServerIs(), this.bootstrapServer.getSecurityMode(), this.bootstrapServer.getClientPublicKeyOrId(), this.bootstrapServer.getServerPublicKey(), this.bootstrapServer.getClientSecretKey(), this.bootstrapServer.getServerId())); - /* Security Configuration (object 0) as defined in LWM2M 1.0.x TS. Server instance = 1 */ - configBs.security.put(1, setServerSecurity(this.lwm2mServer.getHost(), this.lwm2mServer.getPort(), this.lwm2mServer.getSecurityHost(), this.lwm2mServer.getSecurityPort(), this.lwm2mServer.isBootstrapServerIs(), this.lwm2mServer.getSecurityMode(), this.lwm2mServer.getClientPublicKeyOrId(), this.lwm2mServer.getServerPublicKey(), this.lwm2mServer.getClientSecretKey(), this.lwm2mServer.getServerId())); +// this.bootstrapServer.setBootstrapServerIs(true); +// configBs.security.put(0, setServerSecurity(this.lwm2mServer.getHost(), this.lwm2mServer.getPort(), this.lwm2mServer.getSecurityHost(), this.lwm2mServer.getSecurityPort(), this.bootstrapServer.isBootstrapServerIs(), this.bootstrapServer.getSecurityMode(), this.bootstrapServer.getClientPublicKeyOrId(), this.bootstrapServer.getServerPublicKey(), this.bootstrapServer.getClientSecretKey(), this.bootstrapServer.getServerId())); +// /* Security Configuration (object 0) as defined in LWM2M 1.0.x TS. Server instance = 1 */ +// configBs.security.put(1, setServerSecurity(this.lwm2mServer.getHost(), this.lwm2mServer.getPort(), this.lwm2mServer.getSecurityHost(), this.lwm2mServer.getSecurityPort(), this.lwm2mServer.isBootstrapServerIs(), this.lwm2mServer.getSecurityMode(), this.lwm2mServer.getClientPublicKeyOrId(), this.lwm2mServer.getServerPublicKey(), this.lwm2mServer.getClientSecretKey(), this.lwm2mServer.getServerId())); return configBs; } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapSecurityStore.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapSecurityStore.java index 935e95c546..c2c32ca79c 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapSecurityStore.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapSecurityStore.java @@ -71,6 +71,7 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore { @Override public Iterator getAllByEndpoint(String endPoint) { + // TODO TbLwM2MSecurityInfo store = lwM2MCredentialsSecurityInfoValidator.getEndpointSecurityInfoByCredentialsId(endPoint, BOOTSTRAP); if (store.getBootstrapCredentialConfig() != null && store.getSecurityMode() != null) { /* add value to store from BootstrapJson */ @@ -125,20 +126,20 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore { switch (lwM2MBootstrapConfig.getBootstrapServer().getSecurityMode()) { /* Use RPK only */ case PSK: - store.setSecurityInfo(SecurityInfo.newPreSharedKeyInfo(store.getEndpoint(), - lwM2MBootstrapConfig.getBootstrapServer().getClientPublicKeyOrId(), - Hex.decodeHex(lwM2MBootstrapConfig.getBootstrapServer().getClientSecretKey().toCharArray()))); +// store.setSecurityInfo(SecurityInfo.newPreSharedKeyInfo(store.getEndpoint(), +// lwM2MBootstrapConfig.getBootstrapServer().getClientPublicKeyOrId(), +// Hex.decodeHex(lwM2MBootstrapConfig.getBootstrapServer().getClientSecretKey().toCharArray()))); store.setSecurityMode(SecurityMode.PSK); break; case RPK: - try { - store.setSecurityInfo(SecurityInfo.newRawPublicKeyInfo(store.getEndpoint(), - SecurityUtil.publicKey.decode(Hex.decodeHex(lwM2MBootstrapConfig.getBootstrapServer().getClientPublicKeyOrId().toCharArray())))); - store.setSecurityMode(SecurityMode.RPK); - break; - } catch (IOException | GeneralSecurityException e) { - log.error("Unable to decode Client public key for [{}] [{}]", store.getEndpoint(), e.getMessage()); - } +// try { +//// store.setSecurityInfo(SecurityInfo.newRawPublicKeyInfo(store.getEndpoint(), +//// SecurityUtil.publicKey.decode(Hex.decodeHex(lwM2MBootstrapConfig.getBootstrapServer().getClientPublicKeyOrId().toCharArray())))); +//// store.setSecurityMode(SecurityMode.RPK); +// break; +// } catch (IOException | GeneralSecurityException e) { +// log.error("Unable to decode Client public key for [{}] [{}]", store.getEndpoint(), e.getMessage()); +// } case X509: store.setSecurityInfo(SecurityInfo.newX509CertInfo(store.getEndpoint())); store.setSecurityMode(SecurityMode.X509); diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LwM2mCredentialsSecurityInfoValidator.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LwM2mCredentialsSecurityInfoValidator.java index 64498645c8..8b343ab02f 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LwM2mCredentialsSecurityInfoValidator.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LwM2mCredentialsSecurityInfoValidator.java @@ -32,7 +32,7 @@ import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsRes import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceLwM2MCredentialsRequestMsg; import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; -import org.thingsboard.server.transport.lwm2m.secure.credentials.LwM2MCredentials; +import org.thingsboard.server.transport.lwm2m.secure.credentials.LwM2MClientCredentials; import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportContext; import org.thingsboard.server.transport.lwm2m.server.client.LwM2MAuthException; import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mTypeServer; @@ -48,6 +48,7 @@ import static org.eclipse.leshan.core.SecurityMode.PSK; import static org.eclipse.leshan.core.SecurityMode.RPK; import static org.eclipse.leshan.core.SecurityMode.X509; import static org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mTypeServer.BOOTSTRAP; +import static org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mTypeServer.CLIENT; @Slf4j @Component @@ -87,25 +88,23 @@ public class LwM2mCredentialsSecurityInfoValidator { log.error("Failed to await credentials!", e); } - TbLwM2MSecurityInfo securityInfo = resultSecurityStore[0]; + return resultSecurityStore[0]; - if (securityInfo.getSecurityMode() == null) { - throw new LwM2MAuthException(); - } - - return securityInfo; +// if ((CLIENT.equals(keyValue) && securityInfo.getSecurityMode() == null) || +// (BOOTSTRAP.equals(keyValue) && securityInfo.getBootstrapCredentialConfig().getBootstrapServer()==null && securityInfo.getBootstrapCredentialConfig().getLwm2mServer()==null)){ +// throw new LwM2MAuthException(); +// } +// +// return securityInfo; } /** * Create new SecurityInfo - * @param endpoint - - * @param jsonStr - - * @param keyValue - * @return SecurityInfo */ private TbLwM2MSecurityInfo createSecurityInfo(String endpoint, String jsonStr, LwM2mTypeServer keyValue) { TbLwM2MSecurityInfo result = new TbLwM2MSecurityInfo(); - LwM2MCredentials credentials = JacksonUtil.fromString(jsonStr, LwM2MCredentials.class); + LwM2MClientCredentials credentials = JacksonUtil.fromString(jsonStr, LwM2MClientCredentials.class); if (credentials != null) { if (keyValue.equals(BOOTSTRAP)) { result.setBootstrapCredentialConfig(credentials.getBootstrap()); @@ -114,7 +113,7 @@ public class LwM2mCredentialsSecurityInfoValidator { endpoint = StringUtils.isNotEmpty(pskClientConfig.getEndpoint()) ? pskClientConfig.getEndpoint() : endpoint; } result.setEndpoint(endpoint); - result.setSecurityMode(credentials.getBootstrap().getBootstrapServer().getSecurityMode()); +// result.setSecurityMode(credentials.getBootstrap().getBootstrapServer().getSecurityMode()); } else { result.setEndpoint(credentials.getClient().getEndpoint()); switch (credentials.getClient().getSecurityConfigClientMode()) { diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MDtlsCertificateVerifier.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MDtlsCertificateVerifier.java index 0ef0d93f27..e3bfe986c3 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MDtlsCertificateVerifier.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MDtlsCertificateVerifier.java @@ -41,7 +41,7 @@ import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsRes import org.thingsboard.server.common.transport.util.SslUtil; import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; -import org.thingsboard.server.transport.lwm2m.secure.credentials.LwM2MCredentials; +import org.thingsboard.server.transport.lwm2m.secure.credentials.LwM2MClientCredentials; import org.thingsboard.server.transport.lwm2m.server.client.LwM2MAuthException; import org.thingsboard.server.transport.lwm2m.server.store.TbLwM2MDtlsSessionStore; import org.thingsboard.server.transport.lwm2m.server.store.TbMainSecurityStore; @@ -124,7 +124,7 @@ public class TbLwM2MDtlsCertificateVerifier implements NewAdvancedCertificateVer } ValidateDeviceCredentialsResponse msg = securityInfo != null ? securityInfo.getMsg() : null; if (msg != null && org.thingsboard.server.common.data.StringUtils.isNotEmpty(msg.getCredentials())) { - LwM2MCredentials credentials = JacksonUtil.fromString(msg.getCredentials(), LwM2MCredentials.class); + LwM2MClientCredentials credentials = JacksonUtil.fromString(msg.getCredentials(), LwM2MClientCredentials.class); if (!credentials.getClient().getSecurityConfigClientMode().equals(LwM2MSecurityMode.X509)) { continue; } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MSecurityInfo.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MSecurityInfo.java index bc45a77b58..61774228c0 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MSecurityInfo.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MSecurityInfo.java @@ -30,9 +30,9 @@ public class TbLwM2MSecurityInfo implements Serializable { private ValidateDeviceCredentialsResponse msg; private SecurityInfo securityInfo; private SecurityMode securityMode; + private DeviceProfile deviceProfile; /** bootstrap */ - private DeviceProfile deviceProfile; private LwM2MBootstrapConfig bootstrapCredentialConfig; private String endpoint; private BootstrapConfig bootstrapConfig; diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/credentials/LwM2MCredentials.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/credentials/LwM2MClientCredentials.java similarity index 96% rename from common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/credentials/LwM2MCredentials.java rename to common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/credentials/LwM2MClientCredentials.java index 878188bffc..a10e5ec231 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/credentials/LwM2MCredentials.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/credentials/LwM2MClientCredentials.java @@ -20,7 +20,7 @@ import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MClientCr import org.thingsboard.server.transport.lwm2m.bootstrap.secure.LwM2MBootstrapConfig; @Data -public class LwM2MCredentials { +public class LwM2MClientCredentials { private LwM2MClientCredential client; private LwM2MBootstrapConfig bootstrap; } From 5a7673a118787834f1ec06d5b742af3cc777383b Mon Sep 17 00:00:00 2001 From: hanyuepeng Date: Wed, 10 Nov 2021 17:16:17 +0800 Subject: [PATCH 092/432] fix(chinese translate): fix some display problem In Api Usage module,when use chinese ,there are some display problem because of the lose of the translate items --- ui-ngx/src/assets/locale/locale.constant-zh_CN.json | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/ui-ngx/src/assets/locale/locale.constant-zh_CN.json b/ui-ngx/src/assets/locale/locale.constant-zh_CN.json index 270fd6ad4e..39f4063b49 100644 --- a/ui-ngx/src/assets/locale/locale.constant-zh_CN.json +++ b/ui-ngx/src/assets/locale/locale.constant-zh_CN.json @@ -388,7 +388,14 @@ "transport-messages": "传输消息", "transport-monthly-activity": "Transport monthly activity", "view-details": "查看详细信息", - "view-statistics": "查看统计信息" + "view-statistics": "查看统计信息", + "alarm":"警告", + "alarms-created": "创建警告数", + "alarms-created-hourly-activity":"Alarms created hourly activity", + "alarms-created-daily-activity": "Alarms created daily activity", + "alarms-created-monthly-activity": "Alarms created monthly activity", + "notifications": "通知", + "notifications-hourly-activity": "Notifications hourly activity" }, "asset": { "add": "添加资产", From 524ff2f980cf4a5baa963dc29aaf2455e1e7c4d7 Mon Sep 17 00:00:00 2001 From: Vladyslav Date: Wed, 10 Nov 2021 14:36:28 +0200 Subject: [PATCH 093/432] Update locale.constant-zh_CN.json --- ui-ngx/src/assets/locale/locale.constant-zh_CN.json | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/ui-ngx/src/assets/locale/locale.constant-zh_CN.json b/ui-ngx/src/assets/locale/locale.constant-zh_CN.json index 39f4063b49..f8e7e810fe 100644 --- a/ui-ngx/src/assets/locale/locale.constant-zh_CN.json +++ b/ui-ngx/src/assets/locale/locale.constant-zh_CN.json @@ -391,11 +391,7 @@ "view-statistics": "查看统计信息", "alarm":"警告", "alarms-created": "创建警告数", - "alarms-created-hourly-activity":"Alarms created hourly activity", - "alarms-created-daily-activity": "Alarms created daily activity", - "alarms-created-monthly-activity": "Alarms created monthly activity", - "notifications": "通知", - "notifications-hourly-activity": "Notifications hourly activity" + "notifications": "通知" }, "asset": { "add": "添加资产", From 781ef66f0ba202ef3b8092ad397401f38609820b Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Thu, 11 Nov 2021 15:09:34 +0200 Subject: [PATCH 094/432] lwm2m - upDate lwm2mServer --- ...2mDeviceProfileTransportConfiguration.java | 6 +- .../LwM2MBootstrapServersConfiguration.java | 2 +- .../LwM2MTransportBootstrapService.java | 9 +- .../secure/LwM2MBootstrapConfig.java | 88 +++++++++------ .../LwM2mDefaultBootstrapSessionManager.java | 2 + .../LwM2MBootstrapSecurityStore.java | 105 ++++++++++-------- .../LwM2MInMemoryBootstrapConfigStore.java | 2 +- ...LwM2mCredentialsSecurityInfoValidator.java | 79 +++++++------ .../lwm2m/secure/TbLwM2MSecurityInfo.java | 5 +- .../server/store/TbLwM2mSecurityStore.java | 8 +- .../lwm2m/utils/LwM2MTransportUtil.java | 4 +- .../dao/device/DeviceProfileServiceImpl.java | 5 +- 12 files changed, 175 insertions(+), 140 deletions(-) rename common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/{secure => store}/LwM2MBootstrapSecurityStore.java (70%) rename common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/{secure => store}/LwM2MInMemoryBootstrapConfigStore.java (97%) diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/Lwm2mDeviceProfileTransportConfiguration.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/Lwm2mDeviceProfileTransportConfiguration.java index 1bc6ce8004..0c1441f031 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/Lwm2mDeviceProfileTransportConfiguration.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/Lwm2mDeviceProfileTransportConfiguration.java @@ -17,17 +17,19 @@ package org.thingsboard.server.common.data.device.profile; import lombok.Data; import org.thingsboard.server.common.data.DeviceTransportType; -import org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap.LwM2MBootstrapServersConfiguration; +import org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap.LwM2MBootstrapServerCredential; import org.thingsboard.server.common.data.device.profile.lwm2m.OtherConfiguration; import org.thingsboard.server.common.data.device.profile.lwm2m.TelemetryMappingConfiguration; +import java.util.List; + @Data public class Lwm2mDeviceProfileTransportConfiguration implements DeviceProfileTransportConfiguration { private static final long serialVersionUID = 6257277825459600068L; private TelemetryMappingConfiguration observeAttr; - private LwM2MBootstrapServersConfiguration bootstrap; + private List bootstrap; private OtherConfiguration clientLwM2mSettings; @Override diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/LwM2MBootstrapServersConfiguration.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/LwM2MBootstrapServersConfiguration.java index 15d573b50e..0ff1dc2eb5 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/LwM2MBootstrapServersConfiguration.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/LwM2MBootstrapServersConfiguration.java @@ -22,6 +22,6 @@ import java.util.List; @Data public class LwM2MBootstrapServersConfiguration { - List serverConfiguration; + List bootstrap; } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportBootstrapService.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportBootstrapService.java index 3e36d86e8e..ee14a9265d 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportBootstrapService.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportBootstrapService.java @@ -17,7 +17,6 @@ package org.thingsboard.server.transport.lwm2m.bootstrap; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.eclipse.californium.elements.util.SslContextUtil; import org.eclipse.californium.scandium.config.DtlsConnectorConfig; import org.eclipse.leshan.server.bootstrap.BootstrapSessionManager; import org.eclipse.leshan.server.californium.bootstrap.LeshanBootstrapServer; @@ -26,8 +25,8 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.stereotype.Component; import org.thingsboard.server.common.transport.TransportService; import org.thingsboard.server.common.transport.config.ssl.SslCredentials; -import org.thingsboard.server.transport.lwm2m.bootstrap.secure.LwM2MBootstrapSecurityStore; -import org.thingsboard.server.transport.lwm2m.bootstrap.secure.LwM2MInMemoryBootstrapConfigStore; +import org.thingsboard.server.transport.lwm2m.bootstrap.store.LwM2MBootstrapSecurityStore; +import org.thingsboard.server.transport.lwm2m.bootstrap.store.LwM2MInMemoryBootstrapConfigStore; import org.thingsboard.server.transport.lwm2m.bootstrap.secure.LwM2mDefaultBootstrapSessionManager; import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportBootstrapConfig; import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; @@ -35,10 +34,6 @@ import org.thingsboard.server.transport.lwm2m.server.DefaultLwM2mTransportServic import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; -import java.security.KeyStore; -import java.security.KeyStoreException; -import java.security.PrivateKey; -import java.security.PublicKey; import java.security.cert.X509Certificate; import static org.thingsboard.server.transport.lwm2m.server.LwM2MNetworkConfig.getCoapConfig; diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapConfig.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapConfig.java index 2340267926..792cf71c67 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapConfig.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapConfig.java @@ -16,23 +16,27 @@ package org.thingsboard.server.transport.lwm2m.bootstrap.secure; import com.fasterxml.jackson.annotation.JsonIgnore; -import lombok.AllArgsConstructor; import lombok.Data; import lombok.Getter; import lombok.Setter; +import lombok.extern.slf4j.Slf4j; import org.eclipse.leshan.core.SecurityMode; import org.eclipse.leshan.core.request.BindingMode; import org.eclipse.leshan.core.util.Hex; import org.eclipse.leshan.server.bootstrap.BootstrapConfig; +import org.thingsboard.server.common.data.device.credentials.lwm2m.AbstractLwM2MBootstrapClientCredentialWithKeys; import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MBootstrapClientCredential; +import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MSecurityMode; +import org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap.AbstractLwM2MBootstrapServerCredential; import org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap.LwM2MBootstrapServerCredential; import java.io.Serializable; import java.nio.charset.StandardCharsets; import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; +@Slf4j @Data -@AllArgsConstructor public class LwM2MBootstrapConfig implements Serializable { List serverConfiguration; @@ -75,52 +79,68 @@ public class LwM2MBootstrapConfig implements Serializable { @Setter private LwM2MBootstrapClientCredential lwm2mServer; - public LwM2MBootstrapConfig(List serverConfiguration, LwM2MBootstrapClientCredential bootstrapClientCredential) { + public LwM2MBootstrapConfig(){}; + + public LwM2MBootstrapConfig(List serverConfiguration, LwM2MBootstrapClientCredential bootstrapClientServer, LwM2MBootstrapClientCredential lwm2mClientServer) { this.serverConfiguration = serverConfiguration; + this.bootstrapServer = bootstrapClientServer; + this.lwm2mServer = lwm2mClientServer; } @JsonIgnore public BootstrapConfig getLwM2MBootstrapConfig() { BootstrapConfig configBs = new BootstrapConfig(); - /* Delete old security objects */ + AtomicInteger index = new AtomicInteger(); + /** Delete old security/config objects in LwM2mDefaultBootstrapSessionManager -> initTasks */ configBs.toDelete.add("/0"); configBs.toDelete.add("/1"); - /* Server Configuration (object 1) as defined in LWM2M 1.0.x TS. */ - BootstrapConfig.ServerConfig server0 = new BootstrapConfig.ServerConfig(); -// server0.shortId = servers.getShortId(); -// server0.lifetime = servers.getLifetime(); -// server0.defaultMinPeriod = servers.getDefaultMinPeriod(); -// server0.notifIfDisabled = servers.isNotifIfDisabled(); -// server0.binding = BindingMode.parse(servers.getBinding()); - configBs.servers.put(0, server0); - /* Security Configuration (object 0) as defined in LWM2M 1.0.x TS. Bootstrap instance = 0 */ -// this.bootstrapServer.setBootstrapServerIs(true); -// configBs.security.put(0, setServerSecurity(this.lwm2mServer.getHost(), this.lwm2mServer.getPort(), this.lwm2mServer.getSecurityHost(), this.lwm2mServer.getSecurityPort(), this.bootstrapServer.isBootstrapServerIs(), this.bootstrapServer.getSecurityMode(), this.bootstrapServer.getClientPublicKeyOrId(), this.bootstrapServer.getServerPublicKey(), this.bootstrapServer.getClientSecretKey(), this.bootstrapServer.getServerId())); -// /* Security Configuration (object 0) as defined in LWM2M 1.0.x TS. Server instance = 1 */ -// configBs.security.put(1, setServerSecurity(this.lwm2mServer.getHost(), this.lwm2mServer.getPort(), this.lwm2mServer.getSecurityHost(), this.lwm2mServer.getSecurityPort(), this.lwm2mServer.isBootstrapServerIs(), this.lwm2mServer.getSecurityMode(), this.lwm2mServer.getClientPublicKeyOrId(), this.lwm2mServer.getServerPublicKey(), this.lwm2mServer.getClientSecretKey(), this.lwm2mServer.getServerId())); + serverConfiguration.forEach(serverCredential -> { + BootstrapConfig.ServerConfig serverConfig = new BootstrapConfig.ServerConfig(); + serverConfig.shortId = ((AbstractLwM2MBootstrapServerCredential)serverCredential).getShortServerId(); + serverConfig.lifetime = ((AbstractLwM2MBootstrapServerCredential)serverCredential).getLifetime(); + serverConfig.defaultMinPeriod = ((AbstractLwM2MBootstrapServerCredential)serverCredential).getDefaultMinPeriod(); + serverConfig.notifIfDisabled = ((AbstractLwM2MBootstrapServerCredential)serverCredential).isNotifIfDisabled(); + serverConfig.binding = BindingMode.parse(((AbstractLwM2MBootstrapServerCredential)serverCredential).getBinding()); + int k = index.get(); + configBs.servers.put(k, serverConfig); + BootstrapConfig.ServerSecurity serverSecurity = setServerSecurity((AbstractLwM2MBootstrapServerCredential)serverCredential, serverCredential.getSecurityMode()); + configBs.security.put(k, serverSecurity); + index.getAndIncrement(); + + }); return configBs; } - private BootstrapConfig.ServerSecurity setServerSecurity(String host, Integer port, String securityHost, Integer securityPort, boolean bootstrapServer, SecurityMode securityMode, String clientPublicKey, String serverPublicKey, String secretKey, int serverId) { + private BootstrapConfig.ServerSecurity setServerSecurity(AbstractLwM2MBootstrapServerCredential serverCredential, LwM2MSecurityMode securityMode) { BootstrapConfig.ServerSecurity serverSecurity = new BootstrapConfig.ServerSecurity(); - if (securityMode.equals(SecurityMode.NO_SEC)) { - serverSecurity.uri = "coap://" + host + ":" + Integer.toString(port); - } else { - serverSecurity.uri = "coaps://" + securityHost + ":" + Integer.toString(securityPort); + String serverUri = "coap://"; + byte[] publicKeyOrId = new byte[]{};; + byte[] secretKey = new byte[]{};; + serverSecurity.serverId = serverCredential.getShortServerId(); + serverSecurity.securityMode = SecurityMode.valueOf(securityMode.name()); + serverSecurity.bootstrapServer = serverCredential.isBootstrapServerIs(); + if (!LwM2MSecurityMode.NO_SEC.equals(securityMode)) { + serverUri = "coaps://"; + if (serverSecurity.bootstrapServer) { + publicKeyOrId = ((AbstractLwM2MBootstrapClientCredentialWithKeys)this.bootstrapServer).getDecodedClientPublicKeyOrId(); + secretKey = ((AbstractLwM2MBootstrapClientCredentialWithKeys)this.bootstrapServer).getDecodedClientSecretKey(); + + } else { + publicKeyOrId = ((AbstractLwM2MBootstrapClientCredentialWithKeys)this.lwm2mServer).getDecodedClientPublicKeyOrId(); + secretKey = ((AbstractLwM2MBootstrapClientCredentialWithKeys)this.lwm2mServer).getDecodedClientSecretKey(); + } + } - serverSecurity.bootstrapServer = bootstrapServer; - serverSecurity.securityMode = securityMode; - serverSecurity.publicKeyOrId = setPublicKeyOrId(clientPublicKey, securityMode); - serverSecurity.serverPublicKey = (serverPublicKey != null && !serverPublicKey.isEmpty()) ? Hex.decodeHex(serverPublicKey.toCharArray()) : new byte[]{}; - serverSecurity.secretKey = (secretKey != null && !secretKey.isEmpty()) ? Hex.decodeHex(secretKey.toCharArray()) : new byte[]{}; - serverSecurity.serverId = serverId; + serverUri += (((serverCredential.getHost().equals("0.0.0.0") ? "localhost" : serverCredential.getHost()) + ":" + serverCredential.getPort())); + log.info("serverSecurity.uri = [{}]", serverUri); + log.info("publicKeyOrId [{}]", Hex.encodeHexString(publicKeyOrId)); + log.info("secretKey [{}]", Hex.encodeHexString(secretKey)); + log.info("server [{}]", Hex.encodeHexString(serverCredential.getDecodedCServerPublicKey())); + serverSecurity.uri = serverUri; + serverSecurity.publicKeyOrId = publicKeyOrId; + serverSecurity.secretKey = secretKey; + serverSecurity.serverPublicKey = serverCredential.getDecodedCServerPublicKey(); return serverSecurity; } - - private byte[] setPublicKeyOrId(String publicKeyOrIdStr, SecurityMode securityMode) { - return (publicKeyOrIdStr == null || publicKeyOrIdStr.isEmpty()) ? new byte[]{} : - SecurityMode.PSK.equals(securityMode) ? publicKeyOrIdStr.getBytes(StandardCharsets.UTF_8) : - Hex.decodeHex(publicKeyOrIdStr.toCharArray()); - } } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2mDefaultBootstrapSessionManager.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2mDefaultBootstrapSessionManager.java index 097b69f806..4f47079bbe 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2mDefaultBootstrapSessionManager.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2mDefaultBootstrapSessionManager.java @@ -34,6 +34,7 @@ import org.eclipse.leshan.server.security.BootstrapSecurityStore; import org.eclipse.leshan.server.security.SecurityChecker; import org.eclipse.leshan.server.security.SecurityInfo; import org.thingsboard.server.common.transport.TransportService; +import org.thingsboard.server.transport.lwm2m.bootstrap.store.LwM2MBootstrapSecurityStore; import org.thingsboard.server.transport.lwm2m.server.client.LwM2MAuthException; import java.util.ArrayList; @@ -118,6 +119,7 @@ public class LwM2mDefaultBootstrapSessionManager extends DefaultBootstrapSession session.setModel(modelProvider.getObjectModel(session, tasks.supportedObjects)); // set Requests to Send + log.info("tasks.requestsToSend = [{}]", tasks.requestsToSend); session.setRequests(tasks.requestsToSend); // prepare list where we will store Responses diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapSecurityStore.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MBootstrapSecurityStore.java similarity index 70% rename from common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapSecurityStore.java rename to common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MBootstrapSecurityStore.java index c2c32ca79c..ee973f3a23 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapSecurityStore.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MBootstrapSecurityStore.java @@ -13,12 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.transport.lwm2m.bootstrap.secure; +package org.thingsboard.server.transport.lwm2m.bootstrap.store; import lombok.extern.slf4j.Slf4j; import org.eclipse.leshan.core.SecurityMode; -import org.eclipse.leshan.core.util.Hex; -import org.eclipse.leshan.core.util.SecurityUtil; import org.eclipse.leshan.server.bootstrap.BootstrapConfig; import org.eclipse.leshan.server.bootstrap.EditableBootstrapConfigStore; import org.eclipse.leshan.server.bootstrap.InvalidConfigurationException; @@ -26,9 +24,10 @@ import org.eclipse.leshan.server.security.BootstrapSecurityStore; import org.eclipse.leshan.server.security.SecurityInfo; import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.stereotype.Service; -import org.thingsboard.common.util.JacksonUtil; -import org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap.LwM2MBootstrapServersConfiguration; +import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MSecurityMode; +import org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap.AbstractLwM2MBootstrapServerCredential; import org.thingsboard.server.gen.transport.TransportProtos; +import org.thingsboard.server.transport.lwm2m.bootstrap.secure.LwM2MBootstrapConfig; import org.thingsboard.server.transport.lwm2m.secure.LwM2mCredentialsSecurityInfoValidator; import org.thingsboard.server.transport.lwm2m.secure.TbLwM2MSecurityInfo; import org.thingsboard.server.transport.lwm2m.server.LwM2mSessionMsgListener; @@ -42,12 +41,12 @@ import java.util.Iterator; import java.util.Map; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicBoolean; import static org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mTypeServer.BOOTSTRAP; import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.LOG_LWM2M_ERROR; import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.LOG_LWM2M_INFO; import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.LOG_LWM2M_TELEMETRY; -import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.getBootstrapParametersFromThingsboard; @Slf4j @Service("LwM2MBootstrapSecurityStore") @@ -73,7 +72,7 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore { public Iterator getAllByEndpoint(String endPoint) { // TODO TbLwM2MSecurityInfo store = lwM2MCredentialsSecurityInfoValidator.getEndpointSecurityInfoByCredentialsId(endPoint, BOOTSTRAP); - if (store.getBootstrapCredentialConfig() != null && store.getSecurityMode() != null) { + if (store.getBootstrapCredentialConfig() != null) { /* add value to store from BootstrapJson */ this.setBootstrapConfigScurityInfo(store); BootstrapConfig bsConfigNew = store.getBootstrapConfig(); @@ -123,15 +122,15 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore { LwM2MBootstrapConfig lwM2MBootstrapConfig = this.getParametersBootstrap(store); if (lwM2MBootstrapConfig != null) { /* Security info */ - switch (lwM2MBootstrapConfig.getBootstrapServer().getSecurityMode()) { - /* Use RPK only */ - case PSK: +// switch (lwM2MBootstrapConfig.getBootstrapServer().getSecurityMode()) { +// /* Use RPK only */ +// case PSK: // store.setSecurityInfo(SecurityInfo.newPreSharedKeyInfo(store.getEndpoint(), // lwM2MBootstrapConfig.getBootstrapServer().getClientPublicKeyOrId(), // Hex.decodeHex(lwM2MBootstrapConfig.getBootstrapServer().getClientSecretKey().toCharArray()))); - store.setSecurityMode(SecurityMode.PSK); - break; - case RPK: +// store.setSecurityMode(SecurityMode.PSK); +// break; +// case RPK: // try { //// store.setSecurityInfo(SecurityInfo.newRawPublicKeyInfo(store.getEndpoint(), //// SecurityUtil.publicKey.decode(Hex.decodeHex(lwM2MBootstrapConfig.getBootstrapServer().getClientPublicKeyOrId().toCharArray())))); @@ -140,16 +139,16 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore { // } catch (IOException | GeneralSecurityException e) { // log.error("Unable to decode Client public key for [{}] [{}]", store.getEndpoint(), e.getMessage()); // } - case X509: - store.setSecurityInfo(SecurityInfo.newX509CertInfo(store.getEndpoint())); - store.setSecurityMode(SecurityMode.X509); - break; - case NO_SEC: - store.setSecurityMode(SecurityMode.NO_SEC); - store.setSecurityInfo(null); - break; - default: - } +// case X509: +// store.setSecurityInfo(SecurityInfo.newX509CertInfo(store.getEndpoint())); +// store.setSecurityMode(SecurityMode.X509); +// break; +// case NO_SEC: +// store.setSecurityMode(SecurityMode.NO_SEC); +// store.setSecurityInfo(null); +// break; +// default: +// } BootstrapConfig bootstrapConfig = lwM2MBootstrapConfig.getLwM2MBootstrapConfig(); store.setBootstrapConfig(bootstrapConfig); } @@ -158,7 +157,7 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore { private LwM2MBootstrapConfig getParametersBootstrap(TbLwM2MSecurityInfo store) { LwM2MBootstrapConfig lwM2MBootstrapConfig = store.getBootstrapCredentialConfig(); if (lwM2MBootstrapConfig != null) { - LwM2MBootstrapServersConfiguration bootstrapObject = getBootstrapParametersFromThingsboard(store.getDeviceProfile()); +// LwM2MBootstrapServersConfiguration bootstrapObject = getBootstrapParametersFromThingsboard(store.getDeviceProfile()); // lwM2MBootstrapConfig.setServers(JacksonUtil.fromString(JacksonUtil.toString(bootstrapObject.getServers()), LwM2MBootstrapServers.class)); // LwM2MServerBootstrap bootstrapServerProfile = JacksonUtil.fromString(JacksonUtil.toString(bootstrapObject.getBootstrapServer()), LwM2MServerBootstrap.class); // if (SecurityMode.NO_SEC != bootstrapServerProfile.getSecurityMode() && bootstrapServerProfile != null) { @@ -170,23 +169,25 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore { // profileLwm2mServer.setSecurityHost(profileLwm2mServer.getHost()); // profileLwm2mServer.setSecurityPort(profileLwm2mServer.getPort()); // } -// UUID sessionUUiD = UUID.randomUUID(); -// TransportProtos.SessionInfoProto sessionInfo = helper.getValidateSessionInfo(store.getMsg(), sessionUUiD.getMostSignificantBits(), sessionUUiD.getLeastSignificantBits()); -// bsSessions.put(store.getEndpoint(), sessionInfo); -// context.getTransportService().registerAsyncSession(sessionInfo, new LwM2mSessionMsgListener(null, null, null, sessionInfo, context.getTransportService())); -// if (this.getValidatedSecurityMode(lwM2MBootstrapConfig.getBootstrapServer(), bootstrapServerProfile, lwM2MBootstrapConfig.getLwm2mServer(), profileLwm2mServer)) { + + + UUID sessionUUiD = UUID.randomUUID(); + TransportProtos.SessionInfoProto sessionInfo = helper.getValidateSessionInfo(store.getMsg(), sessionUUiD.getMostSignificantBits(), sessionUUiD.getLeastSignificantBits()); + bsSessions.put(store.getEndpoint(), sessionInfo); + context.getTransportService().registerAsyncSession(sessionInfo, new LwM2mSessionMsgListener(null, null, null, sessionInfo, context.getTransportService())); + if (this.getValidatedSecurityMode(lwM2MBootstrapConfig)) { // lwM2MBootstrapConfig.setBootstrapServer(new LwM2MServerBootstrap(lwM2MBootstrapConfig.getBootstrapServer(), bootstrapServerProfile)); // lwM2MBootstrapConfig.setLwm2mServer(new LwM2MServerBootstrap(lwM2MBootstrapConfig.getLwm2mServer(), profileLwm2mServer)); -// String logMsg = String.format("%s: getParametersBootstrap: %s Access connect client with bootstrap server.", LOG_LWM2M_INFO, store.getEndpoint()); -// helper.sendParametersOnThingsboardTelemetry(helper.getKvStringtoThingsboard(LOG_LWM2M_TELEMETRY, logMsg), sessionInfo); -// return lwM2MBootstrapConfig; -// } else { -// log.error(" [{}] Different values SecurityMode between of client and profile.", store.getEndpoint()); -// log.error("{} getParametersBootstrap: [{}] Different values SecurityMode between of client and profile.", LOG_LWM2M_ERROR, store.getEndpoint()); -// String logMsg = String.format("%s: getParametersBootstrap: %s Different values SecurityMode between of client and profile.", LOG_LWM2M_ERROR, store.getEndpoint()); -// helper.sendParametersOnThingsboardTelemetry(helper.getKvStringtoThingsboard(LOG_LWM2M_TELEMETRY, logMsg), sessionInfo); -// return null; -// } + String logMsg = String.format("%s: getParametersBootstrap: %s Access connect client with bootstrap server.", LOG_LWM2M_INFO, store.getEndpoint()); + helper.sendParametersOnThingsboardTelemetry(helper.getKvStringtoThingsboard(LOG_LWM2M_TELEMETRY, logMsg), sessionInfo); + return lwM2MBootstrapConfig; + } else { + log.error(" [{}] Different values SecurityMode between of client and profile.", store.getEndpoint()); + log.error("{} getParametersBootstrap: [{}] Different values SecurityMode between of client and profile.", LOG_LWM2M_ERROR, store.getEndpoint()); + String logMsg = String.format("%s: getParametersBootstrap: %s Different values SecurityMode between of client and profile.", LOG_LWM2M_ERROR, store.getEndpoint()); + helper.sendParametersOnThingsboardTelemetry(helper.getKvStringtoThingsboard(LOG_LWM2M_TELEMETRY, logMsg), sessionInfo); + return null; + } } log.error("Unable to decode Json or Certificate for [{}]", store.getEndpoint()); return null; @@ -196,15 +197,27 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore { * Bootstrap security have to sync between (bootstrapServer in credential and bootstrapServer in profile) * and (lwm2mServer in credential and lwm2mServer in profile * - * @param bootstrapFromCredential - Bootstrap -> Security of bootstrapServer in credential - * @param bootstrapServerProfile - Bootstrap -> Security of bootstrapServer in profile - * @param lwm2mFromCredential - Bootstrap -> Security of lwm2mServer in credential - * @param profileLwm2mServer - Bootstrap -> Security of lwm2mServer in profile * @return false if not sync between SecurityMode of Bootstrap credential and profile */ - private boolean getValidatedSecurityMode(LwM2MServerBootstrap bootstrapFromCredential, LwM2MServerBootstrap bootstrapServerProfile, LwM2MServerBootstrap lwm2mFromCredential, LwM2MServerBootstrap profileLwm2mServer) { - return (bootstrapFromCredential.getSecurityMode().equals(bootstrapServerProfile.getSecurityMode()) && - lwm2mFromCredential.getSecurityMode().equals(profileLwm2mServer.getSecurityMode())); +// private boolean getValidatedSecurityMode(LwM2MServerBootstrap bootstrapFromCredential, LwM2MServerBootstrap bootstrapServerProfile, LwM2MServerBootstrap lwm2mFromCredential, LwM2MServerBootstrap profileLwm2mServer) { + private boolean getValidatedSecurityMode(LwM2MBootstrapConfig lwM2MBootstrapConfig) { + LwM2MSecurityMode bootstrapServerSecurityMode = lwM2MBootstrapConfig.getBootstrapServer().getSecurityMode(); + LwM2MSecurityMode lwm2mServerSecurityMode = lwM2MBootstrapConfig.getLwm2mServer().getSecurityMode(); + AtomicBoolean validBs = new AtomicBoolean(true); + AtomicBoolean validLw = new AtomicBoolean(true); + lwM2MBootstrapConfig.getServerConfiguration().forEach(serverCredential -> { + if (((AbstractLwM2MBootstrapServerCredential)serverCredential).isBootstrapServerIs()) { + if (!bootstrapServerSecurityMode.equals(serverCredential.getSecurityMode())) { + validBs.set(false); + } + } + else { + if (!lwm2mServerSecurityMode.equals(serverCredential.getSecurityMode())) { + validLw.set(false); + } + } + }); + return validBs.get()&validLw.get(); } public TransportProtos.SessionInfoProto getSessionByEndpoint(String endpoint) { diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MInMemoryBootstrapConfigStore.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MInMemoryBootstrapConfigStore.java similarity index 97% rename from common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MInMemoryBootstrapConfigStore.java rename to common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MInMemoryBootstrapConfigStore.java index ba3880c6bc..2fa470a58e 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MInMemoryBootstrapConfigStore.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MInMemoryBootstrapConfigStore.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.transport.lwm2m.bootstrap.secure; +package org.thingsboard.server.transport.lwm2m.bootstrap.store; import lombok.extern.slf4j.Slf4j; import org.eclipse.leshan.core.request.Identity; diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LwM2mCredentialsSecurityInfoValidator.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LwM2mCredentialsSecurityInfoValidator.java index 8b343ab02f..f75aca52c3 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LwM2mCredentialsSecurityInfoValidator.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LwM2mCredentialsSecurityInfoValidator.java @@ -24,13 +24,14 @@ import org.springframework.stereotype.Component; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MClientCredential; -import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MSecurityMode; import org.thingsboard.server.common.data.device.credentials.lwm2m.PSKClientCredential; import org.thingsboard.server.common.data.device.credentials.lwm2m.RPKClientCredential; +import org.thingsboard.server.common.data.device.profile.Lwm2mDeviceProfileTransportConfiguration; import org.thingsboard.server.common.transport.TransportServiceCallback; import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse; import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceLwM2MCredentialsRequestMsg; import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; +import org.thingsboard.server.transport.lwm2m.bootstrap.secure.LwM2MBootstrapConfig; import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; import org.thingsboard.server.transport.lwm2m.secure.credentials.LwM2MClientCredentials; import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportContext; @@ -68,17 +69,16 @@ public class LwM2mCredentialsSecurityInfoValidator { @Override public void onSuccess(ValidateDeviceCredentialsResponse msg) { log.trace("Validated credentials: [{}] [{}]", credentialsId, msg); - String credentialsBody = msg.getCredentials(); - resultSecurityStore[0] = createSecurityInfo(credentialsId, credentialsBody, keyValue); - resultSecurityStore[0].setMsg(msg); - resultSecurityStore[0].setDeviceProfile(msg.getDeviceProfile()); + resultSecurityStore[0] = createSecurityInfo(credentialsId, msg, keyValue); latch.countDown(); } @Override public void onError(Throwable e) { log.trace("[{}] [{}] Failed to process credentials ", credentialsId, e); - resultSecurityStore[0] = createSecurityInfo(credentialsId, null, null); + TbLwM2MSecurityInfo result = new TbLwM2MSecurityInfo(); + result.setEndpoint(credentialsId); + resultSecurityStore[0] = result; latch.countDown(); } }); @@ -88,50 +88,47 @@ public class LwM2mCredentialsSecurityInfoValidator { log.error("Failed to await credentials!", e); } - return resultSecurityStore[0]; - -// if ((CLIENT.equals(keyValue) && securityInfo.getSecurityMode() == null) || -// (BOOTSTRAP.equals(keyValue) && securityInfo.getBootstrapCredentialConfig().getBootstrapServer()==null && securityInfo.getBootstrapCredentialConfig().getLwm2mServer()==null)){ -// throw new LwM2MAuthException(); -// } -// -// return securityInfo; + TbLwM2MSecurityInfo securityInfo = resultSecurityStore[0]; + if ((CLIENT.equals(keyValue) && securityInfo.getSecurityMode() == null)) { + throw new LwM2MAuthException(); + } + return securityInfo; } /** * Create new SecurityInfo + * * @return SecurityInfo */ - private TbLwM2MSecurityInfo createSecurityInfo(String endpoint, String jsonStr, LwM2mTypeServer keyValue) { + private TbLwM2MSecurityInfo createSecurityInfo(String endpoint, ValidateDeviceCredentialsResponse msg, LwM2mTypeServer keyValue) { TbLwM2MSecurityInfo result = new TbLwM2MSecurityInfo(); - LwM2MClientCredentials credentials = JacksonUtil.fromString(jsonStr, LwM2MClientCredentials.class); + LwM2MClientCredentials credentials = JacksonUtil.fromString(msg.getCredentials(), LwM2MClientCredentials.class); if (credentials != null) { + result.setMsg(msg); + result.setDeviceProfile(msg.getDeviceProfile()); + result.setEndpoint(credentials.getClient().getEndpoint()); +// if ((keyValue.equals(CLIENT))) { + switch (credentials.getClient().getSecurityConfigClientMode()) { + case NO_SEC: + createClientSecurityInfoNoSec(result); + break; + case PSK: + createClientSecurityInfoPSK(result, endpoint, credentials.getClient()); + break; + case RPK: + createClientSecurityInfoRPK(result, endpoint, credentials.getClient()); + break; + case X509: + createClientSecurityInfoX509(result, endpoint, credentials.getClient()); + break; + default: + break; + } +// } else if (keyValue.equals(BOOTSTRAP)) { - result.setBootstrapCredentialConfig(credentials.getBootstrap()); - if (LwM2MSecurityMode.PSK.equals(credentials.getClient().getSecurityConfigClientMode())) { - PSKClientCredential pskClientConfig = (PSKClientCredential) credentials.getClient(); - endpoint = StringUtils.isNotEmpty(pskClientConfig.getEndpoint()) ? pskClientConfig.getEndpoint() : endpoint; - } - result.setEndpoint(endpoint); -// result.setSecurityMode(credentials.getBootstrap().getBootstrapServer().getSecurityMode()); - } else { - result.setEndpoint(credentials.getClient().getEndpoint()); - switch (credentials.getClient().getSecurityConfigClientMode()) { - case NO_SEC: - createClientSecurityInfoNoSec(result); - break; - case PSK: - createClientSecurityInfoPSK(result, endpoint, credentials.getClient()); - break; - case RPK: - createClientSecurityInfoRPK(result, endpoint, credentials.getClient()); - break; - case X509: - createClientSecurityInfoX509(result, endpoint, credentials.getClient()); - break; - default: - break; - } + LwM2MBootstrapConfig bootstrapCredentialConfig = new LwM2MBootstrapConfig(((Lwm2mDeviceProfileTransportConfiguration) msg.getDeviceProfile().getProfileData().getTransportConfiguration()).getBootstrap(), + credentials.getBootstrap().getBootstrapServer(), credentials.getBootstrap().getLwm2mServer()); + result.setBootstrapCredentialConfig(bootstrapCredentialConfig); } } return result; diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MSecurityInfo.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MSecurityInfo.java index 61774228c0..fe5ede1bda 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MSecurityInfo.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MSecurityInfo.java @@ -28,12 +28,13 @@ import java.io.Serializable; @Data public class TbLwM2MSecurityInfo implements Serializable { private ValidateDeviceCredentialsResponse msg; + private DeviceProfile deviceProfile; + private String endpoint; private SecurityInfo securityInfo; private SecurityMode securityMode; - private DeviceProfile deviceProfile; + /** bootstrap */ private LwM2MBootstrapConfig bootstrapCredentialConfig; - private String endpoint; private BootstrapConfig bootstrapConfig; } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mSecurityStore.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mSecurityStore.java index a289391dbf..fd7061b9d7 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mSecurityStore.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mSecurityStore.java @@ -22,6 +22,7 @@ import org.eclipse.leshan.server.security.SecurityInfo; import org.jetbrains.annotations.Nullable; import org.thingsboard.server.transport.lwm2m.secure.LwM2mCredentialsSecurityInfoValidator; import org.thingsboard.server.transport.lwm2m.secure.TbLwM2MSecurityInfo; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2MAuthException; import java.util.Arrays; import java.util.HashSet; @@ -71,7 +72,12 @@ public class TbLwM2mSecurityStore implements TbMainSecurityStore { public SecurityInfo getByIdentity(String pskIdentity) { SecurityInfo securityInfo = securityStore.getByIdentity(pskIdentity); if (securityInfo == null) { - securityInfo = fetchAndPutSecurityInfo(pskIdentity); + try { + securityInfo = fetchAndPutSecurityInfo(pskIdentity); + } catch (LwM2MAuthException e) { + log.info("Registration failed: FORBIDDEN, endpointId: [{}]", pskIdentity); + securityInfo = SecurityInfo.newPreSharedKeyInfo(pskIdentity, pskIdentity, new byte[]{0x00}); + } } return securityInfo; } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2MTransportUtil.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2MTransportUtil.java index daa521abc3..3c7a8e523e 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2MTransportUtil.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2MTransportUtil.java @@ -39,7 +39,7 @@ import org.eclipse.leshan.server.registration.Registration; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.DeviceTransportType; -import org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap.LwM2MBootstrapServersConfiguration; +import org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap.LwM2MBootstrapServerCredential; import org.thingsboard.server.common.data.device.profile.DeviceProfileTransportConfiguration; import org.thingsboard.server.common.data.device.profile.Lwm2mDeviceProfileTransportConfiguration; import org.thingsboard.server.common.data.ota.OtaPackageKey; @@ -181,7 +181,7 @@ public class LwM2MTransportUtil { } } - public static LwM2MBootstrapServersConfiguration getBootstrapParametersFromThingsboard(DeviceProfile deviceProfile) { + public static List getBootstrapParametersFromThingsboard(DeviceProfile deviceProfile) { return toLwM2MClientProfile(deviceProfile).getBootstrap(); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java index 5a7bf32518..22a9a00e15 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java @@ -46,7 +46,6 @@ import org.thingsboard.server.common.data.DeviceProfileType; import org.thingsboard.server.common.data.DeviceTransportType; import org.thingsboard.server.common.data.OtaPackage; import org.thingsboard.server.common.data.Tenant; -import org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap.LwM2MBootstrapServersConfiguration; import org.thingsboard.server.common.data.device.profile.CoapDeviceProfileTransportConfiguration; import org.thingsboard.server.common.data.device.profile.CoapDeviceTypeConfiguration; import org.thingsboard.server.common.data.device.profile.DefaultCoapDeviceTypeConfiguration; @@ -418,8 +417,8 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D } } } else if (transportConfiguration instanceof Lwm2mDeviceProfileTransportConfiguration) { - LwM2MBootstrapServersConfiguration lwM2MBootstrapServersConfiguration = ((Lwm2mDeviceProfileTransportConfiguration) transportConfiguration).getBootstrap(); - for (LwM2MBootstrapServerCredential bootstrapServerCredential : lwM2MBootstrapServersConfiguration.getServerConfiguration()) { + List lwM2MBootstrapServersConfigurations = ((Lwm2mDeviceProfileTransportConfiguration) transportConfiguration).getBootstrap(); + for (LwM2MBootstrapServerCredential bootstrapServerCredential : lwM2MBootstrapServersConfigurations) { validateLwm2mServersCredentialOfBootstrapForClient(bootstrapServerCredential); } } From 1d9132b0c65d8860219e310327e2b80e40a5532e Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Wed, 10 Nov 2021 08:38:04 +0200 Subject: [PATCH 095/432] lwm2m - change bootstrapConfig --- .../secure/LwM2MBootstrapConfig.java | 39 ++++++++++--------- .../secure/LwM2MBootstrapSecurityStore.java | 23 +++++------ ...LwM2mCredentialsSecurityInfoValidator.java | 23 ++++++----- .../TbLwM2MDtlsCertificateVerifier.java | 4 +- .../lwm2m/secure/TbLwM2MSecurityInfo.java | 2 +- ...tials.java => LwM2MClientCredentials.java} | 2 +- 6 files changed, 47 insertions(+), 46 deletions(-) rename common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/credentials/{LwM2MCredentials.java => LwM2MClientCredentials.java} (96%) diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapConfig.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapConfig.java index 29024d8f8f..2340267926 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapConfig.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapConfig.java @@ -16,6 +16,7 @@ package org.thingsboard.server.transport.lwm2m.bootstrap.secure; import com.fasterxml.jackson.annotation.JsonIgnore; +import lombok.AllArgsConstructor; import lombok.Data; import lombok.Getter; import lombok.Setter; @@ -31,10 +32,10 @@ import java.nio.charset.StandardCharsets; import java.util.List; @Data +@AllArgsConstructor public class LwM2MBootstrapConfig implements Serializable { - List serversConfiguration; - LwM2MBootstrapClientCredential bootstrapClientCredential; + List serverConfiguration; /* interface BootstrapSecurityConfig servers: BootstrapServersSecurityConfig, @@ -49,9 +50,9 @@ public class LwM2MBootstrapConfig implements Serializable { * notifIfDisabled: boolean, * binding: string * */ - @Getter - @Setter - private LwM2MBootstrapServers servers; +// @Getter +// @Setter +// private LwM2MBootstrapServers servers; /** -bootstrapServer, lwm2mServer * interface ServerSecurityConfig @@ -68,15 +69,15 @@ public class LwM2MBootstrapConfig implements Serializable { * */ @Getter @Setter - private LwM2MServerBootstrap bootstrapServer; + private LwM2MBootstrapClientCredential bootstrapServer; @Getter @Setter - private LwM2MServerBootstrap lwm2mServer; + private LwM2MBootstrapClientCredential lwm2mServer; + + public LwM2MBootstrapConfig(List serverConfiguration, LwM2MBootstrapClientCredential bootstrapClientCredential) { + this.serverConfiguration = serverConfiguration; - public LwM2MBootstrapConfig(List serversConfiguration, LwM2MBootstrapClientCredential bootstrapClientCredential) { - this.serversConfiguration = serversConfiguration; - this.bootstrapClientCredential = bootstrapClientCredential; } @JsonIgnore @@ -87,17 +88,17 @@ public class LwM2MBootstrapConfig implements Serializable { configBs.toDelete.add("/1"); /* Server Configuration (object 1) as defined in LWM2M 1.0.x TS. */ BootstrapConfig.ServerConfig server0 = new BootstrapConfig.ServerConfig(); - server0.shortId = servers.getShortId(); - server0.lifetime = servers.getLifetime(); - server0.defaultMinPeriod = servers.getDefaultMinPeriod(); - server0.notifIfDisabled = servers.isNotifIfDisabled(); - server0.binding = BindingMode.parse(servers.getBinding()); +// server0.shortId = servers.getShortId(); +// server0.lifetime = servers.getLifetime(); +// server0.defaultMinPeriod = servers.getDefaultMinPeriod(); +// server0.notifIfDisabled = servers.isNotifIfDisabled(); +// server0.binding = BindingMode.parse(servers.getBinding()); configBs.servers.put(0, server0); /* Security Configuration (object 0) as defined in LWM2M 1.0.x TS. Bootstrap instance = 0 */ - this.bootstrapServer.setBootstrapServerIs(true); - configBs.security.put(0, setServerSecurity(this.lwm2mServer.getHost(), this.lwm2mServer.getPort(), this.lwm2mServer.getSecurityHost(), this.lwm2mServer.getSecurityPort(), this.bootstrapServer.isBootstrapServerIs(), this.bootstrapServer.getSecurityMode(), this.bootstrapServer.getClientPublicKeyOrId(), this.bootstrapServer.getServerPublicKey(), this.bootstrapServer.getClientSecretKey(), this.bootstrapServer.getServerId())); - /* Security Configuration (object 0) as defined in LWM2M 1.0.x TS. Server instance = 1 */ - configBs.security.put(1, setServerSecurity(this.lwm2mServer.getHost(), this.lwm2mServer.getPort(), this.lwm2mServer.getSecurityHost(), this.lwm2mServer.getSecurityPort(), this.lwm2mServer.isBootstrapServerIs(), this.lwm2mServer.getSecurityMode(), this.lwm2mServer.getClientPublicKeyOrId(), this.lwm2mServer.getServerPublicKey(), this.lwm2mServer.getClientSecretKey(), this.lwm2mServer.getServerId())); +// this.bootstrapServer.setBootstrapServerIs(true); +// configBs.security.put(0, setServerSecurity(this.lwm2mServer.getHost(), this.lwm2mServer.getPort(), this.lwm2mServer.getSecurityHost(), this.lwm2mServer.getSecurityPort(), this.bootstrapServer.isBootstrapServerIs(), this.bootstrapServer.getSecurityMode(), this.bootstrapServer.getClientPublicKeyOrId(), this.bootstrapServer.getServerPublicKey(), this.bootstrapServer.getClientSecretKey(), this.bootstrapServer.getServerId())); +// /* Security Configuration (object 0) as defined in LWM2M 1.0.x TS. Server instance = 1 */ +// configBs.security.put(1, setServerSecurity(this.lwm2mServer.getHost(), this.lwm2mServer.getPort(), this.lwm2mServer.getSecurityHost(), this.lwm2mServer.getSecurityPort(), this.lwm2mServer.isBootstrapServerIs(), this.lwm2mServer.getSecurityMode(), this.lwm2mServer.getClientPublicKeyOrId(), this.lwm2mServer.getServerPublicKey(), this.lwm2mServer.getClientSecretKey(), this.lwm2mServer.getServerId())); return configBs; } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapSecurityStore.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapSecurityStore.java index 935e95c546..c2c32ca79c 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapSecurityStore.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapSecurityStore.java @@ -71,6 +71,7 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore { @Override public Iterator getAllByEndpoint(String endPoint) { + // TODO TbLwM2MSecurityInfo store = lwM2MCredentialsSecurityInfoValidator.getEndpointSecurityInfoByCredentialsId(endPoint, BOOTSTRAP); if (store.getBootstrapCredentialConfig() != null && store.getSecurityMode() != null) { /* add value to store from BootstrapJson */ @@ -125,20 +126,20 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore { switch (lwM2MBootstrapConfig.getBootstrapServer().getSecurityMode()) { /* Use RPK only */ case PSK: - store.setSecurityInfo(SecurityInfo.newPreSharedKeyInfo(store.getEndpoint(), - lwM2MBootstrapConfig.getBootstrapServer().getClientPublicKeyOrId(), - Hex.decodeHex(lwM2MBootstrapConfig.getBootstrapServer().getClientSecretKey().toCharArray()))); +// store.setSecurityInfo(SecurityInfo.newPreSharedKeyInfo(store.getEndpoint(), +// lwM2MBootstrapConfig.getBootstrapServer().getClientPublicKeyOrId(), +// Hex.decodeHex(lwM2MBootstrapConfig.getBootstrapServer().getClientSecretKey().toCharArray()))); store.setSecurityMode(SecurityMode.PSK); break; case RPK: - try { - store.setSecurityInfo(SecurityInfo.newRawPublicKeyInfo(store.getEndpoint(), - SecurityUtil.publicKey.decode(Hex.decodeHex(lwM2MBootstrapConfig.getBootstrapServer().getClientPublicKeyOrId().toCharArray())))); - store.setSecurityMode(SecurityMode.RPK); - break; - } catch (IOException | GeneralSecurityException e) { - log.error("Unable to decode Client public key for [{}] [{}]", store.getEndpoint(), e.getMessage()); - } +// try { +//// store.setSecurityInfo(SecurityInfo.newRawPublicKeyInfo(store.getEndpoint(), +//// SecurityUtil.publicKey.decode(Hex.decodeHex(lwM2MBootstrapConfig.getBootstrapServer().getClientPublicKeyOrId().toCharArray())))); +//// store.setSecurityMode(SecurityMode.RPK); +// break; +// } catch (IOException | GeneralSecurityException e) { +// log.error("Unable to decode Client public key for [{}] [{}]", store.getEndpoint(), e.getMessage()); +// } case X509: store.setSecurityInfo(SecurityInfo.newX509CertInfo(store.getEndpoint())); store.setSecurityMode(SecurityMode.X509); diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LwM2mCredentialsSecurityInfoValidator.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LwM2mCredentialsSecurityInfoValidator.java index 64498645c8..8b343ab02f 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LwM2mCredentialsSecurityInfoValidator.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LwM2mCredentialsSecurityInfoValidator.java @@ -32,7 +32,7 @@ import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsRes import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceLwM2MCredentialsRequestMsg; import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; -import org.thingsboard.server.transport.lwm2m.secure.credentials.LwM2MCredentials; +import org.thingsboard.server.transport.lwm2m.secure.credentials.LwM2MClientCredentials; import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportContext; import org.thingsboard.server.transport.lwm2m.server.client.LwM2MAuthException; import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mTypeServer; @@ -48,6 +48,7 @@ import static org.eclipse.leshan.core.SecurityMode.PSK; import static org.eclipse.leshan.core.SecurityMode.RPK; import static org.eclipse.leshan.core.SecurityMode.X509; import static org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mTypeServer.BOOTSTRAP; +import static org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mTypeServer.CLIENT; @Slf4j @Component @@ -87,25 +88,23 @@ public class LwM2mCredentialsSecurityInfoValidator { log.error("Failed to await credentials!", e); } - TbLwM2MSecurityInfo securityInfo = resultSecurityStore[0]; + return resultSecurityStore[0]; - if (securityInfo.getSecurityMode() == null) { - throw new LwM2MAuthException(); - } - - return securityInfo; +// if ((CLIENT.equals(keyValue) && securityInfo.getSecurityMode() == null) || +// (BOOTSTRAP.equals(keyValue) && securityInfo.getBootstrapCredentialConfig().getBootstrapServer()==null && securityInfo.getBootstrapCredentialConfig().getLwm2mServer()==null)){ +// throw new LwM2MAuthException(); +// } +// +// return securityInfo; } /** * Create new SecurityInfo - * @param endpoint - - * @param jsonStr - - * @param keyValue - * @return SecurityInfo */ private TbLwM2MSecurityInfo createSecurityInfo(String endpoint, String jsonStr, LwM2mTypeServer keyValue) { TbLwM2MSecurityInfo result = new TbLwM2MSecurityInfo(); - LwM2MCredentials credentials = JacksonUtil.fromString(jsonStr, LwM2MCredentials.class); + LwM2MClientCredentials credentials = JacksonUtil.fromString(jsonStr, LwM2MClientCredentials.class); if (credentials != null) { if (keyValue.equals(BOOTSTRAP)) { result.setBootstrapCredentialConfig(credentials.getBootstrap()); @@ -114,7 +113,7 @@ public class LwM2mCredentialsSecurityInfoValidator { endpoint = StringUtils.isNotEmpty(pskClientConfig.getEndpoint()) ? pskClientConfig.getEndpoint() : endpoint; } result.setEndpoint(endpoint); - result.setSecurityMode(credentials.getBootstrap().getBootstrapServer().getSecurityMode()); +// result.setSecurityMode(credentials.getBootstrap().getBootstrapServer().getSecurityMode()); } else { result.setEndpoint(credentials.getClient().getEndpoint()); switch (credentials.getClient().getSecurityConfigClientMode()) { diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MDtlsCertificateVerifier.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MDtlsCertificateVerifier.java index 0ef0d93f27..e3bfe986c3 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MDtlsCertificateVerifier.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MDtlsCertificateVerifier.java @@ -41,7 +41,7 @@ import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsRes import org.thingsboard.server.common.transport.util.SslUtil; import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; -import org.thingsboard.server.transport.lwm2m.secure.credentials.LwM2MCredentials; +import org.thingsboard.server.transport.lwm2m.secure.credentials.LwM2MClientCredentials; import org.thingsboard.server.transport.lwm2m.server.client.LwM2MAuthException; import org.thingsboard.server.transport.lwm2m.server.store.TbLwM2MDtlsSessionStore; import org.thingsboard.server.transport.lwm2m.server.store.TbMainSecurityStore; @@ -124,7 +124,7 @@ public class TbLwM2MDtlsCertificateVerifier implements NewAdvancedCertificateVer } ValidateDeviceCredentialsResponse msg = securityInfo != null ? securityInfo.getMsg() : null; if (msg != null && org.thingsboard.server.common.data.StringUtils.isNotEmpty(msg.getCredentials())) { - LwM2MCredentials credentials = JacksonUtil.fromString(msg.getCredentials(), LwM2MCredentials.class); + LwM2MClientCredentials credentials = JacksonUtil.fromString(msg.getCredentials(), LwM2MClientCredentials.class); if (!credentials.getClient().getSecurityConfigClientMode().equals(LwM2MSecurityMode.X509)) { continue; } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MSecurityInfo.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MSecurityInfo.java index bc45a77b58..61774228c0 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MSecurityInfo.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MSecurityInfo.java @@ -30,9 +30,9 @@ public class TbLwM2MSecurityInfo implements Serializable { private ValidateDeviceCredentialsResponse msg; private SecurityInfo securityInfo; private SecurityMode securityMode; + private DeviceProfile deviceProfile; /** bootstrap */ - private DeviceProfile deviceProfile; private LwM2MBootstrapConfig bootstrapCredentialConfig; private String endpoint; private BootstrapConfig bootstrapConfig; diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/credentials/LwM2MCredentials.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/credentials/LwM2MClientCredentials.java similarity index 96% rename from common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/credentials/LwM2MCredentials.java rename to common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/credentials/LwM2MClientCredentials.java index 878188bffc..a10e5ec231 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/credentials/LwM2MCredentials.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/credentials/LwM2MClientCredentials.java @@ -20,7 +20,7 @@ import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MClientCr import org.thingsboard.server.transport.lwm2m.bootstrap.secure.LwM2MBootstrapConfig; @Data -public class LwM2MCredentials { +public class LwM2MClientCredentials { private LwM2MClientCredential client; private LwM2MBootstrapConfig bootstrap; } From ff1d86e1b0d65b32af8605d1588c9a0e8d9c0717 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Thu, 11 Nov 2021 15:09:34 +0200 Subject: [PATCH 096/432] lwm2m - upDate lwm2mServer --- ...2mDeviceProfileTransportConfiguration.java | 6 +- .../LwM2MBootstrapServersConfiguration.java | 2 +- .../LwM2MTransportBootstrapService.java | 9 +- .../secure/LwM2MBootstrapConfig.java | 88 +++++++++------ .../LwM2mDefaultBootstrapSessionManager.java | 2 + .../LwM2MBootstrapSecurityStore.java | 105 ++++++++++-------- .../LwM2MInMemoryBootstrapConfigStore.java | 2 +- ...LwM2mCredentialsSecurityInfoValidator.java | 79 +++++++------ .../lwm2m/secure/TbLwM2MSecurityInfo.java | 5 +- .../server/store/TbLwM2mSecurityStore.java | 8 +- .../lwm2m/utils/LwM2MTransportUtil.java | 4 +- .../dao/device/DeviceProfileServiceImpl.java | 5 +- 12 files changed, 175 insertions(+), 140 deletions(-) rename common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/{secure => store}/LwM2MBootstrapSecurityStore.java (70%) rename common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/{secure => store}/LwM2MInMemoryBootstrapConfigStore.java (97%) diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/Lwm2mDeviceProfileTransportConfiguration.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/Lwm2mDeviceProfileTransportConfiguration.java index 1bc6ce8004..0c1441f031 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/Lwm2mDeviceProfileTransportConfiguration.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/Lwm2mDeviceProfileTransportConfiguration.java @@ -17,17 +17,19 @@ package org.thingsboard.server.common.data.device.profile; import lombok.Data; import org.thingsboard.server.common.data.DeviceTransportType; -import org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap.LwM2MBootstrapServersConfiguration; +import org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap.LwM2MBootstrapServerCredential; import org.thingsboard.server.common.data.device.profile.lwm2m.OtherConfiguration; import org.thingsboard.server.common.data.device.profile.lwm2m.TelemetryMappingConfiguration; +import java.util.List; + @Data public class Lwm2mDeviceProfileTransportConfiguration implements DeviceProfileTransportConfiguration { private static final long serialVersionUID = 6257277825459600068L; private TelemetryMappingConfiguration observeAttr; - private LwM2MBootstrapServersConfiguration bootstrap; + private List bootstrap; private OtherConfiguration clientLwM2mSettings; @Override diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/LwM2MBootstrapServersConfiguration.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/LwM2MBootstrapServersConfiguration.java index 15d573b50e..0ff1dc2eb5 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/LwM2MBootstrapServersConfiguration.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/LwM2MBootstrapServersConfiguration.java @@ -22,6 +22,6 @@ import java.util.List; @Data public class LwM2MBootstrapServersConfiguration { - List serverConfiguration; + List bootstrap; } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportBootstrapService.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportBootstrapService.java index 3e36d86e8e..ee14a9265d 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportBootstrapService.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportBootstrapService.java @@ -17,7 +17,6 @@ package org.thingsboard.server.transport.lwm2m.bootstrap; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.eclipse.californium.elements.util.SslContextUtil; import org.eclipse.californium.scandium.config.DtlsConnectorConfig; import org.eclipse.leshan.server.bootstrap.BootstrapSessionManager; import org.eclipse.leshan.server.californium.bootstrap.LeshanBootstrapServer; @@ -26,8 +25,8 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.stereotype.Component; import org.thingsboard.server.common.transport.TransportService; import org.thingsboard.server.common.transport.config.ssl.SslCredentials; -import org.thingsboard.server.transport.lwm2m.bootstrap.secure.LwM2MBootstrapSecurityStore; -import org.thingsboard.server.transport.lwm2m.bootstrap.secure.LwM2MInMemoryBootstrapConfigStore; +import org.thingsboard.server.transport.lwm2m.bootstrap.store.LwM2MBootstrapSecurityStore; +import org.thingsboard.server.transport.lwm2m.bootstrap.store.LwM2MInMemoryBootstrapConfigStore; import org.thingsboard.server.transport.lwm2m.bootstrap.secure.LwM2mDefaultBootstrapSessionManager; import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportBootstrapConfig; import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; @@ -35,10 +34,6 @@ import org.thingsboard.server.transport.lwm2m.server.DefaultLwM2mTransportServic import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; -import java.security.KeyStore; -import java.security.KeyStoreException; -import java.security.PrivateKey; -import java.security.PublicKey; import java.security.cert.X509Certificate; import static org.thingsboard.server.transport.lwm2m.server.LwM2MNetworkConfig.getCoapConfig; diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapConfig.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapConfig.java index 2340267926..792cf71c67 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapConfig.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapConfig.java @@ -16,23 +16,27 @@ package org.thingsboard.server.transport.lwm2m.bootstrap.secure; import com.fasterxml.jackson.annotation.JsonIgnore; -import lombok.AllArgsConstructor; import lombok.Data; import lombok.Getter; import lombok.Setter; +import lombok.extern.slf4j.Slf4j; import org.eclipse.leshan.core.SecurityMode; import org.eclipse.leshan.core.request.BindingMode; import org.eclipse.leshan.core.util.Hex; import org.eclipse.leshan.server.bootstrap.BootstrapConfig; +import org.thingsboard.server.common.data.device.credentials.lwm2m.AbstractLwM2MBootstrapClientCredentialWithKeys; import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MBootstrapClientCredential; +import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MSecurityMode; +import org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap.AbstractLwM2MBootstrapServerCredential; import org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap.LwM2MBootstrapServerCredential; import java.io.Serializable; import java.nio.charset.StandardCharsets; import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; +@Slf4j @Data -@AllArgsConstructor public class LwM2MBootstrapConfig implements Serializable { List serverConfiguration; @@ -75,52 +79,68 @@ public class LwM2MBootstrapConfig implements Serializable { @Setter private LwM2MBootstrapClientCredential lwm2mServer; - public LwM2MBootstrapConfig(List serverConfiguration, LwM2MBootstrapClientCredential bootstrapClientCredential) { + public LwM2MBootstrapConfig(){}; + + public LwM2MBootstrapConfig(List serverConfiguration, LwM2MBootstrapClientCredential bootstrapClientServer, LwM2MBootstrapClientCredential lwm2mClientServer) { this.serverConfiguration = serverConfiguration; + this.bootstrapServer = bootstrapClientServer; + this.lwm2mServer = lwm2mClientServer; } @JsonIgnore public BootstrapConfig getLwM2MBootstrapConfig() { BootstrapConfig configBs = new BootstrapConfig(); - /* Delete old security objects */ + AtomicInteger index = new AtomicInteger(); + /** Delete old security/config objects in LwM2mDefaultBootstrapSessionManager -> initTasks */ configBs.toDelete.add("/0"); configBs.toDelete.add("/1"); - /* Server Configuration (object 1) as defined in LWM2M 1.0.x TS. */ - BootstrapConfig.ServerConfig server0 = new BootstrapConfig.ServerConfig(); -// server0.shortId = servers.getShortId(); -// server0.lifetime = servers.getLifetime(); -// server0.defaultMinPeriod = servers.getDefaultMinPeriod(); -// server0.notifIfDisabled = servers.isNotifIfDisabled(); -// server0.binding = BindingMode.parse(servers.getBinding()); - configBs.servers.put(0, server0); - /* Security Configuration (object 0) as defined in LWM2M 1.0.x TS. Bootstrap instance = 0 */ -// this.bootstrapServer.setBootstrapServerIs(true); -// configBs.security.put(0, setServerSecurity(this.lwm2mServer.getHost(), this.lwm2mServer.getPort(), this.lwm2mServer.getSecurityHost(), this.lwm2mServer.getSecurityPort(), this.bootstrapServer.isBootstrapServerIs(), this.bootstrapServer.getSecurityMode(), this.bootstrapServer.getClientPublicKeyOrId(), this.bootstrapServer.getServerPublicKey(), this.bootstrapServer.getClientSecretKey(), this.bootstrapServer.getServerId())); -// /* Security Configuration (object 0) as defined in LWM2M 1.0.x TS. Server instance = 1 */ -// configBs.security.put(1, setServerSecurity(this.lwm2mServer.getHost(), this.lwm2mServer.getPort(), this.lwm2mServer.getSecurityHost(), this.lwm2mServer.getSecurityPort(), this.lwm2mServer.isBootstrapServerIs(), this.lwm2mServer.getSecurityMode(), this.lwm2mServer.getClientPublicKeyOrId(), this.lwm2mServer.getServerPublicKey(), this.lwm2mServer.getClientSecretKey(), this.lwm2mServer.getServerId())); + serverConfiguration.forEach(serverCredential -> { + BootstrapConfig.ServerConfig serverConfig = new BootstrapConfig.ServerConfig(); + serverConfig.shortId = ((AbstractLwM2MBootstrapServerCredential)serverCredential).getShortServerId(); + serverConfig.lifetime = ((AbstractLwM2MBootstrapServerCredential)serverCredential).getLifetime(); + serverConfig.defaultMinPeriod = ((AbstractLwM2MBootstrapServerCredential)serverCredential).getDefaultMinPeriod(); + serverConfig.notifIfDisabled = ((AbstractLwM2MBootstrapServerCredential)serverCredential).isNotifIfDisabled(); + serverConfig.binding = BindingMode.parse(((AbstractLwM2MBootstrapServerCredential)serverCredential).getBinding()); + int k = index.get(); + configBs.servers.put(k, serverConfig); + BootstrapConfig.ServerSecurity serverSecurity = setServerSecurity((AbstractLwM2MBootstrapServerCredential)serverCredential, serverCredential.getSecurityMode()); + configBs.security.put(k, serverSecurity); + index.getAndIncrement(); + + }); return configBs; } - private BootstrapConfig.ServerSecurity setServerSecurity(String host, Integer port, String securityHost, Integer securityPort, boolean bootstrapServer, SecurityMode securityMode, String clientPublicKey, String serverPublicKey, String secretKey, int serverId) { + private BootstrapConfig.ServerSecurity setServerSecurity(AbstractLwM2MBootstrapServerCredential serverCredential, LwM2MSecurityMode securityMode) { BootstrapConfig.ServerSecurity serverSecurity = new BootstrapConfig.ServerSecurity(); - if (securityMode.equals(SecurityMode.NO_SEC)) { - serverSecurity.uri = "coap://" + host + ":" + Integer.toString(port); - } else { - serverSecurity.uri = "coaps://" + securityHost + ":" + Integer.toString(securityPort); + String serverUri = "coap://"; + byte[] publicKeyOrId = new byte[]{};; + byte[] secretKey = new byte[]{};; + serverSecurity.serverId = serverCredential.getShortServerId(); + serverSecurity.securityMode = SecurityMode.valueOf(securityMode.name()); + serverSecurity.bootstrapServer = serverCredential.isBootstrapServerIs(); + if (!LwM2MSecurityMode.NO_SEC.equals(securityMode)) { + serverUri = "coaps://"; + if (serverSecurity.bootstrapServer) { + publicKeyOrId = ((AbstractLwM2MBootstrapClientCredentialWithKeys)this.bootstrapServer).getDecodedClientPublicKeyOrId(); + secretKey = ((AbstractLwM2MBootstrapClientCredentialWithKeys)this.bootstrapServer).getDecodedClientSecretKey(); + + } else { + publicKeyOrId = ((AbstractLwM2MBootstrapClientCredentialWithKeys)this.lwm2mServer).getDecodedClientPublicKeyOrId(); + secretKey = ((AbstractLwM2MBootstrapClientCredentialWithKeys)this.lwm2mServer).getDecodedClientSecretKey(); + } + } - serverSecurity.bootstrapServer = bootstrapServer; - serverSecurity.securityMode = securityMode; - serverSecurity.publicKeyOrId = setPublicKeyOrId(clientPublicKey, securityMode); - serverSecurity.serverPublicKey = (serverPublicKey != null && !serverPublicKey.isEmpty()) ? Hex.decodeHex(serverPublicKey.toCharArray()) : new byte[]{}; - serverSecurity.secretKey = (secretKey != null && !secretKey.isEmpty()) ? Hex.decodeHex(secretKey.toCharArray()) : new byte[]{}; - serverSecurity.serverId = serverId; + serverUri += (((serverCredential.getHost().equals("0.0.0.0") ? "localhost" : serverCredential.getHost()) + ":" + serverCredential.getPort())); + log.info("serverSecurity.uri = [{}]", serverUri); + log.info("publicKeyOrId [{}]", Hex.encodeHexString(publicKeyOrId)); + log.info("secretKey [{}]", Hex.encodeHexString(secretKey)); + log.info("server [{}]", Hex.encodeHexString(serverCredential.getDecodedCServerPublicKey())); + serverSecurity.uri = serverUri; + serverSecurity.publicKeyOrId = publicKeyOrId; + serverSecurity.secretKey = secretKey; + serverSecurity.serverPublicKey = serverCredential.getDecodedCServerPublicKey(); return serverSecurity; } - - private byte[] setPublicKeyOrId(String publicKeyOrIdStr, SecurityMode securityMode) { - return (publicKeyOrIdStr == null || publicKeyOrIdStr.isEmpty()) ? new byte[]{} : - SecurityMode.PSK.equals(securityMode) ? publicKeyOrIdStr.getBytes(StandardCharsets.UTF_8) : - Hex.decodeHex(publicKeyOrIdStr.toCharArray()); - } } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2mDefaultBootstrapSessionManager.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2mDefaultBootstrapSessionManager.java index 097b69f806..4f47079bbe 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2mDefaultBootstrapSessionManager.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2mDefaultBootstrapSessionManager.java @@ -34,6 +34,7 @@ import org.eclipse.leshan.server.security.BootstrapSecurityStore; import org.eclipse.leshan.server.security.SecurityChecker; import org.eclipse.leshan.server.security.SecurityInfo; import org.thingsboard.server.common.transport.TransportService; +import org.thingsboard.server.transport.lwm2m.bootstrap.store.LwM2MBootstrapSecurityStore; import org.thingsboard.server.transport.lwm2m.server.client.LwM2MAuthException; import java.util.ArrayList; @@ -118,6 +119,7 @@ public class LwM2mDefaultBootstrapSessionManager extends DefaultBootstrapSession session.setModel(modelProvider.getObjectModel(session, tasks.supportedObjects)); // set Requests to Send + log.info("tasks.requestsToSend = [{}]", tasks.requestsToSend); session.setRequests(tasks.requestsToSend); // prepare list where we will store Responses diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapSecurityStore.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MBootstrapSecurityStore.java similarity index 70% rename from common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapSecurityStore.java rename to common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MBootstrapSecurityStore.java index c2c32ca79c..ee973f3a23 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapSecurityStore.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MBootstrapSecurityStore.java @@ -13,12 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.transport.lwm2m.bootstrap.secure; +package org.thingsboard.server.transport.lwm2m.bootstrap.store; import lombok.extern.slf4j.Slf4j; import org.eclipse.leshan.core.SecurityMode; -import org.eclipse.leshan.core.util.Hex; -import org.eclipse.leshan.core.util.SecurityUtil; import org.eclipse.leshan.server.bootstrap.BootstrapConfig; import org.eclipse.leshan.server.bootstrap.EditableBootstrapConfigStore; import org.eclipse.leshan.server.bootstrap.InvalidConfigurationException; @@ -26,9 +24,10 @@ import org.eclipse.leshan.server.security.BootstrapSecurityStore; import org.eclipse.leshan.server.security.SecurityInfo; import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.stereotype.Service; -import org.thingsboard.common.util.JacksonUtil; -import org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap.LwM2MBootstrapServersConfiguration; +import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MSecurityMode; +import org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap.AbstractLwM2MBootstrapServerCredential; import org.thingsboard.server.gen.transport.TransportProtos; +import org.thingsboard.server.transport.lwm2m.bootstrap.secure.LwM2MBootstrapConfig; import org.thingsboard.server.transport.lwm2m.secure.LwM2mCredentialsSecurityInfoValidator; import org.thingsboard.server.transport.lwm2m.secure.TbLwM2MSecurityInfo; import org.thingsboard.server.transport.lwm2m.server.LwM2mSessionMsgListener; @@ -42,12 +41,12 @@ import java.util.Iterator; import java.util.Map; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicBoolean; import static org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mTypeServer.BOOTSTRAP; import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.LOG_LWM2M_ERROR; import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.LOG_LWM2M_INFO; import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.LOG_LWM2M_TELEMETRY; -import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.getBootstrapParametersFromThingsboard; @Slf4j @Service("LwM2MBootstrapSecurityStore") @@ -73,7 +72,7 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore { public Iterator getAllByEndpoint(String endPoint) { // TODO TbLwM2MSecurityInfo store = lwM2MCredentialsSecurityInfoValidator.getEndpointSecurityInfoByCredentialsId(endPoint, BOOTSTRAP); - if (store.getBootstrapCredentialConfig() != null && store.getSecurityMode() != null) { + if (store.getBootstrapCredentialConfig() != null) { /* add value to store from BootstrapJson */ this.setBootstrapConfigScurityInfo(store); BootstrapConfig bsConfigNew = store.getBootstrapConfig(); @@ -123,15 +122,15 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore { LwM2MBootstrapConfig lwM2MBootstrapConfig = this.getParametersBootstrap(store); if (lwM2MBootstrapConfig != null) { /* Security info */ - switch (lwM2MBootstrapConfig.getBootstrapServer().getSecurityMode()) { - /* Use RPK only */ - case PSK: +// switch (lwM2MBootstrapConfig.getBootstrapServer().getSecurityMode()) { +// /* Use RPK only */ +// case PSK: // store.setSecurityInfo(SecurityInfo.newPreSharedKeyInfo(store.getEndpoint(), // lwM2MBootstrapConfig.getBootstrapServer().getClientPublicKeyOrId(), // Hex.decodeHex(lwM2MBootstrapConfig.getBootstrapServer().getClientSecretKey().toCharArray()))); - store.setSecurityMode(SecurityMode.PSK); - break; - case RPK: +// store.setSecurityMode(SecurityMode.PSK); +// break; +// case RPK: // try { //// store.setSecurityInfo(SecurityInfo.newRawPublicKeyInfo(store.getEndpoint(), //// SecurityUtil.publicKey.decode(Hex.decodeHex(lwM2MBootstrapConfig.getBootstrapServer().getClientPublicKeyOrId().toCharArray())))); @@ -140,16 +139,16 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore { // } catch (IOException | GeneralSecurityException e) { // log.error("Unable to decode Client public key for [{}] [{}]", store.getEndpoint(), e.getMessage()); // } - case X509: - store.setSecurityInfo(SecurityInfo.newX509CertInfo(store.getEndpoint())); - store.setSecurityMode(SecurityMode.X509); - break; - case NO_SEC: - store.setSecurityMode(SecurityMode.NO_SEC); - store.setSecurityInfo(null); - break; - default: - } +// case X509: +// store.setSecurityInfo(SecurityInfo.newX509CertInfo(store.getEndpoint())); +// store.setSecurityMode(SecurityMode.X509); +// break; +// case NO_SEC: +// store.setSecurityMode(SecurityMode.NO_SEC); +// store.setSecurityInfo(null); +// break; +// default: +// } BootstrapConfig bootstrapConfig = lwM2MBootstrapConfig.getLwM2MBootstrapConfig(); store.setBootstrapConfig(bootstrapConfig); } @@ -158,7 +157,7 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore { private LwM2MBootstrapConfig getParametersBootstrap(TbLwM2MSecurityInfo store) { LwM2MBootstrapConfig lwM2MBootstrapConfig = store.getBootstrapCredentialConfig(); if (lwM2MBootstrapConfig != null) { - LwM2MBootstrapServersConfiguration bootstrapObject = getBootstrapParametersFromThingsboard(store.getDeviceProfile()); +// LwM2MBootstrapServersConfiguration bootstrapObject = getBootstrapParametersFromThingsboard(store.getDeviceProfile()); // lwM2MBootstrapConfig.setServers(JacksonUtil.fromString(JacksonUtil.toString(bootstrapObject.getServers()), LwM2MBootstrapServers.class)); // LwM2MServerBootstrap bootstrapServerProfile = JacksonUtil.fromString(JacksonUtil.toString(bootstrapObject.getBootstrapServer()), LwM2MServerBootstrap.class); // if (SecurityMode.NO_SEC != bootstrapServerProfile.getSecurityMode() && bootstrapServerProfile != null) { @@ -170,23 +169,25 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore { // profileLwm2mServer.setSecurityHost(profileLwm2mServer.getHost()); // profileLwm2mServer.setSecurityPort(profileLwm2mServer.getPort()); // } -// UUID sessionUUiD = UUID.randomUUID(); -// TransportProtos.SessionInfoProto sessionInfo = helper.getValidateSessionInfo(store.getMsg(), sessionUUiD.getMostSignificantBits(), sessionUUiD.getLeastSignificantBits()); -// bsSessions.put(store.getEndpoint(), sessionInfo); -// context.getTransportService().registerAsyncSession(sessionInfo, new LwM2mSessionMsgListener(null, null, null, sessionInfo, context.getTransportService())); -// if (this.getValidatedSecurityMode(lwM2MBootstrapConfig.getBootstrapServer(), bootstrapServerProfile, lwM2MBootstrapConfig.getLwm2mServer(), profileLwm2mServer)) { + + + UUID sessionUUiD = UUID.randomUUID(); + TransportProtos.SessionInfoProto sessionInfo = helper.getValidateSessionInfo(store.getMsg(), sessionUUiD.getMostSignificantBits(), sessionUUiD.getLeastSignificantBits()); + bsSessions.put(store.getEndpoint(), sessionInfo); + context.getTransportService().registerAsyncSession(sessionInfo, new LwM2mSessionMsgListener(null, null, null, sessionInfo, context.getTransportService())); + if (this.getValidatedSecurityMode(lwM2MBootstrapConfig)) { // lwM2MBootstrapConfig.setBootstrapServer(new LwM2MServerBootstrap(lwM2MBootstrapConfig.getBootstrapServer(), bootstrapServerProfile)); // lwM2MBootstrapConfig.setLwm2mServer(new LwM2MServerBootstrap(lwM2MBootstrapConfig.getLwm2mServer(), profileLwm2mServer)); -// String logMsg = String.format("%s: getParametersBootstrap: %s Access connect client with bootstrap server.", LOG_LWM2M_INFO, store.getEndpoint()); -// helper.sendParametersOnThingsboardTelemetry(helper.getKvStringtoThingsboard(LOG_LWM2M_TELEMETRY, logMsg), sessionInfo); -// return lwM2MBootstrapConfig; -// } else { -// log.error(" [{}] Different values SecurityMode between of client and profile.", store.getEndpoint()); -// log.error("{} getParametersBootstrap: [{}] Different values SecurityMode between of client and profile.", LOG_LWM2M_ERROR, store.getEndpoint()); -// String logMsg = String.format("%s: getParametersBootstrap: %s Different values SecurityMode between of client and profile.", LOG_LWM2M_ERROR, store.getEndpoint()); -// helper.sendParametersOnThingsboardTelemetry(helper.getKvStringtoThingsboard(LOG_LWM2M_TELEMETRY, logMsg), sessionInfo); -// return null; -// } + String logMsg = String.format("%s: getParametersBootstrap: %s Access connect client with bootstrap server.", LOG_LWM2M_INFO, store.getEndpoint()); + helper.sendParametersOnThingsboardTelemetry(helper.getKvStringtoThingsboard(LOG_LWM2M_TELEMETRY, logMsg), sessionInfo); + return lwM2MBootstrapConfig; + } else { + log.error(" [{}] Different values SecurityMode between of client and profile.", store.getEndpoint()); + log.error("{} getParametersBootstrap: [{}] Different values SecurityMode between of client and profile.", LOG_LWM2M_ERROR, store.getEndpoint()); + String logMsg = String.format("%s: getParametersBootstrap: %s Different values SecurityMode between of client and profile.", LOG_LWM2M_ERROR, store.getEndpoint()); + helper.sendParametersOnThingsboardTelemetry(helper.getKvStringtoThingsboard(LOG_LWM2M_TELEMETRY, logMsg), sessionInfo); + return null; + } } log.error("Unable to decode Json or Certificate for [{}]", store.getEndpoint()); return null; @@ -196,15 +197,27 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore { * Bootstrap security have to sync between (bootstrapServer in credential and bootstrapServer in profile) * and (lwm2mServer in credential and lwm2mServer in profile * - * @param bootstrapFromCredential - Bootstrap -> Security of bootstrapServer in credential - * @param bootstrapServerProfile - Bootstrap -> Security of bootstrapServer in profile - * @param lwm2mFromCredential - Bootstrap -> Security of lwm2mServer in credential - * @param profileLwm2mServer - Bootstrap -> Security of lwm2mServer in profile * @return false if not sync between SecurityMode of Bootstrap credential and profile */ - private boolean getValidatedSecurityMode(LwM2MServerBootstrap bootstrapFromCredential, LwM2MServerBootstrap bootstrapServerProfile, LwM2MServerBootstrap lwm2mFromCredential, LwM2MServerBootstrap profileLwm2mServer) { - return (bootstrapFromCredential.getSecurityMode().equals(bootstrapServerProfile.getSecurityMode()) && - lwm2mFromCredential.getSecurityMode().equals(profileLwm2mServer.getSecurityMode())); +// private boolean getValidatedSecurityMode(LwM2MServerBootstrap bootstrapFromCredential, LwM2MServerBootstrap bootstrapServerProfile, LwM2MServerBootstrap lwm2mFromCredential, LwM2MServerBootstrap profileLwm2mServer) { + private boolean getValidatedSecurityMode(LwM2MBootstrapConfig lwM2MBootstrapConfig) { + LwM2MSecurityMode bootstrapServerSecurityMode = lwM2MBootstrapConfig.getBootstrapServer().getSecurityMode(); + LwM2MSecurityMode lwm2mServerSecurityMode = lwM2MBootstrapConfig.getLwm2mServer().getSecurityMode(); + AtomicBoolean validBs = new AtomicBoolean(true); + AtomicBoolean validLw = new AtomicBoolean(true); + lwM2MBootstrapConfig.getServerConfiguration().forEach(serverCredential -> { + if (((AbstractLwM2MBootstrapServerCredential)serverCredential).isBootstrapServerIs()) { + if (!bootstrapServerSecurityMode.equals(serverCredential.getSecurityMode())) { + validBs.set(false); + } + } + else { + if (!lwm2mServerSecurityMode.equals(serverCredential.getSecurityMode())) { + validLw.set(false); + } + } + }); + return validBs.get()&validLw.get(); } public TransportProtos.SessionInfoProto getSessionByEndpoint(String endpoint) { diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MInMemoryBootstrapConfigStore.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MInMemoryBootstrapConfigStore.java similarity index 97% rename from common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MInMemoryBootstrapConfigStore.java rename to common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MInMemoryBootstrapConfigStore.java index ba3880c6bc..2fa470a58e 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MInMemoryBootstrapConfigStore.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MInMemoryBootstrapConfigStore.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.transport.lwm2m.bootstrap.secure; +package org.thingsboard.server.transport.lwm2m.bootstrap.store; import lombok.extern.slf4j.Slf4j; import org.eclipse.leshan.core.request.Identity; diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LwM2mCredentialsSecurityInfoValidator.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LwM2mCredentialsSecurityInfoValidator.java index 8b343ab02f..f75aca52c3 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LwM2mCredentialsSecurityInfoValidator.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LwM2mCredentialsSecurityInfoValidator.java @@ -24,13 +24,14 @@ import org.springframework.stereotype.Component; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MClientCredential; -import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MSecurityMode; import org.thingsboard.server.common.data.device.credentials.lwm2m.PSKClientCredential; import org.thingsboard.server.common.data.device.credentials.lwm2m.RPKClientCredential; +import org.thingsboard.server.common.data.device.profile.Lwm2mDeviceProfileTransportConfiguration; import org.thingsboard.server.common.transport.TransportServiceCallback; import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse; import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceLwM2MCredentialsRequestMsg; import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; +import org.thingsboard.server.transport.lwm2m.bootstrap.secure.LwM2MBootstrapConfig; import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; import org.thingsboard.server.transport.lwm2m.secure.credentials.LwM2MClientCredentials; import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportContext; @@ -68,17 +69,16 @@ public class LwM2mCredentialsSecurityInfoValidator { @Override public void onSuccess(ValidateDeviceCredentialsResponse msg) { log.trace("Validated credentials: [{}] [{}]", credentialsId, msg); - String credentialsBody = msg.getCredentials(); - resultSecurityStore[0] = createSecurityInfo(credentialsId, credentialsBody, keyValue); - resultSecurityStore[0].setMsg(msg); - resultSecurityStore[0].setDeviceProfile(msg.getDeviceProfile()); + resultSecurityStore[0] = createSecurityInfo(credentialsId, msg, keyValue); latch.countDown(); } @Override public void onError(Throwable e) { log.trace("[{}] [{}] Failed to process credentials ", credentialsId, e); - resultSecurityStore[0] = createSecurityInfo(credentialsId, null, null); + TbLwM2MSecurityInfo result = new TbLwM2MSecurityInfo(); + result.setEndpoint(credentialsId); + resultSecurityStore[0] = result; latch.countDown(); } }); @@ -88,50 +88,47 @@ public class LwM2mCredentialsSecurityInfoValidator { log.error("Failed to await credentials!", e); } - return resultSecurityStore[0]; - -// if ((CLIENT.equals(keyValue) && securityInfo.getSecurityMode() == null) || -// (BOOTSTRAP.equals(keyValue) && securityInfo.getBootstrapCredentialConfig().getBootstrapServer()==null && securityInfo.getBootstrapCredentialConfig().getLwm2mServer()==null)){ -// throw new LwM2MAuthException(); -// } -// -// return securityInfo; + TbLwM2MSecurityInfo securityInfo = resultSecurityStore[0]; + if ((CLIENT.equals(keyValue) && securityInfo.getSecurityMode() == null)) { + throw new LwM2MAuthException(); + } + return securityInfo; } /** * Create new SecurityInfo + * * @return SecurityInfo */ - private TbLwM2MSecurityInfo createSecurityInfo(String endpoint, String jsonStr, LwM2mTypeServer keyValue) { + private TbLwM2MSecurityInfo createSecurityInfo(String endpoint, ValidateDeviceCredentialsResponse msg, LwM2mTypeServer keyValue) { TbLwM2MSecurityInfo result = new TbLwM2MSecurityInfo(); - LwM2MClientCredentials credentials = JacksonUtil.fromString(jsonStr, LwM2MClientCredentials.class); + LwM2MClientCredentials credentials = JacksonUtil.fromString(msg.getCredentials(), LwM2MClientCredentials.class); if (credentials != null) { + result.setMsg(msg); + result.setDeviceProfile(msg.getDeviceProfile()); + result.setEndpoint(credentials.getClient().getEndpoint()); +// if ((keyValue.equals(CLIENT))) { + switch (credentials.getClient().getSecurityConfigClientMode()) { + case NO_SEC: + createClientSecurityInfoNoSec(result); + break; + case PSK: + createClientSecurityInfoPSK(result, endpoint, credentials.getClient()); + break; + case RPK: + createClientSecurityInfoRPK(result, endpoint, credentials.getClient()); + break; + case X509: + createClientSecurityInfoX509(result, endpoint, credentials.getClient()); + break; + default: + break; + } +// } else if (keyValue.equals(BOOTSTRAP)) { - result.setBootstrapCredentialConfig(credentials.getBootstrap()); - if (LwM2MSecurityMode.PSK.equals(credentials.getClient().getSecurityConfigClientMode())) { - PSKClientCredential pskClientConfig = (PSKClientCredential) credentials.getClient(); - endpoint = StringUtils.isNotEmpty(pskClientConfig.getEndpoint()) ? pskClientConfig.getEndpoint() : endpoint; - } - result.setEndpoint(endpoint); -// result.setSecurityMode(credentials.getBootstrap().getBootstrapServer().getSecurityMode()); - } else { - result.setEndpoint(credentials.getClient().getEndpoint()); - switch (credentials.getClient().getSecurityConfigClientMode()) { - case NO_SEC: - createClientSecurityInfoNoSec(result); - break; - case PSK: - createClientSecurityInfoPSK(result, endpoint, credentials.getClient()); - break; - case RPK: - createClientSecurityInfoRPK(result, endpoint, credentials.getClient()); - break; - case X509: - createClientSecurityInfoX509(result, endpoint, credentials.getClient()); - break; - default: - break; - } + LwM2MBootstrapConfig bootstrapCredentialConfig = new LwM2MBootstrapConfig(((Lwm2mDeviceProfileTransportConfiguration) msg.getDeviceProfile().getProfileData().getTransportConfiguration()).getBootstrap(), + credentials.getBootstrap().getBootstrapServer(), credentials.getBootstrap().getLwm2mServer()); + result.setBootstrapCredentialConfig(bootstrapCredentialConfig); } } return result; diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MSecurityInfo.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MSecurityInfo.java index 61774228c0..fe5ede1bda 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MSecurityInfo.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MSecurityInfo.java @@ -28,12 +28,13 @@ import java.io.Serializable; @Data public class TbLwM2MSecurityInfo implements Serializable { private ValidateDeviceCredentialsResponse msg; + private DeviceProfile deviceProfile; + private String endpoint; private SecurityInfo securityInfo; private SecurityMode securityMode; - private DeviceProfile deviceProfile; + /** bootstrap */ private LwM2MBootstrapConfig bootstrapCredentialConfig; - private String endpoint; private BootstrapConfig bootstrapConfig; } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mSecurityStore.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mSecurityStore.java index a289391dbf..fd7061b9d7 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mSecurityStore.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mSecurityStore.java @@ -22,6 +22,7 @@ import org.eclipse.leshan.server.security.SecurityInfo; import org.jetbrains.annotations.Nullable; import org.thingsboard.server.transport.lwm2m.secure.LwM2mCredentialsSecurityInfoValidator; import org.thingsboard.server.transport.lwm2m.secure.TbLwM2MSecurityInfo; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2MAuthException; import java.util.Arrays; import java.util.HashSet; @@ -71,7 +72,12 @@ public class TbLwM2mSecurityStore implements TbMainSecurityStore { public SecurityInfo getByIdentity(String pskIdentity) { SecurityInfo securityInfo = securityStore.getByIdentity(pskIdentity); if (securityInfo == null) { - securityInfo = fetchAndPutSecurityInfo(pskIdentity); + try { + securityInfo = fetchAndPutSecurityInfo(pskIdentity); + } catch (LwM2MAuthException e) { + log.info("Registration failed: FORBIDDEN, endpointId: [{}]", pskIdentity); + securityInfo = SecurityInfo.newPreSharedKeyInfo(pskIdentity, pskIdentity, new byte[]{0x00}); + } } return securityInfo; } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2MTransportUtil.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2MTransportUtil.java index daa521abc3..3c7a8e523e 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2MTransportUtil.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2MTransportUtil.java @@ -39,7 +39,7 @@ import org.eclipse.leshan.server.registration.Registration; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.DeviceTransportType; -import org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap.LwM2MBootstrapServersConfiguration; +import org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap.LwM2MBootstrapServerCredential; import org.thingsboard.server.common.data.device.profile.DeviceProfileTransportConfiguration; import org.thingsboard.server.common.data.device.profile.Lwm2mDeviceProfileTransportConfiguration; import org.thingsboard.server.common.data.ota.OtaPackageKey; @@ -181,7 +181,7 @@ public class LwM2MTransportUtil { } } - public static LwM2MBootstrapServersConfiguration getBootstrapParametersFromThingsboard(DeviceProfile deviceProfile) { + public static List getBootstrapParametersFromThingsboard(DeviceProfile deviceProfile) { return toLwM2MClientProfile(deviceProfile).getBootstrap(); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java index 5a7bf32518..22a9a00e15 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java @@ -46,7 +46,6 @@ import org.thingsboard.server.common.data.DeviceProfileType; import org.thingsboard.server.common.data.DeviceTransportType; import org.thingsboard.server.common.data.OtaPackage; import org.thingsboard.server.common.data.Tenant; -import org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap.LwM2MBootstrapServersConfiguration; import org.thingsboard.server.common.data.device.profile.CoapDeviceProfileTransportConfiguration; import org.thingsboard.server.common.data.device.profile.CoapDeviceTypeConfiguration; import org.thingsboard.server.common.data.device.profile.DefaultCoapDeviceTypeConfiguration; @@ -418,8 +417,8 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D } } } else if (transportConfiguration instanceof Lwm2mDeviceProfileTransportConfiguration) { - LwM2MBootstrapServersConfiguration lwM2MBootstrapServersConfiguration = ((Lwm2mDeviceProfileTransportConfiguration) transportConfiguration).getBootstrap(); - for (LwM2MBootstrapServerCredential bootstrapServerCredential : lwM2MBootstrapServersConfiguration.getServerConfiguration()) { + List lwM2MBootstrapServersConfigurations = ((Lwm2mDeviceProfileTransportConfiguration) transportConfiguration).getBootstrap(); + for (LwM2MBootstrapServerCredential bootstrapServerCredential : lwM2MBootstrapServersConfigurations) { validateLwm2mServersCredentialOfBootstrapForClient(bootstrapServerCredential); } } From 68920746468c43e8cca418ea43d4af3ad0c10c74 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Thu, 11 Nov 2021 17:16:47 +0200 Subject: [PATCH 097/432] lwm2m - Security config default --- .../server/controller/Lwm2mController.java | 4 +-- .../server/service/lwm2m/LwM2MService.java | 4 +-- .../service/lwm2m/LwM2MServiceImpl.java | 10 +++---- .../bootstrap/LwM2MServerSecurityConfig.java | 4 --- .../LwM2MServerSecurityConfigDefault.java | 29 +++++++++++++++++++ 5 files changed, 38 insertions(+), 13 deletions(-) create mode 100644 common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/LwM2MServerSecurityConfigDefault.java diff --git a/application/src/main/java/org/thingsboard/server/controller/Lwm2mController.java b/application/src/main/java/org/thingsboard/server/controller/Lwm2mController.java index 86ef420192..5870c7304c 100644 --- a/application/src/main/java/org/thingsboard/server/controller/Lwm2mController.java +++ b/application/src/main/java/org/thingsboard/server/controller/Lwm2mController.java @@ -29,8 +29,8 @@ import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.SaveDeviceWithCredentialsRequest; +import org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap.LwM2MServerSecurityConfigDefault; import org.thingsboard.server.common.data.exception.ThingsboardException; -import org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap.LwM2MServerSecurityConfig; import org.thingsboard.server.common.data.security.DeviceCredentials; import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.service.lwm2m.LwM2MService; @@ -61,7 +61,7 @@ public class Lwm2mController extends BaseController { @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/lwm2m/deviceProfile/bootstrap/{isBootstrapServer}", method = RequestMethod.GET) @ResponseBody - public LwM2MServerSecurityConfig getLwm2mBootstrapSecurityInfo( + public LwM2MServerSecurityConfigDefault getLwm2mBootstrapSecurityInfo( @ApiParam(value = IS_BOOTSTRAP_SERVER_PARAM_DESCRIPTION) @PathVariable(IS_BOOTSTRAP_SERVER) boolean bootstrapServer) throws ThingsboardException { try { diff --git a/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MService.java b/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MService.java index e63f66f0bf..f5724e9ec0 100644 --- a/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MService.java +++ b/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MService.java @@ -15,10 +15,10 @@ */ package org.thingsboard.server.service.lwm2m; -import org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap.LwM2MServerSecurityConfig; +import org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap.LwM2MServerSecurityConfigDefault; public interface LwM2MService { - LwM2MServerSecurityConfig getServerSecurityInfo(boolean bootstrapServer); + LwM2MServerSecurityConfigDefault getServerSecurityInfo(boolean bootstrapServer); } diff --git a/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MServiceImpl.java b/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MServiceImpl.java index 0ba57cbc00..5178cbf191 100644 --- a/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MServiceImpl.java +++ b/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MServiceImpl.java @@ -20,7 +20,7 @@ import lombok.extern.slf4j.Slf4j; import org.apache.commons.codec.binary.Base64; import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.stereotype.Service; -import org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap.LwM2MServerSecurityConfig; +import org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap.LwM2MServerSecurityConfigDefault; import org.thingsboard.server.common.transport.config.ssl.SslCredentials; import org.thingsboard.server.transport.lwm2m.config.LwM2MSecureServerConfig; import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportBootstrapConfig; @@ -36,14 +36,14 @@ public class LwM2MServiceImpl implements LwM2MService { private final LwM2MTransportBootstrapConfig bootstrapConfig; @Override - public LwM2MServerSecurityConfig getServerSecurityInfo(boolean bootstrapServer) { - LwM2MServerSecurityConfig result = getServerSecurityConfig(bootstrapServer ? bootstrapConfig : serverConfig); + public LwM2MServerSecurityConfigDefault getServerSecurityInfo(boolean bootstrapServer) { + LwM2MServerSecurityConfigDefault result = getServerSecurityConfig(bootstrapServer ? bootstrapConfig : serverConfig); result.setBootstrapServerIs(bootstrapServer); return result; } - private LwM2MServerSecurityConfig getServerSecurityConfig(LwM2MSecureServerConfig serverConfig) { - LwM2MServerSecurityConfig bsServ = new LwM2MServerSecurityConfig(); + private LwM2MServerSecurityConfigDefault getServerSecurityConfig(LwM2MSecureServerConfig serverConfig) { + LwM2MServerSecurityConfigDefault bsServ = new LwM2MServerSecurityConfigDefault(); bsServ.setShortServerId(serverConfig.getId()); bsServ.setHost(serverConfig.getHost()); bsServ.setPort(serverConfig.getPort()); diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/LwM2MServerSecurityConfig.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/LwM2MServerSecurityConfig.java index 7a43bd60ca..fcbe91743b 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/LwM2MServerSecurityConfig.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/LwM2MServerSecurityConfig.java @@ -34,10 +34,6 @@ public class LwM2MServerSecurityConfig { protected String host; @ApiModelProperty(position = 4, value = "Port for Lwm2m Server: 'No Security' mode: Lwm2m Server or Bootstrap Server", example = "'5685' or '5687'", readOnly = true) protected Integer port; - @ApiModelProperty(position = 5, value = "Host for 'Security' mode (DTLS)", example = "0.0.0.0", readOnly = true) - protected String securityHost; - @ApiModelProperty(position = 6, value = "Port for 'Security' mode (DTLS): Lwm2m Server or Bootstrap Server", example = "5686 or 5688", readOnly = true) - protected Integer securityPort; @ApiModelProperty(position = 7, value = "Client Hold Off Time. The number of seconds to wait before initiating a Client Initiated Bootstrap once the LwM2M Client has determined it should initiate this bootstrap mode. (This information is relevant for use with a Bootstrap-Server only.)", example = "1", readOnly = true) protected Integer clientHoldOffTime = 1; @ApiModelProperty(position = 8, value = "Server Public Key for 'Security' mode (DTLS): RPK or X509. Format: base64 encoded", example = "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEAZ0pSaGKHk/GrDaUDnQZpeEdGwX7m3Ws+U/kiVat\n" + diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/LwM2MServerSecurityConfigDefault.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/LwM2MServerSecurityConfigDefault.java new file mode 100644 index 0000000000..2c79507810 --- /dev/null +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/LwM2MServerSecurityConfigDefault.java @@ -0,0 +1,29 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +@ApiModel +@Data +public class LwM2MServerSecurityConfigDefault extends LwM2MServerSecurityConfig { + @ApiModelProperty(position = 5, value = "Host for 'Security' mode (DTLS)", example = "0.0.0.0", readOnly = true) + protected String securityHost; + @ApiModelProperty(position = 6, value = "Port for 'Security' mode (DTLS): Lwm2m Server or Bootstrap Server", example = "5686 or 5688", readOnly = true) + protected Integer securityPort; +} From 47267e503a58e67f3c3de7012bdc7628f1912c1a Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Thu, 11 Nov 2021 17:16:47 +0200 Subject: [PATCH 098/432] lwm2m - Security config default --- .../server/controller/Lwm2mController.java | 4 +-- .../server/service/lwm2m/LwM2MService.java | 4 +-- .../service/lwm2m/LwM2MServiceImpl.java | 10 +++---- .../bootstrap/LwM2MServerSecurityConfig.java | 4 --- .../LwM2MServerSecurityConfigDefault.java | 29 +++++++++++++++++++ 5 files changed, 38 insertions(+), 13 deletions(-) create mode 100644 common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/LwM2MServerSecurityConfigDefault.java diff --git a/application/src/main/java/org/thingsboard/server/controller/Lwm2mController.java b/application/src/main/java/org/thingsboard/server/controller/Lwm2mController.java index 86ef420192..5870c7304c 100644 --- a/application/src/main/java/org/thingsboard/server/controller/Lwm2mController.java +++ b/application/src/main/java/org/thingsboard/server/controller/Lwm2mController.java @@ -29,8 +29,8 @@ import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.SaveDeviceWithCredentialsRequest; +import org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap.LwM2MServerSecurityConfigDefault; import org.thingsboard.server.common.data.exception.ThingsboardException; -import org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap.LwM2MServerSecurityConfig; import org.thingsboard.server.common.data.security.DeviceCredentials; import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.service.lwm2m.LwM2MService; @@ -61,7 +61,7 @@ public class Lwm2mController extends BaseController { @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/lwm2m/deviceProfile/bootstrap/{isBootstrapServer}", method = RequestMethod.GET) @ResponseBody - public LwM2MServerSecurityConfig getLwm2mBootstrapSecurityInfo( + public LwM2MServerSecurityConfigDefault getLwm2mBootstrapSecurityInfo( @ApiParam(value = IS_BOOTSTRAP_SERVER_PARAM_DESCRIPTION) @PathVariable(IS_BOOTSTRAP_SERVER) boolean bootstrapServer) throws ThingsboardException { try { diff --git a/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MService.java b/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MService.java index e63f66f0bf..f5724e9ec0 100644 --- a/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MService.java +++ b/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MService.java @@ -15,10 +15,10 @@ */ package org.thingsboard.server.service.lwm2m; -import org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap.LwM2MServerSecurityConfig; +import org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap.LwM2MServerSecurityConfigDefault; public interface LwM2MService { - LwM2MServerSecurityConfig getServerSecurityInfo(boolean bootstrapServer); + LwM2MServerSecurityConfigDefault getServerSecurityInfo(boolean bootstrapServer); } diff --git a/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MServiceImpl.java b/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MServiceImpl.java index 0ba57cbc00..5178cbf191 100644 --- a/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MServiceImpl.java +++ b/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MServiceImpl.java @@ -20,7 +20,7 @@ import lombok.extern.slf4j.Slf4j; import org.apache.commons.codec.binary.Base64; import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.stereotype.Service; -import org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap.LwM2MServerSecurityConfig; +import org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap.LwM2MServerSecurityConfigDefault; import org.thingsboard.server.common.transport.config.ssl.SslCredentials; import org.thingsboard.server.transport.lwm2m.config.LwM2MSecureServerConfig; import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportBootstrapConfig; @@ -36,14 +36,14 @@ public class LwM2MServiceImpl implements LwM2MService { private final LwM2MTransportBootstrapConfig bootstrapConfig; @Override - public LwM2MServerSecurityConfig getServerSecurityInfo(boolean bootstrapServer) { - LwM2MServerSecurityConfig result = getServerSecurityConfig(bootstrapServer ? bootstrapConfig : serverConfig); + public LwM2MServerSecurityConfigDefault getServerSecurityInfo(boolean bootstrapServer) { + LwM2MServerSecurityConfigDefault result = getServerSecurityConfig(bootstrapServer ? bootstrapConfig : serverConfig); result.setBootstrapServerIs(bootstrapServer); return result; } - private LwM2MServerSecurityConfig getServerSecurityConfig(LwM2MSecureServerConfig serverConfig) { - LwM2MServerSecurityConfig bsServ = new LwM2MServerSecurityConfig(); + private LwM2MServerSecurityConfigDefault getServerSecurityConfig(LwM2MSecureServerConfig serverConfig) { + LwM2MServerSecurityConfigDefault bsServ = new LwM2MServerSecurityConfigDefault(); bsServ.setShortServerId(serverConfig.getId()); bsServ.setHost(serverConfig.getHost()); bsServ.setPort(serverConfig.getPort()); diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/LwM2MServerSecurityConfig.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/LwM2MServerSecurityConfig.java index 7a43bd60ca..fcbe91743b 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/LwM2MServerSecurityConfig.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/LwM2MServerSecurityConfig.java @@ -34,10 +34,6 @@ public class LwM2MServerSecurityConfig { protected String host; @ApiModelProperty(position = 4, value = "Port for Lwm2m Server: 'No Security' mode: Lwm2m Server or Bootstrap Server", example = "'5685' or '5687'", readOnly = true) protected Integer port; - @ApiModelProperty(position = 5, value = "Host for 'Security' mode (DTLS)", example = "0.0.0.0", readOnly = true) - protected String securityHost; - @ApiModelProperty(position = 6, value = "Port for 'Security' mode (DTLS): Lwm2m Server or Bootstrap Server", example = "5686 or 5688", readOnly = true) - protected Integer securityPort; @ApiModelProperty(position = 7, value = "Client Hold Off Time. The number of seconds to wait before initiating a Client Initiated Bootstrap once the LwM2M Client has determined it should initiate this bootstrap mode. (This information is relevant for use with a Bootstrap-Server only.)", example = "1", readOnly = true) protected Integer clientHoldOffTime = 1; @ApiModelProperty(position = 8, value = "Server Public Key for 'Security' mode (DTLS): RPK or X509. Format: base64 encoded", example = "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEAZ0pSaGKHk/GrDaUDnQZpeEdGwX7m3Ws+U/kiVat\n" + diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/LwM2MServerSecurityConfigDefault.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/LwM2MServerSecurityConfigDefault.java new file mode 100644 index 0000000000..2c79507810 --- /dev/null +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/LwM2MServerSecurityConfigDefault.java @@ -0,0 +1,29 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +@ApiModel +@Data +public class LwM2MServerSecurityConfigDefault extends LwM2MServerSecurityConfig { + @ApiModelProperty(position = 5, value = "Host for 'Security' mode (DTLS)", example = "0.0.0.0", readOnly = true) + protected String securityHost; + @ApiModelProperty(position = 6, value = "Port for 'Security' mode (DTLS): Lwm2m Server or Bootstrap Server", example = "5686 or 5688", readOnly = true) + protected Integer securityPort; +} From 6d657fed466d3e46cc1db3eb9f170aeedc31ffb1 Mon Sep 17 00:00:00 2001 From: van-vanich Date: Fri, 12 Nov 2021 14:02:51 +0200 Subject: [PATCH 099/432] add process pattern for rule node: - customer attribute - tenant attribute - related attribute also, refactoring old tests for customer attribute and add tests related and tenant attribute. --- .../engine/metadata/TbEntityGetAttrNode.java | 25 +- .../TbGetCustomerAttributeNodeTest.java | 49 +-- .../TbGetRelatedAttributeNodeTest.java | 299 ++++++++++++++++++ .../TbGetTenantAttributeNodeTest.java | 278 ++++++++++++++++ 4 files changed, 627 insertions(+), 24 deletions(-) create mode 100644 rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttributeNodeTest.java create mode 100644 rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetTenantAttributeNodeTest.java diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbEntityGetAttrNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbEntityGetAttrNode.java index 79b2edf856..2143639a2c 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbEntityGetAttrNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbEntityGetAttrNode.java @@ -30,12 +30,14 @@ import org.thingsboard.server.common.data.kv.KvEntry; import org.thingsboard.server.common.data.kv.TsKvEntry; import org.thingsboard.server.common.msg.TbMsg; +import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.stream.Collectors; import static org.thingsboard.common.util.DonAsynchron.withCallback; import static org.thingsboard.rule.engine.api.TbRelationTypes.FAILURE; -import static org.thingsboard.rule.engine.api.TbRelationTypes.SUCCESS; import static org.thingsboard.server.common.data.DataConstants.SERVER_SCOPE; @Slf4j @@ -84,10 +86,29 @@ public abstract class TbEntityGetAttrNode implements TbNode private void putAttributesAndTell(TbContext ctx, TbMsg msg, List attributes) { + log.info("attr " + attributes.toString()); + log.info("conf attr " + config.getAttrMapping().toString()); + List attrProcessPattern = new ArrayList<>(); + log.info("msg {}", msg); + log.info("result process {}", attrProcessPattern); + Map updConf = new HashMap<>(); + config.getAttrMapping().forEach((key, value) -> { + String processPattern = TbNodeUtils.processPattern(key, msg); + updConf.put(processPattern, value); + attrProcessPattern.add(processPattern); + }); + attributes.forEach(r -> { - String attrName = config.getAttrMapping().get(r.getKey()); + log.info("r {}", r); + log.info("rkey {}", r.getKey()); + log.info("index {}", attrProcessPattern.indexOf(r.getKey())); + log.info("getByKey {}", updConf.get(r.getKey())); + String attrName = updConf.get(r.getKey()); + log.info("attrName {}", attrName); msg.getMetaData().putValue(attrName, r.getValueAsString()); + log.info(msg.getMetaData().toString()); }); + log.info(msg.toString()); ctx.tellSuccess(msg); } diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNodeTest.java index ca88290808..6720be90de 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNodeTest.java @@ -86,20 +86,24 @@ public class TbGetCustomerAttributeNodeTest { private DeviceService deviceService; private TbMsg msg; + private Map metaData; - private RuleChainId ruleChainId = new RuleChainId(Uuids.timeBased()); - private RuleNodeId ruleNodeId = new RuleNodeId(Uuids.timeBased()); + private final RuleChainId ruleChainId = new RuleChainId(Uuids.timeBased()); + private final RuleNodeId ruleNodeId = new RuleNodeId(Uuids.timeBased()); @Before public void init() throws TbNodeException { TbGetEntityAttrNodeConfiguration config = new TbGetEntityAttrNodeConfiguration(); - Map attrMapping = new HashMap<>(); - attrMapping.putIfAbsent("temperature", "tempo"); - config.setAttrMapping(attrMapping); + Map conf = new HashMap<>(); + conf.put("${word}", "result"); + config.setAttrMapping(conf); config.setTelemetry(false); ObjectMapper mapper = new ObjectMapper(); TbNodeConfiguration nodeConfiguration = new TbNodeConfiguration(mapper.valueToTree(config)); + metaData = new HashMap<>(); + metaData.putIfAbsent("word", "temperature"); + node = new TbGetCustomerAttributeNode(); node.init(null, nodeConfiguration); } @@ -111,13 +115,13 @@ public class TbGetCustomerAttributeNodeTest { User user = new User(); user.setCustomerId(customerId); - msg = TbMsg.newMsg( "USER", userId, new TbMsgMetaData(), TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); + msg = TbMsg.newMsg("USER", userId, new TbMsgMetaData(), TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); when(ctx.getUserService()).thenReturn(userService); when(userService.findUserByIdAsync(any(), eq(userId))).thenReturn(Futures.immediateFuture(user)); when(ctx.getAttributesService()).thenReturn(attributesService); - when(attributesService.find(any(), eq(customerId), eq(SERVER_SCOPE), eq(Collections.singleton("temperature")))) + when(attributesService.find(any(), eq(customerId), eq(SERVER_SCOPE), eq(Collections.singleton("${word}")))) .thenThrow(new IllegalStateException("something wrong")); node.onMsg(ctx, msg); @@ -136,13 +140,13 @@ public class TbGetCustomerAttributeNodeTest { User user = new User(); user.setCustomerId(customerId); - msg = TbMsg.newMsg( "USER", userId, new TbMsgMetaData(), TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); + msg = TbMsg.newMsg("USER", userId, new TbMsgMetaData(), TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); when(ctx.getUserService()).thenReturn(userService); when(userService.findUserByIdAsync(any(), eq(userId))).thenReturn(Futures.immediateFuture(user)); when(ctx.getAttributesService()).thenReturn(attributesService); - when(attributesService.find(any(), eq(customerId), eq(SERVER_SCOPE), eq(Collections.singleton("temperature")))) + when(attributesService.find(any(), eq(customerId), eq(SERVER_SCOPE), eq(Collections.singleton("${word}")))) .thenReturn(Futures.immediateFailedFuture(new IllegalStateException("something wrong"))); node.onMsg(ctx, msg); @@ -161,7 +165,7 @@ public class TbGetCustomerAttributeNodeTest { User user = new User(); user.setCustomerId(customerId); - msg = TbMsg.newMsg( "USER", userId, new TbMsgMetaData(), TbMsgDataType.JSON,"{}", ruleChainId, ruleNodeId); + msg = TbMsg.newMsg("USER", userId, new TbMsgMetaData(), TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); when(ctx.getUserService()).thenReturn(userService); when(userService.findUserByIdAsync(any(), eq(userId))).thenReturn(Futures.immediateFuture(null)); @@ -175,7 +179,7 @@ public class TbGetCustomerAttributeNodeTest { @Test public void customerAttributeAddedInMetadata() { CustomerId customerId = new CustomerId(Uuids.timeBased()); - msg = TbMsg.newMsg( "CUSTOMER", customerId, new TbMsgMetaData(), TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); + msg = TbMsg.newMsg("CUSTOMER", customerId, new TbMsgMetaData(metaData), TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); entityAttributeFetched(customerId); } @@ -186,7 +190,7 @@ public class TbGetCustomerAttributeNodeTest { User user = new User(); user.setCustomerId(customerId); - msg = TbMsg.newMsg( "USER", userId, new TbMsgMetaData(), TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); + msg = TbMsg.newMsg("USER", userId, new TbMsgMetaData(metaData), TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); when(ctx.getUserService()).thenReturn(userService); when(userService.findUserByIdAsync(any(), eq(userId))).thenReturn(Futures.immediateFuture(user)); @@ -201,7 +205,7 @@ public class TbGetCustomerAttributeNodeTest { Asset asset = new Asset(); asset.setCustomerId(customerId); - msg = TbMsg.newMsg( "USER", assetId, new TbMsgMetaData(), TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); + msg = TbMsg.newMsg("USER", assetId, new TbMsgMetaData(metaData), TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); when(ctx.getAssetService()).thenReturn(assetService); when(assetService.findAssetByIdAsync(any(), eq(assetId))).thenReturn(Futures.immediateFuture(asset)); @@ -216,7 +220,7 @@ public class TbGetCustomerAttributeNodeTest { Device device = new Device(); device.setCustomerId(customerId); - msg = TbMsg.newMsg( "USER", deviceId, new TbMsgMetaData(), TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); + msg = TbMsg.newMsg("USER", deviceId, new TbMsgMetaData(metaData), TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); when(ctx.getDeviceService()).thenReturn(deviceService); when(deviceService.findDeviceByIdAsync(any(), eq(deviceId))).thenReturn(Futures.immediateFuture(device)); @@ -227,9 +231,10 @@ public class TbGetCustomerAttributeNodeTest { @Test public void deviceCustomerTelemetryFetched() throws TbNodeException { TbGetEntityAttrNodeConfiguration config = new TbGetEntityAttrNodeConfiguration(); - Map attrMapping = new HashMap<>(); - attrMapping.putIfAbsent("temperature", "tempo"); - config.setAttrMapping(attrMapping); + + Map conf = new HashMap<>(); + conf.put("${word}", "result"); + config.setAttrMapping(conf); config.setTelemetry(true); ObjectMapper mapper = new ObjectMapper(); TbNodeConfiguration nodeConfiguration = new TbNodeConfiguration(mapper.valueToTree(config)); @@ -243,7 +248,7 @@ public class TbGetCustomerAttributeNodeTest { Device device = new Device(); device.setCustomerId(customerId); - msg = TbMsg.newMsg( "USER", deviceId, new TbMsgMetaData(), TbMsgDataType.JSON,"{}", ruleChainId, ruleNodeId); + msg = TbMsg.newMsg("USER", deviceId, new TbMsgMetaData(metaData), TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); when(ctx.getDeviceService()).thenReturn(deviceService); when(deviceService.findDeviceByIdAsync(any(), eq(deviceId))).thenReturn(Futures.immediateFuture(device)); @@ -251,23 +256,23 @@ public class TbGetCustomerAttributeNodeTest { List timeseries = Lists.newArrayList(new BasicTsKvEntry(1L, new StringDataEntry("temperature", "highest"))); when(ctx.getTimeseriesService()).thenReturn(timeseriesService); - when(timeseriesService.findLatest(any(), eq(customerId), eq(Collections.singleton("temperature")))) + when(timeseriesService.findLatest(any(), eq(customerId), eq(Collections.singleton("${word}")))) .thenReturn(Futures.immediateFuture(timeseries)); node.onMsg(ctx, msg); verify(ctx).tellSuccess(msg); - assertEquals(msg.getMetaData().getValue("tempo"), "highest"); + assertEquals(msg.getMetaData().getValue("result"), "highest"); } private void entityAttributeFetched(CustomerId customerId) { List attributes = Lists.newArrayList(new BaseAttributeKvEntry(new StringDataEntry("temperature", "high"), 1L)); when(ctx.getAttributesService()).thenReturn(attributesService); - when(attributesService.find(any(), eq(customerId), eq(SERVER_SCOPE), eq(Collections.singleton("temperature")))) + when(attributesService.find(any(), eq(customerId), eq(SERVER_SCOPE), eq(Collections.singleton("${word}")))) .thenReturn(Futures.immediateFuture(attributes)); node.onMsg(ctx, msg); verify(ctx).tellSuccess(msg); - assertEquals(msg.getMetaData().getValue("tempo"), "high"); + assertEquals(msg.getMetaData().getValue("result"), "high"); } } diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttributeNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttributeNodeTest.java new file mode 100644 index 0000000000..820d3118d4 --- /dev/null +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttributeNodeTest.java @@ -0,0 +1,299 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.rule.engine.metadata; + +import com.datastax.oss.driver.api.core.uuid.Uuids; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.common.collect.Lists; +import com.google.common.util.concurrent.Futures; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; +import org.thingsboard.rule.engine.api.TbContext; +import org.thingsboard.rule.engine.api.TbNodeConfiguration; +import org.thingsboard.rule.engine.api.TbNodeException; +import org.thingsboard.server.common.data.Device; +import org.thingsboard.server.common.data.User; +import org.thingsboard.server.common.data.asset.Asset; +import org.thingsboard.server.common.data.id.AssetId; +import org.thingsboard.server.common.data.id.CustomerId; +import org.thingsboard.server.common.data.id.DeviceId; +import org.thingsboard.server.common.data.id.RuleChainId; +import org.thingsboard.server.common.data.id.RuleNodeId; +import org.thingsboard.server.common.data.id.UserId; +import org.thingsboard.server.common.data.kv.AttributeKvEntry; +import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry; +import org.thingsboard.server.common.data.kv.BasicTsKvEntry; +import org.thingsboard.server.common.data.kv.StringDataEntry; +import org.thingsboard.server.common.data.kv.TsKvEntry; +import org.thingsboard.server.common.data.relation.EntityRelation; +import org.thingsboard.server.common.msg.TbMsg; +import org.thingsboard.server.common.msg.TbMsgDataType; +import org.thingsboard.server.common.msg.TbMsgMetaData; +import org.thingsboard.server.dao.asset.AssetService; +import org.thingsboard.server.dao.attributes.AttributesService; +import org.thingsboard.server.dao.device.DeviceService; +import org.thingsboard.server.dao.relation.RelationService; +import org.thingsboard.server.dao.timeseries.TimeseriesService; +import org.thingsboard.server.dao.user.UserService; + +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.ArgumentMatchers.same; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.thingsboard.rule.engine.api.TbRelationTypes.FAILURE; +import static org.thingsboard.server.common.data.DataConstants.SERVER_SCOPE; + +@RunWith(MockitoJUnitRunner.Silent.class) +public class TbGetRelatedAttributeNodeTest { + private final CustomerId customerId = new CustomerId(Uuids.timeBased()); + private final RuleChainId ruleChainId = new RuleChainId(Uuids.timeBased()); + private final RuleNodeId ruleNodeId = new RuleNodeId(Uuids.timeBased()); + private TbGetRelatedAttributeNode node; + @Mock + private TbContext ctx; + @Mock + private AttributesService attributesService; + @Mock + private TimeseriesService timeseriesService; + @Mock + private UserService userService; + @Mock + private AssetService assetService; + @Mock + private DeviceService deviceService; + @Mock + private RelationService relationService; + private TbMsg msg; + private Map metaData; + private EntityRelation entityRelation; + + @Before + public void init() throws TbNodeException { + TbGetRelatedAttrNodeConfiguration config = new TbGetRelatedAttrNodeConfiguration(); + config = config.defaultConfiguration(); + Map conf = new HashMap<>(); + conf.put("${word}", "result"); + config.setAttrMapping(conf); + config.setTelemetry(false); + ObjectMapper mapper = new ObjectMapper(); + TbNodeConfiguration nodeConfiguration = new TbNodeConfiguration(mapper.valueToTree(config)); + + metaData = new HashMap<>(); + metaData.putIfAbsent("word", "temperature"); + + entityRelation = new EntityRelation(); + entityRelation.setTo(customerId); + entityRelation.setType(EntityRelation.CONTAINS_TYPE); + when(ctx.getRelationService()).thenReturn(relationService); + + node = new TbGetRelatedAttributeNode(); + node.init(null, nodeConfiguration); + } + + @Test + public void errorThrownIfCannotLoadAttributes() { + UserId userId = new UserId(Uuids.timeBased()); + User user = new User(); + user.setCustomerId(customerId); + entityRelation.setFrom(userId); + when(relationService.findByQuery(any(), any())).thenReturn(Futures.immediateFuture(List.of(entityRelation))); + + msg = TbMsg.newMsg("USER", userId, new TbMsgMetaData(), TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); + + when(ctx.getUserService()).thenReturn(userService); + when(userService.findUserByIdAsync(any(), eq(userId))).thenReturn(Futures.immediateFuture(user)); + + when(ctx.getAttributesService()).thenReturn(attributesService); + when(attributesService.find(any(), eq(customerId), eq(SERVER_SCOPE), eq(Collections.singleton("${word}")))) + .thenThrow(new IllegalStateException("something wrong")); + + node.onMsg(ctx, msg); + final ArgumentCaptor captor = ArgumentCaptor.forClass(Throwable.class); + verify(ctx).tellFailure(same(msg), captor.capture()); + + Throwable value = captor.getValue(); + assertEquals("something wrong", value.getMessage()); + assertTrue(msg.getMetaData().getData().isEmpty()); + } + + @Test + public void errorThrownIfCannotLoadAttributesAsync() { + UserId userId = new UserId(Uuids.timeBased()); + User user = new User(); + user.setCustomerId(customerId); + entityRelation.setFrom(userId); + when(relationService.findByQuery(any(), any())).thenReturn(Futures.immediateFuture(List.of(entityRelation))); + + msg = TbMsg.newMsg("USER", userId, new TbMsgMetaData(), TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); + + when(ctx.getUserService()).thenReturn(userService); + when(userService.findUserByIdAsync(any(), eq(userId))).thenReturn(Futures.immediateFuture(user)); + + when(ctx.getAttributesService()).thenReturn(attributesService); + + when(attributesService.find(any(), eq(customerId), eq(SERVER_SCOPE), eq(Collections.singleton("${word}")))) + .thenReturn(Futures.immediateFailedFuture(new IllegalStateException("something wrong"))); + + node.onMsg(ctx, msg); + final ArgumentCaptor captor = ArgumentCaptor.forClass(Throwable.class); + verify(ctx).tellFailure(same(msg), captor.capture()); + + Throwable value = captor.getValue(); + assertEquals("something wrong", value.getMessage()); + assertTrue(msg.getMetaData().getData().isEmpty()); + } + + @Test + public void failedChainUsedIfCustomerCannotBeFound() { + UserId userId = new UserId(Uuids.timeBased()); + User user = new User(); + user.setCustomerId(customerId); + entityRelation.setFrom(customerId); + entityRelation.setTo(null); + when(relationService.findByQuery(any(), any())).thenReturn(Futures.immediateFuture(List.of(entityRelation))); + + msg = TbMsg.newMsg("USER", userId, new TbMsgMetaData(), TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); + + when(ctx.getUserService()).thenReturn(userService); + when(userService.findUserByIdAsync(any(), eq(userId))).thenReturn(Futures.immediateFuture(null)); + + + node.onMsg(ctx, msg); + verify(ctx).tellNext(msg, FAILURE); + assertTrue(msg.getMetaData().getData().isEmpty()); + + entityRelation.setTo(customerId); + } + + @Test + public void customerAttributeAddedInMetadata() { + entityRelation.setFrom(customerId); + when(relationService.findByQuery(any(), any())).thenReturn(Futures.immediateFuture(List.of(entityRelation))); + msg = TbMsg.newMsg("CUSTOMER", customerId, new TbMsgMetaData(metaData), TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); + entityAttributeFetched(customerId); + } + + @Test + public void usersCustomerAttributesFetched() { + UserId userId = new UserId(Uuids.timeBased()); + User user = new User(); + user.setCustomerId(customerId); + entityRelation.setFrom(userId); + when(relationService.findByQuery(any(), any())).thenReturn(Futures.immediateFuture(List.of(entityRelation))); + + msg = TbMsg.newMsg("USER", userId, new TbMsgMetaData(metaData), TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); + + when(ctx.getUserService()).thenReturn(userService); + when(userService.findUserByIdAsync(any(), eq(userId))).thenReturn(Futures.immediateFuture(user)); + + entityAttributeFetched(customerId); + } + + @Test + public void assetsCustomerAttributesFetched() { + AssetId assetId = new AssetId(Uuids.timeBased()); + Asset asset = new Asset(); + asset.setCustomerId(customerId); + entityRelation.setFrom(assetId); + when(relationService.findByQuery(any(), any())).thenReturn(Futures.immediateFuture(List.of(entityRelation))); + + msg = TbMsg.newMsg("USER", assetId, new TbMsgMetaData(metaData), TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); + + when(ctx.getAssetService()).thenReturn(assetService); + when(assetService.findAssetByIdAsync(any(), eq(assetId))).thenReturn(Futures.immediateFuture(asset)); + + entityAttributeFetched(customerId); + } + + @Test + public void deviceCustomerAttributesFetched() { + DeviceId deviceId = new DeviceId(Uuids.timeBased()); + Device device = new Device(); + device.setCustomerId(customerId); + entityRelation.setFrom(deviceId); + when(relationService.findByQuery(any(), any())).thenReturn(Futures.immediateFuture(List.of(entityRelation))); + + msg = TbMsg.newMsg("USER", deviceId, new TbMsgMetaData(metaData), TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); + + when(ctx.getDeviceService()).thenReturn(deviceService); + when(deviceService.findDeviceByIdAsync(any(), eq(deviceId))).thenReturn(Futures.immediateFuture(device)); + + entityAttributeFetched(customerId); + } + + @Test + public void deviceCustomerTelemetryFetched() throws TbNodeException { + TbGetRelatedAttrNodeConfiguration config = new TbGetRelatedAttrNodeConfiguration(); + config = config.defaultConfiguration(); + + Map conf = new HashMap<>(); + conf.put("${word}", "result"); + config.setAttrMapping(conf); + config.setTelemetry(true); + ObjectMapper mapper = new ObjectMapper(); + TbNodeConfiguration nodeConfiguration = new TbNodeConfiguration(mapper.valueToTree(config)); + + node = new TbGetRelatedAttributeNode(); + node.init(null, nodeConfiguration); + + + DeviceId deviceId = new DeviceId(Uuids.timeBased()); + Device device = new Device(); + device.setCustomerId(customerId); + + entityRelation.setFrom(deviceId); + when(relationService.findByQuery(any(), any())).thenReturn(Futures.immediateFuture(List.of(entityRelation))); + + msg = TbMsg.newMsg("USER", deviceId, new TbMsgMetaData(metaData), TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); + + when(ctx.getDeviceService()).thenReturn(deviceService); + when(deviceService.findDeviceByIdAsync(any(), eq(deviceId))).thenReturn(Futures.immediateFuture(device)); + + List timeseries = Lists.newArrayList(new BasicTsKvEntry(1L, new StringDataEntry("temperature", "highest"))); + + when(ctx.getTimeseriesService()).thenReturn(timeseriesService); + when(timeseriesService.findLatest(any(), eq(customerId), eq(Collections.singleton("${word}")))) + .thenReturn(Futures.immediateFuture(timeseries)); + + node.onMsg(ctx, msg); + verify(ctx).tellSuccess(msg); + assertEquals(msg.getMetaData().getValue("result"), "highest"); + } + + private void entityAttributeFetched(CustomerId customerId) { + List attributes = Lists.newArrayList(new BaseAttributeKvEntry(new StringDataEntry("temperature", "high"), 1L)); + + when(ctx.getAttributesService()).thenReturn(attributesService); + when(attributesService.find(any(), eq(customerId), eq(SERVER_SCOPE), eq(Collections.singleton("${word}")))) + .thenReturn(Futures.immediateFuture(attributes)); + + node.onMsg(ctx, msg); + verify(ctx).tellSuccess(msg); + assertEquals(msg.getMetaData().getValue("result"), "high"); + } +} \ No newline at end of file diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetTenantAttributeNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetTenantAttributeNodeTest.java new file mode 100644 index 0000000000..1e111d150c --- /dev/null +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetTenantAttributeNodeTest.java @@ -0,0 +1,278 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.rule.engine.metadata; + +import com.datastax.oss.driver.api.core.uuid.Uuids; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.common.collect.Lists; +import com.google.common.util.concurrent.Futures; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; +import org.thingsboard.rule.engine.api.TbContext; +import org.thingsboard.rule.engine.api.TbNodeConfiguration; +import org.thingsboard.rule.engine.api.TbNodeException; +import org.thingsboard.server.common.data.Device; +import org.thingsboard.server.common.data.User; +import org.thingsboard.server.common.data.asset.Asset; +import org.thingsboard.server.common.data.id.AssetId; +import org.thingsboard.server.common.data.id.CustomerId; +import org.thingsboard.server.common.data.id.DeviceId; +import org.thingsboard.server.common.data.id.RuleChainId; +import org.thingsboard.server.common.data.id.RuleNodeId; +import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.id.UserId; +import org.thingsboard.server.common.data.kv.AttributeKvEntry; +import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry; +import org.thingsboard.server.common.data.kv.BasicTsKvEntry; +import org.thingsboard.server.common.data.kv.StringDataEntry; +import org.thingsboard.server.common.data.kv.TsKvEntry; +import org.thingsboard.server.common.msg.TbMsg; +import org.thingsboard.server.common.msg.TbMsgDataType; +import org.thingsboard.server.common.msg.TbMsgMetaData; +import org.thingsboard.server.dao.asset.AssetService; +import org.thingsboard.server.dao.attributes.AttributesService; +import org.thingsboard.server.dao.device.DeviceService; +import org.thingsboard.server.dao.timeseries.TimeseriesService; +import org.thingsboard.server.dao.user.UserService; + +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.ArgumentMatchers.same; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.thingsboard.rule.engine.api.TbRelationTypes.FAILURE; +import static org.thingsboard.server.common.data.DataConstants.SERVER_SCOPE; + +@RunWith(MockitoJUnitRunner.Silent.class) +public class TbGetTenantAttributeNodeTest { + private TbGetTenantAttributeNode node; + + @Mock + private TbContext ctx; + + @Mock + private AttributesService attributesService; + @Mock + private TimeseriesService timeseriesService; + @Mock + private UserService userService; + @Mock + private AssetService assetService; + @Mock + private DeviceService deviceService; + + private TbMsg msg; + private Map metaData; + + private final RuleChainId ruleChainId = new RuleChainId(Uuids.timeBased()); + private final RuleNodeId ruleNodeId = new RuleNodeId(Uuids.timeBased()); + + @Before + public void init() throws TbNodeException { + TbGetEntityAttrNodeConfiguration config = new TbGetEntityAttrNodeConfiguration(); + Map conf = new HashMap<>(); + conf.put("${word}", "result"); + config.setAttrMapping(conf); + config.setTelemetry(false); + ObjectMapper mapper = new ObjectMapper(); + TbNodeConfiguration nodeConfiguration = new TbNodeConfiguration(mapper.valueToTree(config)); + + metaData = new HashMap<>(); + metaData.putIfAbsent("word", "temperature"); + + node = new TbGetTenantAttributeNode(); + node.init(null, nodeConfiguration); + } + + @Test + public void errorThrownIfCannotLoadAttributes() { + UserId userId = new UserId(Uuids.timeBased()); + TenantId tenantId = new TenantId(Uuids.timeBased()); + User user = new User(); + user.setTenantId(tenantId); + + msg = TbMsg.newMsg("USER", userId, new TbMsgMetaData(), TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); + + when(ctx.getUserService()).thenReturn(userService); + when(userService.findUserByIdAsync(any(), eq(userId))).thenReturn(Futures.immediateFuture(user)); + + when(ctx.getAttributesService()).thenReturn(attributesService); + when(attributesService.find(any(), eq(tenantId), eq(SERVER_SCOPE), eq(Collections.singleton("${word}")))) + .thenThrow(new IllegalStateException("something wrong")); + + node.onMsg(ctx, msg); + final ArgumentCaptor captor = ArgumentCaptor.forClass(Throwable.class); + verify(ctx).tellFailure(same(msg), captor.capture()); + + Throwable value = captor.getValue(); + assertEquals("something wrong", value.getMessage()); + assertTrue(msg.getMetaData().getData().isEmpty()); + } + + @Test + public void errorThrownIfCannotLoadAttributesAsync() { + UserId userId = new UserId(Uuids.timeBased()); + TenantId tenantId = new TenantId(Uuids.timeBased()); + User user = new User(); + user.setTenantId(tenantId); + + msg = TbMsg.newMsg("USER", userId, new TbMsgMetaData(), TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); + + when(ctx.getUserService()).thenReturn(userService); + when(userService.findUserByIdAsync(any(), eq(userId))).thenReturn(Futures.immediateFuture(user)); + + when(ctx.getAttributesService()).thenReturn(attributesService); + when(attributesService.find(any(), eq(tenantId), eq(SERVER_SCOPE), eq(Collections.singleton("${word}")))) + .thenReturn(Futures.immediateFailedFuture(new IllegalStateException("something wrong"))); + + node.onMsg(ctx, msg); + final ArgumentCaptor captor = ArgumentCaptor.forClass(Throwable.class); + verify(ctx).tellFailure(same(msg), captor.capture()); + + Throwable value = captor.getValue(); + assertEquals("something wrong", value.getMessage()); + assertTrue(msg.getMetaData().getData().isEmpty()); + } + + @Test + public void failedChainUsedIfCustomerCannotBeFound() { + UserId userId = new UserId(Uuids.timeBased()); + CustomerId customerId = new CustomerId(Uuids.timeBased()); + User user = new User(); + user.setCustomerId(customerId); + + msg = TbMsg.newMsg("USER", userId, new TbMsgMetaData(), TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); + + when(ctx.getUserService()).thenReturn(userService); + when(userService.findUserByIdAsync(any(), eq(userId))).thenReturn(Futures.immediateFuture(null)); + + + node.onMsg(ctx, msg); + verify(ctx).tellNext(msg, FAILURE); + assertTrue(msg.getMetaData().getData().isEmpty()); + } + + @Test + public void customerAttributeAddedInMetadata() { + TenantId tenantId = new TenantId(Uuids.timeBased()); + msg = TbMsg.newMsg("TENANT", tenantId, new TbMsgMetaData(metaData), TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); + entityAttributeFetched(tenantId); + } + + @Test + public void usersCustomerAttributesFetched() { + UserId userId = new UserId(Uuids.timeBased()); + TenantId tenantId = new TenantId(Uuids.timeBased()); + User user = new User(); + user.setTenantId(tenantId); + + msg = TbMsg.newMsg("USER", userId, new TbMsgMetaData(metaData), TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); + + when(ctx.getUserService()).thenReturn(userService); + when(userService.findUserByIdAsync(any(), eq(userId))).thenReturn(Futures.immediateFuture(user)); + + entityAttributeFetched(tenantId); + } + + @Test + public void assetsCustomerAttributesFetched() { + AssetId assetId = new AssetId(Uuids.timeBased()); + TenantId tenantId = new TenantId(Uuids.timeBased()); + Asset asset = new Asset(); + asset.setTenantId(tenantId); + + msg = TbMsg.newMsg("USER", assetId, new TbMsgMetaData(metaData), TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); + + when(ctx.getAssetService()).thenReturn(assetService); + when(assetService.findAssetByIdAsync(any(), eq(assetId))).thenReturn(Futures.immediateFuture(asset)); + + entityAttributeFetched(tenantId); + } + + @Test + public void deviceCustomerAttributesFetched() { + DeviceId deviceId = new DeviceId(Uuids.timeBased()); + TenantId tenantId = new TenantId(Uuids.timeBased()); + Device device = new Device(); + device.setTenantId(tenantId); + + msg = TbMsg.newMsg("USER", deviceId, new TbMsgMetaData(metaData), TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); + + when(ctx.getDeviceService()).thenReturn(deviceService); + when(deviceService.findDeviceByIdAsync(any(), eq(deviceId))).thenReturn(Futures.immediateFuture(device)); + + entityAttributeFetched(tenantId); + } + + @Test + public void deviceCustomerTelemetryFetched() throws TbNodeException { + TbGetEntityAttrNodeConfiguration config = new TbGetEntityAttrNodeConfiguration(); + + Map conf = new HashMap<>(); + conf.put("${word}", "result"); + config.setAttrMapping(conf); + config.setTelemetry(true); + ObjectMapper mapper = new ObjectMapper(); + TbNodeConfiguration nodeConfiguration = new TbNodeConfiguration(mapper.valueToTree(config)); + + node = new TbGetTenantAttributeNode(); + node.init(null, nodeConfiguration); + + + DeviceId deviceId = new DeviceId(Uuids.timeBased()); + TenantId tenantId = new TenantId(Uuids.timeBased()); + Device device = new Device(); + device.setTenantId(tenantId); + + msg = TbMsg.newMsg("USER", deviceId, new TbMsgMetaData(metaData), TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); + + when(ctx.getDeviceService()).thenReturn(deviceService); + when(deviceService.findDeviceByIdAsync(any(), eq(deviceId))).thenReturn(Futures.immediateFuture(device)); + + List timeseries = Lists.newArrayList(new BasicTsKvEntry(1L, new StringDataEntry("temperature", "highest"))); + + when(ctx.getTimeseriesService()).thenReturn(timeseriesService); + when(timeseriesService.findLatest(any(), eq(tenantId), eq(Collections.singleton("${word}")))) + .thenReturn(Futures.immediateFuture(timeseries)); + + node.onMsg(ctx, msg); + verify(ctx).tellSuccess(msg); + assertEquals(msg.getMetaData().getValue("result"), "highest"); + } + + private void entityAttributeFetched(TenantId customerId) { + List attributes = Lists.newArrayList(new BaseAttributeKvEntry(new StringDataEntry("temperature", "high"), 1L)); + + when(ctx.getAttributesService()).thenReturn(attributesService); + when(attributesService.find(any(), eq(customerId), eq(SERVER_SCOPE), eq(Collections.singleton("${word}")))) + .thenReturn(Futures.immediateFuture(attributes)); + + node.onMsg(ctx, msg); + verify(ctx).tellSuccess(msg); + assertEquals(msg.getMetaData().getValue("result"), "high"); + } +} \ No newline at end of file From 79f3d3826a1c916288c8a89b15c9be64d068d9ef Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Fri, 12 Nov 2021 15:52:58 +0200 Subject: [PATCH 100/432] UI: Added clearing selectedWidgetsBundleAlias when calling resetSortAndFilter function in attribute table --- .../home/components/attribute/attribute-table.component.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/ui-ngx/src/app/modules/home/components/attribute/attribute-table.component.ts b/ui-ngx/src/app/modules/home/components/attribute/attribute-table.component.ts index bcb9edd07e..9e9bbceb6f 100644 --- a/ui-ngx/src/app/modules/home/components/attribute/attribute-table.component.ts +++ b/ui-ngx/src/app/modules/home/components/attribute/attribute-table.component.ts @@ -263,6 +263,7 @@ export class AttributeTableComponent extends PageComponent implements AfterViewI this.attributeScopeSelectionReadonly = true; } this.mode = 'default'; + this.selectedWidgetsBundleAlias = null; this.attributeScope = this.defaultAttributeScope; this.pageLink.textSearch = null; if (this.viewsInited) { From 3fec3aa21c1e85e52f036734a2a51afe8b1ffb53 Mon Sep 17 00:00:00 2001 From: van-vanich Date: Fri, 12 Nov 2021 15:59:24 +0200 Subject: [PATCH 101/432] refactoring and fix bugs --- .../engine/metadata/TbEntityGetAttrNode.java | 23 ++++++------------- .../TbGetCustomerAttributeNodeTest.java | 18 ++++++--------- .../TbGetRelatedAttributeNodeTest.java | 10 ++++---- .../TbGetTenantAttributeNodeTest.java | 18 ++++++--------- 4 files changed, 26 insertions(+), 43 deletions(-) diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbEntityGetAttrNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbEntityGetAttrNode.java index 2143639a2c..f2c52b1ba5 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbEntityGetAttrNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbEntityGetAttrNode.java @@ -67,30 +67,28 @@ public abstract class TbEntityGetAttrNode implements TbNode return; } - withCallback(config.isTelemetry() ? getLatestTelemetry(ctx, entityId) : getAttributesAsync(ctx, entityId), + withCallback(config.isTelemetry() ? getLatestTelemetry(ctx, entityId, msg) : getAttributesAsync(ctx, entityId, msg), attributes -> putAttributesAndTell(ctx, msg, attributes), t -> ctx.tellFailure(msg, t), ctx.getDbCallbackExecutor()); } - private ListenableFuture> getAttributesAsync(TbContext ctx, EntityId entityId) { - ListenableFuture> latest = ctx.getAttributesService().find(ctx.getTenantId(), entityId, SERVER_SCOPE, config.getAttrMapping().keySet()); + private ListenableFuture> getAttributesAsync(TbContext ctx, EntityId entityId, TbMsg msg) { + List attrProcess = TbNodeUtils.processPatterns(List.copyOf(config.getAttrMapping().keySet()), msg); + ListenableFuture> latest = ctx.getAttributesService().find(ctx.getTenantId(), entityId, SERVER_SCOPE, attrProcess); return Futures.transform(latest, l -> l.stream().map(i -> (KvEntry) i).collect(Collectors.toList()), MoreExecutors.directExecutor()); } - private ListenableFuture> getLatestTelemetry(TbContext ctx, EntityId entityId) { - ListenableFuture> latest = ctx.getTimeseriesService().findLatest(ctx.getTenantId(), entityId, config.getAttrMapping().keySet()); + private ListenableFuture> getLatestTelemetry(TbContext ctx, EntityId entityId, TbMsg msg) { + List latestProcess = TbNodeUtils.processPatterns(List.copyOf(config.getAttrMapping().keySet()), msg); + ListenableFuture> latest = ctx.getTimeseriesService().findLatest(ctx.getTenantId(), entityId, latestProcess); return Futures.transform(latest, l -> l.stream().map(i -> (KvEntry) i).collect(Collectors.toList()), MoreExecutors.directExecutor()); } private void putAttributesAndTell(TbContext ctx, TbMsg msg, List attributes) { - log.info("attr " + attributes.toString()); - log.info("conf attr " + config.getAttrMapping().toString()); List attrProcessPattern = new ArrayList<>(); - log.info("msg {}", msg); - log.info("result process {}", attrProcessPattern); Map updConf = new HashMap<>(); config.getAttrMapping().forEach((key, value) -> { String processPattern = TbNodeUtils.processPattern(key, msg); @@ -99,16 +97,9 @@ public abstract class TbEntityGetAttrNode implements TbNode }); attributes.forEach(r -> { - log.info("r {}", r); - log.info("rkey {}", r.getKey()); - log.info("index {}", attrProcessPattern.indexOf(r.getKey())); - log.info("getByKey {}", updConf.get(r.getKey())); String attrName = updConf.get(r.getKey()); - log.info("attrName {}", attrName); msg.getMetaData().putValue(attrName, r.getValueAsString()); - log.info(msg.getMetaData().toString()); }); - log.info(msg.toString()); ctx.tellSuccess(msg); } diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNodeTest.java index 6720be90de..b7db9b6995 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNodeTest.java @@ -51,7 +51,6 @@ import org.thingsboard.server.dao.device.DeviceService; import org.thingsboard.server.dao.timeseries.TimeseriesService; import org.thingsboard.server.dao.user.UserService; -import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -59,6 +58,7 @@ import java.util.Map; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyCollection; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.same; import static org.mockito.Mockito.verify; @@ -69,11 +69,11 @@ import static org.thingsboard.server.common.data.DataConstants.SERVER_SCOPE; @RunWith(MockitoJUnitRunner.class) public class TbGetCustomerAttributeNodeTest { + private final RuleChainId ruleChainId = new RuleChainId(Uuids.timeBased()); + private final RuleNodeId ruleNodeId = new RuleNodeId(Uuids.timeBased()); private TbGetCustomerAttributeNode node; - @Mock private TbContext ctx; - @Mock private AttributesService attributesService; @Mock @@ -84,13 +84,9 @@ public class TbGetCustomerAttributeNodeTest { private AssetService assetService; @Mock private DeviceService deviceService; - private TbMsg msg; private Map metaData; - private final RuleChainId ruleChainId = new RuleChainId(Uuids.timeBased()); - private final RuleNodeId ruleNodeId = new RuleNodeId(Uuids.timeBased()); - @Before public void init() throws TbNodeException { TbGetEntityAttrNodeConfiguration config = new TbGetEntityAttrNodeConfiguration(); @@ -121,7 +117,7 @@ public class TbGetCustomerAttributeNodeTest { when(userService.findUserByIdAsync(any(), eq(userId))).thenReturn(Futures.immediateFuture(user)); when(ctx.getAttributesService()).thenReturn(attributesService); - when(attributesService.find(any(), eq(customerId), eq(SERVER_SCOPE), eq(Collections.singleton("${word}")))) + when(attributesService.find(any(), eq(customerId), eq(SERVER_SCOPE), anyCollection())) .thenThrow(new IllegalStateException("something wrong")); node.onMsg(ctx, msg); @@ -146,7 +142,7 @@ public class TbGetCustomerAttributeNodeTest { when(userService.findUserByIdAsync(any(), eq(userId))).thenReturn(Futures.immediateFuture(user)); when(ctx.getAttributesService()).thenReturn(attributesService); - when(attributesService.find(any(), eq(customerId), eq(SERVER_SCOPE), eq(Collections.singleton("${word}")))) + when(attributesService.find(any(), eq(customerId), eq(SERVER_SCOPE), anyCollection())) .thenReturn(Futures.immediateFailedFuture(new IllegalStateException("something wrong"))); node.onMsg(ctx, msg); @@ -256,7 +252,7 @@ public class TbGetCustomerAttributeNodeTest { List timeseries = Lists.newArrayList(new BasicTsKvEntry(1L, new StringDataEntry("temperature", "highest"))); when(ctx.getTimeseriesService()).thenReturn(timeseriesService); - when(timeseriesService.findLatest(any(), eq(customerId), eq(Collections.singleton("${word}")))) + when(timeseriesService.findLatest(any(), eq(customerId), anyCollection())) .thenReturn(Futures.immediateFuture(timeseries)); node.onMsg(ctx, msg); @@ -268,7 +264,7 @@ public class TbGetCustomerAttributeNodeTest { List attributes = Lists.newArrayList(new BaseAttributeKvEntry(new StringDataEntry("temperature", "high"), 1L)); when(ctx.getAttributesService()).thenReturn(attributesService); - when(attributesService.find(any(), eq(customerId), eq(SERVER_SCOPE), eq(Collections.singleton("${word}")))) + when(attributesService.find(any(), eq(customerId), eq(SERVER_SCOPE), anyCollection())) .thenReturn(Futures.immediateFuture(attributes)); node.onMsg(ctx, msg); diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttributeNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttributeNodeTest.java index 820d3118d4..35340bed0a 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttributeNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttributeNodeTest.java @@ -53,7 +53,6 @@ import org.thingsboard.server.dao.relation.RelationService; import org.thingsboard.server.dao.timeseries.TimeseriesService; import org.thingsboard.server.dao.user.UserService; -import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -61,6 +60,7 @@ import java.util.Map; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyCollection; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.same; import static org.mockito.Mockito.verify; @@ -129,7 +129,7 @@ public class TbGetRelatedAttributeNodeTest { when(userService.findUserByIdAsync(any(), eq(userId))).thenReturn(Futures.immediateFuture(user)); when(ctx.getAttributesService()).thenReturn(attributesService); - when(attributesService.find(any(), eq(customerId), eq(SERVER_SCOPE), eq(Collections.singleton("${word}")))) + when(attributesService.find(any(), eq(customerId), eq(SERVER_SCOPE), anyCollection())) .thenThrow(new IllegalStateException("something wrong")); node.onMsg(ctx, msg); @@ -156,7 +156,7 @@ public class TbGetRelatedAttributeNodeTest { when(ctx.getAttributesService()).thenReturn(attributesService); - when(attributesService.find(any(), eq(customerId), eq(SERVER_SCOPE), eq(Collections.singleton("${word}")))) + when(attributesService.find(any(), eq(customerId), eq(SERVER_SCOPE), anyCollection())) .thenReturn(Futures.immediateFailedFuture(new IllegalStateException("something wrong"))); node.onMsg(ctx, msg); @@ -277,7 +277,7 @@ public class TbGetRelatedAttributeNodeTest { List timeseries = Lists.newArrayList(new BasicTsKvEntry(1L, new StringDataEntry("temperature", "highest"))); when(ctx.getTimeseriesService()).thenReturn(timeseriesService); - when(timeseriesService.findLatest(any(), eq(customerId), eq(Collections.singleton("${word}")))) + when(timeseriesService.findLatest(any(), eq(customerId), anyCollection())) .thenReturn(Futures.immediateFuture(timeseries)); node.onMsg(ctx, msg); @@ -289,7 +289,7 @@ public class TbGetRelatedAttributeNodeTest { List attributes = Lists.newArrayList(new BaseAttributeKvEntry(new StringDataEntry("temperature", "high"), 1L)); when(ctx.getAttributesService()).thenReturn(attributesService); - when(attributesService.find(any(), eq(customerId), eq(SERVER_SCOPE), eq(Collections.singleton("${word}")))) + when(attributesService.find(any(), eq(customerId), eq(SERVER_SCOPE), anyCollection())) .thenReturn(Futures.immediateFuture(attributes)); node.onMsg(ctx, msg); diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetTenantAttributeNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetTenantAttributeNodeTest.java index 1e111d150c..783d786117 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetTenantAttributeNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetTenantAttributeNodeTest.java @@ -52,7 +52,6 @@ import org.thingsboard.server.dao.device.DeviceService; import org.thingsboard.server.dao.timeseries.TimeseriesService; import org.thingsboard.server.dao.user.UserService; -import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -60,6 +59,7 @@ import java.util.Map; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyCollection; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.same; import static org.mockito.Mockito.verify; @@ -69,11 +69,11 @@ import static org.thingsboard.server.common.data.DataConstants.SERVER_SCOPE; @RunWith(MockitoJUnitRunner.Silent.class) public class TbGetTenantAttributeNodeTest { + private final RuleChainId ruleChainId = new RuleChainId(Uuids.timeBased()); + private final RuleNodeId ruleNodeId = new RuleNodeId(Uuids.timeBased()); private TbGetTenantAttributeNode node; - @Mock private TbContext ctx; - @Mock private AttributesService attributesService; @Mock @@ -84,13 +84,9 @@ public class TbGetTenantAttributeNodeTest { private AssetService assetService; @Mock private DeviceService deviceService; - private TbMsg msg; private Map metaData; - private final RuleChainId ruleChainId = new RuleChainId(Uuids.timeBased()); - private final RuleNodeId ruleNodeId = new RuleNodeId(Uuids.timeBased()); - @Before public void init() throws TbNodeException { TbGetEntityAttrNodeConfiguration config = new TbGetEntityAttrNodeConfiguration(); @@ -121,7 +117,7 @@ public class TbGetTenantAttributeNodeTest { when(userService.findUserByIdAsync(any(), eq(userId))).thenReturn(Futures.immediateFuture(user)); when(ctx.getAttributesService()).thenReturn(attributesService); - when(attributesService.find(any(), eq(tenantId), eq(SERVER_SCOPE), eq(Collections.singleton("${word}")))) + when(attributesService.find(any(), eq(tenantId), eq(SERVER_SCOPE), anyCollection())) .thenThrow(new IllegalStateException("something wrong")); node.onMsg(ctx, msg); @@ -146,7 +142,7 @@ public class TbGetTenantAttributeNodeTest { when(userService.findUserByIdAsync(any(), eq(userId))).thenReturn(Futures.immediateFuture(user)); when(ctx.getAttributesService()).thenReturn(attributesService); - when(attributesService.find(any(), eq(tenantId), eq(SERVER_SCOPE), eq(Collections.singleton("${word}")))) + when(attributesService.find(any(), eq(tenantId), eq(SERVER_SCOPE), anyCollection())) .thenReturn(Futures.immediateFailedFuture(new IllegalStateException("something wrong"))); node.onMsg(ctx, msg); @@ -256,7 +252,7 @@ public class TbGetTenantAttributeNodeTest { List timeseries = Lists.newArrayList(new BasicTsKvEntry(1L, new StringDataEntry("temperature", "highest"))); when(ctx.getTimeseriesService()).thenReturn(timeseriesService); - when(timeseriesService.findLatest(any(), eq(tenantId), eq(Collections.singleton("${word}")))) + when(timeseriesService.findLatest(any(), eq(tenantId), anyCollection())) .thenReturn(Futures.immediateFuture(timeseries)); node.onMsg(ctx, msg); @@ -268,7 +264,7 @@ public class TbGetTenantAttributeNodeTest { List attributes = Lists.newArrayList(new BaseAttributeKvEntry(new StringDataEntry("temperature", "high"), 1L)); when(ctx.getAttributesService()).thenReturn(attributesService); - when(attributesService.find(any(), eq(customerId), eq(SERVER_SCOPE), eq(Collections.singleton("${word}")))) + when(attributesService.find(any(), eq(customerId), eq(SERVER_SCOPE), anyCollection())) .thenReturn(Futures.immediateFuture(attributes)); node.onMsg(ctx, msg); From 4f845a82803b42ea6546abb65d9b5dcc8c1dbd06 Mon Sep 17 00:00:00 2001 From: van-vanich Date: Fri, 12 Nov 2021 16:00:55 +0200 Subject: [PATCH 102/432] remove code, which use in hard debugging --- .../thingsboard/rule/engine/metadata/TbEntityGetAttrNode.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbEntityGetAttrNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbEntityGetAttrNode.java index f2c52b1ba5..c8df7b4a92 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbEntityGetAttrNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbEntityGetAttrNode.java @@ -88,12 +88,10 @@ public abstract class TbEntityGetAttrNode implements TbNode private void putAttributesAndTell(TbContext ctx, TbMsg msg, List attributes) { - List attrProcessPattern = new ArrayList<>(); Map updConf = new HashMap<>(); config.getAttrMapping().forEach((key, value) -> { String processPattern = TbNodeUtils.processPattern(key, msg); updConf.put(processPattern, value); - attrProcessPattern.add(processPattern); }); attributes.forEach(r -> { From f247e96d97dfa136c553f9b359a47f33b2d60acf Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Mon, 15 Nov 2021 18:27:53 +0200 Subject: [PATCH 103/432] fixed NPE in case of incorrect partitioning name parameter (now you will see the normal log message with error) --- .../thingsboard/server/dao/timeseries/NoSqlTsPartitionDate.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dao/src/main/java/org/thingsboard/server/dao/timeseries/NoSqlTsPartitionDate.java b/dao/src/main/java/org/thingsboard/server/dao/timeseries/NoSqlTsPartitionDate.java index 694ea9ba4d..9ed7494bf9 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/timeseries/NoSqlTsPartitionDate.java +++ b/dao/src/main/java/org/thingsboard/server/dao/timeseries/NoSqlTsPartitionDate.java @@ -66,6 +66,6 @@ public enum NoSqlTsPartitionDate { } } } - return Optional.of(partition); + return Optional.ofNullable(partition); } } From 1cda63e74d0e47b74ff180efc980dd7c023e784b Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Mon, 15 Nov 2021 18:27:53 +0200 Subject: [PATCH 104/432] fixed NPE in case of incorrect partitioning name parameter (now you will see the normal log message with error) (cherry picked from commit f247e96d97dfa136c553f9b359a47f33b2d60acf) --- .../thingsboard/server/dao/timeseries/NoSqlTsPartitionDate.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dao/src/main/java/org/thingsboard/server/dao/timeseries/NoSqlTsPartitionDate.java b/dao/src/main/java/org/thingsboard/server/dao/timeseries/NoSqlTsPartitionDate.java index 694ea9ba4d..9ed7494bf9 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/timeseries/NoSqlTsPartitionDate.java +++ b/dao/src/main/java/org/thingsboard/server/dao/timeseries/NoSqlTsPartitionDate.java @@ -66,6 +66,6 @@ public enum NoSqlTsPartitionDate { } } } - return Optional.of(partition); + return Optional.ofNullable(partition); } } From 25abfcebf3486f0838876ef3fbef317cdc35fed5 Mon Sep 17 00:00:00 2001 From: Sergey Tarnavskiy Date: Mon, 15 Nov 2021 18:48:03 +0200 Subject: [PATCH 105/432] Bootstrap servers refactoring for LwM2M transport --- .../add-device-profile-dialog.component.html | 1 + .../device-profile-alarms.component.html | 4 +- .../profile/device-profile.component.html | 1 + .../profile/device-profile.component.ts | 3 + ...ile-transport-configuration.component.html | 1 + ...ofile-transport-configuration.component.ts | 3 + ...ap-add-config-server-dialog.component.html | 55 ++++ ...trap-add-config-server-dialog.component.ts | 60 ++++ ...2m-bootstrap-config-servers.component.html | 39 +++ ...wm2m-bootstrap-config-servers.component.ts | 185 +++++++++++++ .../lwm2m-device-config-server.component.html | 257 +++++++++++------- .../lwm2m-device-config-server.component.ts | 44 ++- ...ile-transport-configuration.component.html | 90 +----- ...ofile-transport-configuration.component.ts | 56 +--- .../lwm2m/lwm2m-profile-components.module.ts | 6 + .../lwm2m/lwm2m-profile-config.models.ts | 66 ++--- .../device-wizard-dialog.component.html | 1 + .../device-profile-tabs.component.html | 1 + .../device-profile-tabs.component.ts | 5 + ui-ngx/src/app/shared/models/device.models.ts | 9 +- .../models/lwm2m-security-config.models.ts | 14 +- .../assets/locale/locale.constant-en_US.json | 17 +- 22 files changed, 613 insertions(+), 305 deletions(-) create mode 100644 ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-bootstrap-add-config-server-dialog.component.html create mode 100644 ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-bootstrap-add-config-server-dialog.component.ts create mode 100644 ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-bootstrap-config-servers.component.html create mode 100644 ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-bootstrap-config-servers.component.ts diff --git a/ui-ngx/src/app/modules/home/components/profile/add-device-profile-dialog.component.html b/ui-ngx/src/app/modules/home/components/profile/add-device-profile-dialog.component.html index 23fdf04cde..42ef973988 100644 --- a/ui-ngx/src/app/modules/home/components/profile/add-device-profile-dialog.component.html +++ b/ui-ngx/src/app/modules/home/components/profile/add-device-profile-dialog.component.html @@ -100,6 +100,7 @@ diff --git a/ui-ngx/src/app/modules/home/components/profile/alarm/device-profile-alarms.component.html b/ui-ngx/src/app/modules/home/components/profile/alarm/device-profile-alarms.component.html index c8433fde7c..df0d5af5a3 100644 --- a/ui-ngx/src/app/modules/home/components/profile/alarm/device-profile-alarms.component.html +++ b/ui-ngx/src/app/modules/home/components/profile/alarm/device-profile-alarms.component.html @@ -34,9 +34,7 @@
diff --git a/ui-ngx/src/app/modules/home/components/profile/device-profile.component.html b/ui-ngx/src/app/modules/home/components/profile/device-profile.component.html index 917ad25dd2..d96d1788c7 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device-profile.component.html +++ b/ui-ngx/src/app/modules/home/components/profile/device-profile.component.html @@ -138,6 +138,7 @@ diff --git a/ui-ngx/src/app/modules/home/components/profile/device-profile.component.ts b/ui-ngx/src/app/modules/home/components/profile/device-profile.component.ts index 5621e60418..6492cc2d1e 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device-profile.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device-profile.component.ts @@ -67,6 +67,8 @@ export class DeviceProfileComponent extends EntityComponent { displayTransportConfiguration: boolean; + isTransportTypeChanged = false; + serviceType = ServiceType.TB_RULE_ENGINE; deviceProfileId: EntityId; @@ -158,6 +160,7 @@ export class DeviceProfileComponent extends EntityComponent { const deviceTransportType: DeviceTransportType = form.get('transportType').value; this.displayTransportConfiguration = deviceTransportType && deviceTransportTypeConfigurationInfoMap.get(deviceTransportType).hasProfileConfiguration; + this.isTransportTypeChanged = true; let profileData: DeviceProfileData = form.getRawValue().profileData; if (!profileData) { profileData = { diff --git a/ui-ngx/src/app/modules/home/components/profile/device/device-profile-transport-configuration.component.html b/ui-ngx/src/app/modules/home/components/profile/device/device-profile-transport-configuration.component.html index f8fb2c7baa..87c222216c 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/device-profile-transport-configuration.component.html +++ b/ui-ngx/src/app/modules/home/components/profile/device/device-profile-transport-configuration.component.html @@ -37,6 +37,7 @@ diff --git a/ui-ngx/src/app/modules/home/components/profile/device/device-profile-transport-configuration.component.ts b/ui-ngx/src/app/modules/home/components/profile/device/device-profile-transport-configuration.component.ts index 7d74cbc387..c889fc7eb8 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/device-profile-transport-configuration.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device/device-profile-transport-configuration.component.ts @@ -50,6 +50,9 @@ export class DeviceProfileTransportConfigurationComponent implements ControlValu @Input() disabled: boolean; + @Input() + isAdd: boolean; + transportType: DeviceTransportType; private propagateChange = (v: any) => { }; diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-bootstrap-add-config-server-dialog.component.html b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-bootstrap-add-config-server-dialog.component.html new file mode 100644 index 0000000000..34441d55f5 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-bootstrap-add-config-server-dialog.component.html @@ -0,0 +1,55 @@ + +
+ +

device-profile.lwm2m.add-new-server-title

+ + +
+ + +
+
+ + {{ 'device-profile.lwm2m.server-type' | translate }} + + + {{ serverConfigTypeNamesMap.get(serverType) | translate }} + + + +
+
+ + + +
+
diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-bootstrap-add-config-server-dialog.component.ts b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-bootstrap-add-config-server-dialog.component.ts new file mode 100644 index 0000000000..55fcc7d751 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-bootstrap-add-config-server-dialog.component.ts @@ -0,0 +1,60 @@ +/// +/// Copyright © 2016-2021 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { Component } from '@angular/core'; +import { DialogComponent } from '@shared/components/dialog.component'; +import { FormBuilder, FormGroup } from '@angular/forms'; +import { Store } from '@ngrx/store'; +import { AppState } from '@core/core.state'; +import { Router } from '@angular/router'; +import { MatDialogRef } from '@angular/material/dialog'; +import { + ServerConfigType, + ServerConfigTypeTranslationMap +} from '@home/components/profile/device/lwm2m/lwm2m-profile-config.models'; + +@Component({ + selector: 'tb-profile-lwm2m-bootstrap-add-config-server-dialog', + templateUrl: './lwm2m-bootstrap-add-config-server-dialog.component.html' +}) +export class Lwm2mBootstrapAddConfigServerDialogComponent extends DialogComponent { + + addConfigServerFormGroup: FormGroup; + + serverTypes = Object.values(ServerConfigType); + serverConfigTypeNamesMap = ServerConfigTypeTranslationMap; + + constructor(protected store: Store, + protected router: Router, + private fb: FormBuilder, + public dialogRef: MatDialogRef, + ) { + super(store, router, dialogRef); + this.addConfigServerFormGroup = this.fb.group({ + serverType: [ServerConfigType.LWM2M] + }); + } + + addServerConfig() { + this.dialogRef.close(this.addConfigServerFormGroup.get('serverType').value === ServerConfigType.BOOTSTRAP); + } + + cancel(): void { + this.dialogRef.close(null); + } +} + + diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-bootstrap-config-servers.component.html b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-bootstrap-config-servers.component.html new file mode 100644 index 0000000000..cd00d1661a --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-bootstrap-config-servers.component.html @@ -0,0 +1,39 @@ + +
+ +
+ + +
+
+
+ device-profile.lwm2m.no-config-servers +
+
+ +
+
diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-bootstrap-config-servers.component.ts b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-bootstrap-config-servers.component.ts new file mode 100644 index 0000000000..a4bf5d4958 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-bootstrap-config-servers.component.ts @@ -0,0 +1,185 @@ +/// +/// Copyright © 2016-2021 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { Component, forwardRef, Input, OnInit } from '@angular/core'; +import { + AbstractControl, + ControlValueAccessor, + FormArray, + FormBuilder, FormControl, + FormGroup, + NG_VALIDATORS, + NG_VALUE_ACCESSOR +} from '@angular/forms'; +import { of, Subscription } from 'rxjs'; +import { ServerSecurityConfig } from '@home/components/profile/device/lwm2m/lwm2m-profile-config.models'; +import { TranslateService } from '@ngx-translate/core'; +import { DialogService } from '@core/services/dialog.service'; +import { MatDialog } from '@angular/material/dialog'; +import { Lwm2mBootstrapAddConfigServerDialogComponent } from '@home/components/profile/device/lwm2m/lwm2m-bootstrap-add-config-server-dialog.component'; +import { mergeMap } from 'rxjs/operators'; +import { DeviceProfileService } from '@core/http/device-profile.service'; +import { Lwm2mSecurityType } from '@shared/models/lwm2m-security-config.models'; + +@Component({ + selector: 'tb-profile-lwm2m-bootstrap-config-servers', + templateUrl: './lwm2m-bootstrap-config-servers.component.html', + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => Lwm2mBootstrapConfigServersComponent), + multi: true + }, + { + provide: NG_VALIDATORS, + useExisting: forwardRef(() => Lwm2mBootstrapConfigServersComponent), + multi: true, + } + ] +}) +export class Lwm2mBootstrapConfigServersComponent implements OnInit, ControlValueAccessor { + + bootstrapConfigServersFormGroup: FormGroup; + + @Input() + disabled: boolean; + + private valueChangeSubscription: Subscription = null; + + private propagateChange = (v: any) => { }; + + constructor(public translate: TranslateService, + public matDialog: MatDialog, + private dialogService: DialogService, + private deviceProfileService: DeviceProfileService, + private fb: FormBuilder) { + } + + registerOnChange(fn: any): void { + this.propagateChange = fn; + } + + registerOnTouched(fn: any): void { + } + + ngOnInit() { + this.bootstrapConfigServersFormGroup = this.fb.group({ + serverConfigs: this.fb.array([]) + }); + } + + serverConfigsFromArray(): FormArray { + return this.bootstrapConfigServersFormGroup.get('serverConfigs') as FormArray; + } + + setDisabledState(isDisabled: boolean): void { + this.disabled = isDisabled; + if (this.disabled) { + this.bootstrapConfigServersFormGroup.disable({emitEvent: false}); + } else { + this.bootstrapConfigServersFormGroup.enable({emitEvent: false}); + } + } + + writeValue(serverConfigs: Array | null): void { + if (this.valueChangeSubscription) { + this.valueChangeSubscription.unsubscribe(); + } + const serverConfigsControls: Array = []; + if (serverConfigs) { + serverConfigs.forEach((serverConfig) => { + serverConfigsControls.push(this.fb.control(serverConfig)); + }); + } + this.bootstrapConfigServersFormGroup.setControl('serverConfigs', this.fb.array(serverConfigsControls)); + if (this.disabled) { + this.bootstrapConfigServersFormGroup.disable({emitEvent: false}); + } else { + this.bootstrapConfigServersFormGroup.enable({emitEvent: false}); + } + this.valueChangeSubscription = this.bootstrapConfigServersFormGroup.valueChanges.subscribe(() => { + this.updateModel(); + }); + } + + trackByParams(index: number): number { + return index; + } + + removeServerConfig($event: Event, index: number) { + if ($event) { + $event.stopPropagation(); + $event.preventDefault(); + } + this.dialogService.confirm( + this.translate.instant('device-profile.lwm2m.delete-server-title'), + this.translate.instant('device-profile.lwm2m.delete-server-text'), + this.translate.instant('action.no'), + this.translate.instant('action.yes'), + true + ).subscribe((result) => { + if (result) { + this.serverConfigsFromArray().removeAt(index); + } + }); + } + + addServerConfig(): void { + const addDialogObs = this.isBootstrapAdded() ? of(false) : + this.matDialog.open(Lwm2mBootstrapAddConfigServerDialogComponent, { + disableClose: true, + panelClass: ['tb-dialog', 'tb-fullscreen-dialog'] + }).afterClosed(); + const addServerConfigObs = addDialogObs.pipe( + mergeMap((isBootstrap) => { + if (isBootstrap === null) { + return of(null); + } + return this.deviceProfileService.getLwm2mBootstrapSecurityInfoBySecurityType(isBootstrap, Lwm2mSecurityType.NO_SEC); + }) + ); + addServerConfigObs.subscribe((serverConfig) => { + if (serverConfig) { + serverConfig.securityMode = Lwm2mSecurityType.NO_SEC; + this.serverConfigsFromArray().push(this.fb.control(serverConfig)); + this.updateModel(); + } + }); + } + + public validate(c: FormControl) { + return (this.bootstrapConfigServersFormGroup.valid) ? null : { + serverConfigs: { + valid: false, + }, + }; + } + + public isBootstrapAdded() { + const serverConfigsArray = this.serverConfigsFromArray().getRawValue(); + for (let i = 0; i < serverConfigsArray.length; i++) { + if (serverConfigsArray[i].bootstrapServerIs) { + return true; + } + } + return false; + } + + private updateModel() { + const serverConfigs: Array = this.serverConfigsFromArray().value; + this.propagateChange(serverConfigs); + } +} diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-config-server.component.html b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-config-server.component.html index 3fe4e7cda8..4019c7bf65 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-config-server.component.html +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-config-server.component.html @@ -15,99 +15,170 @@ limitations under the License. --> -
-
- - {{ 'device-profile.lwm2m.mode' | translate }} - - - {{ credentialTypeLwM2MNamesMap.get(securityConfigLwM2MType[securityMode]) }} - - - - - {{ 'device-profile.lwm2m.server-host' | translate }} - - - {{ 'device-profile.lwm2m.server-host-required' | translate }} - - - - {{ 'device-profile.lwm2m.server-port' | translate }} - - - {{ 'device-profile.lwm2m.server-port-required' | translate }} - - - {{ 'device-profile.lwm2m.server-port-pattern' | translate }} - - + +
+ +
+
{{ (serverFormGroup.get('bootstrapServerIs').value ? + 'device-profile.lwm2m.bootstrap-server' : 'device-profile.lwm2m.lwm2m-server') | translate }}
+
+
{{ ('device-profile.lwm2m.short-id' | translate) + ': ' }} + {{ serverFormGroup.get('shortServerId').value }} +
+
{{ ('device-profile.lwm2m.mode' | translate) + ': ' }} + {{ credentialTypeLwM2MNamesMap.get(securityConfigLwM2MType[serverFormGroup.get('securityMode').value]) }} +
+
+
+
+ + +
+
+ +
+
+ + {{ 'device-profile.lwm2m.mode' | translate }} + + + {{ credentialTypeLwM2MNamesMap.get(securityConfigLwM2MType[securityMode]) }} + + + + + {{ 'device-profile.lwm2m.short-id' | translate }} + help + + + {{ 'device-profile.lwm2m.short-id-required' | translate }} + + + {{ 'device-profile.lwm2m.short-id-pattern' | translate }} + + + {{ 'device-profile.lwm2m.short-id-range' | translate }} + + +
+
+ + {{ 'device-profile.lwm2m.server-host' | translate }} + + + {{ 'device-profile.lwm2m.server-host-required' | translate }} + + + + {{ 'device-profile.lwm2m.server-port' | translate }} + + + {{ 'device-profile.lwm2m.server-port-required' | translate }} + + + {{ 'device-profile.lwm2m.server-port-pattern' | translate }} + + - {{ 'device-profile.lwm2m.server-port-range' | translate }} - - -
-
- - {{ 'device-profile.lwm2m.short-id' | translate }} - help - - - {{ 'device-profile.lwm2m.short-id-required' | translate }} - - - {{ 'device-profile.lwm2m.short-id-pattern' | translate }} - - - {{ 'device-profile.lwm2m.short-id-range' | translate }} - - - - {{ 'device-profile.lwm2m.client-hold-off-time' | translate }} - help - - - {{ 'device-profile.lwm2m.client-hold-off-time-required' | translate }} - - + + {{ 'device-profile.lwm2m.client-hold-off-time' | translate }} + help + + + {{ 'device-profile.lwm2m.client-hold-off-time-required' | translate }} + + - {{ 'device-profile.lwm2m.client-hold-off-time-pattern' | translate }} - - - - {{ 'device-profile.lwm2m.account-after-timeout' | translate }} - help - - - {{ 'device-profile.lwm2m.account-after-timeout-required' | translate }} - - help + + + {{ 'device-profile.lwm2m.account-after-timeout-required' | translate }} + + - {{ 'device-profile.lwm2m.account-after-timeout-pattern' | translate }} - - -
-
- - {{ 'device-profile.lwm2m.server-public-key' | translate }} - help - - - {{ 'device-profile.lwm2m.server-public-key-required' | translate }} - - -
-
+ {{ 'device-profile.lwm2m.account-after-timeout-pattern' | translate }} +
+
+
+
+ + {{ 'device-profile.lwm2m.server-public-key' | translate }} + help + + + {{ 'device-profile.lwm2m.server-public-key-required' | translate }} + + +
+
+ + {{ 'device-profile.lwm2m.lifetime' | translate }} + + + {{ 'device-profile.lwm2m.lifetime-required' | translate }} + + + {{ 'device-profile.lwm2m.lifetime-pattern' | translate }} + + + + {{ 'device-profile.lwm2m.default-min-period' | translate }} + help + + + {{ 'device-profile.lwm2m.default-min-period-required' | translate }} + + + {{ 'device-profile.lwm2m.default-min-period-pattern' | translate }} + + +
+ + {{ 'device-profile.lwm2m.binding' | translate }} + help + + + {{ bindingModeTypeNamesMap.get(bindingMode) | translate }} + + + + + {{ 'device-profile.lwm2m.notification-storing' | translate }} + +
+
+ diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-config-server.component.ts b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-config-server.component.ts index 9492b18114..c92cf9ef45 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-config-server.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-config-server.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, forwardRef, Input, OnDestroy, OnInit } from '@angular/core'; +import { Component, EventEmitter, forwardRef, Input, OnDestroy, OnInit, Output } from '@angular/core'; import { ControlValueAccessor, FormBuilder, @@ -26,8 +26,7 @@ import { Validators } from '@angular/forms'; import { - DEFAULT_PORT_BOOTSTRAP_NO_SEC, - DEFAULT_PORT_SERVER_NO_SEC, + BingingMode, BingingModeTranslationsMap, ServerSecurityConfig } from './lwm2m-profile-config.models'; import { DeviceProfileService } from '@core/http/device-profile.service'; @@ -65,14 +64,16 @@ export class Lwm2mDeviceConfigServerComponent implements OnInit, ControlValueAcc private isDataLoadedIntoCache = false; serverFormGroup: FormGroup; + bindingModeTypes = Object.values(BingingMode); + bindingModeTypeNamesMap = BingingModeTranslationsMap; securityConfigLwM2MType = Lwm2mSecurityType; securityConfigLwM2MTypes = Object.keys(Lwm2mSecurityType); credentialTypeLwM2MNamesMap = Lwm2mSecurityTypeTranslationMap; publicKeyOrIdTooltipNamesMap = Lwm2mPublicKeyOrIdTooltipTranslationsMap; currentSecurityMode = null; - @Input() - isBootstrapServer = false; + @Output() + removeServer = new EventEmitter(); private propagateChange = (v: any) => { }; @@ -83,19 +84,29 @@ export class Lwm2mDeviceConfigServerComponent implements OnInit, ControlValueAcc ngOnInit(): void { this.serverFormGroup = this.fb.group({ host: ['', Validators.required], - port: [this.isBootstrapServer ? DEFAULT_PORT_BOOTSTRAP_NO_SEC : DEFAULT_PORT_SERVER_NO_SEC, - [Validators.required, Validators.min(1), Validators.max(65535), Validators.pattern('[0-9]*')]], + port: ['', [Validators.required, Validators.min(1), Validators.max(65535), Validators.pattern('[0-9]*')]], securityMode: [Lwm2mSecurityType.NO_SEC], serverPublicKey: [''], clientHoldOffTime: ['', [Validators.required, Validators.min(0), Validators.pattern('[0-9]*')]], - serverId: ['', [Validators.required, Validators.min(1), Validators.max(65534), Validators.pattern('[0-9]*')]], + shortServerId: ['', [Validators.required, Validators.min(1), Validators.max(65534), Validators.pattern('[0-9]*')]], bootstrapServerAccountTimeout: ['', [Validators.required, Validators.min(0), Validators.pattern('[0-9]*')]], + binding: [''], + lifetime: [null, [Validators.required, Validators.min(0), Validators.pattern('[0-9]*')]], + notifIfDisabled: [], + defaultMinPeriod: [null, [Validators.required, Validators.min(0), Validators.pattern('[0-9]*')]], + bootstrapServerIs: [] }); this.serverFormGroup.get('securityMode').valueChanges.pipe( - tap(securityMode => this.updateValidate(securityMode)), + tap((securityMode) => { + this.currentSecurityMode = securityMode; + this.updateValidate(securityMode); + }), mergeMap(securityMode => this.getLwm2mBootstrapSecurityInfo(securityMode)), takeUntil(this.destroy$) ).subscribe(serverSecurityConfig => { + if (this.currentSecurityMode !== Lwm2mSecurityType.NO_SEC) { + this.changeSecurityHostPortFields(serverSecurityConfig); + } this.serverFormGroup.patchValue(serverSecurityConfig, {emitEvent: false}); }); this.serverFormGroup.valueChanges.pipe( @@ -114,8 +125,13 @@ export class Lwm2mDeviceConfigServerComponent implements OnInit, ControlValueAcc if (serverData) { this.serverFormGroup.patchValue(serverData, {emitEvent: false}); this.updateValidate(serverData.securityMode); + if (serverData.securityHost && serverData.securityPort) { + delete serverData.securityHost; + delete serverData.securityPort; + this.propagateChangeState(this.serverFormGroup.getRawValue()); + } } - if (!this.isDataLoadedIntoCache){ + if (!this.isDataLoadedIntoCache) { this.getLwm2mBootstrapSecurityInfo().subscribe(value => { if (!serverData) { this.serverFormGroup.patchValue(value); @@ -171,11 +187,17 @@ export class Lwm2mDeviceConfigServerComponent implements OnInit, ControlValueAcc } private getLwm2mBootstrapSecurityInfo(securityMode = Lwm2mSecurityType.NO_SEC): Observable { - return this.deviceProfileService.getLwm2mBootstrapSecurityInfoBySecurityType(this.isBootstrapServer, securityMode).pipe( + return this.deviceProfileService.getLwm2mBootstrapSecurityInfoBySecurityType( + this.serverFormGroup.get('bootstrapServerIs').value, securityMode).pipe( tap(() => this.isDataLoadedIntoCache = true) ); } + private changeSecurityHostPortFields(serverData: ServerSecurityConfig): void { + serverData.port = serverData.securityPort; + serverData.host = serverData.securityHost; + } + validate(): ValidationErrors | null { return this.serverFormGroup.valid ? null : { serverFormGroup: true diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.html b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.html index a042ba5ea3..20cbd63168 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.html +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.html @@ -33,93 +33,9 @@
-
- - - - {{ 'device-profile.lwm2m.server' | translate }} - - -
- - {{ 'device-profile.lwm2m.short-id' | translate }} - help - - - {{ 'device-profile.lwm2m.short-id-required' | translate }} - - - {{ 'device-profile.lwm2m.short-id-range' | translate }} - - - {{ 'device-profile.lwm2m.short-id-pattern' | translate }} - - - - {{ 'device-profile.lwm2m.lifetime' | translate }} - - - {{ 'device-profile.lwm2m.lifetime-required' | translate }} - - - {{ 'device-profile.lwm2m.lifetime-pattern' | translate }} - - - - {{ 'device-profile.lwm2m.default-min-period' | translate }} - help - - - {{ 'device-profile.lwm2m.default-min-period-required' | translate }} - - - {{ 'device-profile.lwm2m.default-min-period-pattern' | translate }} - - -
- - {{ 'device-profile.lwm2m.binding' | translate }} - help - - - {{ bindingModeTypeNamesMap.get(bindingMode) | translate }} - - - - - {{ 'device-profile.lwm2m.notification-storing' | translate }} - -
-
- - - {{ 'device-profile.lwm2m.bootstrap-server' | translate }} - - - - - - - - - {{ 'device-profile.lwm2m.lwm2m-server' | translate }} - - - - - - -
+
+ +
diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts index 792aa3c315..1fdf6cf8be 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts @@ -28,20 +28,11 @@ import { import { coerceBooleanProperty } from '@angular/cdk/coercion'; import { ATTRIBUTE, - BingingMode, - BingingModeTranslationsMap, - DEFAULT_BINDING, DEFAULT_EDRX_CYCLE, DEFAULT_FW_UPDATE_RESOURCE, - DEFAULT_ID_SERVER, - DEFAULT_LIFE_TIME, - DEFAULT_MIN_PERIOD, - DEFAULT_NOTIF_IF_DESIBLED, DEFAULT_PAGING_TRANSMISSION_WINDOW, DEFAULT_PSM_ACTIVITY_TIMER, DEFAULT_SW_UPDATE_RESOURCE, - getDefaultBootstrapServerSecurityConfig, - getDefaultLwM2MServerSecurityConfig, Instance, INSTANCES, KEY_NAME, @@ -60,6 +51,7 @@ import { Direction } from '@shared/models/page/sort-order'; import _ from 'lodash'; import { Subject } from 'rxjs'; import { takeUntil } from 'rxjs/operators'; +import { Lwm2mSecurityType } from '@shared/models/lwm2m-security-config.models'; @Component({ selector: 'tb-profile-lwm2m-device-transport-configuration', @@ -83,8 +75,6 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro private requiredValue: boolean; private destroy$ = new Subject(); - bindingModeTypes = Object.values(BingingMode); - bindingModeTypeNamesMap = BingingModeTranslationsMap; lwm2mDeviceProfileFormGroup: FormGroup; configurationValue: Lwm2mProfileConfigModels; sortFunction: (key: string, value: object) => object; @@ -98,6 +88,9 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro this.requiredValue = coerceBooleanProperty(value); } + @Input() + isAdd: boolean; + private propagateChange = (v: any) => { } @@ -106,17 +99,7 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro this.lwm2mDeviceProfileFormGroup = this.fb.group({ objectIds: [null], observeAttrTelemetry: [null], - bootstrap: this.fb.group({ - servers: this.fb.group({ - binding: [DEFAULT_BINDING], - shortId: [DEFAULT_ID_SERVER, [Validators.required, Validators.min(1), Validators.max(65534), Validators.pattern('[0-9]*')]], - lifetime: [DEFAULT_LIFE_TIME, [Validators.required, Validators.min(0), Validators.pattern('[0-9]*')]], - notifIfDisabled: [DEFAULT_NOTIF_IF_DESIBLED, []], - defaultMinPeriod: [DEFAULT_MIN_PERIOD, [Validators.required, Validators.min(0), Validators.pattern('[0-9]*')]], - }), - bootstrapServer: [null, Validators.required], - lwm2mServer: [null, Validators.required] - }), + bootstrap: [[]], clientLwM2mSettings: this.fb.group({ clientOnlyObserveAfterConnect: [1, []], fwUpdateStrategy: [1, []], @@ -187,9 +170,7 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro async writeValue(value: Lwm2mProfileConfigModels | null) { if (isDefinedAndNotNull(value) && (value?.clientLwM2mSettings || value?.observeAttr || value?.bootstrap)) { this.configurationValue = value; - const defaultFormSettings = value.clientLwM2mSettings.fwUpdateStrategy === 1 && - isUndefined(value.clientLwM2mSettings.fwUpdateResource); - if (defaultFormSettings) { + if (this.isAdd) { await this.defaultProfileConfig(); } this.initWriteValue(); @@ -203,23 +184,14 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro } private async defaultProfileConfig(): Promise { - let bootstrap: ServerSecurityConfig; - let lwm2m: ServerSecurityConfig; - try { - [bootstrap, lwm2m] = await Promise.all([ - this.deviceProfileService.getLwm2mBootstrapSecurityInfoBySecurityType(true).toPromise(), - this.deviceProfileService.getLwm2mBootstrapSecurityInfoBySecurityType(false).toPromise() - ]); - } catch (e) { - bootstrap = getDefaultBootstrapServerSecurityConfig(); - lwm2m = getDefaultLwM2MServerSecurityConfig(); + const lwm2m: ServerSecurityConfig = await this.deviceProfileService.getLwm2mBootstrapSecurityInfoBySecurityType(false).toPromise(); + if (lwm2m) { + lwm2m.securityMode = Lwm2mSecurityType.NO_SEC; } - - this.configurationValue.bootstrap.bootstrapServer = bootstrap; - this.configurationValue.bootstrap.lwm2mServer = lwm2m; + this.configurationValue.bootstrap = [lwm2m]; this.lwm2mDeviceProfileFormGroup.patchValue({ bootstrap: this.configurationValue.bootstrap - }, {emitEvent: false}); + }, {emitEvent: true}); } private initWriteValue = (): void => { @@ -282,12 +254,10 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro } private updateDeviceProfileValue(config): void { - if (this.lwm2mDeviceProfileFormGroup.valid) { + if (this.lwm2mDeviceProfileFormGroup.valid && config.observeAttrTelemetry) { this.updateObserveAttrTelemetryFromGroupToJson(config.observeAttrTelemetry); } - this.configurationValue.bootstrap.bootstrapServer = config.bootstrap.bootstrapServer; - this.configurationValue.bootstrap.lwm2mServer = config.bootstrap.lwm2mServer; - this.configurationValue.bootstrap.servers = config.bootstrap.servers; + this.configurationValue.bootstrap = config.bootstrap; this.configurationValue.clientLwM2mSettings = config.clientLwM2mSettings; this.updateModel(); } diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-profile-components.module.ts b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-profile-components.module.ts index aa801f84dc..77ef7ee81e 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-profile-components.module.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-profile-components.module.ts @@ -22,7 +22,9 @@ import { Lwm2mObserveAttrTelemetryResourcesComponent } from './lwm2m-observe-att import { Lwm2mAttributesDialogComponent } from './lwm2m-attributes-dialog.component'; import { Lwm2mAttributesComponent } from './lwm2m-attributes.component'; import { Lwm2mAttributesKeyListComponent } from './lwm2m-attributes-key-list.component'; +import { Lwm2mBootstrapConfigServersComponent } from '@home/components/profile/device/lwm2m/lwm2m-bootstrap-config-servers.component'; import { Lwm2mDeviceConfigServerComponent } from './lwm2m-device-config-server.component'; +import { Lwm2mBootstrapAddConfigServerDialogComponent } from '@home/components/profile/device/lwm2m/lwm2m-bootstrap-add-config-server-dialog.component'; import { Lwm2mObjectAddInstancesDialogComponent } from './lwm2m-object-add-instances-dialog.component'; import { Lwm2mObjectAddInstancesListComponent } from './lwm2m-object-add-instances-list.component'; import { CommonModule } from '@angular/common'; @@ -40,7 +42,9 @@ import { DeviceProfileCommonModule } from '@home/components/profile/device/commo Lwm2mAttributesDialogComponent, Lwm2mAttributesComponent, Lwm2mAttributesKeyListComponent, + Lwm2mBootstrapConfigServersComponent, Lwm2mDeviceConfigServerComponent, + Lwm2mBootstrapAddConfigServerDialogComponent, Lwm2mObjectAddInstancesDialogComponent, Lwm2mObjectAddInstancesListComponent, Lwm2mObserveAttrTelemetryInstancesComponent @@ -58,7 +62,9 @@ import { DeviceProfileCommonModule } from '@home/components/profile/device/commo Lwm2mAttributesDialogComponent, Lwm2mAttributesComponent, Lwm2mAttributesKeyListComponent, + Lwm2mBootstrapConfigServersComponent, Lwm2mDeviceConfigServerComponent, + Lwm2mBootstrapAddConfigServerDialogComponent, Lwm2mObjectAddInstancesDialogComponent, Lwm2mObjectAddInstancesListComponent, Lwm2mObserveAttrTelemetryInstancesComponent diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-profile-config.models.ts b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-profile-config.models.ts index e95d1d22d2..543c000e12 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-profile-config.models.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-profile-config.models.ts @@ -96,6 +96,18 @@ export const AttributeNameTranslationMap = new Map( ] ); +export enum ServerConfigType { + LWM2M = 'LWM2M', + BOOTSTRAP = 'BOOTSTRAP' +} + +export const ServerConfigTypeTranslationMap = new Map( + [ + [ServerConfigType.LWM2M, 'device-profile.lwm2m.lwm2m-server'], + [ServerConfigType.BOOTSTRAP, 'device-profile.lwm2m.bootstrap-server'] + ] +); + export enum PowerMode { PSM = 'PSM', DRX = 'DRX', @@ -110,22 +122,21 @@ export const PowerModeTranslationMap = new Map( ] ); -export interface BootstrapServersSecurityConfig { - shortId: number; - lifetime: number; - defaultMinPeriod: number; - notifIfDisabled: boolean; - binding: string; -} - export interface ServerSecurityConfig { host?: string; port?: number; securityMode: Lwm2mSecurityType; + securityHost?: string; + securityPort?: number; serverPublicKey?: string; clientHoldOffTime?: number; - serverId?: number; + shortServerId?: number; bootstrapServerAccountTimeout: number; + lifetime: number; + defaultMinPeriod: number; + notifIfDisabled: boolean; + binding: string; + bootstrapServerIs: boolean; } export interface ServerSecurityConfigInfo extends ServerSecurityConfig { @@ -134,16 +145,10 @@ export interface ServerSecurityConfigInfo extends ServerSecurityConfig { bootstrapServerIs: boolean; } -interface BootstrapSecurityConfig { - servers: BootstrapServersSecurityConfig; - bootstrapServer: ServerSecurityConfig; - lwm2mServer: ServerSecurityConfig; -} - export interface Lwm2mProfileConfigModels { clientLwM2mSettings: ClientLwM2mSettings; observeAttr: ObservableAttributes; - bootstrap: BootstrapSecurityConfig; + bootstrap: Array; } export interface ClientLwM2mSettings { @@ -167,35 +172,6 @@ export interface ObservableAttributes { attributeLwm2m: AttributesNameValueMap; } -export function getDefaultBootstrapServersSecurityConfig(): BootstrapServersSecurityConfig { - return { - shortId: DEFAULT_ID_SERVER, - lifetime: DEFAULT_LIFE_TIME, - defaultMinPeriod: DEFAULT_MIN_PERIOD, - notifIfDisabled: DEFAULT_NOTIF_IF_DESIBLED, - binding: DEFAULT_BINDING - }; -} - -export function getDefaultBootstrapServerSecurityConfig(): ServerSecurityConfig { - return { - bootstrapServerAccountTimeout: DEFAULT_BOOTSTRAP_SERVER_ACCOUNT_TIME_OUT, - clientHoldOffTime: DEFAULT_CLIENT_HOLD_OFF_TIME, - host: DEFAULT_LOCAL_HOST_NAME, - port: DEFAULT_PORT_BOOTSTRAP_NO_SEC, - securityMode: Lwm2mSecurityType.NO_SEC, - serverId: DEFAULT_ID_BOOTSTRAP, - serverPublicKey: '' - }; -} - -export function getDefaultLwM2MServerSecurityConfig(): ServerSecurityConfig { - const DefaultLwM2MServerSecurityConfig = getDefaultBootstrapServerSecurityConfig(); - DefaultLwM2MServerSecurityConfig.port = DEFAULT_PORT_SERVER_NO_SEC; - DefaultLwM2MServerSecurityConfig.serverId = DEFAULT_ID_SERVER; - return DefaultLwM2MServerSecurityConfig; -} - export function getDefaultProfileObserveAttrConfig(): ObservableAttributes { return { observe: [], diff --git a/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.html b/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.html index ae0be158d5..6a84e626d9 100644 --- a/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.html +++ b/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.html @@ -133,6 +133,7 @@ diff --git a/ui-ngx/src/app/modules/home/pages/device-profile/device-profile-tabs.component.html b/ui-ngx/src/app/modules/home/pages/device-profile/device-profile-tabs.component.html index f1a7af1e46..a0ce99f3db 100644 --- a/ui-ngx/src/app/modules/home/pages/device-profile/device-profile-tabs.component.html +++ b/ui-ngx/src/app/modules/home/pages/device-profile/device-profile-tabs.component.html @@ -35,6 +35,7 @@
diff --git a/ui-ngx/src/app/modules/home/pages/device-profile/device-profile-tabs.component.ts b/ui-ngx/src/app/modules/home/pages/device-profile/device-profile-tabs.component.ts index 2c53f04986..f1afa2559a 100644 --- a/ui-ngx/src/app/modules/home/pages/device-profile/device-profile-tabs.component.ts +++ b/ui-ngx/src/app/modules/home/pages/device-profile/device-profile-tabs.component.ts @@ -38,12 +38,17 @@ export class DeviceProfileTabsComponent extends EntityTabsComponent) { super(store); } ngOnInit() { super.ngOnInit(); + this.detailsForm.get('transportType').valueChanges.subscribe(() => { + this.isTransportTypeChanged = true; + }); } } diff --git a/ui-ngx/src/app/shared/models/device.models.ts b/ui-ngx/src/app/shared/models/device.models.ts index 7ebf7bde47..7fc3d70f78 100644 --- a/ui-ngx/src/app/shared/models/device.models.ts +++ b/ui-ngx/src/app/shared/models/device.models.ts @@ -31,9 +31,6 @@ import { OtaPackageId } from '@shared/models/id/ota-package-id'; import { DashboardId } from '@shared/models/id/dashboard-id'; import { DataType } from '@shared/models/constants'; import { - getDefaultBootstrapServerSecurityConfig, - getDefaultBootstrapServersSecurityConfig, - getDefaultLwM2MServerSecurityConfig, getDefaultProfileClientLwM2mSettingsConfig, getDefaultProfileObserveAttrConfig, PowerMode @@ -384,11 +381,7 @@ export function createDeviceProfileTransportConfiguration(type: DeviceTransportT case DeviceTransportType.LWM2M: const lwm2mTransportConfiguration: Lwm2mDeviceProfileTransportConfiguration = { observeAttr: getDefaultProfileObserveAttrConfig(), - bootstrap: { - servers: getDefaultBootstrapServersSecurityConfig(), - bootstrapServer: getDefaultBootstrapServerSecurityConfig(), - lwm2mServer: getDefaultLwM2MServerSecurityConfig() - }, + bootstrap: [], clientLwM2mSettings: getDefaultProfileClientLwM2mSettingsConfig() }; transportConfiguration = {...lwm2mTransportConfiguration, type: DeviceTransportType.LWM2M}; diff --git a/ui-ngx/src/app/shared/models/lwm2m-security-config.models.ts b/ui-ngx/src/app/shared/models/lwm2m-security-config.models.ts index 024433b0c7..3187f0661c 100644 --- a/ui-ngx/src/app/shared/models/lwm2m-security-config.models.ts +++ b/ui-ngx/src/app/shared/models/lwm2m-security-config.models.ts @@ -67,14 +67,9 @@ export interface ServerSecurityConfig { clientSecretKey?: string; } -interface BootstrapSecurityConfig { - bootstrapServer: ServerSecurityConfig; - lwm2mServer: ServerSecurityConfig; -} - export interface Lwm2mSecurityConfigModels { client: ClientSecurityConfig; - bootstrap: BootstrapSecurityConfig; + bootstrap: Array; } @@ -84,10 +79,9 @@ export function getLwm2mSecurityConfigModelsDefault(): Lwm2mSecurityConfigModels securityConfigClientMode: Lwm2mSecurityType.NO_SEC, endpoint: '' }, - bootstrap: { - bootstrapServer: getDefaultServerSecurityConfig(), - lwm2mServer: getDefaultServerSecurityConfig() - } + bootstrap: [ + getDefaultServerSecurityConfig() + ] }; } diff --git a/ui-ngx/src/assets/locale/locale.constant-en_US.json b/ui-ngx/src/assets/locale/locale.constant-en_US.json index dcc599bc41..47ad830c33 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -1310,16 +1310,18 @@ "edit-attribute": "Edit attribute", "view-attribute": "View attribute", "remove-attribute": "Remove attribute", + "delete-server-text": "Be careful, after the confirmation the server configuration will become unrecoverable.", + "delete-server-title": "Are you sure you want to delete the server?", "mode": "Security config mode", "bootstrap-tab": "Bootstrap", "bootstrap-server-legend": "Bootstrap Server (ShortId...)", "lwm2m-server-legend": "LwM2M Server (ShortId...)", "server": "Server", - "short-id": "Short ID", - "short-id-tooltip": "Server ShortID must be equal Security ShortID ", - "short-id-required": "Short ID is required.", - "short-id-range": "Short ID should be in a range from 1 to 65534.", - "short-id-pattern": "Short ID must be a positive integer.", + "short-id": "Short server ID", + "short-id-tooltip": "Server short Id. Used as link to associate server Object Instance.\nThis identifier uniquely identifies each LwM2M Server configured for the LwM2M Client.\nResource MUST be set when the Bootstrap-Server Resource has a value of 'false'.\nThe values ID:0 and ID:65535 values MUST NOT be used for identifying the LwM2M Server.", + "short-id-required": "Short server ID is required.", + "short-id-range": "Short server ID should be in a range from 1 to 65534.", + "short-id-pattern": "Short server ID must be a positive integer.", "lifetime": "Client registration lifetime", "lifetime-required": "Client registration lifetime is required.", "lifetime-pattern": "Client registration lifetime must be a positive integer.", @@ -1361,6 +1363,11 @@ "account-after-timeout-required": "Account after the timeout is required.", "account-after-timeout-pattern": "Account after the timeout must be a positive integer.", "account-after-timeout-tooltip": "Bootstrap-Server Account after the timeout value given by this resource.", + "server-type": "Server type", + "add-new-server-title": "Add new server config", + "add-server-config": "Add server config", + "add-lwm2m-server-config": "Add LwM2M server", + "no-config-servers": "No servers configured", "others-tab": "Other settings", "client-strategy": "Client strategy when connecting", "client-strategy-label": "Strategy", From fbc785a471ead268ee3eaae7b20dc95314e9a01f Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Mon, 15 Nov 2021 19:11:53 +0200 Subject: [PATCH 106/432] lwm2m - Bootstrap auto --- .../bootstrap/LwM2MServerSecurityConfig.java | 17 +- .../secure/LwM2MBootstrapConfig.java | 89 ++++--- .../LwM2mDefaultBootstrapSessionManager.java | 24 +- ...LwM2MBootstrapConfigStoreTaskProvider.java | 242 ++++++++++++++++++ .../store/LwM2MBootstrapSecurityStore.java | 45 +--- .../device/DeviceCredentialsServiceImpl.java | 7 +- 6 files changed, 313 insertions(+), 111 deletions(-) create mode 100644 common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MBootstrapConfigStoreTaskProvider.java diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/LwM2MServerSecurityConfig.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/LwM2MServerSecurityConfig.java index fcbe91743b..12dd9c5a64 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/LwM2MServerSecurityConfig.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/LwM2MServerSecurityConfig.java @@ -23,12 +23,15 @@ import lombok.Data; @Data public class LwM2MServerSecurityConfig { - @ApiModelProperty(position = 1, value = "Server short Id. Used as link to associate server Object Instance.\nThis identifier uniquely identifies each LwM2M Server configured for the LwM2M Client.\n" + - "This Resource MUST be set when the Bootstrap-Server Resource has a value of 'false'. \n" + + @ApiModelProperty(position = 1, value = "Server short Id. Used as link to associate server Object Instance. This identifier uniquely identifies each LwM2M Server configured for the LwM2M Client. " + + "This Resource MUST be set when the Bootstrap-Server Resource has a value of 'false'. " + "The values ID:0 and ID:65535 values MUST NOT be used for identifying the LwM2M Server.", example = "123", readOnly = true) protected Integer shortServerId = 123; /** Security -> ObjectId = 0 'LWM2M Security' */ - @ApiModelProperty(position = 2, value = "Is Bootstrap Server or Lwm2m Server", example = "true or false", readOnly = true) + @ApiModelProperty(position = 2, value = "Is Bootstrap Server or Lwm2m Server. " + + "The LwM2M Client MAY be configured to use one or more LwM2M Server Account(s). " + + "The LwM2M Client MUST have at most one LwM2M Bootstrap-Server Account. " + + "(*) The LwM2M client MUST have at least one LwM2M server account after completing the boot sequence specified.", example = "true or false", readOnly = true) protected boolean bootstrapServerIs = false; @ApiModelProperty(position = 3, value = "Host for 'No Security' mode", example = "0.0.0.0", readOnly = true) protected String host; @@ -45,15 +48,15 @@ public class LwM2MServerSecurityConfig { /** Config -> ObjectId = 1 'LwM2M Server' */ @ApiModelProperty(position = 10, value = "Specify the lifetime of the registration in seconds.", example = "300", readOnly = true) private Integer lifetime = 300; - @ApiModelProperty(position = 11, value = "The default value the LwM2M Client should use for the Minimum Period of an Observation in the absence of this parameter being included in an Observation.\n" + + @ApiModelProperty(position = 11, value = "The default value the LwM2M Client should use for the Minimum Period of an Observation in the absence of this parameter being included in an Observation. " + "If this Resource doesn’t exist, the default value is 0.", example = "1", readOnly = true) private Integer defaultMinPeriod = 1; /** ResourceID=6 'Notification Storing When Disabled or Offline' */ - @ApiModelProperty(position = 12, value = "If true, the LwM2M Client stores “Notify” operations to the LwM2M Server while the LwM2M Server account is disabled or the LwM2M Client is offline. After the LwM2M Server account is enabled or the LwM2M Client is online, the LwM2M Client reports the stored “Notify” operations to the Server.\n" + - "If false, the LwM2M Client discards all the “Notify” operations or temporarily disables the Observe function while the LwM2M Server is disabled or the LwM2M Client is offline.\n" + + @ApiModelProperty(position = 12, value = "If true, the LwM2M Client stores “Notify” operations to the LwM2M Server while the LwM2M Server account is disabled or the LwM2M Client is offline. After the LwM2M Server account is enabled or the LwM2M Client is online, the LwM2M Client reports the stored “Notify” operations to the Server. " + + "If false, the LwM2M Client discards all the “Notify” operations or temporarily disables the Observe function while the LwM2M Server is disabled or the LwM2M Client is offline. " + "The default value is true.", example = "true", readOnly = true) private boolean notifIfDisabled = true; - @ApiModelProperty(position = 14, value = "This Resource defines the transport binding configured for the LwM2M Client.\n" + + @ApiModelProperty(position = 14, value = "This Resource defines the transport binding configured for the LwM2M Client. " + "If the LwM2M Client supports the binding specified in this Resource, the LwM2M Client MUST use that transport for the Current Binding Mode.", example = "U", readOnly = true) private String binding = "U"; } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapConfig.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapConfig.java index 792cf71c67..124de67fa0 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapConfig.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapConfig.java @@ -40,23 +40,6 @@ import java.util.concurrent.atomic.AtomicInteger; public class LwM2MBootstrapConfig implements Serializable { List serverConfiguration; - /* - interface BootstrapSecurityConfig - servers: BootstrapServersSecurityConfig, - bootstrapServer: ServerSecurityConfig, - lwm2mServer: ServerSecurityConfig - } - */ - /** -servers - * shortId: number, - * lifetime: number, - * defaultMinPeriod: number, - * notifIfDisabled: boolean, - * binding: string - * */ -// @Getter -// @Setter -// private LwM2MBootstrapServers servers; /** -bootstrapServer, lwm2mServer * interface ServerSecurityConfig @@ -91,56 +74,70 @@ public class LwM2MBootstrapConfig implements Serializable { @JsonIgnore public BootstrapConfig getLwM2MBootstrapConfig() { BootstrapConfig configBs = new BootstrapConfig(); - AtomicInteger index = new AtomicInteger(); - /** Delete old security/config objects in LwM2mDefaultBootstrapSessionManager -> initTasks */ - configBs.toDelete.add("/0"); - configBs.toDelete.add("/1"); - serverConfiguration.forEach(serverCredential -> { - BootstrapConfig.ServerConfig serverConfig = new BootstrapConfig.ServerConfig(); - serverConfig.shortId = ((AbstractLwM2MBootstrapServerCredential)serverCredential).getShortServerId(); - serverConfig.lifetime = ((AbstractLwM2MBootstrapServerCredential)serverCredential).getLifetime(); - serverConfig.defaultMinPeriod = ((AbstractLwM2MBootstrapServerCredential)serverCredential).getDefaultMinPeriod(); - serverConfig.notifIfDisabled = ((AbstractLwM2MBootstrapServerCredential)serverCredential).isNotifIfDisabled(); - serverConfig.binding = BindingMode.parse(((AbstractLwM2MBootstrapServerCredential)serverCredential).getBinding()); - int k = index.get(); - configBs.servers.put(k, serverConfig); - BootstrapConfig.ServerSecurity serverSecurity = setServerSecurity((AbstractLwM2MBootstrapServerCredential)serverCredential, serverCredential.getSecurityMode()); - configBs.security.put(k, serverSecurity); - index.getAndIncrement(); + configBs.autoIdForSecurityObject = true; + int id = 0; + for (LwM2MBootstrapServerCredential serverCredential : serverConfiguration) { + BootstrapConfig.ServerConfig serverConfig = setServerConfig((AbstractLwM2MBootstrapServerCredential) serverCredential); + configBs.servers.put(id, serverConfig); + BootstrapConfig.ServerSecurity serverSecurity = setServerSecurity((AbstractLwM2MBootstrapServerCredential) serverCredential, serverCredential.getSecurityMode()); + configBs.security.put(id, serverSecurity); + id++; + } + /** in LwM2mDefaultBootstrapSessionManager -> initTasks + * Delete all security/config objects if update bootstrap server and lwm2m server + * if other: del or update only instances */ - }); return configBs; } private BootstrapConfig.ServerSecurity setServerSecurity(AbstractLwM2MBootstrapServerCredential serverCredential, LwM2MSecurityMode securityMode) { BootstrapConfig.ServerSecurity serverSecurity = new BootstrapConfig.ServerSecurity(); String serverUri = "coap://"; - byte[] publicKeyOrId = new byte[]{};; - byte[] secretKey = new byte[]{};; + byte[] publicKeyOrId = new byte[]{}; + byte[] secretKey = new byte[]{}; + byte[] serverPublicKey = new byte[]{}; serverSecurity.serverId = serverCredential.getShortServerId(); + log.info("serverId = [{}]", serverSecurity.serverId); serverSecurity.securityMode = SecurityMode.valueOf(securityMode.name()); serverSecurity.bootstrapServer = serverCredential.isBootstrapServerIs(); if (!LwM2MSecurityMode.NO_SEC.equals(securityMode)) { - serverUri = "coaps://"; + AbstractLwM2MBootstrapClientCredentialWithKeys server; if (serverSecurity.bootstrapServer) { - publicKeyOrId = ((AbstractLwM2MBootstrapClientCredentialWithKeys)this.bootstrapServer).getDecodedClientPublicKeyOrId(); - secretKey = ((AbstractLwM2MBootstrapClientCredentialWithKeys)this.bootstrapServer).getDecodedClientSecretKey(); + server = (AbstractLwM2MBootstrapClientCredentialWithKeys) this.bootstrapServer; } else { - publicKeyOrId = ((AbstractLwM2MBootstrapClientCredentialWithKeys)this.lwm2mServer).getDecodedClientPublicKeyOrId(); - secretKey = ((AbstractLwM2MBootstrapClientCredentialWithKeys)this.lwm2mServer).getDecodedClientSecretKey(); + server = (AbstractLwM2MBootstrapClientCredentialWithKeys) this.lwm2mServer; } - + serverUri = "coaps://"; + if (LwM2MSecurityMode.PSK.equals(securityMode)) { + publicKeyOrId = server.getClientPublicKeyOrId().getBytes(); + secretKey = Hex.decodeHex(server.getClientSecretKey().toCharArray()); + log.info("publicKeyOrId [{}]", new String(publicKeyOrId, StandardCharsets.UTF_8)); + } else { + publicKeyOrId = server.getDecodedClientPublicKeyOrId(); + secretKey = server.getDecodedClientSecretKey(); + log.info("publicKeyOrId [{}]", Hex.encodeHexString(publicKeyOrId)); + } + serverPublicKey = serverCredential.getDecodedCServerPublicKey(); } + log.info("secretKey [{}]", Hex.encodeHexString(secretKey)); serverUri += (((serverCredential.getHost().equals("0.0.0.0") ? "localhost" : serverCredential.getHost()) + ":" + serverCredential.getPort())); log.info("serverSecurity.uri = [{}]", serverUri); - log.info("publicKeyOrId [{}]", Hex.encodeHexString(publicKeyOrId)); - log.info("secretKey [{}]", Hex.encodeHexString(secretKey)); - log.info("server [{}]", Hex.encodeHexString(serverCredential.getDecodedCServerPublicKey())); serverSecurity.uri = serverUri; serverSecurity.publicKeyOrId = publicKeyOrId; serverSecurity.secretKey = secretKey; - serverSecurity.serverPublicKey = serverCredential.getDecodedCServerPublicKey(); + serverSecurity.serverPublicKey = serverPublicKey; + log.info("server [{}]", Hex.encodeHexString(serverSecurity.serverPublicKey)); return serverSecurity; } + + private BootstrapConfig.ServerConfig setServerConfig (AbstractLwM2MBootstrapServerCredential serverCredential) { + BootstrapConfig.ServerConfig serverConfig = new BootstrapConfig.ServerConfig(); + serverConfig.shortId = serverCredential.getShortServerId(); + serverConfig.lifetime = serverCredential.getLifetime(); + serverConfig.defaultMinPeriod = serverCredential.getDefaultMinPeriod(); + serverConfig.notifIfDisabled = serverCredential.isNotifIfDisabled(); + serverConfig.binding = BindingMode.parse(serverCredential.getBinding()); + return serverConfig; + } } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2mDefaultBootstrapSessionManager.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2mDefaultBootstrapSessionManager.java index 4f47079bbe..6f13b09f56 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2mDefaultBootstrapSessionManager.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2mDefaultBootstrapSessionManager.java @@ -16,13 +16,14 @@ package org.thingsboard.server.transport.lwm2m.bootstrap.secure; import lombok.extern.slf4j.Slf4j; +import org.eclipse.leshan.core.request.BootstrapDiscoverRequest; import org.eclipse.leshan.core.request.BootstrapDownlinkRequest; import org.eclipse.leshan.core.request.BootstrapFinishRequest; import org.eclipse.leshan.core.request.BootstrapRequest; import org.eclipse.leshan.core.request.Identity; +import org.eclipse.leshan.core.response.BootstrapDiscoverResponse; import org.eclipse.leshan.core.response.LwM2mResponse; import org.eclipse.leshan.server.bootstrap.BootstrapConfigStore; -import org.eclipse.leshan.server.bootstrap.BootstrapConfigStoreTaskProvider; import org.eclipse.leshan.server.bootstrap.BootstrapFailureCause; import org.eclipse.leshan.server.bootstrap.BootstrapSession; import org.eclipse.leshan.server.bootstrap.BootstrapTaskProvider; @@ -34,13 +35,13 @@ import org.eclipse.leshan.server.security.BootstrapSecurityStore; import org.eclipse.leshan.server.security.SecurityChecker; import org.eclipse.leshan.server.security.SecurityInfo; import org.thingsboard.server.common.transport.TransportService; +import org.thingsboard.server.transport.lwm2m.bootstrap.store.LwM2MBootstrapConfigStoreTaskProvider; import org.thingsboard.server.transport.lwm2m.bootstrap.store.LwM2MBootstrapSecurityStore; import org.thingsboard.server.transport.lwm2m.server.client.LwM2MAuthException; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; +import java.util.*; +import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.LOG_LWM2M_ERROR; import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.LOG_LWM2M_INFO; @Slf4j @@ -59,7 +60,7 @@ public class LwM2mDefaultBootstrapSessionManager extends DefaultBootstrapSession * @param bsSecurityStore the {@link BootstrapSecurityStore} used by default {@link SecurityChecker}. */ public LwM2mDefaultBootstrapSessionManager(BootstrapSecurityStore bsSecurityStore, BootstrapConfigStore configStore, TransportService transportService) { - this(bsSecurityStore, new SecurityChecker(), new BootstrapConfigStoreTaskProvider(configStore), + this(bsSecurityStore, new SecurityChecker(), new LwM2MBootstrapConfigStoreTaskProvider(configStore), new StandardBootstrapModelProvider()); this.transportService = transportService; } @@ -164,14 +165,15 @@ public class LwM2mDefaultBootstrapSessionManager extends DefaultBootstrapSession // store response DefaultBootstrapSession session = (DefaultBootstrapSession) bsSession; session.getResponses().add(response); - this.sendLogs (bsSession.getEndpoint(), - String.format("%s: %s %s receives success response %s for %s : %s", LOG_LWM2M_INFO, - request.getClass().getSimpleName(), request.getPath().toString(), response.toString(), bsSession.toString(), request.toString())); + String msg = String.format("%s: %s %s receives success response %s for %s : %s", LOG_LWM2M_INFO, + request.getClass().getSimpleName(), request.getPath().toString(), response.toString(), bsSession.toString(), request.toString()); + this.sendLogs(bsSession.getEndpoint(), msg); + // on success for NOT bootstrap finish request we send next request return BootstrapPolicy.continueWith(nextRequest(bsSession)); } else { // on success for bootstrap finish request we stop the session - this.sendLogs (bsSession.getEndpoint(), + this.sendLogs(bsSession.getEndpoint(), String.format("%s: %s receives success response for bootstrap finish request and stop the session: %s", LOG_LWM2M_INFO, request.getClass().getSimpleName(), bsSession.toString())); return BootstrapPolicy.finished(); @@ -194,9 +196,7 @@ public class LwM2mDefaultBootstrapSessionManager extends DefaultBootstrapSession } else { // on response error for bootstrap finish request we stop the session this.sendLogs (bsSession.getEndpoint(), - String.format("%s: %s %s error response %s for request %s bootstrap finish. Stop the session: %s", LOG_LWM2M_INFO, - request.getClass().getSimpleName(), - request.getPath().toString(), response.toString(), request.toString(), bsSession.toString())); + String.format("%s: error response for request bootstrap finish. Stop the session: %s", LOG_LWM2M_ERROR, bsSession.toString())); return BootstrapPolicy.failed(); } } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MBootstrapConfigStoreTaskProvider.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MBootstrapConfigStoreTaskProvider.java new file mode 100644 index 0000000000..ae95dd5ecc --- /dev/null +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MBootstrapConfigStoreTaskProvider.java @@ -0,0 +1,242 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.transport.lwm2m.bootstrap.store; + +import lombok.extern.slf4j.Slf4j; +import org.eclipse.leshan.core.Link; +import org.eclipse.leshan.core.node.LwM2mObject; +import org.eclipse.leshan.core.node.LwM2mPath; +import org.eclipse.leshan.core.request.*; +import org.eclipse.leshan.core.response.BootstrapDiscoverResponse; +import org.eclipse.leshan.core.response.BootstrapReadResponse; +import org.eclipse.leshan.core.response.LwM2mResponse; +import org.eclipse.leshan.server.bootstrap.BootstrapConfig; +import org.eclipse.leshan.server.bootstrap.BootstrapConfigStore; +import org.eclipse.leshan.server.bootstrap.BootstrapSession; +import org.eclipse.leshan.server.bootstrap.BootstrapTaskProvider; +import org.eclipse.leshan.server.bootstrap.BootstrapUtil; + +import java.net.InetSocketAddress; +import java.util.*; + +import static org.eclipse.leshan.server.bootstrap.BootstrapUtil.toWriteRequest; + +@Slf4j +public class LwM2MBootstrapConfigStoreTaskProvider implements BootstrapTaskProvider { + + private BootstrapConfigStore store; + + private Map supportedObjects; + + /** + * Map + */ + protected Map securityInstances; + protected Map serverInstances; + + public LwM2MBootstrapConfigStoreTaskProvider(BootstrapConfigStore store) { + this.store = store; + } + + @Override + public Tasks getTasks(BootstrapSession session, List previousResponse) { + + BootstrapConfig config = store.get(session.getEndpoint(), session.getIdentity(), session); + if (config == null) { + return null; + } + if (previousResponse == null && shouldStartWithDiscover(config)) { + Tasks tasks = new Tasks(); + tasks.requestsToSend = new ArrayList<>(1); + tasks.requestsToSend.add(new BootstrapDiscoverRequest()); + tasks.last = false; + return tasks; + } else { + Tasks tasks = new Tasks(); + if (this.supportedObjects == null) { + initSupportedObjectsDefault(); + + } + // add supportedObjects + tasks.supportedObjects = this.supportedObjects; + // handle bootstrap discover response + if (previousResponse != null) { + if (previousResponse.get(0) instanceof BootstrapDiscoverResponse) { + BootstrapDiscoverResponse discoverResponse = (BootstrapDiscoverResponse) previousResponse.get(0); + if (discoverResponse.isSuccess()) { + this.initAfterBootstrapDiscover(discoverResponse); + findSecurityInstanceId(discoverResponse.getObjectLinks()); + } else { + log.info( + "Bootstrap Discover return error {} : to continue bootstrap session without autoIdForSecurityObject mode. {}", + discoverResponse, session); + } + if (this.securityInstances.get(0) == null) { + log.error( + "Unable to find bootstrap server instance in Security Object (0) in response {}: unable to continue bootstrap session with autoIdForSecurityObject mode. {}", + discoverResponse, session); + return null; + } + tasks.requestsToSend = new ArrayList<>(1); + tasks.requestsToSend.add(new BootstrapReadRequest("/1")); + tasks.last = false; + return tasks; + } + BootstrapReadResponse readResponse = (BootstrapReadResponse) previousResponse.get(0); + findServerInstanceId(readResponse); + // create requests from config + tasks.requestsToSend = this.toRequests(config, + config.contentFormat != null ? config.contentFormat : session.getContentFormat(), + this.securityInstances.get(0)); + } else { + // create requests from config + tasks.requestsToSend = BootstrapUtil.toRequests(config, + config.contentFormat != null ? config.contentFormat : session.getContentFormat()); + + } + return tasks; + } + } + + protected boolean shouldStartWithDiscover(BootstrapConfig config) { + return config.autoIdForSecurityObject; + } + + protected void findSecurityInstanceId(Link[] objectLinks) { + this.securityInstances = new HashMap<>(); + for (Link link : objectLinks) { + if (link.getUrl().startsWith("/0/")) { + try { + LwM2mPath path = new LwM2mPath(link.getUrl()); + if (path.isObjectInstance()) { + if (link.getAttributes().containsKey("ssid")) { + int serverId = Integer.valueOf(link.getAttributes().get("ssid")); + if (!this.securityInstances.containsKey(serverId)) { + this.securityInstances.put(serverId, path.getObjectInstanceId()); + } else { + log.error(String.format("Invalid lwm2mSecurityInstance by [{}]", path.getObjectInstanceId())); + } + this.securityInstances.put(Integer.valueOf(link.getAttributes().get("ssid")), path.getObjectInstanceId()); + } else { + if (!this.securityInstances.containsKey(0)) { + this.securityInstances.put(0, path.getObjectInstanceId()); + } else { + log.error(String.format("Invalid bootstrapSecurityInstance by [{}]", path.getObjectInstanceId())); + } + } + } + } catch (Exception e) { + // ignore if this is not a LWM2M path + log.error("Invalid LwM2MPath starting by \"/0/\""); + } + } + } + } + + protected void findServerInstanceId(BootstrapReadResponse readResponse) { + serverInstances = new HashMap<>(); + ((LwM2mObject) readResponse.getContent()).getInstances().values().forEach(instance -> { + serverInstances.put(((Long) instance.getResource(0).getValue()).intValue(), instance.getId()); + }); + } + + public BootstrapConfigStore getStore() { + return this.store; + } + + private void initAfterBootstrapDiscover(BootstrapDiscoverResponse response) { + Link[] links = response.getObjectLinks(); + Arrays.stream(links).forEach(link -> { + LwM2mPath path = new LwM2mPath(link.getUrl()); + if (path != null && !path.isRoot() && path.getObjectId() < 3) { + if (path.isObject()) { + String ver = link.getAttributes().get("ver") != null ? link.getAttributes().get("ver") : "1.0"; + this.supportedObjects.put(path.getObjectId(), ver); + } + } + }); + } + + + public List> toRequests(BootstrapConfig bootstrapConfig, + ContentFormat contentFormat, int bootstrapSecurityInstanceId) { + List> requests = new ArrayList<>(); + boolean isBsServer = false; + boolean isLwServer = false; + /** Map */ + Map instances = new HashMap<>(); + // handle security + int id = 0; + for (BootstrapConfig.ServerSecurity security : new TreeMap<>(bootstrapConfig.security).values()) { + if (security.bootstrapServer) { + requests.add(toWriteRequest(bootstrapSecurityInstanceId, security, contentFormat)); + isBsServer = true; + instances.put(security.serverId, bootstrapSecurityInstanceId); + } else { + if (id == bootstrapSecurityInstanceId) { + id++; + } + requests.add(toWriteRequest(id, security, contentFormat)); + instances.put(security.serverId, id); + id++; + } + } + // handle server + for (Map.Entry server : bootstrapConfig.servers.entrySet()) { + int securityInstanceId = instances.get(server.getValue().shortId); + requests.add(toWriteRequest(securityInstanceId, server.getValue(), contentFormat)); + if (!isBsServer && this.serverInstances.containsKey(server.getValue().shortId) && securityInstanceId != this.serverInstances.get(server.getValue().shortId)){ + requests.add(new BootstrapDeleteRequest("/0/" + securityInstanceId)); + requests.add(new BootstrapDeleteRequest("/1/" + this.serverInstances.get(server.getValue().shortId))); + } + isLwServer = true; + } + // handle acl + for (Map.Entry acl : bootstrapConfig.acls.entrySet()) { + requests.add(toWriteRequest(acl.getKey(), acl.getValue(), contentFormat)); + } + // handle delete + if (isBsServer & isLwServer) { + requests.add(new BootstrapDeleteRequest("/0")); + requests.add(new BootstrapDeleteRequest("/1")); + } + + return (requests); + } + + private InetSocketAddress getSocketAddress(String uri) { +// String uri1 = "coap://localhost:5687"; + if (uri.contains("coap://")) { + uri = uri.replace("coap://", ""); + } else return null; + String[] uris = uri.split(":"); + if (uris.length == 2) { + try { + return new InetSocketAddress(uris[0], Integer.parseInt(uris[1])); + } catch (Exception e) { + return null; + } + + } else return null; + } + + private void initSupportedObjectsDefault() { + this.supportedObjects = new HashMap<>(); + this.supportedObjects.put(0, "1.1"); + this.supportedObjects.put(1, "1.1"); + this.supportedObjects.put(2, "1.0"); + } +} diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MBootstrapSecurityStore.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MBootstrapSecurityStore.java index ee973f3a23..81d2007c4b 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MBootstrapSecurityStore.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MBootstrapSecurityStore.java @@ -75,6 +75,7 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore { if (store.getBootstrapCredentialConfig() != null) { /* add value to store from BootstrapJson */ this.setBootstrapConfigScurityInfo(store); + endPoint = store.getEndpoint(); BootstrapConfig bsConfigNew = store.getBootstrapConfig(); if (bsConfigNew != null) { try { @@ -121,34 +122,6 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore { /* BootstrapConfig */ LwM2MBootstrapConfig lwM2MBootstrapConfig = this.getParametersBootstrap(store); if (lwM2MBootstrapConfig != null) { - /* Security info */ -// switch (lwM2MBootstrapConfig.getBootstrapServer().getSecurityMode()) { -// /* Use RPK only */ -// case PSK: -// store.setSecurityInfo(SecurityInfo.newPreSharedKeyInfo(store.getEndpoint(), -// lwM2MBootstrapConfig.getBootstrapServer().getClientPublicKeyOrId(), -// Hex.decodeHex(lwM2MBootstrapConfig.getBootstrapServer().getClientSecretKey().toCharArray()))); -// store.setSecurityMode(SecurityMode.PSK); -// break; -// case RPK: -// try { -//// store.setSecurityInfo(SecurityInfo.newRawPublicKeyInfo(store.getEndpoint(), -//// SecurityUtil.publicKey.decode(Hex.decodeHex(lwM2MBootstrapConfig.getBootstrapServer().getClientPublicKeyOrId().toCharArray())))); -//// store.setSecurityMode(SecurityMode.RPK); -// break; -// } catch (IOException | GeneralSecurityException e) { -// log.error("Unable to decode Client public key for [{}] [{}]", store.getEndpoint(), e.getMessage()); -// } -// case X509: -// store.setSecurityInfo(SecurityInfo.newX509CertInfo(store.getEndpoint())); -// store.setSecurityMode(SecurityMode.X509); -// break; -// case NO_SEC: -// store.setSecurityMode(SecurityMode.NO_SEC); -// store.setSecurityInfo(null); -// break; -// default: -// } BootstrapConfig bootstrapConfig = lwM2MBootstrapConfig.getLwM2MBootstrapConfig(); store.setBootstrapConfig(bootstrapConfig); } @@ -157,27 +130,11 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore { private LwM2MBootstrapConfig getParametersBootstrap(TbLwM2MSecurityInfo store) { LwM2MBootstrapConfig lwM2MBootstrapConfig = store.getBootstrapCredentialConfig(); if (lwM2MBootstrapConfig != null) { -// LwM2MBootstrapServersConfiguration bootstrapObject = getBootstrapParametersFromThingsboard(store.getDeviceProfile()); -// lwM2MBootstrapConfig.setServers(JacksonUtil.fromString(JacksonUtil.toString(bootstrapObject.getServers()), LwM2MBootstrapServers.class)); -// LwM2MServerBootstrap bootstrapServerProfile = JacksonUtil.fromString(JacksonUtil.toString(bootstrapObject.getBootstrapServer()), LwM2MServerBootstrap.class); -// if (SecurityMode.NO_SEC != bootstrapServerProfile.getSecurityMode() && bootstrapServerProfile != null) { -// bootstrapServerProfile.setSecurityHost(bootstrapServerProfile.getHost()); -// bootstrapServerProfile.setSecurityPort(bootstrapServerProfile.getPort()); -// } -// LwM2MServerBootstrap profileLwm2mServer = JacksonUtil.fromString(JacksonUtil.toString(bootstrapObject.getLwm2mServer()), LwM2MServerBootstrap.class); -// if (SecurityMode.NO_SEC != profileLwm2mServer.getSecurityMode() && profileLwm2mServer != null) { -// profileLwm2mServer.setSecurityHost(profileLwm2mServer.getHost()); -// profileLwm2mServer.setSecurityPort(profileLwm2mServer.getPort()); -// } - - UUID sessionUUiD = UUID.randomUUID(); TransportProtos.SessionInfoProto sessionInfo = helper.getValidateSessionInfo(store.getMsg(), sessionUUiD.getMostSignificantBits(), sessionUUiD.getLeastSignificantBits()); bsSessions.put(store.getEndpoint(), sessionInfo); context.getTransportService().registerAsyncSession(sessionInfo, new LwM2mSessionMsgListener(null, null, null, sessionInfo, context.getTransportService())); if (this.getValidatedSecurityMode(lwM2MBootstrapConfig)) { -// lwM2MBootstrapConfig.setBootstrapServer(new LwM2MServerBootstrap(lwM2MBootstrapConfig.getBootstrapServer(), bootstrapServerProfile)); -// lwM2MBootstrapConfig.setLwm2mServer(new LwM2MServerBootstrap(lwM2MBootstrapConfig.getLwm2mServer(), profileLwm2mServer)); String logMsg = String.format("%s: getParametersBootstrap: %s Access connect client with bootstrap server.", LOG_LWM2M_INFO, store.getEndpoint()); helper.sendParametersOnThingsboardTelemetry(helper.getKvStringtoThingsboard(LOG_LWM2M_TELEMETRY, logMsg), sessionInfo); return lwM2MBootstrapConfig; diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsServiceImpl.java index c8431da85c..ec8afa77f0 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsServiceImpl.java @@ -48,6 +48,9 @@ import org.thingsboard.server.dao.exception.DataValidationException; import org.thingsboard.server.dao.exception.DeviceCredentialsValidationException; import org.thingsboard.server.dao.service.DataValidator; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; + import static org.thingsboard.server.common.data.CacheConstants.DEVICE_CREDENTIALS_CACHE; import static org.thingsboard.server.dao.service.Validator.validateId; import static org.thingsboard.server.dao.service.Validator.validateString; @@ -238,7 +241,7 @@ public class DeviceCredentialsServiceImpl extends AbstractEntityService implemen case PSK: PSKClientCredential pskCredentials = (PSKClientCredential) clientCredentials; if (StringUtils.isBlank(pskCredentials.getIdentity())) { - throw new DeviceCredentialsValidationException("LwM2M client PSK identity must be specified!"); + throw new DeviceCredentialsValidationException("LwM2M client PSK identity must be specified and must be an utf8 string!"); } // SecurityMode.NO_SEC.toString() == "NO_SEC"; if (pskCredentials.getIdentity().equals(SecurityMode.NO_SEC.toString())) { @@ -295,7 +298,7 @@ public class DeviceCredentialsServiceImpl extends AbstractEntityService implemen case PSK: PSKBootstrapClientCredential pskCredentials = (PSKBootstrapClientCredential) serverCredentials; if (StringUtils.isBlank(pskCredentials.getClientPublicKeyOrId())) { - throw new DeviceCredentialsValidationException(server + " client PSK public key or id must be specified!"); + throw new DeviceCredentialsValidationException(server + " client PSK public key or id must be specified and must be an utf8 string!"); } // SecurityMode.NO_SEC.toString() == "NO_SEC"; From 24dc98156d048c7fbc31ff1b43c169730f75f771 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Tue, 16 Nov 2021 12:19:05 +0200 Subject: [PATCH 107/432] lwm2m - Bootstrap add delete --- ...LwM2MBootstrapConfigStoreTaskProvider.java | 75 +++++++++++-------- 1 file changed, 44 insertions(+), 31 deletions(-) diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MBootstrapConfigStoreTaskProvider.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MBootstrapConfigStoreTaskProvider.java index ae95dd5ecc..bb84f94c59 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MBootstrapConfigStoreTaskProvider.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MBootstrapConfigStoreTaskProvider.java @@ -31,6 +31,7 @@ import org.eclipse.leshan.server.bootstrap.BootstrapUtil; import java.net.InetSocketAddress; import java.util.*; +import java.util.stream.Collectors; import static org.eclipse.leshan.server.bootstrap.BootstrapUtil.toWriteRequest; @@ -46,6 +47,8 @@ public class LwM2MBootstrapConfigStoreTaskProvider implements BootstrapTaskProvi */ protected Map securityInstances; protected Map serverInstances; + protected Integer bootstrapServerIdOld; + protected Integer bootstrapServerIdNew; public LwM2MBootstrapConfigStoreTaskProvider(BootstrapConfigStore store) { this.store = store; @@ -99,8 +102,7 @@ public class LwM2MBootstrapConfigStoreTaskProvider implements BootstrapTaskProvi findServerInstanceId(readResponse); // create requests from config tasks.requestsToSend = this.toRequests(config, - config.contentFormat != null ? config.contentFormat : session.getContentFormat(), - this.securityInstances.get(0)); + config.contentFormat != null ? config.contentFormat : session.getContentFormat()); } else { // create requests from config tasks.requestsToSend = BootstrapUtil.toRequests(config, @@ -116,6 +118,7 @@ public class LwM2MBootstrapConfigStoreTaskProvider implements BootstrapTaskProvi } protected void findSecurityInstanceId(Link[] objectLinks) { + log.info("Object after discover: [{}]", objectLinks); this.securityInstances = new HashMap<>(); for (Link link : objectLinks) { if (link.getUrl().startsWith("/0/")) { @@ -147,10 +150,20 @@ public class LwM2MBootstrapConfigStoreTaskProvider implements BootstrapTaskProvi } protected void findServerInstanceId(BootstrapReadResponse readResponse) { - serverInstances = new HashMap<>(); + this.serverInstances = new HashMap<>(); ((LwM2mObject) readResponse.getContent()).getInstances().values().forEach(instance -> { serverInstances.put(((Long) instance.getResource(0).getValue()).intValue(), instance.getId()); }); + if (this.securityInstances != null && this.securityInstances.size() > 0 && this.serverInstances != null && this.serverInstances.size() > 0) { + this.findBootstrapServerId(); + } + } + + protected void findBootstrapServerId() { + Map filteredMap = this.serverInstances.entrySet() + .stream().filter(x -> !this.securityInstances.containsKey(x.getKey())) + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); + this.bootstrapServerIdOld = filteredMap.keySet().stream().findFirst().get(); } public BootstrapConfigStore getStore() { @@ -172,8 +185,10 @@ public class LwM2MBootstrapConfigStoreTaskProvider implements BootstrapTaskProvi public List> toRequests(BootstrapConfig bootstrapConfig, - ContentFormat contentFormat, int bootstrapSecurityInstanceId) { + ContentFormat contentFormat) { List> requests = new ArrayList<>(); + List> requestsDelete = new ArrayList<>(); + List> requestsWrite = new ArrayList<>(); boolean isBsServer = false; boolean isLwServer = false; /** Map */ @@ -182,57 +197,55 @@ public class LwM2MBootstrapConfigStoreTaskProvider implements BootstrapTaskProvi int id = 0; for (BootstrapConfig.ServerSecurity security : new TreeMap<>(bootstrapConfig.security).values()) { if (security.bootstrapServer) { - requests.add(toWriteRequest(bootstrapSecurityInstanceId, security, contentFormat)); + requestsWrite.add(toWriteRequest(this.securityInstances.get(0), security, contentFormat)); isBsServer = true; - instances.put(security.serverId, bootstrapSecurityInstanceId); + this.bootstrapServerIdNew = security.serverId; + instances.put(security.serverId, this.securityInstances.get(0)); } else { - if (id == bootstrapSecurityInstanceId) { + if (id == this.securityInstances.get(0)) { id++; } - requests.add(toWriteRequest(id, security, contentFormat)); + requestsWrite.add(toWriteRequest(id, security, contentFormat)); instances.put(security.serverId, id); + isLwServer = true; + if (!isBsServer && this.securityInstances.containsKey(security.serverId) && id != this.securityInstances.get(security.serverId)) { + requestsDelete.add(new BootstrapDeleteRequest("/0/" + this.securityInstances.get(security.serverId))); + } id++; } } // handle server for (Map.Entry server : bootstrapConfig.servers.entrySet()) { int securityInstanceId = instances.get(server.getValue().shortId); - requests.add(toWriteRequest(securityInstanceId, server.getValue(), contentFormat)); - if (!isBsServer && this.serverInstances.containsKey(server.getValue().shortId) && securityInstanceId != this.serverInstances.get(server.getValue().shortId)){ - requests.add(new BootstrapDeleteRequest("/0/" + securityInstanceId)); - requests.add(new BootstrapDeleteRequest("/1/" + this.serverInstances.get(server.getValue().shortId))); + requestsWrite.add(toWriteRequest(securityInstanceId, server.getValue(), contentFormat)); + if (!isLwServer && this.bootstrapServerIdNew != null && server.getValue().shortId == this.bootstrapServerIdNew && + (this.bootstrapServerIdNew != this.bootstrapServerIdOld || securityInstanceId != this.serverInstances.get(this.bootstrapServerIdOld))) { + requestsDelete.add(new BootstrapDeleteRequest("/1/" + this.serverInstances.get(this.bootstrapServerIdOld))); + + } else { + if (!isBsServer && this.serverInstances.containsKey(server.getValue().shortId) && securityInstanceId != this.serverInstances.get(server.getValue().shortId)) { + requestsDelete.add(new BootstrapDeleteRequest("/1/" + this.serverInstances.get(server.getValue().shortId))); + } } - isLwServer = true; } // handle acl for (Map.Entry acl : bootstrapConfig.acls.entrySet()) { - requests.add(toWriteRequest(acl.getKey(), acl.getValue(), contentFormat)); + requestsWrite.add(toWriteRequest(acl.getKey(), acl.getValue(), contentFormat)); } // handle delete if (isBsServer & isLwServer) { requests.add(new BootstrapDeleteRequest("/0")); requests.add(new BootstrapDeleteRequest("/1")); + } else if (requestsDelete.size() > 0) { + requests.addAll(requestsDelete); + } + // handle write + if (requestsWrite.size() > 0) { + requests.addAll(requestsWrite); } - return (requests); } - private InetSocketAddress getSocketAddress(String uri) { -// String uri1 = "coap://localhost:5687"; - if (uri.contains("coap://")) { - uri = uri.replace("coap://", ""); - } else return null; - String[] uris = uri.split(":"); - if (uris.length == 2) { - try { - return new InetSocketAddress(uris[0], Integer.parseInt(uris[1])); - } catch (Exception e) { - return null; - } - - } else return null; - } - private void initSupportedObjectsDefault() { this.supportedObjects = new HashMap<>(); this.supportedObjects.put(0, "1.1"); From cf5477ebf9a21a3458d2038dec5b3c2705a33fa4 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Mon, 15 Nov 2021 19:11:53 +0200 Subject: [PATCH 108/432] lwm2m - Bootstrap auto --- .../bootstrap/LwM2MServerSecurityConfig.java | 17 +- .../secure/LwM2MBootstrapConfig.java | 89 ++++--- .../LwM2mDefaultBootstrapSessionManager.java | 24 +- ...LwM2MBootstrapConfigStoreTaskProvider.java | 242 ++++++++++++++++++ .../store/LwM2MBootstrapSecurityStore.java | 45 +--- .../device/DeviceCredentialsServiceImpl.java | 7 +- 6 files changed, 313 insertions(+), 111 deletions(-) create mode 100644 common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MBootstrapConfigStoreTaskProvider.java diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/LwM2MServerSecurityConfig.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/LwM2MServerSecurityConfig.java index fcbe91743b..12dd9c5a64 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/LwM2MServerSecurityConfig.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/LwM2MServerSecurityConfig.java @@ -23,12 +23,15 @@ import lombok.Data; @Data public class LwM2MServerSecurityConfig { - @ApiModelProperty(position = 1, value = "Server short Id. Used as link to associate server Object Instance.\nThis identifier uniquely identifies each LwM2M Server configured for the LwM2M Client.\n" + - "This Resource MUST be set when the Bootstrap-Server Resource has a value of 'false'. \n" + + @ApiModelProperty(position = 1, value = "Server short Id. Used as link to associate server Object Instance. This identifier uniquely identifies each LwM2M Server configured for the LwM2M Client. " + + "This Resource MUST be set when the Bootstrap-Server Resource has a value of 'false'. " + "The values ID:0 and ID:65535 values MUST NOT be used for identifying the LwM2M Server.", example = "123", readOnly = true) protected Integer shortServerId = 123; /** Security -> ObjectId = 0 'LWM2M Security' */ - @ApiModelProperty(position = 2, value = "Is Bootstrap Server or Lwm2m Server", example = "true or false", readOnly = true) + @ApiModelProperty(position = 2, value = "Is Bootstrap Server or Lwm2m Server. " + + "The LwM2M Client MAY be configured to use one or more LwM2M Server Account(s). " + + "The LwM2M Client MUST have at most one LwM2M Bootstrap-Server Account. " + + "(*) The LwM2M client MUST have at least one LwM2M server account after completing the boot sequence specified.", example = "true or false", readOnly = true) protected boolean bootstrapServerIs = false; @ApiModelProperty(position = 3, value = "Host for 'No Security' mode", example = "0.0.0.0", readOnly = true) protected String host; @@ -45,15 +48,15 @@ public class LwM2MServerSecurityConfig { /** Config -> ObjectId = 1 'LwM2M Server' */ @ApiModelProperty(position = 10, value = "Specify the lifetime of the registration in seconds.", example = "300", readOnly = true) private Integer lifetime = 300; - @ApiModelProperty(position = 11, value = "The default value the LwM2M Client should use for the Minimum Period of an Observation in the absence of this parameter being included in an Observation.\n" + + @ApiModelProperty(position = 11, value = "The default value the LwM2M Client should use for the Minimum Period of an Observation in the absence of this parameter being included in an Observation. " + "If this Resource doesn’t exist, the default value is 0.", example = "1", readOnly = true) private Integer defaultMinPeriod = 1; /** ResourceID=6 'Notification Storing When Disabled or Offline' */ - @ApiModelProperty(position = 12, value = "If true, the LwM2M Client stores “Notify” operations to the LwM2M Server while the LwM2M Server account is disabled or the LwM2M Client is offline. After the LwM2M Server account is enabled or the LwM2M Client is online, the LwM2M Client reports the stored “Notify” operations to the Server.\n" + - "If false, the LwM2M Client discards all the “Notify” operations or temporarily disables the Observe function while the LwM2M Server is disabled or the LwM2M Client is offline.\n" + + @ApiModelProperty(position = 12, value = "If true, the LwM2M Client stores “Notify” operations to the LwM2M Server while the LwM2M Server account is disabled or the LwM2M Client is offline. After the LwM2M Server account is enabled or the LwM2M Client is online, the LwM2M Client reports the stored “Notify” operations to the Server. " + + "If false, the LwM2M Client discards all the “Notify” operations or temporarily disables the Observe function while the LwM2M Server is disabled or the LwM2M Client is offline. " + "The default value is true.", example = "true", readOnly = true) private boolean notifIfDisabled = true; - @ApiModelProperty(position = 14, value = "This Resource defines the transport binding configured for the LwM2M Client.\n" + + @ApiModelProperty(position = 14, value = "This Resource defines the transport binding configured for the LwM2M Client. " + "If the LwM2M Client supports the binding specified in this Resource, the LwM2M Client MUST use that transport for the Current Binding Mode.", example = "U", readOnly = true) private String binding = "U"; } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapConfig.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapConfig.java index 792cf71c67..124de67fa0 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapConfig.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapConfig.java @@ -40,23 +40,6 @@ import java.util.concurrent.atomic.AtomicInteger; public class LwM2MBootstrapConfig implements Serializable { List serverConfiguration; - /* - interface BootstrapSecurityConfig - servers: BootstrapServersSecurityConfig, - bootstrapServer: ServerSecurityConfig, - lwm2mServer: ServerSecurityConfig - } - */ - /** -servers - * shortId: number, - * lifetime: number, - * defaultMinPeriod: number, - * notifIfDisabled: boolean, - * binding: string - * */ -// @Getter -// @Setter -// private LwM2MBootstrapServers servers; /** -bootstrapServer, lwm2mServer * interface ServerSecurityConfig @@ -91,56 +74,70 @@ public class LwM2MBootstrapConfig implements Serializable { @JsonIgnore public BootstrapConfig getLwM2MBootstrapConfig() { BootstrapConfig configBs = new BootstrapConfig(); - AtomicInteger index = new AtomicInteger(); - /** Delete old security/config objects in LwM2mDefaultBootstrapSessionManager -> initTasks */ - configBs.toDelete.add("/0"); - configBs.toDelete.add("/1"); - serverConfiguration.forEach(serverCredential -> { - BootstrapConfig.ServerConfig serverConfig = new BootstrapConfig.ServerConfig(); - serverConfig.shortId = ((AbstractLwM2MBootstrapServerCredential)serverCredential).getShortServerId(); - serverConfig.lifetime = ((AbstractLwM2MBootstrapServerCredential)serverCredential).getLifetime(); - serverConfig.defaultMinPeriod = ((AbstractLwM2MBootstrapServerCredential)serverCredential).getDefaultMinPeriod(); - serverConfig.notifIfDisabled = ((AbstractLwM2MBootstrapServerCredential)serverCredential).isNotifIfDisabled(); - serverConfig.binding = BindingMode.parse(((AbstractLwM2MBootstrapServerCredential)serverCredential).getBinding()); - int k = index.get(); - configBs.servers.put(k, serverConfig); - BootstrapConfig.ServerSecurity serverSecurity = setServerSecurity((AbstractLwM2MBootstrapServerCredential)serverCredential, serverCredential.getSecurityMode()); - configBs.security.put(k, serverSecurity); - index.getAndIncrement(); + configBs.autoIdForSecurityObject = true; + int id = 0; + for (LwM2MBootstrapServerCredential serverCredential : serverConfiguration) { + BootstrapConfig.ServerConfig serverConfig = setServerConfig((AbstractLwM2MBootstrapServerCredential) serverCredential); + configBs.servers.put(id, serverConfig); + BootstrapConfig.ServerSecurity serverSecurity = setServerSecurity((AbstractLwM2MBootstrapServerCredential) serverCredential, serverCredential.getSecurityMode()); + configBs.security.put(id, serverSecurity); + id++; + } + /** in LwM2mDefaultBootstrapSessionManager -> initTasks + * Delete all security/config objects if update bootstrap server and lwm2m server + * if other: del or update only instances */ - }); return configBs; } private BootstrapConfig.ServerSecurity setServerSecurity(AbstractLwM2MBootstrapServerCredential serverCredential, LwM2MSecurityMode securityMode) { BootstrapConfig.ServerSecurity serverSecurity = new BootstrapConfig.ServerSecurity(); String serverUri = "coap://"; - byte[] publicKeyOrId = new byte[]{};; - byte[] secretKey = new byte[]{};; + byte[] publicKeyOrId = new byte[]{}; + byte[] secretKey = new byte[]{}; + byte[] serverPublicKey = new byte[]{}; serverSecurity.serverId = serverCredential.getShortServerId(); + log.info("serverId = [{}]", serverSecurity.serverId); serverSecurity.securityMode = SecurityMode.valueOf(securityMode.name()); serverSecurity.bootstrapServer = serverCredential.isBootstrapServerIs(); if (!LwM2MSecurityMode.NO_SEC.equals(securityMode)) { - serverUri = "coaps://"; + AbstractLwM2MBootstrapClientCredentialWithKeys server; if (serverSecurity.bootstrapServer) { - publicKeyOrId = ((AbstractLwM2MBootstrapClientCredentialWithKeys)this.bootstrapServer).getDecodedClientPublicKeyOrId(); - secretKey = ((AbstractLwM2MBootstrapClientCredentialWithKeys)this.bootstrapServer).getDecodedClientSecretKey(); + server = (AbstractLwM2MBootstrapClientCredentialWithKeys) this.bootstrapServer; } else { - publicKeyOrId = ((AbstractLwM2MBootstrapClientCredentialWithKeys)this.lwm2mServer).getDecodedClientPublicKeyOrId(); - secretKey = ((AbstractLwM2MBootstrapClientCredentialWithKeys)this.lwm2mServer).getDecodedClientSecretKey(); + server = (AbstractLwM2MBootstrapClientCredentialWithKeys) this.lwm2mServer; } - + serverUri = "coaps://"; + if (LwM2MSecurityMode.PSK.equals(securityMode)) { + publicKeyOrId = server.getClientPublicKeyOrId().getBytes(); + secretKey = Hex.decodeHex(server.getClientSecretKey().toCharArray()); + log.info("publicKeyOrId [{}]", new String(publicKeyOrId, StandardCharsets.UTF_8)); + } else { + publicKeyOrId = server.getDecodedClientPublicKeyOrId(); + secretKey = server.getDecodedClientSecretKey(); + log.info("publicKeyOrId [{}]", Hex.encodeHexString(publicKeyOrId)); + } + serverPublicKey = serverCredential.getDecodedCServerPublicKey(); } + log.info("secretKey [{}]", Hex.encodeHexString(secretKey)); serverUri += (((serverCredential.getHost().equals("0.0.0.0") ? "localhost" : serverCredential.getHost()) + ":" + serverCredential.getPort())); log.info("serverSecurity.uri = [{}]", serverUri); - log.info("publicKeyOrId [{}]", Hex.encodeHexString(publicKeyOrId)); - log.info("secretKey [{}]", Hex.encodeHexString(secretKey)); - log.info("server [{}]", Hex.encodeHexString(serverCredential.getDecodedCServerPublicKey())); serverSecurity.uri = serverUri; serverSecurity.publicKeyOrId = publicKeyOrId; serverSecurity.secretKey = secretKey; - serverSecurity.serverPublicKey = serverCredential.getDecodedCServerPublicKey(); + serverSecurity.serverPublicKey = serverPublicKey; + log.info("server [{}]", Hex.encodeHexString(serverSecurity.serverPublicKey)); return serverSecurity; } + + private BootstrapConfig.ServerConfig setServerConfig (AbstractLwM2MBootstrapServerCredential serverCredential) { + BootstrapConfig.ServerConfig serverConfig = new BootstrapConfig.ServerConfig(); + serverConfig.shortId = serverCredential.getShortServerId(); + serverConfig.lifetime = serverCredential.getLifetime(); + serverConfig.defaultMinPeriod = serverCredential.getDefaultMinPeriod(); + serverConfig.notifIfDisabled = serverCredential.isNotifIfDisabled(); + serverConfig.binding = BindingMode.parse(serverCredential.getBinding()); + return serverConfig; + } } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2mDefaultBootstrapSessionManager.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2mDefaultBootstrapSessionManager.java index 4f47079bbe..6f13b09f56 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2mDefaultBootstrapSessionManager.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2mDefaultBootstrapSessionManager.java @@ -16,13 +16,14 @@ package org.thingsboard.server.transport.lwm2m.bootstrap.secure; import lombok.extern.slf4j.Slf4j; +import org.eclipse.leshan.core.request.BootstrapDiscoverRequest; import org.eclipse.leshan.core.request.BootstrapDownlinkRequest; import org.eclipse.leshan.core.request.BootstrapFinishRequest; import org.eclipse.leshan.core.request.BootstrapRequest; import org.eclipse.leshan.core.request.Identity; +import org.eclipse.leshan.core.response.BootstrapDiscoverResponse; import org.eclipse.leshan.core.response.LwM2mResponse; import org.eclipse.leshan.server.bootstrap.BootstrapConfigStore; -import org.eclipse.leshan.server.bootstrap.BootstrapConfigStoreTaskProvider; import org.eclipse.leshan.server.bootstrap.BootstrapFailureCause; import org.eclipse.leshan.server.bootstrap.BootstrapSession; import org.eclipse.leshan.server.bootstrap.BootstrapTaskProvider; @@ -34,13 +35,13 @@ import org.eclipse.leshan.server.security.BootstrapSecurityStore; import org.eclipse.leshan.server.security.SecurityChecker; import org.eclipse.leshan.server.security.SecurityInfo; import org.thingsboard.server.common.transport.TransportService; +import org.thingsboard.server.transport.lwm2m.bootstrap.store.LwM2MBootstrapConfigStoreTaskProvider; import org.thingsboard.server.transport.lwm2m.bootstrap.store.LwM2MBootstrapSecurityStore; import org.thingsboard.server.transport.lwm2m.server.client.LwM2MAuthException; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; +import java.util.*; +import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.LOG_LWM2M_ERROR; import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.LOG_LWM2M_INFO; @Slf4j @@ -59,7 +60,7 @@ public class LwM2mDefaultBootstrapSessionManager extends DefaultBootstrapSession * @param bsSecurityStore the {@link BootstrapSecurityStore} used by default {@link SecurityChecker}. */ public LwM2mDefaultBootstrapSessionManager(BootstrapSecurityStore bsSecurityStore, BootstrapConfigStore configStore, TransportService transportService) { - this(bsSecurityStore, new SecurityChecker(), new BootstrapConfigStoreTaskProvider(configStore), + this(bsSecurityStore, new SecurityChecker(), new LwM2MBootstrapConfigStoreTaskProvider(configStore), new StandardBootstrapModelProvider()); this.transportService = transportService; } @@ -164,14 +165,15 @@ public class LwM2mDefaultBootstrapSessionManager extends DefaultBootstrapSession // store response DefaultBootstrapSession session = (DefaultBootstrapSession) bsSession; session.getResponses().add(response); - this.sendLogs (bsSession.getEndpoint(), - String.format("%s: %s %s receives success response %s for %s : %s", LOG_LWM2M_INFO, - request.getClass().getSimpleName(), request.getPath().toString(), response.toString(), bsSession.toString(), request.toString())); + String msg = String.format("%s: %s %s receives success response %s for %s : %s", LOG_LWM2M_INFO, + request.getClass().getSimpleName(), request.getPath().toString(), response.toString(), bsSession.toString(), request.toString()); + this.sendLogs(bsSession.getEndpoint(), msg); + // on success for NOT bootstrap finish request we send next request return BootstrapPolicy.continueWith(nextRequest(bsSession)); } else { // on success for bootstrap finish request we stop the session - this.sendLogs (bsSession.getEndpoint(), + this.sendLogs(bsSession.getEndpoint(), String.format("%s: %s receives success response for bootstrap finish request and stop the session: %s", LOG_LWM2M_INFO, request.getClass().getSimpleName(), bsSession.toString())); return BootstrapPolicy.finished(); @@ -194,9 +196,7 @@ public class LwM2mDefaultBootstrapSessionManager extends DefaultBootstrapSession } else { // on response error for bootstrap finish request we stop the session this.sendLogs (bsSession.getEndpoint(), - String.format("%s: %s %s error response %s for request %s bootstrap finish. Stop the session: %s", LOG_LWM2M_INFO, - request.getClass().getSimpleName(), - request.getPath().toString(), response.toString(), request.toString(), bsSession.toString())); + String.format("%s: error response for request bootstrap finish. Stop the session: %s", LOG_LWM2M_ERROR, bsSession.toString())); return BootstrapPolicy.failed(); } } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MBootstrapConfigStoreTaskProvider.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MBootstrapConfigStoreTaskProvider.java new file mode 100644 index 0000000000..ae95dd5ecc --- /dev/null +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MBootstrapConfigStoreTaskProvider.java @@ -0,0 +1,242 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.transport.lwm2m.bootstrap.store; + +import lombok.extern.slf4j.Slf4j; +import org.eclipse.leshan.core.Link; +import org.eclipse.leshan.core.node.LwM2mObject; +import org.eclipse.leshan.core.node.LwM2mPath; +import org.eclipse.leshan.core.request.*; +import org.eclipse.leshan.core.response.BootstrapDiscoverResponse; +import org.eclipse.leshan.core.response.BootstrapReadResponse; +import org.eclipse.leshan.core.response.LwM2mResponse; +import org.eclipse.leshan.server.bootstrap.BootstrapConfig; +import org.eclipse.leshan.server.bootstrap.BootstrapConfigStore; +import org.eclipse.leshan.server.bootstrap.BootstrapSession; +import org.eclipse.leshan.server.bootstrap.BootstrapTaskProvider; +import org.eclipse.leshan.server.bootstrap.BootstrapUtil; + +import java.net.InetSocketAddress; +import java.util.*; + +import static org.eclipse.leshan.server.bootstrap.BootstrapUtil.toWriteRequest; + +@Slf4j +public class LwM2MBootstrapConfigStoreTaskProvider implements BootstrapTaskProvider { + + private BootstrapConfigStore store; + + private Map supportedObjects; + + /** + * Map + */ + protected Map securityInstances; + protected Map serverInstances; + + public LwM2MBootstrapConfigStoreTaskProvider(BootstrapConfigStore store) { + this.store = store; + } + + @Override + public Tasks getTasks(BootstrapSession session, List previousResponse) { + + BootstrapConfig config = store.get(session.getEndpoint(), session.getIdentity(), session); + if (config == null) { + return null; + } + if (previousResponse == null && shouldStartWithDiscover(config)) { + Tasks tasks = new Tasks(); + tasks.requestsToSend = new ArrayList<>(1); + tasks.requestsToSend.add(new BootstrapDiscoverRequest()); + tasks.last = false; + return tasks; + } else { + Tasks tasks = new Tasks(); + if (this.supportedObjects == null) { + initSupportedObjectsDefault(); + + } + // add supportedObjects + tasks.supportedObjects = this.supportedObjects; + // handle bootstrap discover response + if (previousResponse != null) { + if (previousResponse.get(0) instanceof BootstrapDiscoverResponse) { + BootstrapDiscoverResponse discoverResponse = (BootstrapDiscoverResponse) previousResponse.get(0); + if (discoverResponse.isSuccess()) { + this.initAfterBootstrapDiscover(discoverResponse); + findSecurityInstanceId(discoverResponse.getObjectLinks()); + } else { + log.info( + "Bootstrap Discover return error {} : to continue bootstrap session without autoIdForSecurityObject mode. {}", + discoverResponse, session); + } + if (this.securityInstances.get(0) == null) { + log.error( + "Unable to find bootstrap server instance in Security Object (0) in response {}: unable to continue bootstrap session with autoIdForSecurityObject mode. {}", + discoverResponse, session); + return null; + } + tasks.requestsToSend = new ArrayList<>(1); + tasks.requestsToSend.add(new BootstrapReadRequest("/1")); + tasks.last = false; + return tasks; + } + BootstrapReadResponse readResponse = (BootstrapReadResponse) previousResponse.get(0); + findServerInstanceId(readResponse); + // create requests from config + tasks.requestsToSend = this.toRequests(config, + config.contentFormat != null ? config.contentFormat : session.getContentFormat(), + this.securityInstances.get(0)); + } else { + // create requests from config + tasks.requestsToSend = BootstrapUtil.toRequests(config, + config.contentFormat != null ? config.contentFormat : session.getContentFormat()); + + } + return tasks; + } + } + + protected boolean shouldStartWithDiscover(BootstrapConfig config) { + return config.autoIdForSecurityObject; + } + + protected void findSecurityInstanceId(Link[] objectLinks) { + this.securityInstances = new HashMap<>(); + for (Link link : objectLinks) { + if (link.getUrl().startsWith("/0/")) { + try { + LwM2mPath path = new LwM2mPath(link.getUrl()); + if (path.isObjectInstance()) { + if (link.getAttributes().containsKey("ssid")) { + int serverId = Integer.valueOf(link.getAttributes().get("ssid")); + if (!this.securityInstances.containsKey(serverId)) { + this.securityInstances.put(serverId, path.getObjectInstanceId()); + } else { + log.error(String.format("Invalid lwm2mSecurityInstance by [{}]", path.getObjectInstanceId())); + } + this.securityInstances.put(Integer.valueOf(link.getAttributes().get("ssid")), path.getObjectInstanceId()); + } else { + if (!this.securityInstances.containsKey(0)) { + this.securityInstances.put(0, path.getObjectInstanceId()); + } else { + log.error(String.format("Invalid bootstrapSecurityInstance by [{}]", path.getObjectInstanceId())); + } + } + } + } catch (Exception e) { + // ignore if this is not a LWM2M path + log.error("Invalid LwM2MPath starting by \"/0/\""); + } + } + } + } + + protected void findServerInstanceId(BootstrapReadResponse readResponse) { + serverInstances = new HashMap<>(); + ((LwM2mObject) readResponse.getContent()).getInstances().values().forEach(instance -> { + serverInstances.put(((Long) instance.getResource(0).getValue()).intValue(), instance.getId()); + }); + } + + public BootstrapConfigStore getStore() { + return this.store; + } + + private void initAfterBootstrapDiscover(BootstrapDiscoverResponse response) { + Link[] links = response.getObjectLinks(); + Arrays.stream(links).forEach(link -> { + LwM2mPath path = new LwM2mPath(link.getUrl()); + if (path != null && !path.isRoot() && path.getObjectId() < 3) { + if (path.isObject()) { + String ver = link.getAttributes().get("ver") != null ? link.getAttributes().get("ver") : "1.0"; + this.supportedObjects.put(path.getObjectId(), ver); + } + } + }); + } + + + public List> toRequests(BootstrapConfig bootstrapConfig, + ContentFormat contentFormat, int bootstrapSecurityInstanceId) { + List> requests = new ArrayList<>(); + boolean isBsServer = false; + boolean isLwServer = false; + /** Map */ + Map instances = new HashMap<>(); + // handle security + int id = 0; + for (BootstrapConfig.ServerSecurity security : new TreeMap<>(bootstrapConfig.security).values()) { + if (security.bootstrapServer) { + requests.add(toWriteRequest(bootstrapSecurityInstanceId, security, contentFormat)); + isBsServer = true; + instances.put(security.serverId, bootstrapSecurityInstanceId); + } else { + if (id == bootstrapSecurityInstanceId) { + id++; + } + requests.add(toWriteRequest(id, security, contentFormat)); + instances.put(security.serverId, id); + id++; + } + } + // handle server + for (Map.Entry server : bootstrapConfig.servers.entrySet()) { + int securityInstanceId = instances.get(server.getValue().shortId); + requests.add(toWriteRequest(securityInstanceId, server.getValue(), contentFormat)); + if (!isBsServer && this.serverInstances.containsKey(server.getValue().shortId) && securityInstanceId != this.serverInstances.get(server.getValue().shortId)){ + requests.add(new BootstrapDeleteRequest("/0/" + securityInstanceId)); + requests.add(new BootstrapDeleteRequest("/1/" + this.serverInstances.get(server.getValue().shortId))); + } + isLwServer = true; + } + // handle acl + for (Map.Entry acl : bootstrapConfig.acls.entrySet()) { + requests.add(toWriteRequest(acl.getKey(), acl.getValue(), contentFormat)); + } + // handle delete + if (isBsServer & isLwServer) { + requests.add(new BootstrapDeleteRequest("/0")); + requests.add(new BootstrapDeleteRequest("/1")); + } + + return (requests); + } + + private InetSocketAddress getSocketAddress(String uri) { +// String uri1 = "coap://localhost:5687"; + if (uri.contains("coap://")) { + uri = uri.replace("coap://", ""); + } else return null; + String[] uris = uri.split(":"); + if (uris.length == 2) { + try { + return new InetSocketAddress(uris[0], Integer.parseInt(uris[1])); + } catch (Exception e) { + return null; + } + + } else return null; + } + + private void initSupportedObjectsDefault() { + this.supportedObjects = new HashMap<>(); + this.supportedObjects.put(0, "1.1"); + this.supportedObjects.put(1, "1.1"); + this.supportedObjects.put(2, "1.0"); + } +} diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MBootstrapSecurityStore.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MBootstrapSecurityStore.java index ee973f3a23..81d2007c4b 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MBootstrapSecurityStore.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MBootstrapSecurityStore.java @@ -75,6 +75,7 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore { if (store.getBootstrapCredentialConfig() != null) { /* add value to store from BootstrapJson */ this.setBootstrapConfigScurityInfo(store); + endPoint = store.getEndpoint(); BootstrapConfig bsConfigNew = store.getBootstrapConfig(); if (bsConfigNew != null) { try { @@ -121,34 +122,6 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore { /* BootstrapConfig */ LwM2MBootstrapConfig lwM2MBootstrapConfig = this.getParametersBootstrap(store); if (lwM2MBootstrapConfig != null) { - /* Security info */ -// switch (lwM2MBootstrapConfig.getBootstrapServer().getSecurityMode()) { -// /* Use RPK only */ -// case PSK: -// store.setSecurityInfo(SecurityInfo.newPreSharedKeyInfo(store.getEndpoint(), -// lwM2MBootstrapConfig.getBootstrapServer().getClientPublicKeyOrId(), -// Hex.decodeHex(lwM2MBootstrapConfig.getBootstrapServer().getClientSecretKey().toCharArray()))); -// store.setSecurityMode(SecurityMode.PSK); -// break; -// case RPK: -// try { -//// store.setSecurityInfo(SecurityInfo.newRawPublicKeyInfo(store.getEndpoint(), -//// SecurityUtil.publicKey.decode(Hex.decodeHex(lwM2MBootstrapConfig.getBootstrapServer().getClientPublicKeyOrId().toCharArray())))); -//// store.setSecurityMode(SecurityMode.RPK); -// break; -// } catch (IOException | GeneralSecurityException e) { -// log.error("Unable to decode Client public key for [{}] [{}]", store.getEndpoint(), e.getMessage()); -// } -// case X509: -// store.setSecurityInfo(SecurityInfo.newX509CertInfo(store.getEndpoint())); -// store.setSecurityMode(SecurityMode.X509); -// break; -// case NO_SEC: -// store.setSecurityMode(SecurityMode.NO_SEC); -// store.setSecurityInfo(null); -// break; -// default: -// } BootstrapConfig bootstrapConfig = lwM2MBootstrapConfig.getLwM2MBootstrapConfig(); store.setBootstrapConfig(bootstrapConfig); } @@ -157,27 +130,11 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore { private LwM2MBootstrapConfig getParametersBootstrap(TbLwM2MSecurityInfo store) { LwM2MBootstrapConfig lwM2MBootstrapConfig = store.getBootstrapCredentialConfig(); if (lwM2MBootstrapConfig != null) { -// LwM2MBootstrapServersConfiguration bootstrapObject = getBootstrapParametersFromThingsboard(store.getDeviceProfile()); -// lwM2MBootstrapConfig.setServers(JacksonUtil.fromString(JacksonUtil.toString(bootstrapObject.getServers()), LwM2MBootstrapServers.class)); -// LwM2MServerBootstrap bootstrapServerProfile = JacksonUtil.fromString(JacksonUtil.toString(bootstrapObject.getBootstrapServer()), LwM2MServerBootstrap.class); -// if (SecurityMode.NO_SEC != bootstrapServerProfile.getSecurityMode() && bootstrapServerProfile != null) { -// bootstrapServerProfile.setSecurityHost(bootstrapServerProfile.getHost()); -// bootstrapServerProfile.setSecurityPort(bootstrapServerProfile.getPort()); -// } -// LwM2MServerBootstrap profileLwm2mServer = JacksonUtil.fromString(JacksonUtil.toString(bootstrapObject.getLwm2mServer()), LwM2MServerBootstrap.class); -// if (SecurityMode.NO_SEC != profileLwm2mServer.getSecurityMode() && profileLwm2mServer != null) { -// profileLwm2mServer.setSecurityHost(profileLwm2mServer.getHost()); -// profileLwm2mServer.setSecurityPort(profileLwm2mServer.getPort()); -// } - - UUID sessionUUiD = UUID.randomUUID(); TransportProtos.SessionInfoProto sessionInfo = helper.getValidateSessionInfo(store.getMsg(), sessionUUiD.getMostSignificantBits(), sessionUUiD.getLeastSignificantBits()); bsSessions.put(store.getEndpoint(), sessionInfo); context.getTransportService().registerAsyncSession(sessionInfo, new LwM2mSessionMsgListener(null, null, null, sessionInfo, context.getTransportService())); if (this.getValidatedSecurityMode(lwM2MBootstrapConfig)) { -// lwM2MBootstrapConfig.setBootstrapServer(new LwM2MServerBootstrap(lwM2MBootstrapConfig.getBootstrapServer(), bootstrapServerProfile)); -// lwM2MBootstrapConfig.setLwm2mServer(new LwM2MServerBootstrap(lwM2MBootstrapConfig.getLwm2mServer(), profileLwm2mServer)); String logMsg = String.format("%s: getParametersBootstrap: %s Access connect client with bootstrap server.", LOG_LWM2M_INFO, store.getEndpoint()); helper.sendParametersOnThingsboardTelemetry(helper.getKvStringtoThingsboard(LOG_LWM2M_TELEMETRY, logMsg), sessionInfo); return lwM2MBootstrapConfig; diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsServiceImpl.java index c8431da85c..ec8afa77f0 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsServiceImpl.java @@ -48,6 +48,9 @@ import org.thingsboard.server.dao.exception.DataValidationException; import org.thingsboard.server.dao.exception.DeviceCredentialsValidationException; import org.thingsboard.server.dao.service.DataValidator; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; + import static org.thingsboard.server.common.data.CacheConstants.DEVICE_CREDENTIALS_CACHE; import static org.thingsboard.server.dao.service.Validator.validateId; import static org.thingsboard.server.dao.service.Validator.validateString; @@ -238,7 +241,7 @@ public class DeviceCredentialsServiceImpl extends AbstractEntityService implemen case PSK: PSKClientCredential pskCredentials = (PSKClientCredential) clientCredentials; if (StringUtils.isBlank(pskCredentials.getIdentity())) { - throw new DeviceCredentialsValidationException("LwM2M client PSK identity must be specified!"); + throw new DeviceCredentialsValidationException("LwM2M client PSK identity must be specified and must be an utf8 string!"); } // SecurityMode.NO_SEC.toString() == "NO_SEC"; if (pskCredentials.getIdentity().equals(SecurityMode.NO_SEC.toString())) { @@ -295,7 +298,7 @@ public class DeviceCredentialsServiceImpl extends AbstractEntityService implemen case PSK: PSKBootstrapClientCredential pskCredentials = (PSKBootstrapClientCredential) serverCredentials; if (StringUtils.isBlank(pskCredentials.getClientPublicKeyOrId())) { - throw new DeviceCredentialsValidationException(server + " client PSK public key or id must be specified!"); + throw new DeviceCredentialsValidationException(server + " client PSK public key or id must be specified and must be an utf8 string!"); } // SecurityMode.NO_SEC.toString() == "NO_SEC"; From 22609c34934ec2800db5646b1810e54e1039e55d Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Tue, 16 Nov 2021 12:19:05 +0200 Subject: [PATCH 109/432] lwm2m - Bootstrap add delete --- ...LwM2MBootstrapConfigStoreTaskProvider.java | 75 +++++++++++-------- 1 file changed, 44 insertions(+), 31 deletions(-) diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MBootstrapConfigStoreTaskProvider.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MBootstrapConfigStoreTaskProvider.java index ae95dd5ecc..bb84f94c59 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MBootstrapConfigStoreTaskProvider.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MBootstrapConfigStoreTaskProvider.java @@ -31,6 +31,7 @@ import org.eclipse.leshan.server.bootstrap.BootstrapUtil; import java.net.InetSocketAddress; import java.util.*; +import java.util.stream.Collectors; import static org.eclipse.leshan.server.bootstrap.BootstrapUtil.toWriteRequest; @@ -46,6 +47,8 @@ public class LwM2MBootstrapConfigStoreTaskProvider implements BootstrapTaskProvi */ protected Map securityInstances; protected Map serverInstances; + protected Integer bootstrapServerIdOld; + protected Integer bootstrapServerIdNew; public LwM2MBootstrapConfigStoreTaskProvider(BootstrapConfigStore store) { this.store = store; @@ -99,8 +102,7 @@ public class LwM2MBootstrapConfigStoreTaskProvider implements BootstrapTaskProvi findServerInstanceId(readResponse); // create requests from config tasks.requestsToSend = this.toRequests(config, - config.contentFormat != null ? config.contentFormat : session.getContentFormat(), - this.securityInstances.get(0)); + config.contentFormat != null ? config.contentFormat : session.getContentFormat()); } else { // create requests from config tasks.requestsToSend = BootstrapUtil.toRequests(config, @@ -116,6 +118,7 @@ public class LwM2MBootstrapConfigStoreTaskProvider implements BootstrapTaskProvi } protected void findSecurityInstanceId(Link[] objectLinks) { + log.info("Object after discover: [{}]", objectLinks); this.securityInstances = new HashMap<>(); for (Link link : objectLinks) { if (link.getUrl().startsWith("/0/")) { @@ -147,10 +150,20 @@ public class LwM2MBootstrapConfigStoreTaskProvider implements BootstrapTaskProvi } protected void findServerInstanceId(BootstrapReadResponse readResponse) { - serverInstances = new HashMap<>(); + this.serverInstances = new HashMap<>(); ((LwM2mObject) readResponse.getContent()).getInstances().values().forEach(instance -> { serverInstances.put(((Long) instance.getResource(0).getValue()).intValue(), instance.getId()); }); + if (this.securityInstances != null && this.securityInstances.size() > 0 && this.serverInstances != null && this.serverInstances.size() > 0) { + this.findBootstrapServerId(); + } + } + + protected void findBootstrapServerId() { + Map filteredMap = this.serverInstances.entrySet() + .stream().filter(x -> !this.securityInstances.containsKey(x.getKey())) + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); + this.bootstrapServerIdOld = filteredMap.keySet().stream().findFirst().get(); } public BootstrapConfigStore getStore() { @@ -172,8 +185,10 @@ public class LwM2MBootstrapConfigStoreTaskProvider implements BootstrapTaskProvi public List> toRequests(BootstrapConfig bootstrapConfig, - ContentFormat contentFormat, int bootstrapSecurityInstanceId) { + ContentFormat contentFormat) { List> requests = new ArrayList<>(); + List> requestsDelete = new ArrayList<>(); + List> requestsWrite = new ArrayList<>(); boolean isBsServer = false; boolean isLwServer = false; /** Map */ @@ -182,57 +197,55 @@ public class LwM2MBootstrapConfigStoreTaskProvider implements BootstrapTaskProvi int id = 0; for (BootstrapConfig.ServerSecurity security : new TreeMap<>(bootstrapConfig.security).values()) { if (security.bootstrapServer) { - requests.add(toWriteRequest(bootstrapSecurityInstanceId, security, contentFormat)); + requestsWrite.add(toWriteRequest(this.securityInstances.get(0), security, contentFormat)); isBsServer = true; - instances.put(security.serverId, bootstrapSecurityInstanceId); + this.bootstrapServerIdNew = security.serverId; + instances.put(security.serverId, this.securityInstances.get(0)); } else { - if (id == bootstrapSecurityInstanceId) { + if (id == this.securityInstances.get(0)) { id++; } - requests.add(toWriteRequest(id, security, contentFormat)); + requestsWrite.add(toWriteRequest(id, security, contentFormat)); instances.put(security.serverId, id); + isLwServer = true; + if (!isBsServer && this.securityInstances.containsKey(security.serverId) && id != this.securityInstances.get(security.serverId)) { + requestsDelete.add(new BootstrapDeleteRequest("/0/" + this.securityInstances.get(security.serverId))); + } id++; } } // handle server for (Map.Entry server : bootstrapConfig.servers.entrySet()) { int securityInstanceId = instances.get(server.getValue().shortId); - requests.add(toWriteRequest(securityInstanceId, server.getValue(), contentFormat)); - if (!isBsServer && this.serverInstances.containsKey(server.getValue().shortId) && securityInstanceId != this.serverInstances.get(server.getValue().shortId)){ - requests.add(new BootstrapDeleteRequest("/0/" + securityInstanceId)); - requests.add(new BootstrapDeleteRequest("/1/" + this.serverInstances.get(server.getValue().shortId))); + requestsWrite.add(toWriteRequest(securityInstanceId, server.getValue(), contentFormat)); + if (!isLwServer && this.bootstrapServerIdNew != null && server.getValue().shortId == this.bootstrapServerIdNew && + (this.bootstrapServerIdNew != this.bootstrapServerIdOld || securityInstanceId != this.serverInstances.get(this.bootstrapServerIdOld))) { + requestsDelete.add(new BootstrapDeleteRequest("/1/" + this.serverInstances.get(this.bootstrapServerIdOld))); + + } else { + if (!isBsServer && this.serverInstances.containsKey(server.getValue().shortId) && securityInstanceId != this.serverInstances.get(server.getValue().shortId)) { + requestsDelete.add(new BootstrapDeleteRequest("/1/" + this.serverInstances.get(server.getValue().shortId))); + } } - isLwServer = true; } // handle acl for (Map.Entry acl : bootstrapConfig.acls.entrySet()) { - requests.add(toWriteRequest(acl.getKey(), acl.getValue(), contentFormat)); + requestsWrite.add(toWriteRequest(acl.getKey(), acl.getValue(), contentFormat)); } // handle delete if (isBsServer & isLwServer) { requests.add(new BootstrapDeleteRequest("/0")); requests.add(new BootstrapDeleteRequest("/1")); + } else if (requestsDelete.size() > 0) { + requests.addAll(requestsDelete); + } + // handle write + if (requestsWrite.size() > 0) { + requests.addAll(requestsWrite); } - return (requests); } - private InetSocketAddress getSocketAddress(String uri) { -// String uri1 = "coap://localhost:5687"; - if (uri.contains("coap://")) { - uri = uri.replace("coap://", ""); - } else return null; - String[] uris = uri.split(":"); - if (uris.length == 2) { - try { - return new InetSocketAddress(uris[0], Integer.parseInt(uris[1])); - } catch (Exception e) { - return null; - } - - } else return null; - } - private void initSupportedObjectsDefault() { this.supportedObjects = new HashMap<>(); this.supportedObjects.put(0, "1.1"); From d31bb08bf3d06d9df967c897a2ab0e7f34270283 Mon Sep 17 00:00:00 2001 From: van-vanich Date: Tue, 16 Nov 2021 13:07:00 +0200 Subject: [PATCH 110/432] equals for BaseReadTsKvQuery don't check startTs and endTs, so @EqualsAndHashCode(callSuper = true) fix this problems --- .../thingsboard/server/common/data/kv/BaseReadTsKvQuery.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/kv/BaseReadTsKvQuery.java b/common/data/src/main/java/org/thingsboard/server/common/data/kv/BaseReadTsKvQuery.java index 2a81fe0cbe..be424288ba 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/kv/BaseReadTsKvQuery.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/kv/BaseReadTsKvQuery.java @@ -16,8 +16,10 @@ package org.thingsboard.server.common.data.kv; import lombok.Data; +import lombok.EqualsAndHashCode; @Data +@EqualsAndHashCode(callSuper = true) public class BaseReadTsKvQuery extends BaseTsKvQuery implements ReadTsKvQuery { private final long interval; From 77b9a8c1af31bc8e3c988c7d77a6113f602c649f Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Tue, 16 Nov 2021 14:32:52 +0200 Subject: [PATCH 111/432] Minor improvements to the thingsboard.yml comments --- application/src/main/resources/thingsboard.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index 90b52c8b02..85394e67a8 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -211,7 +211,7 @@ cassandra: init_retry_interval_ms: "${CASSANDRA_CLUSTER_INIT_RETRY_INTERVAL_MS:3000}" max_requests_per_connection_local: "${CASSANDRA_MAX_REQUESTS_PER_CONNECTION_LOCAL:32768}" max_requests_per_connection_remote: "${CASSANDRA_MAX_REQUESTS_PER_CONNECTION_REMOTE:32768}" - # Credential parameters # + # Credential parameters credentials: "${CASSANDRA_USE_CREDENTIALS:false}" # Specify your username username: "${CASSANDRA_USERNAME:}" @@ -595,7 +595,7 @@ js: remote: # Maximum allowed JavaScript execution errors before JavaScript will be blacklisted max_errors: "${REMOTE_JS_SANDBOX_MAX_ERRORS:3}" - # Maximum time in seconds for black listed function to stay in 1:the list. + # Maximum time in seconds for black listed function to stay in the list. max_black_list_duration_sec: "${REMOTE_JS_SANDBOX_MAX_BLACKLIST_DURATION_SEC:60}" stats: enabled: "${TB_JS_REMOTE_STATS_ENABLED:false}" @@ -1030,8 +1030,8 @@ queue: # For RETRY_ALL, RETRY_FAILED, RETRY_TIMED_OUT, RETRY_FAILED_AND_TIMED_OUT retries: "${TB_QUEUE_RE_MAIN_PROCESSING_STRATEGY_RETRIES:3}" # Number of retries, 0 is unlimited failure-percentage: "${TB_QUEUE_RE_MAIN_PROCESSING_STRATEGY_FAILURE_PERCENTAGE:0}" # Skip retry if failures or timeouts are less then X percentage of messages; - pause-between-retries: "${TB_QUEUE_RE_MAIN_PROCESSING_STRATEGY_RETRY_PAUSE:3}"# Time in seconds to wait in consumer thread before retries; - max-pause-between-retries: "${TB_QUEUE_RE_MAIN_PROCESSING_STRATEGY_MAX_RETRY_PAUSE:3}"# Max allowed time in seconds for pause between retries. + pause-between-retries: "${TB_QUEUE_RE_MAIN_PROCESSING_STRATEGY_RETRY_PAUSE:3}" # Time in seconds to wait in consumer thread before retries; + max-pause-between-retries: "${TB_QUEUE_RE_MAIN_PROCESSING_STRATEGY_MAX_RETRY_PAUSE:3}" # Max allowed time in seconds for pause between retries. - name: "${TB_QUEUE_RE_HP_QUEUE_NAME:HighPriority}" topic: "${TB_QUEUE_RE_HP_TOPIC:tb_rule_engine.hp}" poll-interval: "${TB_QUEUE_RE_HP_POLL_INTERVAL_MS:25}" @@ -1047,8 +1047,8 @@ queue: # For RETRY_ALL, RETRY_FAILED, RETRY_TIMED_OUT, RETRY_FAILED_AND_TIMED_OUT retries: "${TB_QUEUE_RE_HP_PROCESSING_STRATEGY_RETRIES:0}" # Number of retries, 0 is unlimited failure-percentage: "${TB_QUEUE_RE_HP_PROCESSING_STRATEGY_FAILURE_PERCENTAGE:0}" # Skip retry if failures or timeouts are less then X percentage of messages; - pause-between-retries: "${TB_QUEUE_RE_HP_PROCESSING_STRATEGY_RETRY_PAUSE:5}"# Time in seconds to wait in consumer thread before retries; - max-pause-between-retries: "${TB_QUEUE_RE_HP_PROCESSING_STRATEGY_MAX_RETRY_PAUSE:5}"# Max allowed time in seconds for pause between retries. + pause-between-retries: "${TB_QUEUE_RE_HP_PROCESSING_STRATEGY_RETRY_PAUSE:5}" # Time in seconds to wait in consumer thread before retries; + max-pause-between-retries: "${TB_QUEUE_RE_HP_PROCESSING_STRATEGY_MAX_RETRY_PAUSE:5}" # Max allowed time in seconds for pause between retries. - name: "${TB_QUEUE_RE_SQ_QUEUE_NAME:SequentialByOriginator}" topic: "${TB_QUEUE_RE_SQ_TOPIC:tb_rule_engine.sq}" poll-interval: "${TB_QUEUE_RE_SQ_POLL_INTERVAL_MS:25}" @@ -1064,8 +1064,8 @@ queue: # For RETRY_ALL, RETRY_FAILED, RETRY_TIMED_OUT, RETRY_FAILED_AND_TIMED_OUT retries: "${TB_QUEUE_RE_SQ_PROCESSING_STRATEGY_RETRIES:3}" # Number of retries, 0 is unlimited failure-percentage: "${TB_QUEUE_RE_SQ_PROCESSING_STRATEGY_FAILURE_PERCENTAGE:0}" # Skip retry if failures or timeouts are less then X percentage of messages; - pause-between-retries: "${TB_QUEUE_RE_SQ_PROCESSING_STRATEGY_RETRY_PAUSE:5}"# Time in seconds to wait in consumer thread before retries; - max-pause-between-retries: "${TB_QUEUE_RE_SQ_PROCESSING_STRATEGY_MAX_RETRY_PAUSE:5}"# Max allowed time in seconds for pause between retries. + pause-between-retries: "${TB_QUEUE_RE_SQ_PROCESSING_STRATEGY_RETRY_PAUSE:5}" # Time in seconds to wait in consumer thread before retries; + max-pause-between-retries: "${TB_QUEUE_RE_SQ_PROCESSING_STRATEGY_MAX_RETRY_PAUSE:5}" # Max allowed time in seconds for pause between retries. transport: # For high priority notifications that require minimum latency and processing time notifications_topic: "${TB_QUEUE_TRANSPORT_NOTIFICATIONS_TOPIC:tb_transport.notifications}" From 6f8b52056b953f488ebb63563381b4169c50d579 Mon Sep 17 00:00:00 2001 From: ShvaykaD Date: Tue, 16 Nov 2021 15:04:10 +0200 Subject: [PATCH 112/432] fixed widget type based methods in rest client --- .../org/thingsboard/rest/client/RestClient.java | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/rest-client/src/main/java/org/thingsboard/rest/client/RestClient.java b/rest-client/src/main/java/org/thingsboard/rest/client/RestClient.java index a64dd97cdc..ebc7df1f25 100644 --- a/rest-client/src/main/java/org/thingsboard/rest/client/RestClient.java +++ b/rest-client/src/main/java/org/thingsboard/rest/client/RestClient.java @@ -134,6 +134,7 @@ import org.thingsboard.server.common.data.security.model.SecuritySettings; import org.thingsboard.server.common.data.security.model.UserPasswordPolicy; import org.thingsboard.server.common.data.sms.config.TestSmsRequest; import org.thingsboard.server.common.data.widget.WidgetType; +import org.thingsboard.server.common.data.widget.WidgetTypeDetails; import org.thingsboard.server.common.data.widget.WidgetsBundle; import java.io.Closeable; @@ -2423,11 +2424,11 @@ public class RestClient implements ClientHttpRequestInterceptor, Closeable { }).getBody(); } - public Optional getWidgetTypeById(WidgetTypeId widgetTypeId) { + public Optional getWidgetTypeById(WidgetTypeId widgetTypeId) { try { - ResponseEntity widgetType = - restTemplate.getForEntity(baseURL + "/api/widgetType/{widgetTypeId}", WidgetType.class, widgetTypeId.getId()); - return Optional.ofNullable(widgetType.getBody()); + ResponseEntity widgetTypeDetails = + restTemplate.getForEntity(baseURL + "/api/widgetType/{widgetTypeId}", WidgetTypeDetails.class, widgetTypeId.getId()); + return Optional.ofNullable(widgetTypeDetails.getBody()); } catch (HttpClientErrorException exception) { if (exception.getStatusCode() == HttpStatus.NOT_FOUND) { return Optional.empty(); @@ -2437,8 +2438,8 @@ public class RestClient implements ClientHttpRequestInterceptor, Closeable { } } - public WidgetType saveWidgetType(WidgetType widgetType) { - return restTemplate.postForEntity(baseURL + "/api/widgetType", widgetType, WidgetType.class).getBody(); + public WidgetTypeDetails saveWidgetType(WidgetTypeDetails widgetTypeDetails) { + return restTemplate.postForEntity(baseURL + "/api/widgetType", widgetTypeDetails, WidgetTypeDetails.class).getBody(); } public void deleteWidgetType(WidgetTypeId widgetTypeId) { From 225a97c8e4043b603f30294c69f14988a7f9f860 Mon Sep 17 00:00:00 2001 From: ShvaykaD Date: Tue, 16 Nov 2021 15:10:48 +0200 Subject: [PATCH 113/432] added new widget type based methods to rest client --- .../thingsboard/rest/client/RestClient.java | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/rest-client/src/main/java/org/thingsboard/rest/client/RestClient.java b/rest-client/src/main/java/org/thingsboard/rest/client/RestClient.java index ebc7df1f25..b990bbe5c3 100644 --- a/rest-client/src/main/java/org/thingsboard/rest/client/RestClient.java +++ b/rest-client/src/main/java/org/thingsboard/rest/client/RestClient.java @@ -135,6 +135,7 @@ import org.thingsboard.server.common.data.security.model.UserPasswordPolicy; import org.thingsboard.server.common.data.sms.config.TestSmsRequest; import org.thingsboard.server.common.data.widget.WidgetType; import org.thingsboard.server.common.data.widget.WidgetTypeDetails; +import org.thingsboard.server.common.data.widget.WidgetTypeInfo; import org.thingsboard.server.common.data.widget.WidgetsBundle; import java.io.Closeable; @@ -2457,6 +2458,28 @@ public class RestClient implements ClientHttpRequestInterceptor, Closeable { bundleAlias).getBody(); } + public List getBundleWidgetTypesDetails(boolean isSystem, String bundleAlias) { + return restTemplate.exchange( + baseURL + "/api/widgetTypesDetails?isSystem={isSystem}&bundleAlias={bundleAlias}", + HttpMethod.GET, + HttpEntity.EMPTY, + new ParameterizedTypeReference>() { + }, + isSystem, + bundleAlias).getBody(); + } + + public List getBundleWidgetTypesInfos(boolean isSystem, String bundleAlias) { + return restTemplate.exchange( + baseURL + "/api/widgetTypesInfos?isSystem={isSystem}&bundleAlias={bundleAlias}", + HttpMethod.GET, + HttpEntity.EMPTY, + new ParameterizedTypeReference>() { + }, + isSystem, + bundleAlias).getBody(); + } + public Optional getWidgetType(boolean isSystem, String bundleAlias, String alias) { try { ResponseEntity widgetType = From c43e8950a2b46d001a1ebe5d18b883cb3b4c2aba Mon Sep 17 00:00:00 2001 From: Dima Landiak Date: Fri, 12 Nov 2021 12:01:50 +0200 Subject: [PATCH 114/432] save ts without latest --- .../DefaultTelemetrySubscriptionService.java | 31 +++++++++++++++++++ .../dao/timeseries/TimeseriesService.java | 2 ++ .../dao/timeseries/BaseTimeseriesService.java | 21 +++++++++++++ .../api/RuleEngineTelemetryService.java | 2 ++ .../engine/telemetry/TbMsgTimeseriesNode.java | 8 +++-- .../TbMsgTimeseriesNodeConfiguration.java | 2 ++ 6 files changed, 64 insertions(+), 2 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetrySubscriptionService.java b/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetrySubscriptionService.java index a3771988cf..df1421798e 100644 --- a/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetrySubscriptionService.java +++ b/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetrySubscriptionService.java @@ -140,6 +140,37 @@ public class DefaultTelemetrySubscriptionService extends AbstractSubscriptionSer } } + @Override + public void saveWithoutLatestAndNotify(TenantId tenantId, CustomerId customerId, EntityId entityId, List ts, long ttl, FutureCallback callback) { + checkInternalEntity(entityId); + boolean sysTenant = TenantId.SYS_TENANT_ID.equals(tenantId) || tenantId == null; + if (sysTenant || apiUsageStateService.getApiUsageState(tenantId).isDbStorageEnabled()) { + saveWithoutLatestAndNotifyInternal(tenantId, entityId, ts, ttl, new FutureCallback() { + @Override + public void onSuccess(Integer result) { + if (!sysTenant && result != null && result > 0) { + apiUsageClient.report(tenantId, customerId, ApiUsageRecordKey.STORAGE_DP_COUNT, result); + } + callback.onSuccess(null); + } + + @Override + public void onFailure(Throwable t) { + callback.onFailure(t); + } + }); + } else { + callback.onFailure(new RuntimeException("DB storage writes are disabled due to API limits!")); + } + } + + private void saveWithoutLatestAndNotifyInternal(TenantId tenantId, EntityId entityId, List ts, long ttl, FutureCallback callback) { + ListenableFuture saveFuture = tsService.saveWithoutLatest(tenantId, entityId, ts, ttl); + addMainCallback(saveFuture, callback); + addWsCallback(saveFuture, success -> onTimeSeriesUpdate(tenantId, entityId, ts)); + // TODO: 12/11/2021 do we need entityView searching here? + } + @Override public void saveAndNotifyInternal(TenantId tenantId, EntityId entityId, List ts, FutureCallback callback) { saveAndNotifyInternal(tenantId, entityId, ts, 0L, callback); diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/timeseries/TimeseriesService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/timeseries/TimeseriesService.java index b1a2541fc7..4418a826f3 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/timeseries/TimeseriesService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/timeseries/TimeseriesService.java @@ -41,6 +41,8 @@ public interface TimeseriesService { ListenableFuture save(TenantId tenantId, EntityId entityId, List tsKvEntry, long ttl); + ListenableFuture saveWithoutLatest(TenantId tenantId, EntityId entityId, List tsKvEntry, long ttl); + ListenableFuture> saveLatest(TenantId tenantId, EntityId entityId, List tsKvEntry); ListenableFuture> remove(TenantId tenantId, EntityId entityId, List queries); diff --git a/dao/src/main/java/org/thingsboard/server/dao/timeseries/BaseTimeseriesService.java b/dao/src/main/java/org/thingsboard/server/dao/timeseries/BaseTimeseriesService.java index 3170f6c256..48cced688a 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/timeseries/BaseTimeseriesService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/timeseries/BaseTimeseriesService.java @@ -56,6 +56,7 @@ import static org.apache.commons.lang3.StringUtils.isBlank; public class BaseTimeseriesService implements TimeseriesService { private static final int INSERTS_PER_ENTRY = 3; + private static final int INSERTS_PER_ENTRY_WITHOUT_LATEST = 2; private static final int DELETES_PER_ENTRY = INSERTS_PER_ENTRY; public static final Function, Integer> SUM_ALL_INTEGERS = new Function, Integer>() { @Override @@ -154,6 +155,18 @@ public class BaseTimeseriesService implements TimeseriesService { return Futures.transform(Futures.allAsList(futures), SUM_ALL_INTEGERS, MoreExecutors.directExecutor()); } + @Override + public ListenableFuture saveWithoutLatest(TenantId tenantId, EntityId entityId, List tsKvEntries, long ttl) { + List> futures = Lists.newArrayListWithExpectedSize(tsKvEntries.size() * INSERTS_PER_ENTRY_WITHOUT_LATEST); + for (TsKvEntry tsKvEntry : tsKvEntries) { + if (tsKvEntry == null) { + throw new IncorrectParameterException("Key value entry can't be null"); + } + saveWithoutLatestAndRegisterFutures(tenantId, futures, entityId, tsKvEntry, ttl); + } + return Futures.transform(Futures.allAsList(futures), SUM_ALL_INTEGERS, MoreExecutors.directExecutor()); + } + @Override public ListenableFuture> saveLatest(TenantId tenantId, EntityId entityId, List tsKvEntries) { List> futures = Lists.newArrayListWithExpectedSize(tsKvEntries.size()); @@ -175,6 +188,14 @@ public class BaseTimeseriesService implements TimeseriesService { futures.add(timeseriesDao.save(tenantId, entityId, tsKvEntry, ttl)); } + private void saveWithoutLatestAndRegisterFutures(TenantId tenantId, List> futures, EntityId entityId, TsKvEntry tsKvEntry, long ttl) { + if (entityId.getEntityType().equals(EntityType.ENTITY_VIEW)) { + throw new IncorrectParameterException("Telemetry data can't be stored for entity view. Read only"); + } + futures.add(timeseriesDao.savePartition(tenantId, entityId, tsKvEntry.getTs(), tsKvEntry.getKey())); + futures.add(timeseriesDao.save(tenantId, entityId, tsKvEntry, ttl)); + } + private List updateQueriesForEntityView(EntityView entityView, List queries) { return queries.stream().map(query -> { long startTs; diff --git a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/RuleEngineTelemetryService.java b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/RuleEngineTelemetryService.java index e641c83144..b2fd7d2a97 100644 --- a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/RuleEngineTelemetryService.java +++ b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/RuleEngineTelemetryService.java @@ -34,6 +34,8 @@ public interface RuleEngineTelemetryService { void saveAndNotify(TenantId tenantId, CustomerId id, EntityId entityId, List ts, long ttl, FutureCallback callback); + void saveWithoutLatestAndNotify(TenantId tenantId, CustomerId id, EntityId entityId, List ts, long ttl, FutureCallback callback); + void saveAndNotify(TenantId tenantId, EntityId entityId, String scope, List attributes, FutureCallback callback); void saveAndNotify(TenantId tenantId, EntityId entityId, String scope, List attributes, boolean notifyDevice, FutureCallback callback); diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbMsgTimeseriesNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbMsgTimeseriesNode.java index c99a575cc3..dfc078b86a 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbMsgTimeseriesNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbMsgTimeseriesNode.java @@ -48,7 +48,7 @@ import java.util.concurrent.TimeUnit; nodeDescription = "Saves timeseries data", nodeDetails = "Saves timeseries telemetry data based on configurable TTL parameter. Expects messages with 'POST_TELEMETRY_REQUEST' message type", uiResources = {"static/rulenode/rulenode-core-config.js"}, - configDirective = "tbActionNodeTimeseriesConfig", + configDirective = "tbActionNodeCustomTimeseriesConfig", icon = "file_upload" ) public class TbMsgTimeseriesNode implements TbNode { @@ -94,7 +94,11 @@ public class TbMsgTimeseriesNode implements TbNode { if (ttl == 0L) { ttl = tenantProfileDefaultStorageTtl; } - ctx.getTelemetryService().saveAndNotify(ctx.getTenantId(), msg.getCustomerId(), msg.getOriginator(), tsKvEntryList, ttl, new TelemetryNodeCallback(ctx, msg)); + if (config.isSkipLatestPersistence()) { + ctx.getTelemetryService().saveWithoutLatestAndNotify(ctx.getTenantId(), msg.getCustomerId(), msg.getOriginator(), tsKvEntryList, ttl, new TelemetryNodeCallback(ctx, msg)); + } else { + ctx.getTelemetryService().saveAndNotify(ctx.getTenantId(), msg.getCustomerId(), msg.getOriginator(), tsKvEntryList, ttl, new TelemetryNodeCallback(ctx, msg)); + } } public static long getTs(TbMsg msg) { diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbMsgTimeseriesNodeConfiguration.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbMsgTimeseriesNodeConfiguration.java index fb63fbdbde..bb661df905 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbMsgTimeseriesNodeConfiguration.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbMsgTimeseriesNodeConfiguration.java @@ -22,11 +22,13 @@ import org.thingsboard.rule.engine.api.NodeConfiguration; public class TbMsgTimeseriesNodeConfiguration implements NodeConfiguration { private long defaultTTL; + private boolean skipLatestPersistence; @Override public TbMsgTimeseriesNodeConfiguration defaultConfiguration() { TbMsgTimeseriesNodeConfiguration configuration = new TbMsgTimeseriesNodeConfiguration(); configuration.setDefaultTTL(0L); + configuration.setSkipLatestPersistence(false); return configuration; } } From fbdbea7f598899d2da21975712f7a0df183ea956 Mon Sep 17 00:00:00 2001 From: Dima Landiak Date: Fri, 12 Nov 2021 14:09:39 +0200 Subject: [PATCH 115/432] refactoring --- .../DefaultTelemetrySubscriptionService.java | 77 +++++++++---------- .../dao/timeseries/BaseTimeseriesService.java | 32 ++++---- .../engine/telemetry/TbMsgTimeseriesNode.java | 9 ++- 3 files changed, 59 insertions(+), 59 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetrySubscriptionService.java b/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetrySubscriptionService.java index df1421798e..232f8bfd00 100644 --- a/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetrySubscriptionService.java +++ b/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetrySubscriptionService.java @@ -20,8 +20,10 @@ import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.MoreExecutors; import lombok.extern.slf4j.Slf4j; +import org.jetbrains.annotations.NotNull; import org.springframework.stereotype.Service; import org.thingsboard.common.util.ThingsBoardThreadFactory; +import org.thingsboard.server.cluster.TbClusterService; import org.thingsboard.server.common.data.ApiUsageRecordKey; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.EntityView; @@ -45,7 +47,6 @@ import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.queue.discovery.PartitionService; import org.thingsboard.server.queue.usagestats.TbApiUsageClient; import org.thingsboard.server.service.apiusage.TbApiUsageStateService; -import org.thingsboard.server.cluster.TbClusterService; import org.thingsboard.server.service.subscription.TbSubscriptionUtils; import javax.annotation.Nullable; @@ -118,57 +119,44 @@ public class DefaultTelemetrySubscriptionService extends AbstractSubscriptionSer @Override public void saveAndNotify(TenantId tenantId, CustomerId customerId, EntityId entityId, List ts, long ttl, FutureCallback callback) { - checkInternalEntity(entityId); - boolean sysTenant = TenantId.SYS_TENANT_ID.equals(tenantId) || tenantId == null; - if (sysTenant || apiUsageStateService.getApiUsageState(tenantId).isDbStorageEnabled()) { - saveAndNotifyInternal(tenantId, entityId, ts, ttl, new FutureCallback() { - @Override - public void onSuccess(Integer result) { - if (!sysTenant && result != null && result > 0) { - apiUsageClient.report(tenantId, customerId, ApiUsageRecordKey.STORAGE_DP_COUNT, result); - } - callback.onSuccess(null); - } - - @Override - public void onFailure(Throwable t) { - callback.onFailure(t); - } - }); - } else { - callback.onFailure(new RuntimeException("DB storage writes are disabled due to API limits!")); - } + doSaveAndNotify(tenantId, customerId, entityId, ts, ttl, callback, true); } @Override public void saveWithoutLatestAndNotify(TenantId tenantId, CustomerId customerId, EntityId entityId, List ts, long ttl, FutureCallback callback) { + doSaveAndNotify(tenantId, customerId, entityId, ts, ttl, callback, false); + } + + private void doSaveAndNotify(TenantId tenantId, CustomerId customerId, EntityId entityId, List ts, long ttl, FutureCallback callback, boolean saveLatest) { checkInternalEntity(entityId); boolean sysTenant = TenantId.SYS_TENANT_ID.equals(tenantId) || tenantId == null; if (sysTenant || apiUsageStateService.getApiUsageState(tenantId).isDbStorageEnabled()) { - saveWithoutLatestAndNotifyInternal(tenantId, entityId, ts, ttl, new FutureCallback() { - @Override - public void onSuccess(Integer result) { - if (!sysTenant && result != null && result > 0) { - apiUsageClient.report(tenantId, customerId, ApiUsageRecordKey.STORAGE_DP_COUNT, result); - } - callback.onSuccess(null); - } - - @Override - public void onFailure(Throwable t) { - callback.onFailure(t); - } - }); + if (saveLatest) { + saveAndNotifyInternal(tenantId, entityId, ts, ttl, getCallback(tenantId, customerId, sysTenant, callback)); + } else { + saveWithoutLatestAndNotifyInternal(tenantId, entityId, ts, ttl, getCallback(tenantId, customerId, sysTenant, callback)); + } } else { callback.onFailure(new RuntimeException("DB storage writes are disabled due to API limits!")); } } - private void saveWithoutLatestAndNotifyInternal(TenantId tenantId, EntityId entityId, List ts, long ttl, FutureCallback callback) { - ListenableFuture saveFuture = tsService.saveWithoutLatest(tenantId, entityId, ts, ttl); - addMainCallback(saveFuture, callback); - addWsCallback(saveFuture, success -> onTimeSeriesUpdate(tenantId, entityId, ts)); - // TODO: 12/11/2021 do we need entityView searching here? + @NotNull + private FutureCallback getCallback(TenantId tenantId, CustomerId customerId, boolean sysTenant, FutureCallback callback) { + return new FutureCallback<>() { + @Override + public void onSuccess(Integer result) { + if (!sysTenant && result != null && result > 0) { + apiUsageClient.report(tenantId, customerId, ApiUsageRecordKey.STORAGE_DP_COUNT, result); + } + callback.onSuccess(null); + } + + @Override + public void onFailure(Throwable t) { + callback.onFailure(t); + } + }; } @Override @@ -179,6 +167,15 @@ public class DefaultTelemetrySubscriptionService extends AbstractSubscriptionSer @Override public void saveAndNotifyInternal(TenantId tenantId, EntityId entityId, List ts, long ttl, FutureCallback callback) { ListenableFuture saveFuture = tsService.save(tenantId, entityId, ts, ttl); + addCallbacks(tenantId, entityId, ts, callback, saveFuture); + } + + private void saveWithoutLatestAndNotifyInternal(TenantId tenantId, EntityId entityId, List ts, long ttl, FutureCallback callback) { + ListenableFuture saveFuture = tsService.saveWithoutLatest(tenantId, entityId, ts, ttl); + addCallbacks(tenantId, entityId, ts, callback, saveFuture); + } + + private void addCallbacks(TenantId tenantId, EntityId entityId, List ts, FutureCallback callback, ListenableFuture saveFuture) { addMainCallback(saveFuture, callback); addWsCallback(saveFuture, success -> onTimeSeriesUpdate(tenantId, entityId, ts)); if (EntityType.DEVICE.equals(entityId.getEntityType()) || EntityType.ASSET.equals(entityId.getEntityType())) { diff --git a/dao/src/main/java/org/thingsboard/server/dao/timeseries/BaseTimeseriesService.java b/dao/src/main/java/org/thingsboard/server/dao/timeseries/BaseTimeseriesService.java index 48cced688a..da3fe05024 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/timeseries/BaseTimeseriesService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/timeseries/BaseTimeseriesService.java @@ -145,24 +145,26 @@ public class BaseTimeseriesService implements TimeseriesService { @Override public ListenableFuture save(TenantId tenantId, EntityId entityId, List tsKvEntries, long ttl) { - List> futures = Lists.newArrayListWithExpectedSize(tsKvEntries.size() * INSERTS_PER_ENTRY); - for (TsKvEntry tsKvEntry : tsKvEntries) { - if (tsKvEntry == null) { - throw new IncorrectParameterException("Key value entry can't be null"); - } - saveAndRegisterFutures(tenantId, futures, entityId, tsKvEntry, ttl); - } - return Futures.transform(Futures.allAsList(futures), SUM_ALL_INTEGERS, MoreExecutors.directExecutor()); + return doSave(tenantId, entityId, tsKvEntries, ttl, true); } @Override public ListenableFuture saveWithoutLatest(TenantId tenantId, EntityId entityId, List tsKvEntries, long ttl) { - List> futures = Lists.newArrayListWithExpectedSize(tsKvEntries.size() * INSERTS_PER_ENTRY_WITHOUT_LATEST); + return doSave(tenantId, entityId, tsKvEntries, ttl, false); + } + + private ListenableFuture doSave(TenantId tenantId, EntityId entityId, List tsKvEntries, long ttl, boolean saveLatest) { + int inserts = saveLatest ? INSERTS_PER_ENTRY : INSERTS_PER_ENTRY_WITHOUT_LATEST; + List> futures = Lists.newArrayListWithExpectedSize(tsKvEntries.size() * inserts); for (TsKvEntry tsKvEntry : tsKvEntries) { if (tsKvEntry == null) { throw new IncorrectParameterException("Key value entry can't be null"); } - saveWithoutLatestAndRegisterFutures(tenantId, futures, entityId, tsKvEntry, ttl); + if (saveLatest) { + saveAndRegisterFutures(tenantId, futures, entityId, tsKvEntry, ttl); + } else { + saveWithoutLatestAndRegisterFutures(tenantId, futures, entityId, tsKvEntry, ttl); + } } return Futures.transform(Futures.allAsList(futures), SUM_ALL_INTEGERS, MoreExecutors.directExecutor()); } @@ -180,15 +182,15 @@ public class BaseTimeseriesService implements TimeseriesService { } private void saveAndRegisterFutures(TenantId tenantId, List> futures, EntityId entityId, TsKvEntry tsKvEntry, long ttl) { - if (entityId.getEntityType().equals(EntityType.ENTITY_VIEW)) { - throw new IncorrectParameterException("Telemetry data can't be stored for entity view. Read only"); - } - futures.add(timeseriesDao.savePartition(tenantId, entityId, tsKvEntry.getTs(), tsKvEntry.getKey())); + doSaveAndRegisterFuturesFor(tenantId, futures, entityId, tsKvEntry, ttl); futures.add(Futures.transform(timeseriesLatestDao.saveLatest(tenantId, entityId, tsKvEntry), v -> 0, MoreExecutors.directExecutor())); - futures.add(timeseriesDao.save(tenantId, entityId, tsKvEntry, ttl)); } private void saveWithoutLatestAndRegisterFutures(TenantId tenantId, List> futures, EntityId entityId, TsKvEntry tsKvEntry, long ttl) { + doSaveAndRegisterFuturesFor(tenantId, futures, entityId, tsKvEntry, ttl); + } + + private void doSaveAndRegisterFuturesFor(TenantId tenantId, List> futures, EntityId entityId, TsKvEntry tsKvEntry, long ttl) { if (entityId.getEntityType().equals(EntityType.ENTITY_VIEW)) { throw new IncorrectParameterException("Telemetry data can't be stored for entity view. Read only"); } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbMsgTimeseriesNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbMsgTimeseriesNode.java index dfc078b86a..c5f978841a 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbMsgTimeseriesNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbMsgTimeseriesNode.java @@ -23,9 +23,8 @@ import org.thingsboard.rule.engine.api.TbContext; import org.thingsboard.rule.engine.api.TbNode; import org.thingsboard.rule.engine.api.TbNodeConfiguration; import org.thingsboard.rule.engine.api.TbNodeException; -import org.thingsboard.server.common.data.TenantProfile; import org.thingsboard.rule.engine.api.util.TbNodeUtils; -import org.thingsboard.server.common.data.id.CustomerId; +import org.thingsboard.server.common.data.TenantProfile; import org.thingsboard.server.common.data.kv.BasicTsKvEntry; import org.thingsboard.server.common.data.kv.KvEntry; import org.thingsboard.server.common.data.kv.TsKvEntry; @@ -46,7 +45,9 @@ import java.util.concurrent.TimeUnit; name = "save timeseries", configClazz = TbMsgTimeseriesNodeConfiguration.class, nodeDescription = "Saves timeseries data", - nodeDetails = "Saves timeseries telemetry data based on configurable TTL parameter. Expects messages with 'POST_TELEMETRY_REQUEST' message type", + nodeDetails = "Saves timeseries telemetry data based on configurable TTL parameter. Expects messages with 'POST_TELEMETRY_REQUEST' message type. " + + "Timestamp in milliseconds will be taken from metadata.ts, otherwise 'now' timestamp will be applied. " + + "Allows stopping updating values for incoming keys in the latest ts_kv table if 'skipLatestPersistence' is set to true.", uiResources = {"static/rulenode/rulenode-core-config.js"}, configDirective = "tbActionNodeCustomTimeseriesConfig", icon = "file_upload" @@ -107,7 +108,7 @@ public class TbMsgTimeseriesNode implements TbNode { if (!StringUtils.isEmpty(tsStr)) { try { ts = Long.parseLong(tsStr); - } catch (NumberFormatException e) { + } catch (NumberFormatException ignored) { } } else { ts = msg.getTs(); From 916b32264cbf781c8e51669864810afcd0d7207d Mon Sep 17 00:00:00 2001 From: Dima Landiak Date: Fri, 12 Nov 2021 14:36:27 +0200 Subject: [PATCH 116/432] added test --- .../timeseries/BaseTimeseriesServiceTest.java | 27 ++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/timeseries/BaseTimeseriesServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/timeseries/BaseTimeseriesServiceTest.java index b7872fc239..c92c9f809a 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/timeseries/BaseTimeseriesServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/timeseries/BaseTimeseriesServiceTest.java @@ -17,7 +17,10 @@ package org.thingsboard.server.dao.service.timeseries; import com.datastax.oss.driver.api.core.uuid.Uuids; import lombok.extern.slf4j.Slf4j; -import org.junit.*; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; import org.thingsboard.server.common.data.EntityView; import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.id.DeviceId; @@ -139,6 +142,19 @@ public abstract class BaseTimeseriesServiceTest extends AbstractServiceTest { Assert.assertEquals(toTsEntry(TS, stringKvEntry), entries.get(0)); } + @Test + public void testFindLatestWithoutLatestUpdate() throws Exception { + DeviceId deviceId = new DeviceId(Uuids.timeBased()); + + saveEntries(deviceId, TS - 2); + saveEntries(deviceId, TS - 1); + saveEntriesWithoutLatest(deviceId, TS); + + List entries = tsService.findLatest(tenantId, deviceId, Collections.singleton(STRING_KEY)).get(); + Assert.assertEquals(1, entries.size()); + Assert.assertEquals(toTsEntry(TS - 1, stringKvEntry), entries.get(0)); + } + @Test public void testFindByQueryAscOrder() throws Exception { DeviceId deviceId = new DeviceId(Uuids.timeBased()); @@ -479,6 +495,15 @@ public abstract class BaseTimeseriesServiceTest extends AbstractServiceTest { tsService.save(tenantId, deviceId, toTsEntry(ts, booleanKvEntry)).get(); } + private void saveEntriesWithoutLatest(DeviceId deviceId, long ts) throws ExecutionException, InterruptedException { + TsKvEntry entry1 = toTsEntry(ts, stringKvEntry); + TsKvEntry entry2 = toTsEntry(ts, longKvEntry); + TsKvEntry entry3 = toTsEntry(ts, doubleKvEntry); + TsKvEntry entry4 = toTsEntry(ts, booleanKvEntry); + List entries = new ArrayList<>(Arrays.asList(entry1, entry2, entry3, entry4)); + tsService.saveWithoutLatest(tenantId, deviceId, entries, 0).get(); + } + private static TsKvEntry toTsEntry(long ts, KvEntry entry) { return new BasicTsKvEntry(ts, entry); } From 4dc2b6ca01b41b23e4a3491b1224d37adb85889d Mon Sep 17 00:00:00 2001 From: Dima Landiak Date: Fri, 12 Nov 2021 14:45:07 +0200 Subject: [PATCH 117/432] test improved --- .../timeseries/BaseTimeseriesServiceTest.java | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/timeseries/BaseTimeseriesServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/timeseries/BaseTimeseriesServiceTest.java index c92c9f809a..40589abbde 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/timeseries/BaseTimeseriesServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/timeseries/BaseTimeseriesServiceTest.java @@ -45,6 +45,8 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; @@ -55,6 +57,7 @@ import static org.junit.Assert.assertNotNull; @Slf4j public abstract class BaseTimeseriesServiceTest extends AbstractServiceTest { + static final int MAX_TIMEOUT = 30; private static final String STRING_KEY = "stringKey"; private static final String LONG_KEY = "longKey"; @@ -495,13 +498,13 @@ public abstract class BaseTimeseriesServiceTest extends AbstractServiceTest { tsService.save(tenantId, deviceId, toTsEntry(ts, booleanKvEntry)).get(); } - private void saveEntriesWithoutLatest(DeviceId deviceId, long ts) throws ExecutionException, InterruptedException { - TsKvEntry entry1 = toTsEntry(ts, stringKvEntry); - TsKvEntry entry2 = toTsEntry(ts, longKvEntry); - TsKvEntry entry3 = toTsEntry(ts, doubleKvEntry); - TsKvEntry entry4 = toTsEntry(ts, booleanKvEntry); - List entries = new ArrayList<>(Arrays.asList(entry1, entry2, entry3, entry4)); - tsService.saveWithoutLatest(tenantId, deviceId, entries, 0).get(); + private void saveEntriesWithoutLatest(DeviceId deviceId, long ts) throws ExecutionException, InterruptedException, TimeoutException { + List tsKvEntry = List.of( + toTsEntry(ts, stringKvEntry), + toTsEntry(ts, longKvEntry), + toTsEntry(ts, doubleKvEntry), + toTsEntry(ts, booleanKvEntry)); + tsService.saveWithoutLatest(tenantId, deviceId, tsKvEntry, 0).get(MAX_TIMEOUT, TimeUnit.SECONDS); } private static TsKvEntry toTsEntry(long ts, KvEntry entry) { From 453b1b82ba3bf5867d67d0446bd6bf0cfe2a0cf6 Mon Sep 17 00:00:00 2001 From: Dima Landiak Date: Tue, 16 Nov 2021 19:03:02 +0200 Subject: [PATCH 118/432] added max timeout param to the get calls in tests --- .../timeseries/BaseTimeseriesServiceTest.java | 70 +++++++++---------- 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/timeseries/BaseTimeseriesServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/timeseries/BaseTimeseriesServiceTest.java index 40589abbde..bba679d509 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/timeseries/BaseTimeseriesServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/timeseries/BaseTimeseriesServiceTest.java @@ -99,8 +99,8 @@ public abstract class BaseTimeseriesServiceTest extends AbstractServiceTest { testLatestTsAndVerify(deviceId); } - private void testLatestTsAndVerify(EntityId entityId) throws ExecutionException, InterruptedException { - List tsList = tsService.findAllLatest(tenantId, entityId).get(); + private void testLatestTsAndVerify(EntityId entityId) throws ExecutionException, InterruptedException, TimeoutException { + List tsList = tsService.findAllLatest(tenantId, entityId).get(MAX_TIMEOUT, TimeUnit.SECONDS); assertNotNull(tsList); assertEquals(4, tsList.size()); @@ -140,7 +140,7 @@ public abstract class BaseTimeseriesServiceTest extends AbstractServiceTest { saveEntries(deviceId, TS - 1); saveEntries(deviceId, TS); - List entries = tsService.findLatest(tenantId, deviceId, Collections.singleton(STRING_KEY)).get(); + List entries = tsService.findLatest(tenantId, deviceId, Collections.singleton(STRING_KEY)).get(MAX_TIMEOUT, TimeUnit.SECONDS); Assert.assertEquals(1, entries.size()); Assert.assertEquals(toTsEntry(TS, stringKvEntry), entries.get(0)); } @@ -153,7 +153,7 @@ public abstract class BaseTimeseriesServiceTest extends AbstractServiceTest { saveEntries(deviceId, TS - 1); saveEntriesWithoutLatest(deviceId, TS); - List entries = tsService.findLatest(tenantId, deviceId, Collections.singleton(STRING_KEY)).get(); + List entries = tsService.findLatest(tenantId, deviceId, Collections.singleton(STRING_KEY)).get(MAX_TIMEOUT, TimeUnit.SECONDS); Assert.assertEquals(1, entries.size()); Assert.assertEquals(toTsEntry(TS - 1, stringKvEntry), entries.get(0)); } @@ -169,7 +169,7 @@ public abstract class BaseTimeseriesServiceTest extends AbstractServiceTest { List queries = new ArrayList<>(); queries.add(new BaseReadTsKvQuery(STRING_KEY, TS - 3, TS, 0, 1000, Aggregation.NONE, "ASC")); - List entries = tsService.findAll(tenantId, deviceId, queries).get(); + List entries = tsService.findAll(tenantId, deviceId, queries).get(MAX_TIMEOUT, TimeUnit.SECONDS); Assert.assertEquals(3, entries.size()); Assert.assertEquals(toTsEntry(TS - 3, stringKvEntry), entries.get(0)); Assert.assertEquals(toTsEntry(TS - 2, stringKvEntry), entries.get(1)); @@ -177,7 +177,7 @@ public abstract class BaseTimeseriesServiceTest extends AbstractServiceTest { EntityView entityView = saveAndCreateEntityView(deviceId, Arrays.asList(STRING_KEY)); - entries = tsService.findAll(tenantId, entityView.getId(), queries).get(); + entries = tsService.findAll(tenantId, entityView.getId(), queries).get(MAX_TIMEOUT, TimeUnit.SECONDS); Assert.assertEquals(3, entries.size()); Assert.assertEquals(toTsEntry(TS - 3, stringKvEntry), entries.get(0)); Assert.assertEquals(toTsEntry(TS - 2, stringKvEntry), entries.get(1)); @@ -195,7 +195,7 @@ public abstract class BaseTimeseriesServiceTest extends AbstractServiceTest { List queries = new ArrayList<>(); queries.add(new BaseReadTsKvQuery(STRING_KEY, TS - 3, TS, 0, 1000, Aggregation.NONE, "DESC")); - List entries = tsService.findAll(tenantId, deviceId, queries).get(); + List entries = tsService.findAll(tenantId, deviceId, queries).get(MAX_TIMEOUT, TimeUnit.SECONDS); Assert.assertEquals(3, entries.size()); Assert.assertEquals(toTsEntry(TS - 1, stringKvEntry), entries.get(0)); Assert.assertEquals(toTsEntry(TS - 2, stringKvEntry), entries.get(1)); @@ -203,7 +203,7 @@ public abstract class BaseTimeseriesServiceTest extends AbstractServiceTest { EntityView entityView = saveAndCreateEntityView(deviceId, Arrays.asList(STRING_KEY)); - entries = tsService.findAll(tenantId, entityView.getId(), queries).get(); + entries = tsService.findAll(tenantId, entityView.getId(), queries).get(MAX_TIMEOUT, TimeUnit.SECONDS); Assert.assertEquals(3, entries.size()); Assert.assertEquals(toTsEntry(TS - 1, stringKvEntry), entries.get(0)); Assert.assertEquals(toTsEntry(TS - 2, stringKvEntry), entries.get(1)); @@ -220,13 +220,13 @@ public abstract class BaseTimeseriesServiceTest extends AbstractServiceTest { saveEntries(deviceId, 40000); tsService.remove(tenantId, deviceId, Collections.singletonList( - new BaseDeleteTsKvQuery(STRING_KEY, 25000, 45000, true))).get(); + new BaseDeleteTsKvQuery(STRING_KEY, 25000, 45000, true))).get(MAX_TIMEOUT, TimeUnit.SECONDS); List list = tsService.findAll(tenantId, deviceId, Collections.singletonList( - new BaseReadTsKvQuery(STRING_KEY, 5000, 45000, 10000, 10, Aggregation.NONE))).get(); + new BaseReadTsKvQuery(STRING_KEY, 5000, 45000, 10000, 10, Aggregation.NONE))).get(MAX_TIMEOUT, TimeUnit.SECONDS); Assert.assertEquals(2, list.size()); - List latest = tsService.findLatest(tenantId, deviceId, Collections.singletonList(STRING_KEY)).get(); + List latest = tsService.findLatest(tenantId, deviceId, Collections.singletonList(STRING_KEY)).get(MAX_TIMEOUT, TimeUnit.SECONDS); Assert.assertEquals(20000, latest.get(0).getTs()); } @@ -245,7 +245,7 @@ public abstract class BaseTimeseriesServiceTest extends AbstractServiceTest { entries.add(save(deviceId, 55000, 600)); List list = tsService.findAll(tenantId, deviceId, Collections.singletonList(new BaseReadTsKvQuery(LONG_KEY, 0, - 60000, 20000, 3, Aggregation.NONE))).get(); + 60000, 20000, 3, Aggregation.NONE))).get(MAX_TIMEOUT, TimeUnit.SECONDS); assertEquals(3, list.size()); assertEquals(55000, list.get(0).getTs()); assertEquals(java.util.Optional.of(600L), list.get(0).getLongValue()); @@ -257,7 +257,7 @@ public abstract class BaseTimeseriesServiceTest extends AbstractServiceTest { assertEquals(java.util.Optional.of(400L), list.get(2).getLongValue()); list = tsService.findAll(tenantId, deviceId, Collections.singletonList(new BaseReadTsKvQuery(LONG_KEY, 0, - 60000, 20000, 3, Aggregation.AVG))).get(); + 60000, 20000, 3, Aggregation.AVG))).get(MAX_TIMEOUT, TimeUnit.SECONDS); assertEquals(3, list.size()); assertEquals(10000, list.get(0).getTs()); assertEquals(java.util.Optional.of(150.0), list.get(0).getDoubleValue()); @@ -269,7 +269,7 @@ public abstract class BaseTimeseriesServiceTest extends AbstractServiceTest { assertEquals(java.util.Optional.of(550.0), list.get(2).getDoubleValue()); list = tsService.findAll(tenantId, deviceId, Collections.singletonList(new BaseReadTsKvQuery(LONG_KEY, 0, - 60000, 20000, 3, Aggregation.SUM))).get(); + 60000, 20000, 3, Aggregation.SUM))).get(MAX_TIMEOUT, TimeUnit.SECONDS); assertEquals(3, list.size()); assertEquals(10000, list.get(0).getTs()); @@ -282,7 +282,7 @@ public abstract class BaseTimeseriesServiceTest extends AbstractServiceTest { assertEquals(java.util.Optional.of(1100L), list.get(2).getLongValue()); list = tsService.findAll(tenantId, deviceId, Collections.singletonList(new BaseReadTsKvQuery(LONG_KEY, 0, - 60000, 20000, 3, Aggregation.MIN))).get(); + 60000, 20000, 3, Aggregation.MIN))).get(MAX_TIMEOUT, TimeUnit.SECONDS); assertEquals(3, list.size()); assertEquals(10000, list.get(0).getTs()); @@ -295,7 +295,7 @@ public abstract class BaseTimeseriesServiceTest extends AbstractServiceTest { assertEquals(java.util.Optional.of(500L), list.get(2).getLongValue()); list = tsService.findAll(tenantId, deviceId, Collections.singletonList(new BaseReadTsKvQuery(LONG_KEY, 0, - 60000, 20000, 3, Aggregation.MAX))).get(); + 60000, 20000, 3, Aggregation.MAX))).get(MAX_TIMEOUT, TimeUnit.SECONDS); assertEquals(3, list.size()); assertEquals(10000, list.get(0).getTs()); @@ -308,7 +308,7 @@ public abstract class BaseTimeseriesServiceTest extends AbstractServiceTest { assertEquals(java.util.Optional.of(600L), list.get(2).getLongValue()); list = tsService.findAll(tenantId, deviceId, Collections.singletonList(new BaseReadTsKvQuery(LONG_KEY, 0, - 60000, 20000, 3, Aggregation.COUNT))).get(); + 60000, 20000, 3, Aggregation.COUNT))).get(MAX_TIMEOUT, TimeUnit.SECONDS); assertEquals(3, list.size()); assertEquals(10000, list.get(0).getTs()); @@ -329,7 +329,7 @@ public abstract class BaseTimeseriesServiceTest extends AbstractServiceTest { entries.add(save(deviceId, 115000, "C2")); list = tsService.findAll(tenantId, deviceId, Collections.singletonList(new BaseReadTsKvQuery(LONG_KEY, 60000, - 120000, 20000, 3, Aggregation.NONE))).get(); + 120000, 20000, 3, Aggregation.NONE))).get(MAX_TIMEOUT, TimeUnit.SECONDS); assertEquals(3, list.size()); assertEquals(115000, list.get(0).getTs()); assertEquals(java.util.Optional.of("C2"), list.get(0).getStrValue()); @@ -342,7 +342,7 @@ public abstract class BaseTimeseriesServiceTest extends AbstractServiceTest { list = tsService.findAll(tenantId, deviceId, Collections.singletonList(new BaseReadTsKvQuery(LONG_KEY, 60000, - 120000, 20000, 3, Aggregation.MIN))).get(); + 120000, 20000, 3, Aggregation.MIN))).get(MAX_TIMEOUT, TimeUnit.SECONDS); assertEquals(3, list.size()); assertEquals(70000, list.get(0).getTs()); @@ -355,7 +355,7 @@ public abstract class BaseTimeseriesServiceTest extends AbstractServiceTest { assertEquals(java.util.Optional.of("C1"), list.get(2).getStrValue()); list = tsService.findAll(tenantId, deviceId, Collections.singletonList(new BaseReadTsKvQuery(LONG_KEY, 60000, - 120000, 20000, 3, Aggregation.MAX))).get(); + 120000, 20000, 3, Aggregation.MAX))).get(MAX_TIMEOUT, TimeUnit.SECONDS); assertEquals(3, list.size()); assertEquals(70000, list.get(0).getTs()); @@ -368,7 +368,7 @@ public abstract class BaseTimeseriesServiceTest extends AbstractServiceTest { assertEquals(java.util.Optional.of("C2"), list.get(2).getStrValue()); list = tsService.findAll(tenantId, deviceId, Collections.singletonList(new BaseReadTsKvQuery(LONG_KEY, 60000, - 120000, 20000, 3, Aggregation.COUNT))).get(); + 120000, 20000, 3, Aggregation.COUNT))).get(MAX_TIMEOUT, TimeUnit.SECONDS); assertEquals(3, list.size()); assertEquals(70000, list.get(0).getTs()); @@ -396,7 +396,7 @@ public abstract class BaseTimeseriesServiceTest extends AbstractServiceTest { entries.add(save(deviceId, 55000, 600.0)); List list = tsService.findAll(tenantId, deviceId, Collections.singletonList(new BaseReadTsKvQuery(LONG_KEY, 0, - 60000, 20000, 3, Aggregation.NONE))).get(); + 60000, 20000, 3, Aggregation.NONE))).get(MAX_TIMEOUT, TimeUnit.SECONDS); assertEquals(3, list.size()); assertEquals(55000, list.get(0).getTs()); assertEquals(java.util.Optional.of(600.0), list.get(0).getDoubleValue()); @@ -408,7 +408,7 @@ public abstract class BaseTimeseriesServiceTest extends AbstractServiceTest { assertEquals(java.util.Optional.of(400.0), list.get(2).getDoubleValue()); list = tsService.findAll(tenantId, deviceId, Collections.singletonList(new BaseReadTsKvQuery(LONG_KEY, 0, - 60000, 20000, 3, Aggregation.AVG))).get(); + 60000, 20000, 3, Aggregation.AVG))).get(MAX_TIMEOUT, TimeUnit.SECONDS); assertEquals(3, list.size()); assertEquals(10000, list.get(0).getTs()); assertEquals(java.util.Optional.of(150.0), list.get(0).getDoubleValue()); @@ -420,7 +420,7 @@ public abstract class BaseTimeseriesServiceTest extends AbstractServiceTest { assertEquals(java.util.Optional.of(550.0), list.get(2).getDoubleValue()); list = tsService.findAll(tenantId, deviceId, Collections.singletonList(new BaseReadTsKvQuery(LONG_KEY, 0, - 60000, 20000, 3, Aggregation.SUM))).get(); + 60000, 20000, 3, Aggregation.SUM))).get(MAX_TIMEOUT, TimeUnit.SECONDS); assertEquals(3, list.size()); assertEquals(10000, list.get(0).getTs()); @@ -433,7 +433,7 @@ public abstract class BaseTimeseriesServiceTest extends AbstractServiceTest { assertEquals(java.util.Optional.of(1100.0), list.get(2).getDoubleValue()); list = tsService.findAll(tenantId, deviceId, Collections.singletonList(new BaseReadTsKvQuery(LONG_KEY, 0, - 60000, 20000, 3, Aggregation.MIN))).get(); + 60000, 20000, 3, Aggregation.MIN))).get(MAX_TIMEOUT, TimeUnit.SECONDS); assertEquals(3, list.size()); assertEquals(10000, list.get(0).getTs()); @@ -446,7 +446,7 @@ public abstract class BaseTimeseriesServiceTest extends AbstractServiceTest { assertEquals(java.util.Optional.of(500.0), list.get(2).getDoubleValue()); list = tsService.findAll(tenantId, deviceId, Collections.singletonList(new BaseReadTsKvQuery(LONG_KEY, 0, - 60000, 20000, 3, Aggregation.MAX))).get(); + 60000, 20000, 3, Aggregation.MAX))).get(MAX_TIMEOUT, TimeUnit.SECONDS); assertEquals(3, list.size()); assertEquals(10000, list.get(0).getTs()); @@ -459,7 +459,7 @@ public abstract class BaseTimeseriesServiceTest extends AbstractServiceTest { assertEquals(java.util.Optional.of(600.0), list.get(2).getDoubleValue()); list = tsService.findAll(tenantId, deviceId, Collections.singletonList(new BaseReadTsKvQuery(LONG_KEY, 0, - 60000, 20000, 3, Aggregation.COUNT))).get(); + 60000, 20000, 3, Aggregation.COUNT))).get(MAX_TIMEOUT, TimeUnit.SECONDS); assertEquals(3, list.size()); assertEquals(10000, list.get(0).getTs()); @@ -474,28 +474,28 @@ public abstract class BaseTimeseriesServiceTest extends AbstractServiceTest { private TsKvEntry save(DeviceId deviceId, long ts, long value) throws Exception { TsKvEntry entry = new BasicTsKvEntry(ts, new LongDataEntry(LONG_KEY, value)); - tsService.save(tenantId, deviceId, entry).get(); + tsService.save(tenantId, deviceId, entry).get(MAX_TIMEOUT, TimeUnit.SECONDS); return entry; } private TsKvEntry save(DeviceId deviceId, long ts, double value) throws Exception { TsKvEntry entry = new BasicTsKvEntry(ts, new DoubleDataEntry(LONG_KEY, value)); - tsService.save(tenantId, deviceId, entry).get(); + tsService.save(tenantId, deviceId, entry).get(MAX_TIMEOUT, TimeUnit.SECONDS); return entry; } private TsKvEntry save(DeviceId deviceId, long ts, String value) throws Exception { TsKvEntry entry = new BasicTsKvEntry(ts, new StringDataEntry(LONG_KEY, value)); - tsService.save(tenantId, deviceId, entry).get(); + tsService.save(tenantId, deviceId, entry).get(MAX_TIMEOUT, TimeUnit.SECONDS); return entry; } - private void saveEntries(DeviceId deviceId, long ts) throws ExecutionException, InterruptedException { - tsService.save(tenantId, deviceId, toTsEntry(ts, stringKvEntry)).get(); - tsService.save(tenantId, deviceId, toTsEntry(ts, longKvEntry)).get(); - tsService.save(tenantId, deviceId, toTsEntry(ts, doubleKvEntry)).get(); - tsService.save(tenantId, deviceId, toTsEntry(ts, booleanKvEntry)).get(); + private void saveEntries(DeviceId deviceId, long ts) throws ExecutionException, InterruptedException, TimeoutException { + tsService.save(tenantId, deviceId, toTsEntry(ts, stringKvEntry)).get(MAX_TIMEOUT, TimeUnit.SECONDS); + tsService.save(tenantId, deviceId, toTsEntry(ts, longKvEntry)).get(MAX_TIMEOUT, TimeUnit.SECONDS); + tsService.save(tenantId, deviceId, toTsEntry(ts, doubleKvEntry)).get(MAX_TIMEOUT, TimeUnit.SECONDS); + tsService.save(tenantId, deviceId, toTsEntry(ts, booleanKvEntry)).get(MAX_TIMEOUT, TimeUnit.SECONDS); } private void saveEntriesWithoutLatest(DeviceId deviceId, long ts) throws ExecutionException, InterruptedException, TimeoutException { From 11f0916b342852651fe5eee10e23641236a3e941 Mon Sep 17 00:00:00 2001 From: Dima Landiak Date: Wed, 17 Nov 2021 09:45:49 +0200 Subject: [PATCH 119/432] revert the configDirective for timeseries node --- .../thingsboard/rule/engine/telemetry/TbMsgTimeseriesNode.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbMsgTimeseriesNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbMsgTimeseriesNode.java index c5f978841a..1d52b7cdfa 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbMsgTimeseriesNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbMsgTimeseriesNode.java @@ -49,7 +49,7 @@ import java.util.concurrent.TimeUnit; "Timestamp in milliseconds will be taken from metadata.ts, otherwise 'now' timestamp will be applied. " + "Allows stopping updating values for incoming keys in the latest ts_kv table if 'skipLatestPersistence' is set to true.", uiResources = {"static/rulenode/rulenode-core-config.js"}, - configDirective = "tbActionNodeCustomTimeseriesConfig", + configDirective = "tbActionNodeTimeseriesConfig", icon = "file_upload" ) public class TbMsgTimeseriesNode implements TbNode { From 52578645b86fb9591bf8bf461c4c36b27731fe34 Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Wed, 17 Nov 2021 12:13:05 +0200 Subject: [PATCH 120/432] added ability to configure network configuration for lwm2m --- application/src/main/resources/thingsboard.yml | 3 +++ .../thingsboard/server/common/data/TbProperty.java} | 4 ++-- .../server/queue/kafka/TbKafkaSettings.java | 5 +++-- .../lwm2m/config/LwM2MTransportServerConfig.java | 11 +++++++---- .../transport/lwm2m/server/LwM2mNetworkConfig.java | 9 +++++++-- .../lwm2m/src/main/resources/tb-lwm2m-transport.yml | 3 +++ 6 files changed, 25 insertions(+), 10 deletions(-) rename common/{queue/src/main/java/org/thingsboard/server/queue/kafka/TbKafkaProperty.java => data/src/main/java/org/thingsboard/server/common/data/TbProperty.java} (90%) diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index 85394e67a8..1273555176 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -819,6 +819,9 @@ transport: log_max_length: "${LWM2M_LOG_MAX_LENGTH:1024}" # Use redis for Security and Registration stores redis.enabled: "${LWM2M_REDIS_ENABLED:false}" + network_config: + - key: "PROTOCOL_STAGE_THREAD_COUNT" + value: "${LWM2M_PROTOCOL_STAGE_THREAD_COUNT:12}" snmp: enabled: "${SNMP_ENABLED:true}" response_processing: diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/kafka/TbKafkaProperty.java b/common/data/src/main/java/org/thingsboard/server/common/data/TbProperty.java similarity index 90% rename from common/queue/src/main/java/org/thingsboard/server/queue/kafka/TbKafkaProperty.java rename to common/data/src/main/java/org/thingsboard/server/common/data/TbProperty.java index 993142850d..4824915521 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/kafka/TbKafkaProperty.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/TbProperty.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.queue.kafka; +package org.thingsboard.server.common.data; import lombok.Data; @@ -21,7 +21,7 @@ import lombok.Data; * Created by ashvayka on 25.09.18. */ @Data -public class TbKafkaProperty { +public class TbProperty { private String key; private String value; diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/kafka/TbKafkaSettings.java b/common/queue/src/main/java/org/thingsboard/server/queue/kafka/TbKafkaSettings.java index 5dd7c40ba8..0dbb2401b3 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/kafka/TbKafkaSettings.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/kafka/TbKafkaSettings.java @@ -30,6 +30,7 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Component; +import org.thingsboard.server.common.data.TbProperty; import java.util.Collections; import java.util.List; @@ -104,10 +105,10 @@ public class TbKafkaSettings { private String securityProtocol; @Setter - private List other; + private List other; @Setter - private Map> consumerPropertiesPerTopic = Collections.emptyMap(); + private Map> consumerPropertiesPerTopic = Collections.emptyMap(); public Properties toAdminProps() { Properties props = toProps(); diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/config/LwM2MTransportServerConfig.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/config/LwM2MTransportServerConfig.java index f444b74c2b..e5ef613495 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/config/LwM2MTransportServerConfig.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/config/LwM2MTransportServerConfig.java @@ -25,17 +25,16 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Component; -import org.thingsboard.server.common.data.ResourceUtils; +import org.thingsboard.server.common.data.TbProperty; import org.thingsboard.server.common.transport.config.ssl.SslCredentials; import org.thingsboard.server.common.transport.config.ssl.SslCredentialsConfig; -import javax.annotation.PostConstruct; -import java.io.InputStream; -import java.security.KeyStore; +import java.util.List; @Slf4j @Component @ConditionalOnExpression("('${service.type:null}'=='tb-transport' && '${transport.lwm2m.enabled:false}'=='true') || '${service.type:null}'=='monolith' || '${service.type:null}'=='tb-core'") +@ConfigurationProperties(prefix = "transport.lwm2m") public class LwM2MTransportServerConfig implements LwM2MSecureServerConfig { @Getter @@ -102,6 +101,10 @@ public class LwM2MTransportServerConfig implements LwM2MSecureServerConfig { @Value("${transport.lwm2m.paging_transmission_window:10000}") private long pagingTransmissionWindow; + @Getter + @Setter + private List networkConfig; + @Bean @ConfigurationProperties(prefix = "transport.lwm2m.server.security.credentials") public SslCredentialsConfig lwm2mServerCredentials() { diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mNetworkConfig.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mNetworkConfig.java index 4fc60aecfc..2b488a3ab9 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mNetworkConfig.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mNetworkConfig.java @@ -17,6 +17,7 @@ package org.thingsboard.server.transport.lwm2m.server; import org.eclipse.californium.core.network.config.NetworkConfig; import org.eclipse.californium.core.network.config.NetworkConfigDefaults; +import org.springframework.util.CollectionUtils; import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; import static org.eclipse.californium.core.network.config.NetworkConfigDefaults.DEFAULT_BLOCKWISE_STATUS_LIFETIME; @@ -25,8 +26,8 @@ public class LwM2mNetworkConfig { public static NetworkConfig getCoapConfig(Integer serverPortNoSec, Integer serverSecurePort, LwM2MTransportServerConfig config) { NetworkConfig coapConfig = new NetworkConfig(); - coapConfig.setInt(NetworkConfig.Keys.COAP_PORT,serverPortNoSec); - coapConfig.setInt(NetworkConfig.Keys.COAP_SECURE_PORT,serverSecurePort); + coapConfig.setInt(NetworkConfig.Keys.COAP_PORT, serverPortNoSec); + coapConfig.setInt(NetworkConfig.Keys.COAP_SECURE_PORT, serverSecurePort); /** Example:Property for large packet: #NetworkConfig config = new NetworkConfig(); @@ -105,6 +106,10 @@ public class LwM2mNetworkConfig { coapConfig.setInt(NetworkConfig.Keys.MAX_RETRANSMIT, 10); + if (!CollectionUtils.isEmpty(config.getNetworkConfig())) { + config.getNetworkConfig().forEach(p -> coapConfig.setString(p.getKey(), p.getValue())); + } + return coapConfig; } } \ No newline at end of file diff --git a/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml b/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml index 8864b99e8c..34c08029b0 100644 --- a/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml +++ b/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml @@ -204,6 +204,9 @@ transport: paging_transmission_window: "${LWM2M_PAGING_TRANSMISSION_WINDOW:10000}" # Use redis for Security and Registration stores redis.enabled: "${LWM2M_REDIS_ENABLED:false}" + network_config: + - key: "PROTOCOL_STAGE_THREAD_COUNT" + value: "${LWM2M_PROTOCOL_STAGE_THREAD_COUNT:12}" stats: enabled: "${TB_TRANSPORT_STATS_ENABLED:true}" print-interval-ms: "${TB_TRANSPORT_STATS_PRINT_INTERVAL_MS:60000}" From 8d88baceff3d47e43e7822af6d871c7cd8dcc5d6 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Wed, 17 Nov 2021 14:41:47 +0200 Subject: [PATCH 121/432] lwm2m - Bootstrap add factory --- .../transport/coap/CoapTransportResource.java | 1 - .../LwM2mDefaultBootstrapSessionManager.java | 7 ++-- ...LwM2MBootstrapConfigStoreTaskProvider.java | 41 +++++++++++++------ .../ota/DefaultLwM2MOtaUpdateService.java | 4 +- .../device/DeviceCredentialsServiceImpl.java | 4 -- 5 files changed, 34 insertions(+), 23 deletions(-) diff --git a/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/CoapTransportResource.java b/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/CoapTransportResource.java index 78b25c2d42..0aa01246e3 100644 --- a/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/CoapTransportResource.java +++ b/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/CoapTransportResource.java @@ -52,7 +52,6 @@ import java.util.List; import java.util.Optional; import java.util.Random; import java.util.UUID; -import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2mDefaultBootstrapSessionManager.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2mDefaultBootstrapSessionManager.java index 6f13b09f56..07a41c668e 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2mDefaultBootstrapSessionManager.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2mDefaultBootstrapSessionManager.java @@ -16,12 +16,10 @@ package org.thingsboard.server.transport.lwm2m.bootstrap.secure; import lombok.extern.slf4j.Slf4j; -import org.eclipse.leshan.core.request.BootstrapDiscoverRequest; import org.eclipse.leshan.core.request.BootstrapDownlinkRequest; import org.eclipse.leshan.core.request.BootstrapFinishRequest; import org.eclipse.leshan.core.request.BootstrapRequest; import org.eclipse.leshan.core.request.Identity; -import org.eclipse.leshan.core.response.BootstrapDiscoverResponse; import org.eclipse.leshan.core.response.LwM2mResponse; import org.eclipse.leshan.server.bootstrap.BootstrapConfigStore; import org.eclipse.leshan.server.bootstrap.BootstrapFailureCause; @@ -38,8 +36,9 @@ import org.thingsboard.server.common.transport.TransportService; import org.thingsboard.server.transport.lwm2m.bootstrap.store.LwM2MBootstrapConfigStoreTaskProvider; import org.thingsboard.server.transport.lwm2m.bootstrap.store.LwM2MBootstrapSecurityStore; import org.thingsboard.server.transport.lwm2m.server.client.LwM2MAuthException; - -import java.util.*; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.LOG_LWM2M_ERROR; import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.LOG_LWM2M_INFO; diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MBootstrapConfigStoreTaskProvider.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MBootstrapConfigStoreTaskProvider.java index bb84f94c59..74ca2ca92a 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MBootstrapConfigStoreTaskProvider.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MBootstrapConfigStoreTaskProvider.java @@ -32,6 +32,7 @@ import org.eclipse.leshan.server.bootstrap.BootstrapUtil; import java.net.InetSocketAddress; import java.util.*; import java.util.stream.Collectors; +import java.util.stream.Stream; import static org.eclipse.leshan.server.bootstrap.BootstrapUtil.toWriteRequest; @@ -163,7 +164,9 @@ public class LwM2MBootstrapConfigStoreTaskProvider implements BootstrapTaskProvi Map filteredMap = this.serverInstances.entrySet() .stream().filter(x -> !this.securityInstances.containsKey(x.getKey())) .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); - this.bootstrapServerIdOld = filteredMap.keySet().stream().findFirst().get(); + if (filteredMap.size() > 0) { + this.bootstrapServerIdOld = filteredMap.keySet().stream().findFirst().get(); + } } public BootstrapConfigStore getStore() { @@ -187,7 +190,7 @@ public class LwM2MBootstrapConfigStoreTaskProvider implements BootstrapTaskProvi public List> toRequests(BootstrapConfig bootstrapConfig, ContentFormat contentFormat) { List> requests = new ArrayList<>(); - List> requestsDelete = new ArrayList<>(); + Set pathsDelete = new HashSet<>(); List> requestsWrite = new ArrayList<>(); boolean isBsServer = false; boolean isLwServer = false; @@ -209,7 +212,20 @@ public class LwM2MBootstrapConfigStoreTaskProvider implements BootstrapTaskProvi instances.put(security.serverId, id); isLwServer = true; if (!isBsServer && this.securityInstances.containsKey(security.serverId) && id != this.securityInstances.get(security.serverId)) { - requestsDelete.add(new BootstrapDeleteRequest("/0/" + this.securityInstances.get(security.serverId))); + pathsDelete.add("/0/" + this.securityInstances.get(security.serverId)); + } + /** + * If there is an instance in the serverInstances with serverId which we replace in the securityInstances + */ + // find serverId in securityInstances by id (instance) + Integer serverIdOld = null; + for (Map.Entry entry : this.securityInstances.entrySet()) { + if (entry.getValue().equals(id)) { + serverIdOld = entry.getKey(); + } + } + if (!isBsServer && serverIdOld != null && this.serverInstances.containsKey(serverIdOld)) { + pathsDelete.add("/1/" + this.serverInstances.get(serverIdOld)); } id++; } @@ -218,13 +234,14 @@ public class LwM2MBootstrapConfigStoreTaskProvider implements BootstrapTaskProvi for (Map.Entry server : bootstrapConfig.servers.entrySet()) { int securityInstanceId = instances.get(server.getValue().shortId); requestsWrite.add(toWriteRequest(securityInstanceId, server.getValue(), contentFormat)); - if (!isLwServer && this.bootstrapServerIdNew != null && server.getValue().shortId == this.bootstrapServerIdNew && - (this.bootstrapServerIdNew != this.bootstrapServerIdOld || securityInstanceId != this.serverInstances.get(this.bootstrapServerIdOld))) { - requestsDelete.add(new BootstrapDeleteRequest("/1/" + this.serverInstances.get(this.bootstrapServerIdOld))); - - } else { - if (!isBsServer && this.serverInstances.containsKey(server.getValue().shortId) && securityInstanceId != this.serverInstances.get(server.getValue().shortId)) { - requestsDelete.add(new BootstrapDeleteRequest("/1/" + this.serverInstances.get(server.getValue().shortId))); + if (!isBsServer) { + /** Delete instance if bootstrapServerIdNew not equals bootstrapServerIdOld or securityInstanceBsIdNew not equals serverInstanceBsIdOld */ + if (this.bootstrapServerIdNew != null && server.getValue().shortId == this.bootstrapServerIdNew && + (this.bootstrapServerIdNew != this.bootstrapServerIdOld || securityInstanceId != this.serverInstances.get(this.bootstrapServerIdOld))) { + pathsDelete.add("/1/" + this.serverInstances.get(this.bootstrapServerIdOld)); + /** Delete instance if serverIdNew is present in serverInstances and securityInstanceIdOld by serverIdNew not equals serverInstanceIdOld */ + } else if (this.serverInstances.containsKey(server.getValue().shortId) && securityInstanceId != this.serverInstances.get(server.getValue().shortId)) { + pathsDelete.add("/1/" + this.serverInstances.get(server.getValue().shortId)); } } } @@ -236,8 +253,8 @@ public class LwM2MBootstrapConfigStoreTaskProvider implements BootstrapTaskProvi if (isBsServer & isLwServer) { requests.add(new BootstrapDeleteRequest("/0")); requests.add(new BootstrapDeleteRequest("/1")); - } else if (requestsDelete.size() > 0) { - requests.addAll(requestsDelete); + } else { + pathsDelete.forEach(pathDelete -> requests.add(new BootstrapDeleteRequest(pathDelete))); } // handle write if (requestsWrite.size() > 0) { diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/DefaultLwM2MOtaUpdateService.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/DefaultLwM2MOtaUpdateService.java index a368d74ded..050929c470 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/DefaultLwM2MOtaUpdateService.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/DefaultLwM2MOtaUpdateService.java @@ -399,7 +399,7 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl log.debug("[{}] Starting update to [{}{}] using binary", client.getEndpoint(), fwInfo.getTargetName(), fwInfo.getTargetVersion()); startUpdateUsingBinary(client, fwInfo); } - } else { + } else if (fwInfo.updateState != null) { log.debug("[{}] failed to process firmware update: [{}]. Previous update failed.", client.getEndpoint(), fwInfo); logService.log(client, "Failed to process firmware update: " + fwInfo + ". Previous update failed."); } @@ -427,7 +427,7 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl startUpdateUsingBinary(client, swInfo); } } - } else { + } else if (swInfo.updateState != null) { log.debug("[{}] failed to update client: [{}], previous update failed.", client.getEndpoint(), swInfo); logService.log(client, "Failed to process software update: " + swInfo + ". Previous update failed."); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsServiceImpl.java index ec8afa77f0..a547a3b039 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsServiceImpl.java @@ -47,10 +47,6 @@ import org.thingsboard.server.dao.entity.AbstractEntityService; import org.thingsboard.server.dao.exception.DataValidationException; import org.thingsboard.server.dao.exception.DeviceCredentialsValidationException; import org.thingsboard.server.dao.service.DataValidator; - -import java.nio.charset.StandardCharsets; -import java.util.Arrays; - import static org.thingsboard.server.common.data.CacheConstants.DEVICE_CREDENTIALS_CACHE; import static org.thingsboard.server.dao.service.Validator.validateId; import static org.thingsboard.server.dao.service.Validator.validateString; From 0680b272799d314d24d76592f1e652b878de5b4b Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Wed, 17 Nov 2021 17:06:25 +0200 Subject: [PATCH 122/432] lwm2m - Test base64 and new profile --- .../lwm2m/AbstractLwM2MIntegrationTest.java | 64 +++++++++-------- .../ota/sql/OtaLwM2MIntegrationTest.java | 69 ++++++++++--------- .../rpc/AbstractRpcLwM2MIntegrationTest.java | 64 +++++++++-------- 3 files changed, 109 insertions(+), 88 deletions(-) diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/AbstractLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/AbstractLwM2MIntegrationTest.java index 37e174d09c..7c8e8e64ab 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/AbstractLwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/AbstractLwM2MIntegrationTest.java @@ -82,38 +82,46 @@ public abstract class AbstractLwM2MIntegrationTest extends AbstractWebsocketTest " ],\n" + " \"attributeLwm2m\": {}\n" + " },\n" + - " \"bootstrap\": {\n" + - " \"servers\": {\n" + - " \"binding\": \"U\",\n" + - " \"shortId\": 123,\n" + - " \"lifetime\": 300,\n" + - " \"notifIfDisabled\": true,\n" + - " \"defaultMinPeriod\": 1\n" + + " \"bootstrap\": [\n" + + " {\n" + + " \"host\": \"0.0.0.0\",\n" + + " \"port\": 5687,\n" + + " \"binding\": \"U\",\n" + + " \"lifetime\": 300,\n" + + " \"securityMode\": \"NO_SEC\",\n" + + " \"shortServerId\": 111,\n" + + " \"notifIfDisabled\": true,\n" + + " \"serverPublicKey\": \"\",\n" + + " \"defaultMinPeriod\": 1,\n" + + " \"bootstrapServerIs\": true,\n" + + " \"clientHoldOffTime\": 1,\n" + + " \"bootstrapServerAccountTimeout\": 0\n" + " },\n" + - " \"lwm2mServer\": {\n" + - " \"host\": \"localhost\",\n" + - " \"port\": 5686,\n" + - " \"serverId\": 123,\n" + - " \"serverPublicKey\": \"\",\n" + - " \"bootstrapServerIs\": false,\n" + - " \"clientHoldOffTime\": 1,\n" + - " \"bootstrapServerAccountTimeout\": 0\n" + - " },\n" + - " \"bootstrapServer\": {\n" + - " \"host\": \"localhost\",\n" + - " \"port\": 5687,\n" + - " \"serverId\": 111,\n" + - " \"securityMode\": \"NO_SEC\",\n" + - " \"serverPublicKey\": \"\",\n" + - " \"bootstrapServerIs\": true,\n" + - " \"clientHoldOffTime\": 1,\n" + - " \"bootstrapServerAccountTimeout\": 0\n" + + " {\n" + + " \"host\": \"0.0.0.0\",\n" + + " \"port\": 5685,\n" + + " \"binding\": \"U\",\n" + + " \"lifetime\": 300,\n" + + " \"securityMode\": \"NO_SEC\",\n" + + " \"shortServerId\": 123,\n" + + " \"notifIfDisabled\": true,\n" + + " \"serverPublicKey\": \"\",\n" + + " \"defaultMinPeriod\": 1,\n" + + " \"bootstrapServerIs\": false,\n" + + " \"clientHoldOffTime\": 1,\n" + + " \"bootstrapServerAccountTimeout\": 0\n" + " }\n" + - " },\n" + + " ],\n" + " \"clientLwM2mSettings\": {\n" + - " \"clientOnlyObserveAfterConnect\": 1,\n" + + " \"edrxCycle\": null,\n" + + " \"powerMode\": \"DRX\",\n" + + " \"fwUpdateResource\": null,\n" + " \"fwUpdateStrategy\": 1,\n" + - " \"swUpdateStrategy\": 1\n" + + " \"psmActivityTimer\": null,\n" + + " \"swUpdateResource\": null,\n" + + " \"swUpdateStrategy\": 1,\n" + + " \"pagingTransmissionWindow\": null,\n" + + " \"clientOnlyObserveAfterConnect\": 1\n" + " }\n" + "}"; diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/ota/sql/OtaLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/ota/sql/OtaLwM2MIntegrationTest.java index 440a8a8532..ae1ef48235 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/ota/sql/OtaLwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/ota/sql/OtaLwM2MIntegrationTest.java @@ -54,6 +54,7 @@ public class OtaLwM2MIntegrationTest extends AbstractOtaLwM2MIntegrationTest { public static final int TIMEOUT = 30; private final String OTA_TRANSPORT_CONFIGURATION = "{\n" + + " \"type\": \"LWM2M\",\n" + " \"observeAttr\": {\n" + " \"keyName\": {\n" + " \"/5_1.0/0/3\": \"state\",\n" + @@ -91,43 +92,47 @@ public class OtaLwM2MIntegrationTest extends AbstractOtaLwM2MIntegrationTest { " ],\n" + " \"attributeLwm2m\": {}\n" + " },\n" + - " \"bootstrap\": {\n" + - " \"servers\": {\n" + - " \"binding\": \"UQ\",\n" + - " \"shortId\": 123,\n" + - " \"lifetime\": 300,\n" + - " \"notifIfDisabled\": true,\n" + - " \"defaultMinPeriod\": 1\n" + + " \"bootstrap\": [\n" + + " {\n" + + " \"host\": \"0.0.0.0\",\n" + + " \"port\": 5687,\n" + + " \"binding\": \"U\",\n" + + " \"lifetime\": 300,\n" + + " \"securityMode\": \"NO_SEC\",\n" + + " \"shortServerId\": 111,\n" + + " \"notifIfDisabled\": true,\n" + + " \"serverPublicKey\": \"\",\n" + + " \"defaultMinPeriod\": 1,\n" + + " \"bootstrapServerIs\": true,\n" + + " \"clientHoldOffTime\": 1,\n" + + " \"bootstrapServerAccountTimeout\": 0\n" + " },\n" + - " \"lwm2mServer\": {\n" + - " \"host\": \"localhost\",\n" + - " \"port\": 5685,\n" + - " \"serverId\": 123,\n" + - " \"securityMode\": \"NO_SEC\",\n" + - " \"serverPublicKey\": \"\",\n" + - " \"clientHoldOffTime\": 1,\n" + - " \"bootstrapServerAccountTimeout\": 0\n" + - " },\n" + - " \"bootstrapServer\": {\n" + - " \"host\": \"localhost\",\n" + - " \"port\": 5687,\n" + - " \"serverId\": 111,\n" + - " \"securityMode\": \"NO_SEC\",\n" + - " \"serverPublicKey\": \"\",\n" + - " \"clientHoldOffTime\": 1,\n" + - " \"bootstrapServerAccountTimeout\": 0\n" + + " {\n" + + " \"host\": \"0.0.0.0\",\n" + + " \"port\": 5685,\n" + + " \"binding\": \"U\",\n" + + " \"lifetime\": 300,\n" + + " \"securityMode\": \"NO_SEC\",\n" + + " \"shortServerId\": 123,\n" + + " \"notifIfDisabled\": true,\n" + + " \"serverPublicKey\": \"\",\n" + + " \"defaultMinPeriod\": 1,\n" + + " \"bootstrapServerIs\": false,\n" + + " \"clientHoldOffTime\": 1,\n" + + " \"bootstrapServerAccountTimeout\": 0\n" + " }\n" + - " },\n" + + " ],\n" + " \"clientLwM2mSettings\": {\n" + + " \"edrxCycle\": null,\n" + + " \"powerMode\": \"DRX\",\n" + + " \"fwUpdateResource\": null,\n" + " \"fwUpdateStrategy\": 1,\n" + + " \"psmActivityTimer\": null,\n" + + " \"swUpdateResource\": null,\n" + " \"swUpdateStrategy\": 1,\n" + - " \"clientOnlyObserveAfterConnect\": 1,\n" + - " \"powerMode\": \"PSM\",\n" + - " \"fwUpdateResource\": \"\",\n" + - " \"swUpdateResource\": \"\",\n" + - " \"compositeOperationsSupport\": false\n" + - " },\n" + - " \"type\": \"LWM2M\"\n" + + " \"pagingTransmissionWindow\": null,\n" + + " \"clientOnlyObserveAfterConnect\": 1\n" + + " }\n" + "}"; @Test diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/AbstractRpcLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/AbstractRpcLwM2MIntegrationTest.java index 2906fb0215..6f4a520295 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/AbstractRpcLwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/AbstractRpcLwM2MIntegrationTest.java @@ -142,38 +142,46 @@ public abstract class AbstractRpcLwM2MIntegrationTest extends AbstractLwM2MInteg " ],\n" + " \"attributeLwm2m\": {}\n" + " },\n" + - " \"bootstrap\": {\n" + - " \"servers\": {\n" + - " \"binding\": \"U\",\n" + - " \"shortId\": 123,\n" + - " \"lifetime\": 300,\n" + - " \"notifIfDisabled\": true,\n" + - " \"defaultMinPeriod\": 1\n" + + " \"bootstrap\": [\n" + + " {\n" + + " \"host\": \"0.0.0.0\",\n" + + " \"port\": 5687,\n" + + " \"binding\": \"U\",\n" + + " \"lifetime\": 300,\n" + + " \"securityMode\": \"NO_SEC\",\n" + + " \"shortServerId\": 111,\n" + + " \"notifIfDisabled\": true,\n" + + " \"serverPublicKey\": \"\",\n" + + " \"defaultMinPeriod\": 1,\n" + + " \"bootstrapServerIs\": true,\n" + + " \"clientHoldOffTime\": 1,\n" + + " \"bootstrapServerAccountTimeout\": 0\n" + " },\n" + - " \"lwm2mServer\": {\n" + - " \"host\": \"localhost\",\n" + - " \"port\": 5686,\n" + - " \"serverId\": 123,\n" + - " \"serverPublicKey\": \"\",\n" + - " \"bootstrapServerIs\": false,\n" + - " \"clientHoldOffTime\": 1,\n" + - " \"bootstrapServerAccountTimeout\": 0\n" + - " },\n" + - " \"bootstrapServer\": {\n" + - " \"host\": \"localhost\",\n" + - " \"port\": 5687,\n" + - " \"serverId\": 111,\n" + - " \"securityMode\": \"NO_SEC\",\n" + - " \"serverPublicKey\": \"\",\n" + - " \"bootstrapServerIs\": true,\n" + - " \"clientHoldOffTime\": 1,\n" + - " \"bootstrapServerAccountTimeout\": 0\n" + + " {\n" + + " \"host\": \"0.0.0.0\",\n" + + " \"port\": 5685,\n" + + " \"binding\": \"U\",\n" + + " \"lifetime\": 300,\n" + + " \"securityMode\": \"NO_SEC\",\n" + + " \"shortServerId\": 123,\n" + + " \"notifIfDisabled\": true,\n" + + " \"serverPublicKey\": \"\",\n" + + " \"defaultMinPeriod\": 1,\n" + + " \"bootstrapServerIs\": false,\n" + + " \"clientHoldOffTime\": 1,\n" + + " \"bootstrapServerAccountTimeout\": 0\n" + " }\n" + - " },\n" + + " ],\n" + " \"clientLwM2mSettings\": {\n" + - " \"clientOnlyObserveAfterConnect\": 1,\n" + + " \"edrxCycle\": null,\n" + + " \"powerMode\": \"DRX\",\n" + + " \"fwUpdateResource\": null,\n" + " \"fwUpdateStrategy\": 1,\n" + - " \"swUpdateStrategy\": 1\n" + + " \"psmActivityTimer\": null,\n" + + " \"swUpdateResource\": null,\n" + + " \"swUpdateStrategy\": 1,\n" + + " \"pagingTransmissionWindow\": null,\n" + + " \"clientOnlyObserveAfterConnect\": 1\n" + " }\n" + "}"; createDeviceProfile(RPC_TRANSPORT_CONFIGURATION); From 59fb501e25ba2d3daa36fd7696742650a30517d0 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Wed, 17 Nov 2021 18:39:46 +0200 Subject: [PATCH 123/432] lwm2m - Fix bug test msg "Device credentials type should be specified" --- .../server/dao/device/DeviceCredentialsServiceImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsServiceImpl.java index a547a3b039..e131dd34a4 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsServiceImpl.java @@ -89,7 +89,7 @@ public class DeviceCredentialsServiceImpl extends AbstractEntityService implemen private DeviceCredentials saveOrUpdate(TenantId tenantId, DeviceCredentials deviceCredentials) { if (deviceCredentials.getCredentialsType() == null) { - throw new DataValidationException("Device credentials type must be specified"); + throw new DataValidationException("Device credentials type should be specified"); } formatCredentials(deviceCredentials); log.trace("Executing updateDeviceCredentials [{}]", deviceCredentials); From c47940940406b1f9180db82d3a80254c47977518 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Wed, 17 Nov 2021 21:43:02 +0200 Subject: [PATCH 124/432] lwm2m - Validation config servers --- .../dao/device/DeviceProfileServiceImpl.java | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java index 22a9a00e15..fc901abd35 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java @@ -46,6 +46,7 @@ import org.thingsboard.server.common.data.DeviceProfileType; import org.thingsboard.server.common.data.DeviceTransportType; import org.thingsboard.server.common.data.OtaPackage; import org.thingsboard.server.common.data.Tenant; +import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MSecurityMode; import org.thingsboard.server.common.data.device.profile.CoapDeviceProfileTransportConfiguration; import org.thingsboard.server.common.data.device.profile.CoapDeviceTypeConfiguration; import org.thingsboard.server.common.data.device.profile.DefaultCoapDeviceTypeConfiguration; @@ -59,6 +60,7 @@ import org.thingsboard.server.common.data.device.profile.Lwm2mDeviceProfileTrans import org.thingsboard.server.common.data.device.profile.MqttDeviceProfileTransportConfiguration; import org.thingsboard.server.common.data.device.profile.ProtoTransportPayloadConfiguration; import org.thingsboard.server.common.data.device.profile.TransportPayloadTypeConfiguration; +import org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap.AbstractLwM2MBootstrapServerCredential; import org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap.RPKLwM2MBootstrapServerCredential; import org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap.LwM2MBootstrapServerCredential; import org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap.X509LwM2MBootstrapServerCredential; @@ -418,6 +420,7 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D } } else if (transportConfiguration instanceof Lwm2mDeviceProfileTransportConfiguration) { List lwM2MBootstrapServersConfigurations = ((Lwm2mDeviceProfileTransportConfiguration) transportConfiguration).getBootstrap(); + validateLwm2mServersConfigOfBootstrapForClient(lwM2MBootstrapServersConfigurations); for (LwM2MBootstrapServerCredential bootstrapServerCredential : lwM2MBootstrapServersConfigurations) { validateLwm2mServersCredentialOfBootstrapForClient(bootstrapServerCredential); } @@ -704,6 +707,32 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D } } + private void validateLwm2mServersConfigOfBootstrapForClient(List lwM2MBootstrapServersConfigurations) { + Set uris = new HashSet<>(); + for (LwM2MBootstrapServerCredential bootstrapServerCredential : lwM2MBootstrapServersConfigurations) { + AbstractLwM2MBootstrapServerCredential serverConfig = (AbstractLwM2MBootstrapServerCredential) bootstrapServerCredential; + String server = serverConfig.isBootstrapServerIs() ? "Bootstrap Server" : "LwM2M Server" + " shortServerId: " + serverConfig.getShortServerId() + ":"; + if (serverConfig.getShortServerId() < 1 || serverConfig.getShortServerId() > 65534) { + throw new DeviceCredentialsValidationException(server + " ShortServerId must not be less than 1 and more than 65534!"); + } + String uri = serverConfig.getHost() + ":" + serverConfig.getPort(); + if (!uris.add(uri)){ + throw new DeviceCredentialsValidationException(server + " \"Host + port\" value = " + uri + ". This value must be a unique value for all servers!"); + }; + Integer port; + if (LwM2MSecurityMode.NO_SEC.equals(serverConfig.getSecurityMode())) { + port = serverConfig.isBootstrapServerIs() ? 5687 : 5685; + } + else { + port = serverConfig.isBootstrapServerIs() ? 5688 : 5686; + } + if (serverConfig.getPort() == null || serverConfig.getPort().intValue() != port) { + throw new DeviceCredentialsValidationException(server + " \"Port\" value = " + serverConfig.getPort() + ". This value for security " + serverConfig.getSecurityMode().name() + " must be " + port + "!"); + + } + } + } + private void validateLwm2mServersCredentialOfBootstrapForClient(LwM2MBootstrapServerCredential bootstrapServerConfig) { String server; switch (bootstrapServerConfig.getSecurityMode()) { From 3f6fb04949e160d87130edabcbbd2cfef3b7e790 Mon Sep 17 00:00:00 2001 From: Dima Landiak Date: Thu, 18 Nov 2021 16:42:46 +0200 Subject: [PATCH 125/432] no class entity with id exists for relation fix --- .../thingsboard/server/dao/sql/relation/JpaRelationDao.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/relation/JpaRelationDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/relation/JpaRelationDao.java index 2eaa5c28a2..5388d091f4 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/relation/JpaRelationDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/relation/JpaRelationDao.java @@ -19,6 +19,7 @@ import com.google.common.util.concurrent.ListenableFuture; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.dao.ConcurrencyFailureException; +import org.springframework.dao.DataAccessException; import org.springframework.data.jpa.domain.Specification; import org.springframework.stereotype.Component; import org.thingsboard.server.common.data.EntityType; @@ -159,7 +160,7 @@ public class JpaRelationDao extends JpaAbstractDaoListeningExecutorService imple if (relationExistsBeforeDelete) { try { relationRepository.deleteById(key); - } catch (ConcurrencyFailureException e) { + } catch (DataAccessException e) { log.debug("[{}] Concurrency exception while deleting relation", key, e); } } @@ -200,7 +201,7 @@ public class JpaRelationDao extends JpaAbstractDaoListeningExecutorService imple return (root, criteriaQuery, criteriaBuilder) -> { List predicates = new ArrayList<>(); if (from != null) { - Predicate fromIdPredicate = criteriaBuilder.equal(root.get("fromId"), from.getId()); + Predicate fromIdPredicate = criteriaBuilder.equal(root.get("fromId"), from.getId()); predicates.add(fromIdPredicate); Predicate fromEntityTypePredicate = criteriaBuilder.equal(root.get("fromType"), from.getEntityType().name()); predicates.add(fromEntityTypePredicate); From 31a1af58142c355c0f666f757fdc6e522de80351 Mon Sep 17 00:00:00 2001 From: Sergey Tarnavskiy Date: Fri, 19 Nov 2021 15:18:42 +0200 Subject: [PATCH 126/432] Fixed bug with missing required credential-config for LwM2M device-profiles. --- .../components/wizard/device-wizard-dialog.component.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.ts b/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.ts index fdbc25107f..b40130719a 100644 --- a/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.ts +++ b/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.ts @@ -252,6 +252,14 @@ export class DeviceWizardDialogComponent extends private deviceProfileTransportTypeChanged(deviceTransportType: DeviceTransportType): void { this.transportConfigFormGroup.patchValue( {transportConfiguration: createDeviceProfileTransportConfiguration(deviceTransportType)}); + const setCredentialBox = this.credentialsFormGroup.get('setCredential'); + if (deviceTransportType === DeviceTransportType.LWM2M) { + setCredentialBox.patchValue(true); + setCredentialBox.disable(); + } else { + setCredentialBox.patchValue(false); + setCredentialBox.enable(); + } } add(): void { From c532bc6508b8ecf2f968e4999db75a9f1d3a0fe9 Mon Sep 17 00:00:00 2001 From: Sergey Tarnavskiy Date: Fri, 19 Nov 2021 16:08:56 +0200 Subject: [PATCH 127/432] Fixed bug with UI updating of bootstrap-config for LwM2M device-profiles --- .../lwm2m-device-profile-transport-configuration.component.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts index 1fdf6cf8be..89bc65fa0f 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, forwardRef, Input, OnDestroy } from '@angular/core'; +import { ChangeDetectorRef, Component, forwardRef, Input, OnDestroy } from '@angular/core'; import { ControlValueAccessor, FormBuilder, @@ -95,6 +95,7 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro } constructor(private fb: FormBuilder, + private cd: ChangeDetectorRef, private deviceProfileService: DeviceProfileService) { this.lwm2mDeviceProfileFormGroup = this.fb.group({ objectIds: [null], @@ -236,6 +237,7 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro this.lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.fwUpdateStrategy').updateValueAndValidity({onlySelf: true}); this.lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.swUpdateStrategy').updateValueAndValidity({onlySelf: true}); } + this.cd.detectChanges(); } private updateModel = (): void => { From a77d4c8dec70470407f254c27d7bf0b5dd4960ec Mon Sep 17 00:00:00 2001 From: Sergey Tarnavskiy Date: Fri, 19 Nov 2021 17:15:27 +0200 Subject: [PATCH 128/432] Minor fixes for main commits --- .../lwm2m-device-profile-transport-configuration.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts index 89bc65fa0f..d16a0eafca 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts @@ -237,7 +237,7 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro this.lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.fwUpdateStrategy').updateValueAndValidity({onlySelf: true}); this.lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.swUpdateStrategy').updateValueAndValidity({onlySelf: true}); } - this.cd.detectChanges(); + this.cd.markForCheck(); } private updateModel = (): void => { From 1ba805012c1790d71b2a8db4f763584af9e5cb77 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Fri, 19 Nov 2021 18:14:03 +0200 Subject: [PATCH 129/432] lwm2m - sql - Updating device profile profile_data transport_type==LWM2M... --- .../server/install/ThingsboardInstallService.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java b/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java index ccdac8b363..7158b9d1b2 100644 --- a/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java +++ b/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java @@ -213,6 +213,11 @@ public class ThingsboardInstallService { log.info("Updating system data..."); systemDataLoaderService.updateSystemWidgets(); break; + case "3.3.2": + log.info("Upgrading ThingsBoard from version 3.3.2 to 3.3.3 ..."); + log.info("Updating system data..."); + databaseEntitiesUpgradeService.upgradeDatabase("3.3.2"); + break; //TODO update CacheCleanupService on the next version upgrade From a9151b5100539b0ce4a734726eb1aacbbe3a22dc Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Fri, 19 Nov 2021 17:54:16 +0200 Subject: [PATCH 130/432] fixed NPE --- .../server/client/LwM2mClientContextImpl.java | 4 +- .../rpc/DefaultLwM2MRpcRequestHandler.java | 162 +++++++++--------- 2 files changed, 83 insertions(+), 83 deletions(-) diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java index f89edb6353..da304821da 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java @@ -278,8 +278,8 @@ public class LwM2mClientContextImpl implements LwM2mClientContext { public LwM2mClient getClientBySessionInfo(TransportProtos.SessionInfoProto sessionInfo) { LwM2mClient lwM2mClient = null; UUID sessionId = new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB()); - Predicate isClientFilter = c -> - sessionId.equals((new UUID(c.getSession().getSessionIdMSB(), c.getSession().getSessionIdLSB()))); + Predicate isClientFilter = + c -> c.getSession() != null && sessionId.equals((new UUID(c.getSession().getSessionIdMSB(), c.getSession().getSessionIdLSB()))); if (this.lwM2mClientsByEndpoint.size() > 0) { lwM2mClient = this.lwM2mClientsByEndpoint.values().stream().filter(isClientFilter).findAny().orElse(null); } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/DefaultLwM2MRpcRequestHandler.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/DefaultLwM2MRpcRequestHandler.java index 118961850c..161ca3d2f1 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/DefaultLwM2MRpcRequestHandler.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/DefaultLwM2MRpcRequestHandler.java @@ -17,15 +17,12 @@ package org.thingsboard.server.transport.lwm2m.server.rpc; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.exception.ExceptionUtils; import org.eclipse.leshan.core.ResponseCode; -import org.eclipse.leshan.core.request.ReadCompositeRequest; -import org.eclipse.leshan.core.response.ReadCompositeResponse; import org.springframework.stereotype.Service; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.StringUtils; -import org.thingsboard.server.common.data.rpc.RpcStatus; import org.thingsboard.server.common.transport.TransportService; -import org.thingsboard.server.common.transport.TransportServiceCallback; import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; @@ -63,11 +60,9 @@ import org.thingsboard.server.transport.lwm2m.server.rpc.composite.RpcReadRespon import org.thingsboard.server.transport.lwm2m.server.rpc.composite.RpcWriteCompositeRequest; import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler; -import java.util.Map; import java.util.Set; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; -import java.util.stream.Collectors; @Slf4j @Service @@ -85,91 +80,96 @@ public class DefaultLwM2MRpcRequestHandler implements LwM2MRpcRequestHandler { @Override public void onToDeviceRpcRequest(TransportProtos.ToDeviceRpcRequestMsg rpcRequest, TransportProtos.SessionInfoProto sessionInfo) { log.debug("Received params: {}", rpcRequest.getParams()); - LwM2mOperationType operationType = LwM2mOperationType.fromType(rpcRequest.getMethodName()); - if (operationType == null) { - this.sendErrorRpcResponse(sessionInfo, rpcRequest.getRequestId(), ResponseCode.METHOD_NOT_ALLOWED, "Unsupported operation type: " + rpcRequest.getMethodName()); - return; - } - LwM2mClient client = clientContext.getClientBySessionInfo(sessionInfo); - if (client.getRegistration() == null) { - this.sendErrorRpcResponse(sessionInfo, rpcRequest.getRequestId(), ResponseCode.INTERNAL_SERVER_ERROR, "Registration is empty"); - return; - } - UUID rpcId = new UUID(rpcRequest.getRequestIdMSB(), rpcRequest.getRequestIdLSB()); - - if (rpcId.equals(client.getLastSentRpcId())) { - log.debug("[{}]][{}] Rpc has already sent!", client.getEndpoint(), rpcId); - return; - } try { - if (operationType.isHasObjectId()) { - String objectId = getIdFromParameters(client, rpcRequest); - switch (operationType) { - case READ: - sendReadRequest(client, rpcRequest, objectId); - break; - case OBSERVE: - sendObserveRequest(client, rpcRequest, objectId); - break; - case DISCOVER: - sendDiscoverRequest(client, rpcRequest, objectId); - break; - case EXECUTE: - sendExecuteRequest(client, rpcRequest, objectId); - break; - case WRITE_ATTRIBUTES: - sendWriteAttributesRequest(client, rpcRequest, objectId); - break; - case OBSERVE_CANCEL: - sendCancelObserveRequest(client, rpcRequest, objectId); - break; - case DELETE: - sendDeleteRequest(client, rpcRequest, objectId); - break; - case WRITE_UPDATE: - sendWriteUpdateRequest(client, rpcRequest, objectId); - break; - case WRITE_REPLACE: - sendWriteReplaceRequest(client, rpcRequest, objectId); - break; - default: - throw new IllegalArgumentException("Unsupported operation: " + operationType.name()); - } - } else if (operationType.isComposite()) { - if (clientContext.isComposite(client)) { + LwM2mOperationType operationType = LwM2mOperationType.fromType(rpcRequest.getMethodName()); + if (operationType == null) { + this.sendErrorRpcResponse(sessionInfo, rpcRequest.getRequestId(), ResponseCode.METHOD_NOT_ALLOWED, "Unsupported operation type: " + rpcRequest.getMethodName()); + return; + } + LwM2mClient client = clientContext.getClientBySessionInfo(sessionInfo); + if (client.getRegistration() == null) { + this.sendErrorRpcResponse(sessionInfo, rpcRequest.getRequestId(), ResponseCode.INTERNAL_SERVER_ERROR, "Registration is empty"); + return; + } + UUID rpcId = new UUID(rpcRequest.getRequestIdMSB(), rpcRequest.getRequestIdLSB()); + + if (rpcId.equals(client.getLastSentRpcId())) { + log.debug("[{}]][{}] Rpc has already sent!", client.getEndpoint(), rpcId); + return; + } + try { + if (operationType.isHasObjectId()) { + String objectId = getIdFromParameters(client, rpcRequest); switch (operationType) { - case READ_COMPOSITE: - sendReadCompositeRequest(client, rpcRequest); + case READ: + sendReadRequest(client, rpcRequest, objectId); + break; + case OBSERVE: + sendObserveRequest(client, rpcRequest, objectId); + break; + case DISCOVER: + sendDiscoverRequest(client, rpcRequest, objectId); + break; + case EXECUTE: + sendExecuteRequest(client, rpcRequest, objectId); + break; + case WRITE_ATTRIBUTES: + sendWriteAttributesRequest(client, rpcRequest, objectId); break; - case WRITE_COMPOSITE: - sendWriteCompositeRequest(client, rpcRequest); + case OBSERVE_CANCEL: + sendCancelObserveRequest(client, rpcRequest, objectId); + break; + case DELETE: + sendDeleteRequest(client, rpcRequest, objectId); + break; + case WRITE_UPDATE: + sendWriteUpdateRequest(client, rpcRequest, objectId); + break; + case WRITE_REPLACE: + sendWriteReplaceRequest(client, rpcRequest, objectId); break; default: throw new IllegalArgumentException("Unsupported operation: " + operationType.name()); } + } else if (operationType.isComposite()) { + if (clientContext.isComposite(client)) { + switch (operationType) { + case READ_COMPOSITE: + sendReadCompositeRequest(client, rpcRequest); + break; + case WRITE_COMPOSITE: + sendWriteCompositeRequest(client, rpcRequest); + break; + default: + throw new IllegalArgumentException("Unsupported operation: " + operationType.name()); + } + } else { + this.sendErrorRpcResponse(sessionInfo, rpcRequest.getRequestId(), + ResponseCode.INTERNAL_SERVER_ERROR, "This device does not support Composite Operation"); + } } else { - this.sendErrorRpcResponse(sessionInfo, rpcRequest.getRequestId(), - ResponseCode.INTERNAL_SERVER_ERROR, "This device does not support Composite Operation"); - } - } else { - switch (operationType) { - case OBSERVE_CANCEL_ALL: - sendCancelAllObserveRequest(client, rpcRequest); - break; - case OBSERVE_READ_ALL: - sendObserveAllRequest(client, rpcRequest); - break; - case DISCOVER_ALL: - sendDiscoverAllRequest(client, rpcRequest); - break; - case FW_UPDATE: - //TODO: implement and add break statement - default: - throw new IllegalArgumentException("Unsupported operation: " + operationType.name()); + switch (operationType) { + case OBSERVE_CANCEL_ALL: + sendCancelAllObserveRequest(client, rpcRequest); + break; + case OBSERVE_READ_ALL: + sendObserveAllRequest(client, rpcRequest); + break; + case DISCOVER_ALL: + sendDiscoverAllRequest(client, rpcRequest); + break; + case FW_UPDATE: + //TODO: implement and add break statement + default: + throw new IllegalArgumentException("Unsupported operation: " + operationType.name()); + } } + } catch (IllegalArgumentException e) { + this.sendErrorRpcResponse(sessionInfo, rpcRequest.getRequestId(), ResponseCode.BAD_REQUEST, e.getMessage()); } - } catch (IllegalArgumentException e) { - this.sendErrorRpcResponse(sessionInfo, rpcRequest.getRequestId(), ResponseCode.BAD_REQUEST, e.getMessage()); + } catch (Exception e) { + log.error("[{}] Failed to send RPC: [{}]", sessionInfo, rpcRequest, e); + this.sendErrorRpcResponse(sessionInfo, rpcRequest.getRequestId(), ResponseCode.INTERNAL_SERVER_ERROR, ExceptionUtils.getRootCauseMessage(e)); } } From 3bf3efebdb5bcfb556b8749ab6b9ce67f8c1f2b4 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Fri, 19 Nov 2021 21:01:29 +0200 Subject: [PATCH 131/432] lwm2m - Updating device profile profile_data transport_type==LWM2M... --- .../3.3.2/schema_update_lwm2m_bootstrap.sql | 82 +++++++++++++++++++ .../install/SqlDatabaseUpgradeService.java | 18 ++++ .../update/DefaultCacheCleanupService.java | 5 +- 3 files changed, 104 insertions(+), 1 deletion(-) create mode 100644 application/src/main/data/upgrade/3.3.2/schema_update_lwm2m_bootstrap.sql diff --git a/application/src/main/data/upgrade/3.3.2/schema_update_lwm2m_bootstrap.sql b/application/src/main/data/upgrade/3.3.2/schema_update_lwm2m_bootstrap.sql new file mode 100644 index 0000000000..6f25ede8b2 --- /dev/null +++ b/application/src/main/data/upgrade/3.3.2/schema_update_lwm2m_bootstrap.sql @@ -0,0 +1,82 @@ +-- +-- Copyright © 2016-2021 The Thingsboard Authors +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- + +CREATE OR REPLACE FUNCTION get_bootstrap_3_3_3(bootstrap_in jsonb, publickey_bs text, publickey_lw text) RETURNS jsonb AS +$$ +BEGIN + RETURN json_build_array( + json_build_object('shortServerId', bootstrap_in::json #> '{bootstrapServer}' -> 'serverId', + 'securityMode', bootstrap_in::json #> '{bootstrapServer}' ->> 'securityMode', + 'binding', bootstrap_in::json #> '{servers}' ->> 'binding', + 'lifetime', bootstrap_in::json #> '{servers}' -> 'lifetime', + 'notifIfDisabled', bootstrap_in::json #> '{servers}' -> 'notifIfDisabled', + 'defaultMinPeriod', bootstrap_in::json #> '{servers}' -> 'defaultMinPeriod', + 'host', bootstrap_in::json #> '{bootstrapServer}' ->> 'host', + 'port', bootstrap_in::json #> '{bootstrapServer}' -> 'port', + 'serverPublicKey', publickey_bs, + 'bootstrapServerIs', true, + 'clientHoldOffTime', bootstrap_in::json #> '{bootstrapServer}' -> 'clientHoldOffTime', + 'bootstrapServerAccountTimeout', + bootstrap_in::json #> '{bootstrapServer}' -> 'bootstrapServerAccountTimeout' + ), + json_build_object('shortServerId', bootstrap_in::json #> '{lwm2mServer}' -> 'serverId', + 'securityMode', bootstrap_in::json #> '{lwm2mServer}' ->> 'securityMode', + 'binding', bootstrap_in::json #> '{servers}' ->> 'binding', + 'lifetime', bootstrap_in::json #> '{servers}' -> 'lifetime', + 'notifIfDisabled', bootstrap_in::json #> '{servers}' -> 'notifIfDisabled', + 'defaultMinPeriod', bootstrap_in::json #> '{servers}' -> 'defaultMinPeriod', + 'host', bootstrap_in::json #> '{lwm2mServer}' ->> 'host', + 'port', bootstrap_in::json #> '{lwm2mServer}' -> 'port', + 'serverPublicKey', publickey_lw, + 'bootstrapServerIs', false, + 'clientHoldOffTime', bootstrap_in::json #> '{lwm2mServer}' -> 'clientHoldOffTime', + 'bootstrapServerAccountTimeout', + bootstrap_in::json #> '{lwm2mServer}' -> 'bootstrapServerAccountTimeout' + ) + ); +END ; +$$ LANGUAGE plpgsql; + +CREATE OR REPLACE PROCEDURE update_profile_bootstrap() + LANGUAGE plpgsql AS +$$ + +BEGIN + + UPDATE device_profile + SET profile_data = jsonb_set( + profile_data, + '{transportConfiguration, bootstrap}', + get_bootstrap_3_3_3( + profile_data::jsonb #> '{transportConfiguration,bootstrap}', + subquery.publickey_bs, + subquery.publickey_lw), + true) + FROM ( + SELECT id, + encode( + decode(profile_data::json #> '{transportConfiguration,bootstrap,bootstrapServer}' ->> + 'serverPublicKey', 'hex')::bytea, 'base64') AS publickey_bs, + encode( + decode(profile_data::json #> '{transportConfiguration,bootstrap,lwm2mServer}' ->> + 'serverPublicKey', 'hex')::bytea, 'base64') AS publickey_lw + FROM device_profile + WHERE transport_type = 'LWM2M' + ) AS subquery + WHERE device_profile.id = subquery.id; + +END; +$$; diff --git a/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java b/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java index fcb9632020..0a1428ad49 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java @@ -469,6 +469,24 @@ public class SqlDatabaseUpgradeService implements DatabaseEntitiesUpgradeService log.error("Failed updating schema!!!", e); } break; + case "3.3.2": + try (Connection conn = DriverManager.getConnection(dbUrl, dbUserName, dbPassword)) { + log.info("Updating device (section bootstrap) and device profile profile_data transport_type==LWM2M..."); + schemaUpdateFile = Paths.get(installScripts.getDataDir(), "upgrade", "3.3.2", "schema_update_lwm2m_bootstrap.sql"); + loadSql(schemaUpdateFile, conn); + log.info("Updating device profile profile_data transport_type==LWM2M..."); + conn.createStatement().execute("call update_profile_bootstrap();"); + log.info("Device profile profile_data transport_type==LWM2M updated."); + + log.info("Updating device (section bootstrap) transport_type==LWM2M..."); +// conn.createStatement().execute("call update_device_bootstrap();"); + log.info("Device (section bootstrap) transport_type==LWM2M updated."); +// conn.createStatement().execute("UPDATE tb_schema_settings SET schema_version = 3003003;"); +// log.info("Schema updated."); + } catch (Exception e) { + log.error("Failed updating schema!!!", e); + } + break; default: throw new RuntimeException("Unable to upgrade SQL database, unsupported fromVersion: " + fromVersion); } diff --git a/application/src/main/java/org/thingsboard/server/service/install/update/DefaultCacheCleanupService.java b/application/src/main/java/org/thingsboard/server/service/install/update/DefaultCacheCleanupService.java index 3e5a5658f7..5d5782cbdf 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/update/DefaultCacheCleanupService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/update/DefaultCacheCleanupService.java @@ -55,7 +55,10 @@ public class DefaultCacheCleanupService implements CacheCleanupService { clearCacheByName("deviceProfiles"); clearCacheByName("tenantProfiles"); clearCacheByName("relations"); - + break; + case "3.3.2": + log.info("Clear cache to upgrade from version 3.3.2 to 3.3.3 ..."); + clearAllCaches(); break; default: throw new RuntimeException("Unable to update cache, unsupported fromVersion: " + fromVersion); From f8220aa3184bd71e9b1845d801947c4ddd4ef57c Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Mon, 22 Nov 2021 11:16:45 +0200 Subject: [PATCH 132/432] lwm2m - Revert to master code --- .../org/thingsboard/server/controller/AssetController.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/AssetController.java b/application/src/main/java/org/thingsboard/server/controller/AssetController.java index 9e50b6171e..b03e446c7b 100644 --- a/application/src/main/java/org/thingsboard/server/controller/AssetController.java +++ b/application/src/main/java/org/thingsboard/server/controller/AssetController.java @@ -379,9 +379,9 @@ public class AssetController extends BaseController { notes = "Requested asset must be owned by tenant that the user belongs to. " + "Asset name is an unique property of asset. So it can be used to identify the asset." + TENANT_AUTHORITY_PARAGRAPH, produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAuthority('TENANT_ADMIN')") - @RequestMapping(value = "/tenant/assets/name", method = RequestMethod.GET) + @RequestMapping(value = "/tenant/assets", params = {"assetName"}, method = RequestMethod.GET) @ResponseBody - public Asset getTenantAssetByName( + public Asset getTenantAsset( @ApiParam(value = ASSET_NAME_DESCRIPTION) @RequestParam String assetName) throws ThingsboardException { try { From 866238acda28d91c3e5f8b3add9377da8b9868e0 Mon Sep 17 00:00:00 2001 From: van-vanich Date: Mon, 22 Nov 2021 11:45:58 +0200 Subject: [PATCH 133/432] first version refactoring test code --- .../metadata/AbstractAttributeNodeTest.java | 227 +++++++++++++++ .../TbGetCustomerAttributeNodeTest.java | 246 ++++------------ .../TbGetRelatedAttributeNodeTest.java | 269 +++++------------- .../TbGetTenantAttributeNodeTest.java | 248 ++++------------ 4 files changed, 392 insertions(+), 598 deletions(-) create mode 100644 rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/AbstractAttributeNodeTest.java diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/AbstractAttributeNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/AbstractAttributeNodeTest.java new file mode 100644 index 0000000000..97e9ddf30b --- /dev/null +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/AbstractAttributeNodeTest.java @@ -0,0 +1,227 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.rule.engine.metadata; + +import com.datastax.oss.driver.api.core.uuid.Uuids; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.common.collect.Lists; +import com.google.common.util.concurrent.Futures; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; +import org.thingsboard.common.util.JacksonUtil; +import org.thingsboard.rule.engine.api.TbContext; +import org.thingsboard.rule.engine.api.TbNodeConfiguration; +import org.thingsboard.rule.engine.api.TbNodeException; +import org.thingsboard.server.common.data.Device; +import org.thingsboard.server.common.data.User; +import org.thingsboard.server.common.data.asset.Asset; +import org.thingsboard.server.common.data.id.CustomerId; +import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.id.RuleChainId; +import org.thingsboard.server.common.data.id.RuleNodeId; +import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.kv.AttributeKvEntry; +import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry; +import org.thingsboard.server.common.data.kv.BasicTsKvEntry; +import org.thingsboard.server.common.data.kv.StringDataEntry; +import org.thingsboard.server.common.data.kv.TsKvEntry; +import org.thingsboard.server.common.msg.TbMsg; +import org.thingsboard.server.common.msg.TbMsgDataType; +import org.thingsboard.server.common.msg.TbMsgMetaData; +import org.thingsboard.server.dao.asset.AssetService; +import org.thingsboard.server.dao.attributes.AttributesService; +import org.thingsboard.server.dao.device.DeviceService; +import org.thingsboard.server.dao.timeseries.TimeseriesService; +import org.thingsboard.server.dao.user.UserService; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyCollection; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.ArgumentMatchers.same; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.thingsboard.rule.engine.api.TbRelationTypes.FAILURE; +import static org.thingsboard.server.common.data.DataConstants.SERVER_SCOPE; + +@RunWith(MockitoJUnitRunner.class) +public abstract class AbstractAttributeNodeTest { + final CustomerId customerId = new CustomerId(Uuids.timeBased()); + final TenantId tenantId = new TenantId(Uuids.timeBased()); + final RuleChainId ruleChainId = new RuleChainId(Uuids.timeBased()); + final RuleNodeId ruleNodeId = new RuleNodeId(Uuids.timeBased()); + final String keyAttrConf = "${word}"; + final String valueAttrConf = "result"; + @Mock + TbContext ctx; + @Mock + AttributesService attributesService; + @Mock + TimeseriesService timeseriesService; + @Mock + UserService userService; + @Mock + AssetService assetService; + @Mock + DeviceService deviceService; + TbMsg msg; + Map metaData; + TbEntityGetAttrNode node; + + void init(TbEntityGetAttrNode node) throws TbNodeException { + ObjectMapper mapper = JacksonUtil.OBJECT_MAPPER; + TbNodeConfiguration nodeConfiguration = new TbNodeConfiguration(mapper.valueToTree(getTbNodeConfig())); + + metaData = new HashMap<>(); + metaData.putIfAbsent("word", "temperature"); + + this.node = node; + this.node.init(null, nodeConfiguration); + } + + void errorThrownIfCannotLoadAttributes(User user) { + msg = TbMsg.newMsg("USER", user.getId(), new TbMsgMetaData(), TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); + + when(ctx.getUserService()).thenReturn(userService); + when(userService.findUserByIdAsync(any(), eq(user.getId()))).thenReturn(Futures.immediateFuture(user)); + + when(ctx.getAttributesService()).thenReturn(attributesService); + when(attributesService.find(any(), eq(getEntityId()), eq(SERVER_SCOPE), anyCollection())) + .thenThrow(new IllegalStateException("something wrong")); + + node.onMsg(ctx, msg); + final ArgumentCaptor captor = ArgumentCaptor.forClass(Throwable.class); + verify(ctx).tellFailure(same(msg), captor.capture()); + + Throwable value = captor.getValue(); + assertEquals("something wrong", value.getMessage()); + assertTrue(msg.getMetaData().getData().isEmpty()); + } + + void errorThrownIfCannotLoadAttributesAsync(User user) { + + msg = TbMsg.newMsg("USER", user.getId(), new TbMsgMetaData(), TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); + + when(ctx.getUserService()).thenReturn(userService); + when(userService.findUserByIdAsync(any(), eq(user.getId()))).thenReturn(Futures.immediateFuture(user)); + + when(ctx.getAttributesService()).thenReturn(attributesService); + when(attributesService.find(any(), eq(getEntityId()), eq(SERVER_SCOPE), anyCollection())) + .thenReturn(Futures.immediateFailedFuture(new IllegalStateException("something wrong"))); + + node.onMsg(ctx, msg); + final ArgumentCaptor captor = ArgumentCaptor.forClass(Throwable.class); + verify(ctx).tellFailure(same(msg), captor.capture()); + + Throwable value = captor.getValue(); + assertEquals("something wrong", value.getMessage()); + assertTrue(msg.getMetaData().getData().isEmpty()); + } + + void failedChainUsedIfCustomerCannotBeFound(User user) { + msg = TbMsg.newMsg("USER", user.getId(), new TbMsgMetaData(), TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); + + when(ctx.getUserService()).thenReturn(userService); + when(userService.findUserByIdAsync(any(), eq(user.getId()))).thenReturn(Futures.immediateFuture(null)); + + node.onMsg(ctx, msg); + verify(ctx).tellNext(msg, FAILURE); + assertTrue(msg.getMetaData().getData().isEmpty()); + } + + void entityAttributeAddedInMetadata(EntityId entityId, String type) { + msg = TbMsg.newMsg(type, entityId, new TbMsgMetaData(metaData), TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); + entityAttributeFetched(getEntityId()); + } + + void usersCustomerAttributesFetched(User user) { + msg = TbMsg.newMsg("USER", user.getId(), new TbMsgMetaData(metaData), TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); + + when(ctx.getUserService()).thenReturn(userService); + when(userService.findUserByIdAsync(any(), eq(user.getId()))).thenReturn(Futures.immediateFuture(user)); + + entityAttributeFetched(getEntityId()); + } + + void assetsCustomerAttributesFetched(Asset asset) { + msg = TbMsg.newMsg("ASSET", asset.getId(), new TbMsgMetaData(metaData), TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); + + when(ctx.getAssetService()).thenReturn(assetService); + when(assetService.findAssetByIdAsync(any(), eq(asset.getId()))).thenReturn(Futures.immediateFuture(asset)); + + entityAttributeFetched(getEntityId()); + } + + void deviceCustomerAttributesFetched(Device device) { + msg = TbMsg.newMsg("USER", device.getId(), new TbMsgMetaData(metaData), TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); + + when(ctx.getDeviceService()).thenReturn(deviceService); + when(deviceService.findDeviceByIdAsync(any(), eq(device.getId()))).thenReturn(Futures.immediateFuture(device)); + + entityAttributeFetched(getEntityId()); + } + + void deviceCustomerTelemetryFetched(Device device) throws TbNodeException { + ObjectMapper mapper = JacksonUtil.OBJECT_MAPPER; + TbNodeConfiguration nodeConfiguration = new TbNodeConfiguration(mapper.valueToTree(getTbNodeConfigFotTelemetry())); + + TbEntityGetAttrNode node = getEmptyNode(); + node.init(null, nodeConfiguration); + + msg = TbMsg.newMsg("USER", device.getId(), new TbMsgMetaData(metaData), TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); + + when(ctx.getDeviceService()).thenReturn(deviceService); + when(deviceService.findDeviceByIdAsync(any(), eq(device.getId()))).thenReturn(Futures.immediateFuture(device)); + + List timeseries = Lists.newArrayList(new BasicTsKvEntry(1L, new StringDataEntry("temperature", "highest"))); + + when(ctx.getTimeseriesService()).thenReturn(timeseriesService); + when(timeseriesService.findLatest(any(), eq(getEntityId()), anyCollection())) + .thenReturn(Futures.immediateFuture(timeseries)); + + node.onMsg(ctx, msg); + verify(ctx).tellSuccess(msg); + assertEquals(msg.getMetaData().getValue("result"), "highest"); + } + + void entityAttributeFetched(EntityId entityId) { + List attributes = Lists.newArrayList(new BaseAttributeKvEntry(new StringDataEntry("temperature", "high"), 1L)); + + when(ctx.getAttributesService()).thenReturn(attributesService); + when(attributesService.find(any(), eq(entityId), eq(SERVER_SCOPE), anyCollection())) + .thenReturn(Futures.immediateFuture(attributes)); + + node.onMsg(ctx, msg); + verify(ctx).tellSuccess(msg); + assertEquals(msg.getMetaData().getValue("result"), "high"); + } + + protected abstract TbEntityGetAttrNode getEmptyNode(); + + abstract T getTbNodeConfig(); + + abstract T getTbNodeConfigFotTelemetry(); + + abstract EntityId getEntityId(); +} diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNodeTest.java index b7db9b6995..3ed2e35702 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNodeTest.java @@ -16,259 +16,109 @@ package org.thingsboard.rule.engine.metadata; import com.datastax.oss.driver.api.core.uuid.Uuids; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.google.common.collect.Lists; -import com.google.common.util.concurrent.Futures; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; -import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; -import org.thingsboard.rule.engine.api.TbContext; -import org.thingsboard.rule.engine.api.TbNodeConfiguration; import org.thingsboard.rule.engine.api.TbNodeException; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.asset.Asset; import org.thingsboard.server.common.data.id.AssetId; -import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.DeviceId; -import org.thingsboard.server.common.data.id.RuleChainId; -import org.thingsboard.server.common.data.id.RuleNodeId; +import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.UserId; -import org.thingsboard.server.common.data.kv.AttributeKvEntry; -import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry; -import org.thingsboard.server.common.data.kv.BasicTsKvEntry; -import org.thingsboard.server.common.data.kv.StringDataEntry; -import org.thingsboard.server.common.data.kv.TsKvEntry; -import org.thingsboard.server.common.msg.TbMsg; -import org.thingsboard.server.common.msg.TbMsgDataType; -import org.thingsboard.server.common.msg.TbMsgMetaData; -import org.thingsboard.server.dao.asset.AssetService; -import org.thingsboard.server.dao.attributes.AttributesService; -import org.thingsboard.server.dao.device.DeviceService; -import org.thingsboard.server.dao.timeseries.TimeseriesService; -import org.thingsboard.server.dao.user.UserService; import java.util.HashMap; -import java.util.List; import java.util.Map; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyCollection; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.ArgumentMatchers.same; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static org.thingsboard.rule.engine.api.TbRelationTypes.FAILURE; -import static org.thingsboard.server.common.data.DataConstants.SERVER_SCOPE; +import java.util.UUID; @RunWith(MockitoJUnitRunner.class) -public class TbGetCustomerAttributeNodeTest { - - private final RuleChainId ruleChainId = new RuleChainId(Uuids.timeBased()); - private final RuleNodeId ruleNodeId = new RuleNodeId(Uuids.timeBased()); - private TbGetCustomerAttributeNode node; - @Mock - private TbContext ctx; - @Mock - private AttributesService attributesService; - @Mock - private TimeseriesService timeseriesService; - @Mock - private UserService userService; - @Mock - private AssetService assetService; - @Mock - private DeviceService deviceService; - private TbMsg msg; - private Map metaData; +public class TbGetCustomerAttributeNodeTest extends AbstractAttributeNodeTest { + User user = new User(); + Asset asset = new Asset(); + Device device = new Device(); @Before - public void init() throws TbNodeException { + public void initDataForTests() throws TbNodeException { + init(new TbGetCustomerAttributeNode()); + user.setCustomerId(customerId); + user.setId(new UserId(UUID.randomUUID())); + + asset.setCustomerId(customerId); + asset.setId(new AssetId(UUID.randomUUID())); + + device.setCustomerId(customerId); + device.setId(new DeviceId(Uuids.timeBased())); + } + + @Override + protected TbEntityGetAttrNode getEmptyNode() { + return new TbGetCustomerAttributeNode(); + } + + @Override + T getTbNodeConfig() { TbGetEntityAttrNodeConfiguration config = new TbGetEntityAttrNodeConfiguration(); Map conf = new HashMap<>(); - conf.put("${word}", "result"); + conf.put(keyAttrConf, valueAttrConf); config.setAttrMapping(conf); config.setTelemetry(false); - ObjectMapper mapper = new ObjectMapper(); - TbNodeConfiguration nodeConfiguration = new TbNodeConfiguration(mapper.valueToTree(config)); + return (T) config; + } - metaData = new HashMap<>(); - metaData.putIfAbsent("word", "temperature"); + @Override + T getTbNodeConfigFotTelemetry() { + TbGetEntityAttrNodeConfiguration config = new TbGetEntityAttrNodeConfiguration(); + Map conf = new HashMap<>(); + conf.put(keyAttrConf, valueAttrConf); + config.setAttrMapping(conf); + config.setTelemetry(true); + return (T) config; + } - node = new TbGetCustomerAttributeNode(); - node.init(null, nodeConfiguration); + @Override + EntityId getEntityId() { + return customerId; } @Test public void errorThrownIfCannotLoadAttributes() { - UserId userId = new UserId(Uuids.timeBased()); - CustomerId customerId = new CustomerId(Uuids.timeBased()); - User user = new User(); - user.setCustomerId(customerId); - - msg = TbMsg.newMsg("USER", userId, new TbMsgMetaData(), TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); - - when(ctx.getUserService()).thenReturn(userService); - when(userService.findUserByIdAsync(any(), eq(userId))).thenReturn(Futures.immediateFuture(user)); - - when(ctx.getAttributesService()).thenReturn(attributesService); - when(attributesService.find(any(), eq(customerId), eq(SERVER_SCOPE), anyCollection())) - .thenThrow(new IllegalStateException("something wrong")); - - node.onMsg(ctx, msg); - final ArgumentCaptor captor = ArgumentCaptor.forClass(Throwable.class); - verify(ctx).tellFailure(same(msg), captor.capture()); - - Throwable value = captor.getValue(); - assertEquals("something wrong", value.getMessage()); - assertTrue(msg.getMetaData().getData().isEmpty()); + errorThrownIfCannotLoadAttributes(user); } @Test public void errorThrownIfCannotLoadAttributesAsync() { - UserId userId = new UserId(Uuids.timeBased()); - CustomerId customerId = new CustomerId(Uuids.timeBased()); - User user = new User(); - user.setCustomerId(customerId); - - msg = TbMsg.newMsg("USER", userId, new TbMsgMetaData(), TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); - - when(ctx.getUserService()).thenReturn(userService); - when(userService.findUserByIdAsync(any(), eq(userId))).thenReturn(Futures.immediateFuture(user)); - - when(ctx.getAttributesService()).thenReturn(attributesService); - when(attributesService.find(any(), eq(customerId), eq(SERVER_SCOPE), anyCollection())) - .thenReturn(Futures.immediateFailedFuture(new IllegalStateException("something wrong"))); - - node.onMsg(ctx, msg); - final ArgumentCaptor captor = ArgumentCaptor.forClass(Throwable.class); - verify(ctx).tellFailure(same(msg), captor.capture()); - - Throwable value = captor.getValue(); - assertEquals("something wrong", value.getMessage()); - assertTrue(msg.getMetaData().getData().isEmpty()); + errorThrownIfCannotLoadAttributesAsync(user); } @Test public void failedChainUsedIfCustomerCannotBeFound() { - UserId userId = new UserId(Uuids.timeBased()); - CustomerId customerId = new CustomerId(Uuids.timeBased()); - User user = new User(); - user.setCustomerId(customerId); - - msg = TbMsg.newMsg("USER", userId, new TbMsgMetaData(), TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); - - when(ctx.getUserService()).thenReturn(userService); - when(userService.findUserByIdAsync(any(), eq(userId))).thenReturn(Futures.immediateFuture(null)); - - - node.onMsg(ctx, msg); - verify(ctx).tellNext(msg, FAILURE); - assertTrue(msg.getMetaData().getData().isEmpty()); + failedChainUsedIfCustomerCannotBeFound(user); } @Test public void customerAttributeAddedInMetadata() { - CustomerId customerId = new CustomerId(Uuids.timeBased()); - msg = TbMsg.newMsg("CUSTOMER", customerId, new TbMsgMetaData(metaData), TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); - entityAttributeFetched(customerId); + entityAttributeAddedInMetadata(customerId, "CUSTOMER"); } @Test public void usersCustomerAttributesFetched() { - UserId userId = new UserId(Uuids.timeBased()); - CustomerId customerId = new CustomerId(Uuids.timeBased()); - User user = new User(); - user.setCustomerId(customerId); - - msg = TbMsg.newMsg("USER", userId, new TbMsgMetaData(metaData), TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); - - when(ctx.getUserService()).thenReturn(userService); - when(userService.findUserByIdAsync(any(), eq(userId))).thenReturn(Futures.immediateFuture(user)); - - entityAttributeFetched(customerId); + usersCustomerAttributesFetched(user); } @Test public void assetsCustomerAttributesFetched() { - AssetId assetId = new AssetId(Uuids.timeBased()); - CustomerId customerId = new CustomerId(Uuids.timeBased()); - Asset asset = new Asset(); - asset.setCustomerId(customerId); - - msg = TbMsg.newMsg("USER", assetId, new TbMsgMetaData(metaData), TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); - - when(ctx.getAssetService()).thenReturn(assetService); - when(assetService.findAssetByIdAsync(any(), eq(assetId))).thenReturn(Futures.immediateFuture(asset)); - - entityAttributeFetched(customerId); + assetsCustomerAttributesFetched(asset); } @Test public void deviceCustomerAttributesFetched() { - DeviceId deviceId = new DeviceId(Uuids.timeBased()); - CustomerId customerId = new CustomerId(Uuids.timeBased()); - Device device = new Device(); - device.setCustomerId(customerId); - - msg = TbMsg.newMsg("USER", deviceId, new TbMsgMetaData(metaData), TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); - - when(ctx.getDeviceService()).thenReturn(deviceService); - when(deviceService.findDeviceByIdAsync(any(), eq(deviceId))).thenReturn(Futures.immediateFuture(device)); - - entityAttributeFetched(customerId); + deviceCustomerAttributesFetched(device); } @Test public void deviceCustomerTelemetryFetched() throws TbNodeException { - TbGetEntityAttrNodeConfiguration config = new TbGetEntityAttrNodeConfiguration(); - - Map conf = new HashMap<>(); - conf.put("${word}", "result"); - config.setAttrMapping(conf); - config.setTelemetry(true); - ObjectMapper mapper = new ObjectMapper(); - TbNodeConfiguration nodeConfiguration = new TbNodeConfiguration(mapper.valueToTree(config)); - - node = new TbGetCustomerAttributeNode(); - node.init(null, nodeConfiguration); - - - DeviceId deviceId = new DeviceId(Uuids.timeBased()); - CustomerId customerId = new CustomerId(Uuids.timeBased()); - Device device = new Device(); - device.setCustomerId(customerId); - - msg = TbMsg.newMsg("USER", deviceId, new TbMsgMetaData(metaData), TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); - - when(ctx.getDeviceService()).thenReturn(deviceService); - when(deviceService.findDeviceByIdAsync(any(), eq(deviceId))).thenReturn(Futures.immediateFuture(device)); - - List timeseries = Lists.newArrayList(new BasicTsKvEntry(1L, new StringDataEntry("temperature", "highest"))); - - when(ctx.getTimeseriesService()).thenReturn(timeseriesService); - when(timeseriesService.findLatest(any(), eq(customerId), anyCollection())) - .thenReturn(Futures.immediateFuture(timeseries)); - - node.onMsg(ctx, msg); - verify(ctx).tellSuccess(msg); - assertEquals(msg.getMetaData().getValue("result"), "highest"); - } - - private void entityAttributeFetched(CustomerId customerId) { - List attributes = Lists.newArrayList(new BaseAttributeKvEntry(new StringDataEntry("temperature", "high"), 1L)); - - when(ctx.getAttributesService()).thenReturn(attributesService); - when(attributesService.find(any(), eq(customerId), eq(SERVER_SCOPE), anyCollection())) - .thenReturn(Futures.immediateFuture(attributes)); - - node.onMsg(ctx, msg); - verify(ctx).tellSuccess(msg); - assertEquals(msg.getMetaData().getValue("result"), "high"); + deviceCustomerTelemetryFetched(device); } } diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttributeNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttributeNodeTest.java index 35340bed0a..abb647c78c 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttributeNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttributeNodeTest.java @@ -15,285 +15,152 @@ */ package org.thingsboard.rule.engine.metadata; -import com.datastax.oss.driver.api.core.uuid.Uuids; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.google.common.collect.Lists; import com.google.common.util.concurrent.Futures; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; -import org.thingsboard.rule.engine.api.TbContext; -import org.thingsboard.rule.engine.api.TbNodeConfiguration; import org.thingsboard.rule.engine.api.TbNodeException; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.asset.Asset; import org.thingsboard.server.common.data.id.AssetId; -import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.DeviceId; -import org.thingsboard.server.common.data.id.RuleChainId; -import org.thingsboard.server.common.data.id.RuleNodeId; +import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.UserId; -import org.thingsboard.server.common.data.kv.AttributeKvEntry; -import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry; -import org.thingsboard.server.common.data.kv.BasicTsKvEntry; -import org.thingsboard.server.common.data.kv.StringDataEntry; -import org.thingsboard.server.common.data.kv.TsKvEntry; import org.thingsboard.server.common.data.relation.EntityRelation; -import org.thingsboard.server.common.msg.TbMsg; -import org.thingsboard.server.common.msg.TbMsgDataType; -import org.thingsboard.server.common.msg.TbMsgMetaData; -import org.thingsboard.server.dao.asset.AssetService; -import org.thingsboard.server.dao.attributes.AttributesService; -import org.thingsboard.server.dao.device.DeviceService; import org.thingsboard.server.dao.relation.RelationService; -import org.thingsboard.server.dao.timeseries.TimeseriesService; -import org.thingsboard.server.dao.user.UserService; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.UUID; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyCollection; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.ArgumentMatchers.same; -import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import static org.thingsboard.rule.engine.api.TbRelationTypes.FAILURE; -import static org.thingsboard.server.common.data.DataConstants.SERVER_SCOPE; @RunWith(MockitoJUnitRunner.Silent.class) -public class TbGetRelatedAttributeNodeTest { - private final CustomerId customerId = new CustomerId(Uuids.timeBased()); - private final RuleChainId ruleChainId = new RuleChainId(Uuids.timeBased()); - private final RuleNodeId ruleNodeId = new RuleNodeId(Uuids.timeBased()); - private TbGetRelatedAttributeNode node; - @Mock - private TbContext ctx; - @Mock - private AttributesService attributesService; - @Mock - private TimeseriesService timeseriesService; - @Mock - private UserService userService; - @Mock - private AssetService assetService; - @Mock - private DeviceService deviceService; +public class TbGetRelatedAttributeNodeTest extends AbstractAttributeNodeTest { + User user = new User(); + Asset asset = new Asset(); + Device device = new Device(); @Mock private RelationService relationService; - private TbMsg msg; - private Map metaData; private EntityRelation entityRelation; @Before - public void init() throws TbNodeException { + public void initDataForTests() throws TbNodeException { + init(new TbGetRelatedAttributeNode()); + entityRelation = new EntityRelation(); + entityRelation.setTo(customerId); + entityRelation.setType(EntityRelation.CONTAINS_TYPE); + when(ctx.getRelationService()).thenReturn(relationService); + + user.setCustomerId(customerId); + user.setId(new UserId(UUID.randomUUID())); + entityRelation.setFrom(user.getId()); + + asset.setCustomerId(customerId); + asset.setId(new AssetId(UUID.randomUUID())); + + device.setCustomerId(customerId); + device.setId(new DeviceId(UUID.randomUUID())); + } + + @Override + protected TbEntityGetAttrNode getEmptyNode() { + return new TbGetRelatedAttributeNode(); + } + + @Override + T getTbNodeConfig() { TbGetRelatedAttrNodeConfiguration config = new TbGetRelatedAttrNodeConfiguration(); config = config.defaultConfiguration(); Map conf = new HashMap<>(); - conf.put("${word}", "result"); + conf.put(keyAttrConf, valueAttrConf); config.setAttrMapping(conf); config.setTelemetry(false); - ObjectMapper mapper = new ObjectMapper(); - TbNodeConfiguration nodeConfiguration = new TbNodeConfiguration(mapper.valueToTree(config)); - - metaData = new HashMap<>(); - metaData.putIfAbsent("word", "temperature"); + return (T) config; + } - entityRelation = new EntityRelation(); - entityRelation.setTo(customerId); - entityRelation.setType(EntityRelation.CONTAINS_TYPE); - when(ctx.getRelationService()).thenReturn(relationService); + @Override + T getTbNodeConfigFotTelemetry() { + TbGetRelatedAttrNodeConfiguration config = new TbGetRelatedAttrNodeConfiguration(); + config = config.defaultConfiguration(); + Map conf = new HashMap<>(); + conf.put(keyAttrConf, valueAttrConf); + config.setAttrMapping(conf); + config.setTelemetry(true); + return (T) config; + } - node = new TbGetRelatedAttributeNode(); - node.init(null, nodeConfiguration); + @Override + EntityId getEntityId() { + return customerId; } @Test public void errorThrownIfCannotLoadAttributes() { - UserId userId = new UserId(Uuids.timeBased()); - User user = new User(); - user.setCustomerId(customerId); - entityRelation.setFrom(userId); + entityRelation.setFrom(user.getId()); + entityRelation.setTo(customerId); when(relationService.findByQuery(any(), any())).thenReturn(Futures.immediateFuture(List.of(entityRelation))); - - msg = TbMsg.newMsg("USER", userId, new TbMsgMetaData(), TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); - - when(ctx.getUserService()).thenReturn(userService); - when(userService.findUserByIdAsync(any(), eq(userId))).thenReturn(Futures.immediateFuture(user)); - - when(ctx.getAttributesService()).thenReturn(attributesService); - when(attributesService.find(any(), eq(customerId), eq(SERVER_SCOPE), anyCollection())) - .thenThrow(new IllegalStateException("something wrong")); - - node.onMsg(ctx, msg); - final ArgumentCaptor captor = ArgumentCaptor.forClass(Throwable.class); - verify(ctx).tellFailure(same(msg), captor.capture()); - - Throwable value = captor.getValue(); - assertEquals("something wrong", value.getMessage()); - assertTrue(msg.getMetaData().getData().isEmpty()); + errorThrownIfCannotLoadAttributes(user); } @Test public void errorThrownIfCannotLoadAttributesAsync() { - UserId userId = new UserId(Uuids.timeBased()); - User user = new User(); - user.setCustomerId(customerId); - entityRelation.setFrom(userId); + entityRelation.setFrom(user.getId()); + entityRelation.setTo(customerId); when(relationService.findByQuery(any(), any())).thenReturn(Futures.immediateFuture(List.of(entityRelation))); - - msg = TbMsg.newMsg("USER", userId, new TbMsgMetaData(), TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); - - when(ctx.getUserService()).thenReturn(userService); - when(userService.findUserByIdAsync(any(), eq(userId))).thenReturn(Futures.immediateFuture(user)); - - when(ctx.getAttributesService()).thenReturn(attributesService); - - when(attributesService.find(any(), eq(customerId), eq(SERVER_SCOPE), anyCollection())) - .thenReturn(Futures.immediateFailedFuture(new IllegalStateException("something wrong"))); - - node.onMsg(ctx, msg); - final ArgumentCaptor captor = ArgumentCaptor.forClass(Throwable.class); - verify(ctx).tellFailure(same(msg), captor.capture()); - - Throwable value = captor.getValue(); - assertEquals("something wrong", value.getMessage()); - assertTrue(msg.getMetaData().getData().isEmpty()); + errorThrownIfCannotLoadAttributesAsync(user); } @Test public void failedChainUsedIfCustomerCannotBeFound() { - UserId userId = new UserId(Uuids.timeBased()); - User user = new User(); - user.setCustomerId(customerId); entityRelation.setFrom(customerId); entityRelation.setTo(null); when(relationService.findByQuery(any(), any())).thenReturn(Futures.immediateFuture(List.of(entityRelation))); - - msg = TbMsg.newMsg("USER", userId, new TbMsgMetaData(), TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); - - when(ctx.getUserService()).thenReturn(userService); - when(userService.findUserByIdAsync(any(), eq(userId))).thenReturn(Futures.immediateFuture(null)); - - - node.onMsg(ctx, msg); - verify(ctx).tellNext(msg, FAILURE); - assertTrue(msg.getMetaData().getData().isEmpty()); - - entityRelation.setTo(customerId); + failedChainUsedIfCustomerCannotBeFound(user); } @Test public void customerAttributeAddedInMetadata() { entityRelation.setFrom(customerId); + entityRelation.setTo(customerId); when(relationService.findByQuery(any(), any())).thenReturn(Futures.immediateFuture(List.of(entityRelation))); - msg = TbMsg.newMsg("CUSTOMER", customerId, new TbMsgMetaData(metaData), TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); - entityAttributeFetched(customerId); + entityAttributeAddedInMetadata(customerId, "CUSTOMER"); } @Test public void usersCustomerAttributesFetched() { - UserId userId = new UserId(Uuids.timeBased()); - User user = new User(); - user.setCustomerId(customerId); - entityRelation.setFrom(userId); + entityRelation.setFrom(user.getId()); + entityRelation.setTo(customerId); when(relationService.findByQuery(any(), any())).thenReturn(Futures.immediateFuture(List.of(entityRelation))); - - msg = TbMsg.newMsg("USER", userId, new TbMsgMetaData(metaData), TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); - - when(ctx.getUserService()).thenReturn(userService); - when(userService.findUserByIdAsync(any(), eq(userId))).thenReturn(Futures.immediateFuture(user)); - - entityAttributeFetched(customerId); + usersCustomerAttributesFetched(user); } @Test public void assetsCustomerAttributesFetched() { - AssetId assetId = new AssetId(Uuids.timeBased()); - Asset asset = new Asset(); - asset.setCustomerId(customerId); - entityRelation.setFrom(assetId); + entityRelation.setFrom(asset.getId()); + entityRelation.setTo(customerId); when(relationService.findByQuery(any(), any())).thenReturn(Futures.immediateFuture(List.of(entityRelation))); - - msg = TbMsg.newMsg("USER", assetId, new TbMsgMetaData(metaData), TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); - - when(ctx.getAssetService()).thenReturn(assetService); - when(assetService.findAssetByIdAsync(any(), eq(assetId))).thenReturn(Futures.immediateFuture(asset)); - - entityAttributeFetched(customerId); + assetsCustomerAttributesFetched(asset); } @Test public void deviceCustomerAttributesFetched() { - DeviceId deviceId = new DeviceId(Uuids.timeBased()); - Device device = new Device(); - device.setCustomerId(customerId); - entityRelation.setFrom(deviceId); + entityRelation.setFrom(device.getId()); + entityRelation.setTo(customerId); when(relationService.findByQuery(any(), any())).thenReturn(Futures.immediateFuture(List.of(entityRelation))); - - msg = TbMsg.newMsg("USER", deviceId, new TbMsgMetaData(metaData), TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); - - when(ctx.getDeviceService()).thenReturn(deviceService); - when(deviceService.findDeviceByIdAsync(any(), eq(deviceId))).thenReturn(Futures.immediateFuture(device)); - - entityAttributeFetched(customerId); + deviceCustomerAttributesFetched(device); } @Test public void deviceCustomerTelemetryFetched() throws TbNodeException { - TbGetRelatedAttrNodeConfiguration config = new TbGetRelatedAttrNodeConfiguration(); - config = config.defaultConfiguration(); - - Map conf = new HashMap<>(); - conf.put("${word}", "result"); - config.setAttrMapping(conf); - config.setTelemetry(true); - ObjectMapper mapper = new ObjectMapper(); - TbNodeConfiguration nodeConfiguration = new TbNodeConfiguration(mapper.valueToTree(config)); - - node = new TbGetRelatedAttributeNode(); - node.init(null, nodeConfiguration); - - - DeviceId deviceId = new DeviceId(Uuids.timeBased()); - Device device = new Device(); - device.setCustomerId(customerId); - - entityRelation.setFrom(deviceId); + entityRelation.setFrom(device.getId()); + entityRelation.setTo(customerId); when(relationService.findByQuery(any(), any())).thenReturn(Futures.immediateFuture(List.of(entityRelation))); - - msg = TbMsg.newMsg("USER", deviceId, new TbMsgMetaData(metaData), TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); - - when(ctx.getDeviceService()).thenReturn(deviceService); - when(deviceService.findDeviceByIdAsync(any(), eq(deviceId))).thenReturn(Futures.immediateFuture(device)); - - List timeseries = Lists.newArrayList(new BasicTsKvEntry(1L, new StringDataEntry("temperature", "highest"))); - - when(ctx.getTimeseriesService()).thenReturn(timeseriesService); - when(timeseriesService.findLatest(any(), eq(customerId), anyCollection())) - .thenReturn(Futures.immediateFuture(timeseries)); - - node.onMsg(ctx, msg); - verify(ctx).tellSuccess(msg); - assertEquals(msg.getMetaData().getValue("result"), "highest"); - } - - private void entityAttributeFetched(CustomerId customerId) { - List attributes = Lists.newArrayList(new BaseAttributeKvEntry(new StringDataEntry("temperature", "high"), 1L)); - - when(ctx.getAttributesService()).thenReturn(attributesService); - when(attributesService.find(any(), eq(customerId), eq(SERVER_SCOPE), anyCollection())) - .thenReturn(Futures.immediateFuture(attributes)); - - node.onMsg(ctx, msg); - verify(ctx).tellSuccess(msg); - assertEquals(msg.getMetaData().getValue("result"), "high"); + deviceCustomerTelemetryFetched(device); } } \ No newline at end of file diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetTenantAttributeNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetTenantAttributeNodeTest.java index 783d786117..63cee9fb46 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetTenantAttributeNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetTenantAttributeNodeTest.java @@ -15,260 +15,110 @@ */ package org.thingsboard.rule.engine.metadata; -import com.datastax.oss.driver.api.core.uuid.Uuids; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.google.common.collect.Lists; -import com.google.common.util.concurrent.Futures; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; -import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; -import org.thingsboard.rule.engine.api.TbContext; -import org.thingsboard.rule.engine.api.TbNodeConfiguration; import org.thingsboard.rule.engine.api.TbNodeException; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.asset.Asset; import org.thingsboard.server.common.data.id.AssetId; -import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.DeviceId; -import org.thingsboard.server.common.data.id.RuleChainId; -import org.thingsboard.server.common.data.id.RuleNodeId; -import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.UserId; -import org.thingsboard.server.common.data.kv.AttributeKvEntry; -import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry; -import org.thingsboard.server.common.data.kv.BasicTsKvEntry; -import org.thingsboard.server.common.data.kv.StringDataEntry; -import org.thingsboard.server.common.data.kv.TsKvEntry; -import org.thingsboard.server.common.msg.TbMsg; -import org.thingsboard.server.common.msg.TbMsgDataType; -import org.thingsboard.server.common.msg.TbMsgMetaData; -import org.thingsboard.server.dao.asset.AssetService; -import org.thingsboard.server.dao.attributes.AttributesService; -import org.thingsboard.server.dao.device.DeviceService; -import org.thingsboard.server.dao.timeseries.TimeseriesService; -import org.thingsboard.server.dao.user.UserService; import java.util.HashMap; -import java.util.List; import java.util.Map; +import java.util.UUID; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyCollection; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.ArgumentMatchers.same; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static org.thingsboard.rule.engine.api.TbRelationTypes.FAILURE; -import static org.thingsboard.server.common.data.DataConstants.SERVER_SCOPE; +@RunWith(MockitoJUnitRunner.class) +public class TbGetTenantAttributeNodeTest extends AbstractAttributeNodeTest { -@RunWith(MockitoJUnitRunner.Silent.class) -public class TbGetTenantAttributeNodeTest { - private final RuleChainId ruleChainId = new RuleChainId(Uuids.timeBased()); - private final RuleNodeId ruleNodeId = new RuleNodeId(Uuids.timeBased()); - private TbGetTenantAttributeNode node; - @Mock - private TbContext ctx; - @Mock - private AttributesService attributesService; - @Mock - private TimeseriesService timeseriesService; - @Mock - private UserService userService; - @Mock - private AssetService assetService; - @Mock - private DeviceService deviceService; - private TbMsg msg; - private Map metaData; + User user = new User(); + Asset asset = new Asset(); + Device device = new Device(); @Before - public void init() throws TbNodeException { + public void initDataForTests() throws TbNodeException { + init(new TbGetTenantAttributeNode()); + user.setTenantId(tenantId); + user.setId(new UserId(UUID.randomUUID())); + + asset.setTenantId(tenantId); + asset.setId(new AssetId(UUID.randomUUID())); + + device.setTenantId(tenantId); + device.setId(new DeviceId(UUID.randomUUID())); + } + + @Override + protected TbEntityGetAttrNode getEmptyNode() { + return new TbGetTenantAttributeNode(); + } + + @Override + T getTbNodeConfig() { TbGetEntityAttrNodeConfiguration config = new TbGetEntityAttrNodeConfiguration(); Map conf = new HashMap<>(); - conf.put("${word}", "result"); + conf.put(keyAttrConf, valueAttrConf); config.setAttrMapping(conf); config.setTelemetry(false); - ObjectMapper mapper = new ObjectMapper(); - TbNodeConfiguration nodeConfiguration = new TbNodeConfiguration(mapper.valueToTree(config)); + return (T) config; + } - metaData = new HashMap<>(); - metaData.putIfAbsent("word", "temperature"); + @Override + T getTbNodeConfigFotTelemetry() { + TbGetEntityAttrNodeConfiguration config = new TbGetEntityAttrNodeConfiguration(); + Map conf = new HashMap<>(); + conf.put(keyAttrConf, valueAttrConf); + config.setAttrMapping(conf); + config.setTelemetry(true); + return (T) config; + } - node = new TbGetTenantAttributeNode(); - node.init(null, nodeConfiguration); + @Override + EntityId getEntityId() { + return tenantId; } @Test public void errorThrownIfCannotLoadAttributes() { - UserId userId = new UserId(Uuids.timeBased()); - TenantId tenantId = new TenantId(Uuids.timeBased()); - User user = new User(); - user.setTenantId(tenantId); - - msg = TbMsg.newMsg("USER", userId, new TbMsgMetaData(), TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); - - when(ctx.getUserService()).thenReturn(userService); - when(userService.findUserByIdAsync(any(), eq(userId))).thenReturn(Futures.immediateFuture(user)); - - when(ctx.getAttributesService()).thenReturn(attributesService); - when(attributesService.find(any(), eq(tenantId), eq(SERVER_SCOPE), anyCollection())) - .thenThrow(new IllegalStateException("something wrong")); - - node.onMsg(ctx, msg); - final ArgumentCaptor captor = ArgumentCaptor.forClass(Throwable.class); - verify(ctx).tellFailure(same(msg), captor.capture()); - - Throwable value = captor.getValue(); - assertEquals("something wrong", value.getMessage()); - assertTrue(msg.getMetaData().getData().isEmpty()); + errorThrownIfCannotLoadAttributes(user); } @Test public void errorThrownIfCannotLoadAttributesAsync() { - UserId userId = new UserId(Uuids.timeBased()); - TenantId tenantId = new TenantId(Uuids.timeBased()); - User user = new User(); - user.setTenantId(tenantId); - - msg = TbMsg.newMsg("USER", userId, new TbMsgMetaData(), TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); - - when(ctx.getUserService()).thenReturn(userService); - when(userService.findUserByIdAsync(any(), eq(userId))).thenReturn(Futures.immediateFuture(user)); - - when(ctx.getAttributesService()).thenReturn(attributesService); - when(attributesService.find(any(), eq(tenantId), eq(SERVER_SCOPE), anyCollection())) - .thenReturn(Futures.immediateFailedFuture(new IllegalStateException("something wrong"))); - - node.onMsg(ctx, msg); - final ArgumentCaptor captor = ArgumentCaptor.forClass(Throwable.class); - verify(ctx).tellFailure(same(msg), captor.capture()); - - Throwable value = captor.getValue(); - assertEquals("something wrong", value.getMessage()); - assertTrue(msg.getMetaData().getData().isEmpty()); + errorThrownIfCannotLoadAttributesAsync(user); } @Test public void failedChainUsedIfCustomerCannotBeFound() { - UserId userId = new UserId(Uuids.timeBased()); - CustomerId customerId = new CustomerId(Uuids.timeBased()); - User user = new User(); - user.setCustomerId(customerId); - - msg = TbMsg.newMsg("USER", userId, new TbMsgMetaData(), TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); - - when(ctx.getUserService()).thenReturn(userService); - when(userService.findUserByIdAsync(any(), eq(userId))).thenReturn(Futures.immediateFuture(null)); - - - node.onMsg(ctx, msg); - verify(ctx).tellNext(msg, FAILURE); - assertTrue(msg.getMetaData().getData().isEmpty()); + failedChainUsedIfCustomerCannotBeFound(user); } @Test public void customerAttributeAddedInMetadata() { - TenantId tenantId = new TenantId(Uuids.timeBased()); - msg = TbMsg.newMsg("TENANT", tenantId, new TbMsgMetaData(metaData), TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); - entityAttributeFetched(tenantId); + entityAttributeAddedInMetadata(tenantId, "TENANT"); } @Test public void usersCustomerAttributesFetched() { - UserId userId = new UserId(Uuids.timeBased()); - TenantId tenantId = new TenantId(Uuids.timeBased()); - User user = new User(); - user.setTenantId(tenantId); - - msg = TbMsg.newMsg("USER", userId, new TbMsgMetaData(metaData), TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); - - when(ctx.getUserService()).thenReturn(userService); - when(userService.findUserByIdAsync(any(), eq(userId))).thenReturn(Futures.immediateFuture(user)); - - entityAttributeFetched(tenantId); + usersCustomerAttributesFetched(user); } @Test public void assetsCustomerAttributesFetched() { - AssetId assetId = new AssetId(Uuids.timeBased()); - TenantId tenantId = new TenantId(Uuids.timeBased()); - Asset asset = new Asset(); - asset.setTenantId(tenantId); - - msg = TbMsg.newMsg("USER", assetId, new TbMsgMetaData(metaData), TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); - - when(ctx.getAssetService()).thenReturn(assetService); - when(assetService.findAssetByIdAsync(any(), eq(assetId))).thenReturn(Futures.immediateFuture(asset)); - - entityAttributeFetched(tenantId); + assetsCustomerAttributesFetched(asset); } @Test public void deviceCustomerAttributesFetched() { - DeviceId deviceId = new DeviceId(Uuids.timeBased()); - TenantId tenantId = new TenantId(Uuids.timeBased()); - Device device = new Device(); - device.setTenantId(tenantId); - - msg = TbMsg.newMsg("USER", deviceId, new TbMsgMetaData(metaData), TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); - - when(ctx.getDeviceService()).thenReturn(deviceService); - when(deviceService.findDeviceByIdAsync(any(), eq(deviceId))).thenReturn(Futures.immediateFuture(device)); - - entityAttributeFetched(tenantId); + deviceCustomerAttributesFetched(device); } @Test public void deviceCustomerTelemetryFetched() throws TbNodeException { - TbGetEntityAttrNodeConfiguration config = new TbGetEntityAttrNodeConfiguration(); - - Map conf = new HashMap<>(); - conf.put("${word}", "result"); - config.setAttrMapping(conf); - config.setTelemetry(true); - ObjectMapper mapper = new ObjectMapper(); - TbNodeConfiguration nodeConfiguration = new TbNodeConfiguration(mapper.valueToTree(config)); - - node = new TbGetTenantAttributeNode(); - node.init(null, nodeConfiguration); - - - DeviceId deviceId = new DeviceId(Uuids.timeBased()); - TenantId tenantId = new TenantId(Uuids.timeBased()); - Device device = new Device(); - device.setTenantId(tenantId); - - msg = TbMsg.newMsg("USER", deviceId, new TbMsgMetaData(metaData), TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); - - when(ctx.getDeviceService()).thenReturn(deviceService); - when(deviceService.findDeviceByIdAsync(any(), eq(deviceId))).thenReturn(Futures.immediateFuture(device)); - - List timeseries = Lists.newArrayList(new BasicTsKvEntry(1L, new StringDataEntry("temperature", "highest"))); - - when(ctx.getTimeseriesService()).thenReturn(timeseriesService); - when(timeseriesService.findLatest(any(), eq(tenantId), anyCollection())) - .thenReturn(Futures.immediateFuture(timeseries)); - - node.onMsg(ctx, msg); - verify(ctx).tellSuccess(msg); - assertEquals(msg.getMetaData().getValue("result"), "highest"); - } - - private void entityAttributeFetched(TenantId customerId) { - List attributes = Lists.newArrayList(new BaseAttributeKvEntry(new StringDataEntry("temperature", "high"), 1L)); - - when(ctx.getAttributesService()).thenReturn(attributesService); - when(attributesService.find(any(), eq(customerId), eq(SERVER_SCOPE), anyCollection())) - .thenReturn(Futures.immediateFuture(attributes)); - - node.onMsg(ctx, msg); - verify(ctx).tellSuccess(msg); - assertEquals(msg.getMetaData().getValue("result"), "high"); + deviceCustomerTelemetryFetched(device); } } \ No newline at end of file From a0e06abe1f5b6d1c6168a92580c5cfc3f9e042b2 Mon Sep 17 00:00:00 2001 From: van-vanich Date: Mon, 22 Nov 2021 13:55:24 +0200 Subject: [PATCH 134/432] refactoring tests and some program --- .../rule/engine/metadata/TbEntityGetAttrNode.java | 9 ++++----- .../engine/metadata/TbGetRelatedAttributeNodeTest.java | 2 +- .../engine/metadata/TbGetTenantAttributeNodeTest.java | 2 +- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbEntityGetAttrNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbEntityGetAttrNode.java index c8df7b4a92..757d0d7ca3 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbEntityGetAttrNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbEntityGetAttrNode.java @@ -67,20 +67,19 @@ public abstract class TbEntityGetAttrNode implements TbNode return; } - withCallback(config.isTelemetry() ? getLatestTelemetry(ctx, entityId, msg) : getAttributesAsync(ctx, entityId, msg), + List latestProcess = TbNodeUtils.processPatterns(List.copyOf(config.getAttrMapping().keySet()), msg); + withCallback(config.isTelemetry() ? getLatestTelemetry(ctx, entityId, latestProcess) : getAttributesAsync(ctx, entityId, latestProcess), attributes -> putAttributesAndTell(ctx, msg, attributes), t -> ctx.tellFailure(msg, t), ctx.getDbCallbackExecutor()); } - private ListenableFuture> getAttributesAsync(TbContext ctx, EntityId entityId, TbMsg msg) { - List attrProcess = TbNodeUtils.processPatterns(List.copyOf(config.getAttrMapping().keySet()), msg); + private ListenableFuture> getAttributesAsync(TbContext ctx, EntityId entityId, List attrProcess) { ListenableFuture> latest = ctx.getAttributesService().find(ctx.getTenantId(), entityId, SERVER_SCOPE, attrProcess); return Futures.transform(latest, l -> l.stream().map(i -> (KvEntry) i).collect(Collectors.toList()), MoreExecutors.directExecutor()); } - private ListenableFuture> getLatestTelemetry(TbContext ctx, EntityId entityId, TbMsg msg) { - List latestProcess = TbNodeUtils.processPatterns(List.copyOf(config.getAttrMapping().keySet()), msg); + private ListenableFuture> getLatestTelemetry(TbContext ctx, EntityId entityId, List latestProcess) { ListenableFuture> latest = ctx.getTimeseriesService().findLatest(ctx.getTenantId(), entityId, latestProcess); return Futures.transform(latest, l -> l.stream().map(i -> (KvEntry) i).collect(Collectors.toList()), MoreExecutors.directExecutor()); diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttributeNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttributeNodeTest.java index abb647c78c..d2067ca893 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttributeNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttributeNodeTest.java @@ -163,4 +163,4 @@ public class TbGetRelatedAttributeNodeTest extends AbstractAttributeNodeTest { when(relationService.findByQuery(any(), any())).thenReturn(Futures.immediateFuture(List.of(entityRelation))); deviceCustomerTelemetryFetched(device); } -} \ No newline at end of file +} diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetTenantAttributeNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetTenantAttributeNodeTest.java index 63cee9fb46..e297722928 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetTenantAttributeNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetTenantAttributeNodeTest.java @@ -121,4 +121,4 @@ public class TbGetTenantAttributeNodeTest extends AbstractAttributeNodeTest { public void deviceCustomerTelemetryFetched() throws TbNodeException { deviceCustomerTelemetryFetched(device); } -} \ No newline at end of file +} From 5da827bf4859265116a953affe6ad86f3d83496f Mon Sep 17 00:00:00 2001 From: ArtemDzhereleiko Date: Mon, 22 Nov 2021 17:02:16 +0200 Subject: [PATCH 135/432] UI: Fix layout for firefox --- .../widget/widget-config.component.html | 39 ++++++++----------- .../widget/widget-config.component.scss | 9 +++++ 2 files changed, 25 insertions(+), 23 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/widget-config.component.html b/ui-ngx/src/app/modules/home/components/widget/widget-config.component.html index 761603a3ee..97542fd3cb 100644 --- a/ui-ngx/src/app/modules/home/components/widget/widget-config.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/widget-config.component.html @@ -295,8 +295,7 @@ widget-config.data-settings -
+
widget-config.units @@ -320,13 +319,12 @@
-
+
widget-config.title - + {{ 'widget-config.display-title' | translate }} -
+
widget-config.title @@ -336,13 +334,12 @@
-
+
widget-config.title-icon - + {{ 'widget-config.display-icon' | translate }} -
+
@@ -374,12 +371,10 @@
-
+
widget-config.widget-style -
-
+
+
-
+
widget-config.padding @@ -405,10 +399,10 @@
- + {{ 'widget-config.drop-shadow' | translate }} - + {{ 'widget-config.enable-fullscreen' | translate }} @@ -427,7 +421,7 @@
-
+
widget-config.legend @@ -445,7 +439,7 @@
-
+
widget-config.mobile-mode-settings @@ -459,8 +453,7 @@ -
+
widget-config.order diff --git a/ui-ngx/src/app/modules/home/components/widget/widget-config.component.scss b/ui-ngx/src/app/modules/home/components/widget/widget-config.component.scss index 8d8cd742c6..c29afa5629 100644 --- a/ui-ngx/src/app/modules/home/components/widget/widget-config.component.scss +++ b/ui-ngx/src/app/modules/home/components/widget/widget-config.component.scss @@ -201,6 +201,15 @@ } } } + .mat-slide { + margin: 8px 0; + } + .slide-block { + display: block; + &:not(:last-child) { + margin-bottom: 8px; + } + } .mat-slide-toggle-content { white-space: normal; } From 41b8a2be54d3bccfad184d1a27ce6a5d5031950a Mon Sep 17 00:00:00 2001 From: Viacheslav Klimov Date: Tue, 23 Nov 2021 12:33:40 +0200 Subject: [PATCH 136/432] Add Redis config for SNMP transport --- .../src/main/resources/tb-snmp-transport.yml | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/transport/snmp/src/main/resources/tb-snmp-transport.yml b/transport/snmp/src/main/resources/tb-snmp-transport.yml index 80bc257a8b..fcdce12e1b 100644 --- a/transport/snmp/src/main/resources/tb-snmp-transport.yml +++ b/transport/snmp/src/main/resources/tb-snmp-transport.yml @@ -40,6 +40,49 @@ zk: # Name of the directory in zookeeper 'filesystem' zk_dir: "${ZOOKEEPER_NODES_DIR:/thingsboard}" +cache: + type: "${CACHE_TYPE:redis}" + +redis: + # standalone or cluster + connection: + type: "${REDIS_CONNECTION_TYPE:standalone}" + standalone: + host: "${REDIS_HOST:localhost}" + port: "${REDIS_PORT:6379}" + useDefaultClientConfig: "${REDIS_USE_DEFAULT_CLIENT_CONFIG:true}" + # this value may be used only if you used not default ClientConfig + clientName: "${REDIS_CLIENT_NAME:standalone}" + # this value may be used only if you used not default ClientConfig + connectTimeout: "${REDIS_CLIENT_CONNECT_TIMEOUT:30000}" + # this value may be used only if you used not default ClientConfig + readTimeout: "${REDIS_CLIENT_READ_TIMEOUT:60000}" + # this value may be used only if you used not default ClientConfig + usePoolConfig: "${REDIS_CLIENT_USE_POOL_CONFIG:false}" + cluster: + # Comma-separated list of "host:port" pairs to bootstrap from. + nodes: "${REDIS_NODES:}" + # Maximum number of redirects to follow when executing commands across the cluster. + max-redirects: "${REDIS_MAX_REDIRECTS:12}" + useDefaultPoolConfig: "${REDIS_USE_DEFAULT_POOL_CONFIG:true}" + # db index + db: "${REDIS_DB:0}" + # db password + password: "${REDIS_PASSWORD:}" + # pool config + pool_config: + maxTotal: "${REDIS_POOL_CONFIG_MAX_TOTAL:128}" + maxIdle: "${REDIS_POOL_CONFIG_MAX_IDLE:128}" + minIdle: "${REDIS_POOL_CONFIG_MIN_IDLE:16}" + testOnBorrow: "${REDIS_POOL_CONFIG_TEST_ON_BORROW:true}" + testOnReturn: "${REDIS_POOL_CONFIG_TEST_ON_RETURN:true}" + testWhileIdle: "${REDIS_POOL_CONFIG_TEST_WHILE_IDLE:true}" + minEvictableMs: "${REDIS_POOL_CONFIG_MIN_EVICTABLE_MS:60000}" + evictionRunsMs: "${REDIS_POOL_CONFIG_EVICTION_RUNS_MS:30000}" + maxWaitMills: "${REDIS_POOL_CONFIG_MAX_WAIT_MS:60000}" + numberTestsPerEvictionRun: "${REDIS_POOL_CONFIG_NUMBER_TESTS_PER_EVICTION_RUN:3}" + blockWhenExhausted: "${REDIS_POOL_CONFIG_BLOCK_WHEN_EXHAUSTED:true}" + transport: snmp: enabled: "${SNMP_ENABLED:true}" From 4feaeecaba872568ea9520cf6184e264cadf8268 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Tue, 23 Nov 2021 15:18:35 +0200 Subject: [PATCH 137/432] lwm2m - Add device credentials from HexDec ro Bas64 --- .../3.3.2/schema_update_lwm2m_bootstrap.sql | 199 ++++++++++++++---- .../install/SqlDatabaseUpgradeService.java | 2 +- 2 files changed, 154 insertions(+), 47 deletions(-) diff --git a/application/src/main/data/upgrade/3.3.2/schema_update_lwm2m_bootstrap.sql b/application/src/main/data/upgrade/3.3.2/schema_update_lwm2m_bootstrap.sql index 6f25ede8b2..3b48f6252a 100644 --- a/application/src/main/data/upgrade/3.3.2/schema_update_lwm2m_bootstrap.sql +++ b/application/src/main/data/upgrade/3.3.2/schema_update_lwm2m_bootstrap.sql @@ -14,57 +14,21 @@ -- limitations under the License. -- -CREATE OR REPLACE FUNCTION get_bootstrap_3_3_3(bootstrap_in jsonb, publickey_bs text, publickey_lw text) RETURNS jsonb AS -$$ -BEGIN - RETURN json_build_array( - json_build_object('shortServerId', bootstrap_in::json #> '{bootstrapServer}' -> 'serverId', - 'securityMode', bootstrap_in::json #> '{bootstrapServer}' ->> 'securityMode', - 'binding', bootstrap_in::json #> '{servers}' ->> 'binding', - 'lifetime', bootstrap_in::json #> '{servers}' -> 'lifetime', - 'notifIfDisabled', bootstrap_in::json #> '{servers}' -> 'notifIfDisabled', - 'defaultMinPeriod', bootstrap_in::json #> '{servers}' -> 'defaultMinPeriod', - 'host', bootstrap_in::json #> '{bootstrapServer}' ->> 'host', - 'port', bootstrap_in::json #> '{bootstrapServer}' -> 'port', - 'serverPublicKey', publickey_bs, - 'bootstrapServerIs', true, - 'clientHoldOffTime', bootstrap_in::json #> '{bootstrapServer}' -> 'clientHoldOffTime', - 'bootstrapServerAccountTimeout', - bootstrap_in::json #> '{bootstrapServer}' -> 'bootstrapServerAccountTimeout' - ), - json_build_object('shortServerId', bootstrap_in::json #> '{lwm2mServer}' -> 'serverId', - 'securityMode', bootstrap_in::json #> '{lwm2mServer}' ->> 'securityMode', - 'binding', bootstrap_in::json #> '{servers}' ->> 'binding', - 'lifetime', bootstrap_in::json #> '{servers}' -> 'lifetime', - 'notifIfDisabled', bootstrap_in::json #> '{servers}' -> 'notifIfDisabled', - 'defaultMinPeriod', bootstrap_in::json #> '{servers}' -> 'defaultMinPeriod', - 'host', bootstrap_in::json #> '{lwm2mServer}' ->> 'host', - 'port', bootstrap_in::json #> '{lwm2mServer}' -> 'port', - 'serverPublicKey', publickey_lw, - 'bootstrapServerIs', false, - 'clientHoldOffTime', bootstrap_in::json #> '{lwm2mServer}' -> 'clientHoldOffTime', - 'bootstrapServerAccountTimeout', - bootstrap_in::json #> '{lwm2mServer}' -> 'bootstrapServerAccountTimeout' - ) - ); -END ; -$$ LANGUAGE plpgsql; - CREATE OR REPLACE PROCEDURE update_profile_bootstrap() LANGUAGE plpgsql AS $$ BEGIN - UPDATE device_profile - SET profile_data = jsonb_set( - profile_data, - '{transportConfiguration, bootstrap}', - get_bootstrap_3_3_3( - profile_data::jsonb #> '{transportConfiguration,bootstrap}', - subquery.publickey_bs, - subquery.publickey_lw), - true) +UPDATE device_profile +SET profile_data = jsonb_set( + profile_data, + '{transportConfiguration, bootstrap}', + get_bootstrap_3_3_3( + profile_data::jsonb #> '{transportConfiguration,bootstrap}', + subquery.publickey_bs, + subquery.publickey_lw), + true) FROM ( SELECT id, encode( @@ -76,7 +40,150 @@ BEGIN FROM device_profile WHERE transport_type = 'LWM2M' ) AS subquery - WHERE device_profile.id = subquery.id; +WHERE device_profile.id = subquery.id + AND subquery.publickey_bs IS NOT NULL + AND subquery.publickey_lw IS NOT NULL; END; $$; + +CREATE OR REPLACE FUNCTION get_bootstrap_3_3_3(bootstrap_in jsonb, publickey_bs text, publickey_lw text) RETURNS jsonb AS +$$ +BEGIN + +RETURN json_build_array( + json_build_object('shortServerId', bootstrap_in::json #> '{bootstrapServer}' -> 'serverId', + 'securityMode', bootstrap_in::json #> '{bootstrapServer}' ->> 'securityMode', + 'binding', bootstrap_in::json #> '{servers}' ->> 'binding', + 'lifetime', bootstrap_in::json #> '{servers}' -> 'lifetime', + 'notifIfDisabled', bootstrap_in::json #> '{servers}' -> 'notifIfDisabled', + 'defaultMinPeriod', bootstrap_in::json #> '{servers}' -> 'defaultMinPeriod', + 'host', bootstrap_in::json #> '{bootstrapServer}' ->> 'host', + 'port', bootstrap_in::json #> '{bootstrapServer}' -> 'port', + 'serverPublicKey', publickey_bs, + 'bootstrapServerIs', true, + 'clientHoldOffTime', bootstrap_in::json #> '{bootstrapServer}' -> 'clientHoldOffTime', + 'bootstrapServerAccountTimeout', + bootstrap_in::json #> '{bootstrapServer}' -> 'bootstrapServerAccountTimeout' + ), + json_build_object('shortServerId', bootstrap_in::json #> '{lwm2mServer}' -> 'serverId', + 'securityMode', bootstrap_in::json #> '{lwm2mServer}' ->> 'securityMode', + 'binding', bootstrap_in::json #> '{servers}' ->> 'binding', + 'lifetime', bootstrap_in::json #> '{servers}' -> 'lifetime', + 'notifIfDisabled', bootstrap_in::json #> '{servers}' -> 'notifIfDisabled', + 'defaultMinPeriod', bootstrap_in::json #> '{servers}' -> 'defaultMinPeriod', + 'host', bootstrap_in::json #> '{lwm2mServer}' ->> 'host', + 'port', bootstrap_in::json #> '{lwm2mServer}' -> 'port', + 'serverPublicKey', publickey_lw, + 'bootstrapServerIs', false, + 'clientHoldOffTime', bootstrap_in::json #> '{lwm2mServer}' -> 'clientHoldOffTime', + 'bootstrapServerAccountTimeout', + bootstrap_in::json #> '{lwm2mServer}' -> 'bootstrapServerAccountTimeout' + ) + ); + +END ; +$$ LANGUAGE plpgsql; + +CREATE OR REPLACE PROCEDURE update_device_credentials_to_base64_and_bootstrap() + LANGUAGE plpgsql AS +$$ + +BEGIN + +UPDATE device_credentials +SET credentials_value = get_device_and_bootstrap_3_3_3(credentials_value::text) +WHERE credentials_type = 'LWM2M_CREDENTIALS'; +END; +$$; + +CREATE OR REPLACE FUNCTION get_device_and_bootstrap_3_3_3(IN credentials_value text, OUT credentials_value_new text) + LANGUAGE plpgsql AS +$$ +DECLARE +client_secret_key text; + client_public_key_or_id text; + client_key_value_object jsonb; + client_bootstrap_server_value_object jsonb; + client_bootstrap_server_object jsonb; + client_bootstrap_object jsonb; + +BEGIN + credentials_value_new := credentials_value; + IF credentials_value::jsonb #> '{client}' ->> 'securityConfigClientMode' = 'RPK' AND + NULLIF((credentials_value::jsonb #> '{client}' ->> 'key' ~ '^[0-9a-fA-F]+$')::text, 'false') = 'true' THEN + client_public_key_or_id := encode(decode(credentials_value::jsonb #> '{client}' ->> 'key', 'hex')::bytea, 'base64'); + client_key_value_object := json_build_object( + 'endpoint', credentials_value::jsonb #> '{client}' ->> 'endpoint', + 'securityConfigClientMode', credentials_value::jsonb #> '{client}' ->> 'securityConfigClientMode', + 'key', client_public_key_or_id); + credentials_value_new := + credentials_value_new::jsonb || json_build_object('client', client_key_value_object)::jsonb; +END IF; + IF credentials_value::jsonb #> '{client}' ->> 'securityConfigClientMode' = 'X509' AND + NULLIF((credentials_value::jsonb #> '{client}' ->> 'cert' ~ '^[0-9a-fA-F]+$')::text, 'false') = 'true' THEN + client_public_key_or_id := + encode(decode(credentials_value::jsonb #> '{client}' ->> 'cert', 'hex')::bytea, 'base64'); + client_key_value_object := json_build_object( + 'endpoint', credentials_value::jsonb #> '{client}' ->> 'endpoint', + 'securityConfigClientMode', credentials_value::jsonb #> '{client}' ->> 'securityConfigClientMode', + 'cert', client_public_key_or_id); + credentials_value_new := + credentials_value_new::jsonb || json_build_object('client', client_key_value_object)::jsonb; +END IF; + + IF credentials_value::jsonb #> '{bootstrap,lwm2mServer}' ->> 'securityMode' = 'RPK' OR + credentials_value::jsonb #> '{bootstrap,lwm2mServer}' ->> 'securityMode' = 'X509' THEN + IF NULLIF((credentials_value::jsonb #> '{bootstrap,lwm2mServer}' ->> 'clientSecretKey' ~ '^[0-9a-fA-F]+$')::text, + 'false') = 'true' AND + NULLIF( + (credentials_value::jsonb #> '{bootstrap,lwm2mServer}' ->> 'clientPublicKeyOrId' ~ '^[0-9a-fA-F]+$')::text, + 'false') = 'true' THEN + client_secret_key := + encode(decode(credentials_value::jsonb #> '{bootstrap,lwm2mServer}' ->> 'clientSecretKey', 'hex')::bytea, + 'base64'); + client_public_key_or_id := encode( + decode(credentials_value::jsonb #> '{bootstrap,lwm2mServer}' ->> 'clientPublicKeyOrId', 'hex')::bytea, + 'base64'); + client_bootstrap_server_value_object := jsonb_build_object( + 'securityMode', credentials_value::jsonb #> '{bootstrap,lwm2mServer}' ->> 'securityMode', + 'clientPublicKeyOrId', client_public_key_or_id, + 'clientSecretKey', client_secret_key + ); + client_bootstrap_server_object := jsonb_build_object('lwm2mServer', client_bootstrap_server_value_object::jsonb); + client_bootstrap_object := credentials_value_new::jsonb #> '{bootstrap}' || client_bootstrap_server_object::jsonb; + credentials_value_new := + jsonb_set(credentials_value_new::jsonb, '{bootstrap}', client_bootstrap_object::jsonb, false)::jsonb; +END IF; +END IF; + + IF credentials_value::jsonb #> '{bootstrap,bootstrapServer}' ->> 'securityMode' = 'RPK' OR + credentials_value::jsonb #> '{bootstrap,bootstrapServer}' ->> 'securityMode' = 'X509' THEN + IF NULLIF( + (credentials_value::jsonb #> '{bootstrap,bootstrapServer}' ->> 'clientSecretKey' ~ '^[0-9a-fA-F]+$')::text, + 'false') = 'true' AND + NULLIF( + (credentials_value::jsonb #> '{bootstrap,bootstrapServer}' ->> 'clientPublicKeyOrId' ~ '^[0-9a-fA-F]+$')::text, + 'false') = 'true' THEN + client_secret_key := + encode( + decode(credentials_value::jsonb #> '{bootstrap,bootstrapServer}' ->> 'clientSecretKey', 'hex')::bytea, + 'base64'); + client_public_key_or_id := encode( + decode(credentials_value::jsonb #> '{bootstrap,bootstrapServer}' ->> 'clientPublicKeyOrId', 'hex')::bytea, + 'base64'); + client_bootstrap_server_value_object := jsonb_build_object( + 'securityMode', credentials_value::jsonb #> '{bootstrap,bootstrapServer}' ->> 'securityMode', + 'clientPublicKeyOrId', client_public_key_or_id, + 'clientSecretKey', client_secret_key + ); + client_bootstrap_server_object := + jsonb_build_object('bootstrapServer', client_bootstrap_server_value_object::jsonb); + client_bootstrap_object := credentials_value_new::jsonb #> '{bootstrap}' || client_bootstrap_server_object::jsonb; + credentials_value_new := + jsonb_set(credentials_value_new::jsonb, '{bootstrap}', client_bootstrap_object::jsonb, false)::jsonb; +END IF; +END IF; + +END; +$$; \ No newline at end of file diff --git a/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java b/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java index 0a1428ad49..7e65b1fe2f 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java @@ -479,7 +479,7 @@ public class SqlDatabaseUpgradeService implements DatabaseEntitiesUpgradeService log.info("Device profile profile_data transport_type==LWM2M updated."); log.info("Updating device (section bootstrap) transport_type==LWM2M..."); -// conn.createStatement().execute("call update_device_bootstrap();"); + conn.createStatement().execute("call update_device_credentials_to_base64_and_bootstrap();"); log.info("Device (section bootstrap) transport_type==LWM2M updated."); // conn.createStatement().execute("UPDATE tb_schema_settings SET schema_version = 3003003;"); // log.info("Schema updated."); From c5d5e8226bdd2e46445431644c2c3354403e8aa6 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Tue, 23 Nov 2021 16:13:40 +0200 Subject: [PATCH 138/432] lwm2m - refactoring by comments --- .../3.3.2/schema_update_lwm2m_bootstrap.sql | 8 ++++---- .../install/SqlDatabaseUpgradeService.java | 15 +++++++-------- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/application/src/main/data/upgrade/3.3.2/schema_update_lwm2m_bootstrap.sql b/application/src/main/data/upgrade/3.3.2/schema_update_lwm2m_bootstrap.sql index 3b48f6252a..f21d895eb9 100644 --- a/application/src/main/data/upgrade/3.3.2/schema_update_lwm2m_bootstrap.sql +++ b/application/src/main/data/upgrade/3.3.2/schema_update_lwm2m_bootstrap.sql @@ -24,7 +24,7 @@ UPDATE device_profile SET profile_data = jsonb_set( profile_data, '{transportConfiguration, bootstrap}', - get_bootstrap_3_3_3( + get_bootstrap( profile_data::jsonb #> '{transportConfiguration,bootstrap}', subquery.publickey_bs, subquery.publickey_lw), @@ -47,7 +47,7 @@ WHERE device_profile.id = subquery.id END; $$; -CREATE OR REPLACE FUNCTION get_bootstrap_3_3_3(bootstrap_in jsonb, publickey_bs text, publickey_lw text) RETURNS jsonb AS +CREATE OR REPLACE FUNCTION get_bootstrap(bootstrap_in jsonb, publickey_bs text, publickey_lw text) RETURNS jsonb AS $$ BEGIN @@ -92,12 +92,12 @@ $$ BEGIN UPDATE device_credentials -SET credentials_value = get_device_and_bootstrap_3_3_3(credentials_value::text) +SET credentials_value = get_device_and_bootstrap(credentials_value::text) WHERE credentials_type = 'LWM2M_CREDENTIALS'; END; $$; -CREATE OR REPLACE FUNCTION get_device_and_bootstrap_3_3_3(IN credentials_value text, OUT credentials_value_new text) +CREATE OR REPLACE FUNCTION get_device_and_bootstrap(IN credentials_value text, OUT credentials_value_new text) LANGUAGE plpgsql AS $$ DECLARE diff --git a/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java b/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java index 7e65b1fe2f..aacfe5e230 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java @@ -471,18 +471,17 @@ public class SqlDatabaseUpgradeService implements DatabaseEntitiesUpgradeService break; case "3.3.2": try (Connection conn = DriverManager.getConnection(dbUrl, dbUserName, dbPassword)) { - log.info("Updating device (section bootstrap) and device profile profile_data transport_type==LWM2M..."); + log.info("Updating schema ..."); schemaUpdateFile = Paths.get(installScripts.getDataDir(), "upgrade", "3.3.2", "schema_update_lwm2m_bootstrap.sql"); loadSql(schemaUpdateFile, conn); - log.info("Updating device profile profile_data transport_type==LWM2M..."); + log.info("Updating server`s public key from HexDec to Base64 in profile for LWM2M..."); conn.createStatement().execute("call update_profile_bootstrap();"); - log.info("Device profile profile_data transport_type==LWM2M updated."); - - log.info("Updating device (section bootstrap) transport_type==LWM2M..."); + log.info("Server`s public key from HexDec to Base64 in profile for LWM2M updated."); + log.info("Updating client`s public key and secret key from HexDec to Base64 for LWM2M..."); conn.createStatement().execute("call update_device_credentials_to_base64_and_bootstrap();"); - log.info("Device (section bootstrap) transport_type==LWM2M updated."); -// conn.createStatement().execute("UPDATE tb_schema_settings SET schema_version = 3003003;"); -// log.info("Schema updated."); + log.info("Client`s public key and secret key from HexDec to Base64 for LWM2M updated."); + conn.createStatement().execute("UPDATE tb_schema_settings SET schema_version = 3003003;"); + log.info("Schema updated."); } catch (Exception e) { log.error("Failed updating schema!!!", e); } From 436e19d6524532765edb063f83115c9861fcdba8 Mon Sep 17 00:00:00 2001 From: van-vanich Date: Tue, 23 Nov 2021 16:14:22 +0200 Subject: [PATCH 139/432] refactoring and improve code --- .../engine/metadata/TbEntityGetAttrNode.java | 31 +++++---- .../metadata/AbstractAttributeNodeTest.java | 64 +++++++++++-------- .../TbGetCustomerAttributeNodeTest.java | 35 ++++------ .../TbGetRelatedAttributeNodeTest.java | 24 +++---- .../TbGetTenantAttributeNodeTest.java | 35 ++++------ 5 files changed, 89 insertions(+), 100 deletions(-) diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbEntityGetAttrNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbEntityGetAttrNode.java index 757d0d7ca3..747549cd77 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbEntityGetAttrNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbEntityGetAttrNode.java @@ -30,7 +30,6 @@ import org.thingsboard.server.common.data.kv.KvEntry; import org.thingsboard.server.common.data.kv.TsKvEntry; import org.thingsboard.server.common.msg.TbMsg; -import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -67,34 +66,34 @@ public abstract class TbEntityGetAttrNode implements TbNode return; } - List latestProcess = TbNodeUtils.processPatterns(List.copyOf(config.getAttrMapping().keySet()), msg); - withCallback(config.isTelemetry() ? getLatestTelemetry(ctx, entityId, latestProcess) : getAttributesAsync(ctx, entityId, latestProcess), - attributes -> putAttributesAndTell(ctx, msg, attributes), + Map mappingsMap = new HashMap<>(); + config.getAttrMapping().forEach((key, value) -> { + String processPattern = TbNodeUtils.processPattern(key, msg); + mappingsMap.put(processPattern, value); + }); + + List keys = List.copyOf(mappingsMap.keySet()); + withCallback(config.isTelemetry() ? getLatestTelemetry(ctx, entityId, keys) : getAttributesAsync(ctx, entityId, keys), + attributes -> putAttributesAndTell(ctx, msg, attributes, mappingsMap), t -> ctx.tellFailure(msg, t), ctx.getDbCallbackExecutor()); } - private ListenableFuture> getAttributesAsync(TbContext ctx, EntityId entityId, List attrProcess) { - ListenableFuture> latest = ctx.getAttributesService().find(ctx.getTenantId(), entityId, SERVER_SCOPE, attrProcess); + private ListenableFuture> getAttributesAsync(TbContext ctx, EntityId entityId, List attrKeys) { + ListenableFuture> latest = ctx.getAttributesService().find(ctx.getTenantId(), entityId, SERVER_SCOPE, attrKeys); return Futures.transform(latest, l -> l.stream().map(i -> (KvEntry) i).collect(Collectors.toList()), MoreExecutors.directExecutor()); } - private ListenableFuture> getLatestTelemetry(TbContext ctx, EntityId entityId, List latestProcess) { - ListenableFuture> latest = ctx.getTimeseriesService().findLatest(ctx.getTenantId(), entityId, latestProcess); + private ListenableFuture> getLatestTelemetry(TbContext ctx, EntityId entityId, List timeseriesKeys) { + ListenableFuture> latest = ctx.getTimeseriesService().findLatest(ctx.getTenantId(), entityId, timeseriesKeys); return Futures.transform(latest, l -> l.stream().map(i -> (KvEntry) i).collect(Collectors.toList()), MoreExecutors.directExecutor()); } - private void putAttributesAndTell(TbContext ctx, TbMsg msg, List attributes) { - Map updConf = new HashMap<>(); - config.getAttrMapping().forEach((key, value) -> { - String processPattern = TbNodeUtils.processPattern(key, msg); - updConf.put(processPattern, value); - }); - + private void putAttributesAndTell(TbContext ctx, TbMsg msg, List attributes, Map map) { attributes.forEach(r -> { - String attrName = updConf.get(r.getKey()); + String attrName = map.get(r.getKey()); msg.getMetaData().putValue(attrName, r.getValueAsString()); }); ctx.tellSuccess(msg); diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/AbstractAttributeNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/AbstractAttributeNodeTest.java index 97e9ddf30b..005b40b4e7 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/AbstractAttributeNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/AbstractAttributeNodeTest.java @@ -19,6 +19,7 @@ import com.datastax.oss.driver.api.core.uuid.Uuids; import com.fasterxml.jackson.databind.ObjectMapper; import com.google.common.collect.Lists; import com.google.common.util.concurrent.Futures; +import org.jetbrains.annotations.NotNull; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.Mock; @@ -59,7 +60,6 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyCollection; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.same; -import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.thingsboard.rule.engine.api.TbRelationTypes.FAILURE; @@ -103,9 +103,6 @@ public abstract class AbstractAttributeNodeTest { void errorThrownIfCannotLoadAttributes(User user) { msg = TbMsg.newMsg("USER", user.getId(), new TbMsgMetaData(), TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); - when(ctx.getUserService()).thenReturn(userService); - when(userService.findUserByIdAsync(any(), eq(user.getId()))).thenReturn(Futures.immediateFuture(user)); - when(ctx.getAttributesService()).thenReturn(attributesService); when(attributesService.find(any(), eq(getEntityId()), eq(SERVER_SCOPE), anyCollection())) .thenThrow(new IllegalStateException("something wrong")); @@ -123,9 +120,6 @@ public abstract class AbstractAttributeNodeTest { msg = TbMsg.newMsg("USER", user.getId(), new TbMsgMetaData(), TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); - when(ctx.getUserService()).thenReturn(userService); - when(userService.findUserByIdAsync(any(), eq(user.getId()))).thenReturn(Futures.immediateFuture(user)); - when(ctx.getAttributesService()).thenReturn(attributesService); when(attributesService.find(any(), eq(getEntityId()), eq(SERVER_SCOPE), anyCollection())) .thenReturn(Futures.immediateFailedFuture(new IllegalStateException("something wrong"))); @@ -142,9 +136,6 @@ public abstract class AbstractAttributeNodeTest { void failedChainUsedIfCustomerCannotBeFound(User user) { msg = TbMsg.newMsg("USER", user.getId(), new TbMsgMetaData(), TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); - when(ctx.getUserService()).thenReturn(userService); - when(userService.findUserByIdAsync(any(), eq(user.getId()))).thenReturn(Futures.immediateFuture(null)); - node.onMsg(ctx, msg); verify(ctx).tellNext(msg, FAILURE); assertTrue(msg.getMetaData().getData().isEmpty()); @@ -158,41 +149,29 @@ public abstract class AbstractAttributeNodeTest { void usersCustomerAttributesFetched(User user) { msg = TbMsg.newMsg("USER", user.getId(), new TbMsgMetaData(metaData), TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); - when(ctx.getUserService()).thenReturn(userService); - when(userService.findUserByIdAsync(any(), eq(user.getId()))).thenReturn(Futures.immediateFuture(user)); - entityAttributeFetched(getEntityId()); } void assetsCustomerAttributesFetched(Asset asset) { msg = TbMsg.newMsg("ASSET", asset.getId(), new TbMsgMetaData(metaData), TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); - when(ctx.getAssetService()).thenReturn(assetService); - when(assetService.findAssetByIdAsync(any(), eq(asset.getId()))).thenReturn(Futures.immediateFuture(asset)); - entityAttributeFetched(getEntityId()); } void deviceCustomerAttributesFetched(Device device) { - msg = TbMsg.newMsg("USER", device.getId(), new TbMsgMetaData(metaData), TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); - - when(ctx.getDeviceService()).thenReturn(deviceService); - when(deviceService.findDeviceByIdAsync(any(), eq(device.getId()))).thenReturn(Futures.immediateFuture(device)); + msg = TbMsg.newMsg("DEVICE", device.getId(), new TbMsgMetaData(metaData), TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); entityAttributeFetched(getEntityId()); } void deviceCustomerTelemetryFetched(Device device) throws TbNodeException { ObjectMapper mapper = JacksonUtil.OBJECT_MAPPER; - TbNodeConfiguration nodeConfiguration = new TbNodeConfiguration(mapper.valueToTree(getTbNodeConfigFotTelemetry())); + TbNodeConfiguration nodeConfiguration = new TbNodeConfiguration(mapper.valueToTree(getTbNodeConfigForTelemetry())); TbEntityGetAttrNode node = getEmptyNode(); node.init(null, nodeConfiguration); - msg = TbMsg.newMsg("USER", device.getId(), new TbMsgMetaData(metaData), TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); - - when(ctx.getDeviceService()).thenReturn(deviceService); - when(deviceService.findDeviceByIdAsync(any(), eq(device.getId()))).thenReturn(Futures.immediateFuture(device)); + msg = TbMsg.newMsg("DEVICE", device.getId(), new TbMsgMetaData(metaData), TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); List timeseries = Lists.newArrayList(new BasicTsKvEntry(1L, new StringDataEntry("temperature", "highest"))); @@ -217,11 +196,40 @@ public abstract class AbstractAttributeNodeTest { assertEquals(msg.getMetaData().getValue("result"), "high"); } - protected abstract TbEntityGetAttrNode getEmptyNode(); + TbGetEntityAttrNodeConfiguration getTbNodeConfig() { + return getConfig(false); + } + + TbGetEntityAttrNodeConfiguration getTbNodeConfigForTelemetry() { + return getConfig(true); + } - abstract T getTbNodeConfig(); + @NotNull + private TbGetEntityAttrNodeConfiguration getConfig(boolean isTelemetry) { + TbGetEntityAttrNodeConfiguration config = new TbGetEntityAttrNodeConfiguration(); + Map conf = new HashMap<>(); + conf.put(keyAttrConf, valueAttrConf); + config.setAttrMapping(conf); + config.setTelemetry(isTelemetry); + return config; + } - abstract T getTbNodeConfigFotTelemetry(); + protected abstract TbEntityGetAttrNode getEmptyNode(); abstract EntityId getEntityId(); + + void mockFindDevice(Device device) { + when(ctx.getDeviceService()).thenReturn(deviceService); + when(deviceService.findDeviceByIdAsync(any(), eq(device.getId()))).thenReturn(Futures.immediateFuture(device)); + } + + void mockFindAsset(Asset asset) { + when(ctx.getAssetService()).thenReturn(assetService); + when(assetService.findAssetByIdAsync(any(), eq(asset.getId()))).thenReturn(Futures.immediateFuture(asset)); + } + + void mockFindUser(User user) { + when(ctx.getUserService()).thenReturn(userService); + when(userService.findUserByIdAsync(any(), eq(user.getId()))).thenReturn(Futures.immediateFuture(user)); + } } diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNodeTest.java index 3ed2e35702..707a204334 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNodeTest.java @@ -16,6 +16,7 @@ package org.thingsboard.rule.engine.metadata; import com.datastax.oss.driver.api.core.uuid.Uuids; +import com.google.common.util.concurrent.Futures; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -29,10 +30,12 @@ import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.UserId; -import java.util.HashMap; -import java.util.Map; import java.util.UUID; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.when; + @RunWith(MockitoJUnitRunner.class) public class TbGetCustomerAttributeNodeTest extends AbstractAttributeNodeTest { User user = new User(); @@ -57,26 +60,6 @@ public class TbGetCustomerAttributeNodeTest extends AbstractAttributeNodeTest { return new TbGetCustomerAttributeNode(); } - @Override - T getTbNodeConfig() { - TbGetEntityAttrNodeConfiguration config = new TbGetEntityAttrNodeConfiguration(); - Map conf = new HashMap<>(); - conf.put(keyAttrConf, valueAttrConf); - config.setAttrMapping(conf); - config.setTelemetry(false); - return (T) config; - } - - @Override - T getTbNodeConfigFotTelemetry() { - TbGetEntityAttrNodeConfiguration config = new TbGetEntityAttrNodeConfiguration(); - Map conf = new HashMap<>(); - conf.put(keyAttrConf, valueAttrConf); - config.setAttrMapping(conf); - config.setTelemetry(true); - return (T) config; - } - @Override EntityId getEntityId() { return customerId; @@ -84,16 +67,20 @@ public class TbGetCustomerAttributeNodeTest extends AbstractAttributeNodeTest { @Test public void errorThrownIfCannotLoadAttributes() { + mockFindUser(user); errorThrownIfCannotLoadAttributes(user); } @Test public void errorThrownIfCannotLoadAttributesAsync() { + mockFindUser(user); errorThrownIfCannotLoadAttributesAsync(user); } @Test public void failedChainUsedIfCustomerCannotBeFound() { + when(ctx.getUserService()).thenReturn(userService); + when(userService.findUserByIdAsync(any(), eq(user.getId()))).thenReturn(Futures.immediateFuture(null)); failedChainUsedIfCustomerCannotBeFound(user); } @@ -104,21 +91,25 @@ public class TbGetCustomerAttributeNodeTest extends AbstractAttributeNodeTest { @Test public void usersCustomerAttributesFetched() { + mockFindUser(user); usersCustomerAttributesFetched(user); } @Test public void assetsCustomerAttributesFetched() { + mockFindAsset(asset); assetsCustomerAttributesFetched(asset); } @Test public void deviceCustomerAttributesFetched() { + mockFindDevice(device); deviceCustomerAttributesFetched(device); } @Test public void deviceCustomerTelemetryFetched() throws TbNodeException { + mockFindDevice(device); deviceCustomerTelemetryFetched(device); } } diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttributeNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttributeNodeTest.java index d2067ca893..4f125a2466 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttributeNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttributeNodeTest.java @@ -16,6 +16,7 @@ package org.thingsboard.rule.engine.metadata; import com.google.common.util.concurrent.Futures; +import org.jetbrains.annotations.NotNull; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -40,7 +41,7 @@ import java.util.UUID; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.when; -@RunWith(MockitoJUnitRunner.Silent.class) +@RunWith(MockitoJUnitRunner.class) public class TbGetRelatedAttributeNodeTest extends AbstractAttributeNodeTest { User user = new User(); Asset asset = new Asset(); @@ -74,25 +75,24 @@ public class TbGetRelatedAttributeNodeTest extends AbstractAttributeNodeTest { } @Override - T getTbNodeConfig() { - TbGetRelatedAttrNodeConfiguration config = new TbGetRelatedAttrNodeConfiguration(); - config = config.defaultConfiguration(); - Map conf = new HashMap<>(); - conf.put(keyAttrConf, valueAttrConf); - config.setAttrMapping(conf); - config.setTelemetry(false); - return (T) config; + TbGetEntityAttrNodeConfiguration getTbNodeConfig() { + return getConfig(false); } @Override - T getTbNodeConfigFotTelemetry() { + TbGetEntityAttrNodeConfiguration getTbNodeConfigForTelemetry() { + return getConfig(true); + } + + @NotNull + private TbGetEntityAttrNodeConfiguration getConfig(boolean isTelemetry) { TbGetRelatedAttrNodeConfiguration config = new TbGetRelatedAttrNodeConfiguration(); config = config.defaultConfiguration(); Map conf = new HashMap<>(); conf.put(keyAttrConf, valueAttrConf); config.setAttrMapping(conf); - config.setTelemetry(true); - return (T) config; + config.setTelemetry(isTelemetry); + return config; } @Override diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetTenantAttributeNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetTenantAttributeNodeTest.java index e297722928..2a5798d1e2 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetTenantAttributeNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetTenantAttributeNodeTest.java @@ -15,6 +15,7 @@ */ package org.thingsboard.rule.engine.metadata; +import com.google.common.util.concurrent.Futures; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -28,10 +29,12 @@ import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.UserId; -import java.util.HashMap; -import java.util.Map; import java.util.UUID; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.when; + @RunWith(MockitoJUnitRunner.class) public class TbGetTenantAttributeNodeTest extends AbstractAttributeNodeTest { @@ -57,26 +60,6 @@ public class TbGetTenantAttributeNodeTest extends AbstractAttributeNodeTest { return new TbGetTenantAttributeNode(); } - @Override - T getTbNodeConfig() { - TbGetEntityAttrNodeConfiguration config = new TbGetEntityAttrNodeConfiguration(); - Map conf = new HashMap<>(); - conf.put(keyAttrConf, valueAttrConf); - config.setAttrMapping(conf); - config.setTelemetry(false); - return (T) config; - } - - @Override - T getTbNodeConfigFotTelemetry() { - TbGetEntityAttrNodeConfiguration config = new TbGetEntityAttrNodeConfiguration(); - Map conf = new HashMap<>(); - conf.put(keyAttrConf, valueAttrConf); - config.setAttrMapping(conf); - config.setTelemetry(true); - return (T) config; - } - @Override EntityId getEntityId() { return tenantId; @@ -84,16 +67,20 @@ public class TbGetTenantAttributeNodeTest extends AbstractAttributeNodeTest { @Test public void errorThrownIfCannotLoadAttributes() { + mockFindUser(user); errorThrownIfCannotLoadAttributes(user); } @Test public void errorThrownIfCannotLoadAttributesAsync() { + mockFindUser(user); errorThrownIfCannotLoadAttributesAsync(user); } @Test public void failedChainUsedIfCustomerCannotBeFound() { + when(ctx.getUserService()).thenReturn(userService); + when(userService.findUserByIdAsync(any(), eq(user.getId()))).thenReturn(Futures.immediateFuture(null)); failedChainUsedIfCustomerCannotBeFound(user); } @@ -104,21 +91,25 @@ public class TbGetTenantAttributeNodeTest extends AbstractAttributeNodeTest { @Test public void usersCustomerAttributesFetched() { + mockFindUser(user); usersCustomerAttributesFetched(user); } @Test public void assetsCustomerAttributesFetched() { + mockFindAsset(asset); assetsCustomerAttributesFetched(asset); } @Test public void deviceCustomerAttributesFetched() { + mockFindDevice(device); deviceCustomerAttributesFetched(device); } @Test public void deviceCustomerTelemetryFetched() throws TbNodeException { + mockFindDevice(device); deviceCustomerTelemetryFetched(device); } } From 2a54196f82f72e5745829eca484bcb25779b5e18 Mon Sep 17 00:00:00 2001 From: nickAS21 <44275303+nickAS21@users.noreply.github.com> Date: Tue, 23 Nov 2021 18:06:28 +0200 Subject: [PATCH 140/432] [3.3.3] Lwm2m bootstrap edit info (#5610) * lwm2m - edit info from bootstrap --- .../LwM2mDefaultBootstrapSessionManager.java | 25 +++++++++---------- .../store/LwM2MBootstrapSecurityStore.java | 8 +----- 2 files changed, 13 insertions(+), 20 deletions(-) diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2mDefaultBootstrapSessionManager.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2mDefaultBootstrapSessionManager.java index 07a41c668e..5c2494ed6a 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2mDefaultBootstrapSessionManager.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2mDefaultBootstrapSessionManager.java @@ -36,6 +36,7 @@ import org.thingsboard.server.common.transport.TransportService; import org.thingsboard.server.transport.lwm2m.bootstrap.store.LwM2MBootstrapConfigStoreTaskProvider; import org.thingsboard.server.transport.lwm2m.bootstrap.store.LwM2MBootstrapSecurityStore; import org.thingsboard.server.transport.lwm2m.server.client.LwM2MAuthException; + import java.util.ArrayList; import java.util.Iterator; import java.util.List; @@ -98,8 +99,7 @@ public class LwM2mDefaultBootstrapSessionManager extends DefaultBootstrapSession DefaultBootstrapSession session = new DefaultBootstrapSession(request, clientIdentity, authorized); if (authorized) { this.sendLogs (request.getEndpointName(), - String.format("%s: Bootstrap session started endpoint: %s, session: %s ", LOG_LWM2M_INFO, request.getEndpointName(), - session.toString())); + String.format("%s: Bootstrap session started...", LOG_LWM2M_INFO, request.getEndpointName())); } return session; } @@ -164,8 +164,8 @@ public class LwM2mDefaultBootstrapSessionManager extends DefaultBootstrapSession // store response DefaultBootstrapSession session = (DefaultBootstrapSession) bsSession; session.getResponses().add(response); - String msg = String.format("%s: %s %s receives success response %s for %s : %s", LOG_LWM2M_INFO, - request.getClass().getSimpleName(), request.getPath().toString(), response.toString(), bsSession.toString(), request.toString()); + String msg = String.format("%s: receives success response for: %s %s %s", LOG_LWM2M_INFO, + request.getClass().getSimpleName(), request.getPath().toString(), response.toString()); this.sendLogs(bsSession.getEndpoint(), msg); // on success for NOT bootstrap finish request we send next request @@ -173,8 +173,7 @@ public class LwM2mDefaultBootstrapSessionManager extends DefaultBootstrapSession } else { // on success for bootstrap finish request we stop the session this.sendLogs(bsSession.getEndpoint(), - String.format("%s: %s receives success response for bootstrap finish request and stop the session: %s", LOG_LWM2M_INFO, - request.getClass().getSimpleName(), bsSession.toString())); + String.format("%s: receives success response for bootstrap finish.", LOG_LWM2M_INFO)); return BootstrapPolicy.finished(); } } @@ -187,9 +186,9 @@ public class LwM2mDefaultBootstrapSessionManager extends DefaultBootstrapSession DefaultBootstrapSession session = (DefaultBootstrapSession) bsSession; session.getResponses().add(response); this.sendLogs (bsSession.getEndpoint(), - String.format("%s: %s %s receives error response %s for %s : %s", LOG_LWM2M_INFO, + String.format("%s: %s %s receives error response %s ", LOG_LWM2M_INFO, request.getClass().getSimpleName(), - request.getPath().toString(), response.toString(), bsSession.toString(), request.toString())); + request.getPath().toString(), response.toString())); // on response error for NOT bootstrap finish request we continue any sending next request return BootstrapPolicy.continueWith(nextRequest(bsSession)); } else { @@ -204,20 +203,20 @@ public class LwM2mDefaultBootstrapSessionManager extends DefaultBootstrapSession public BootstrapPolicy onRequestFailure(BootstrapSession bsSession, BootstrapDownlinkRequest request, Throwable cause) { this.sendLogs(bsSession.getEndpoint(), - String.format("%s: %s %s failed because of %s for %s : %s", LOG_LWM2M_INFO, request.getClass().getSimpleName(), - request.getPath().toString(), cause.toString(), bsSession.toString(), request.toString())); + String.format("%s: %s %s failed because of %s", LOG_LWM2M_ERROR, request.getClass().getSimpleName(), + request.getPath().toString(), cause.toString())); return BootstrapPolicy.failed(); } @Override public void end(BootstrapSession bsSession) { - this.sendLogs(bsSession.getEndpoint(), String.format("%s: Bootstrap session finished : %s", LOG_LWM2M_INFO, bsSession.toString())); + this.sendLogs(bsSession.getEndpoint(), String.format("%s: Bootstrap session finished.", LOG_LWM2M_INFO)); } @Override public void failed(BootstrapSession bsSession, BootstrapFailureCause cause) { - this.sendLogs(bsSession.getEndpoint(), String.format("%s: Bootstrap session failed by %s: %s", LOG_LWM2M_INFO, - cause.toString(), bsSession.toString())); + this.sendLogs(bsSession.getEndpoint(), String.format("%s: Bootstrap session failed because of %s", LOG_LWM2M_ERROR, + cause.toString())); } private void sendLogs(String endpointName, String logMsg) { diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MBootstrapSecurityStore.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MBootstrapSecurityStore.java index 81d2007c4b..5c1669fcf3 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MBootstrapSecurityStore.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MBootstrapSecurityStore.java @@ -16,7 +16,6 @@ package org.thingsboard.server.transport.lwm2m.bootstrap.store; import lombok.extern.slf4j.Slf4j; -import org.eclipse.leshan.core.SecurityMode; import org.eclipse.leshan.server.bootstrap.BootstrapConfig; import org.eclipse.leshan.server.bootstrap.EditableBootstrapConfigStore; import org.eclipse.leshan.server.bootstrap.InvalidConfigurationException; @@ -34,8 +33,6 @@ import org.thingsboard.server.transport.lwm2m.server.LwM2mSessionMsgListener; import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportContext; import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportServerHelper; -import java.io.IOException; -import java.security.GeneralSecurityException; import java.util.Collections; import java.util.Iterator; import java.util.Map; @@ -45,7 +42,6 @@ import java.util.concurrent.atomic.AtomicBoolean; import static org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mTypeServer.BOOTSTRAP; import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.LOG_LWM2M_ERROR; -import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.LOG_LWM2M_INFO; import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.LOG_LWM2M_TELEMETRY; @Slf4j @@ -135,13 +131,11 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore { bsSessions.put(store.getEndpoint(), sessionInfo); context.getTransportService().registerAsyncSession(sessionInfo, new LwM2mSessionMsgListener(null, null, null, sessionInfo, context.getTransportService())); if (this.getValidatedSecurityMode(lwM2MBootstrapConfig)) { - String logMsg = String.format("%s: getParametersBootstrap: %s Access connect client with bootstrap server.", LOG_LWM2M_INFO, store.getEndpoint()); - helper.sendParametersOnThingsboardTelemetry(helper.getKvStringtoThingsboard(LOG_LWM2M_TELEMETRY, logMsg), sessionInfo); return lwM2MBootstrapConfig; } else { log.error(" [{}] Different values SecurityMode between of client and profile.", store.getEndpoint()); log.error("{} getParametersBootstrap: [{}] Different values SecurityMode between of client and profile.", LOG_LWM2M_ERROR, store.getEndpoint()); - String logMsg = String.format("%s: getParametersBootstrap: %s Different values SecurityMode between of client and profile.", LOG_LWM2M_ERROR, store.getEndpoint()); + String logMsg = String.format("%s: Different values SecurityMode between of client and profile.", LOG_LWM2M_ERROR); helper.sendParametersOnThingsboardTelemetry(helper.getKvStringtoThingsboard(LOG_LWM2M_TELEMETRY, logMsg), sessionInfo); return null; } From 3ffd62f8443aed8e02938ba360aa50e57cdd583e Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Wed, 24 Nov 2021 09:36:14 +0200 Subject: [PATCH 141/432] Fix corner case when access token matches user name in credentials --- .../BasicCredentialsValidationResult.java | 18 ++ .../transport/DefaultTransportApiService.java | 95 +++++--- .../transport/TransportSqlTestSuite.java | 1 + .../credentials/BasicMqttCredentialsTest.java | 226 ++++++++++++++++++ .../dao/device/DeviceCredentialsService.java | 3 + 5 files changed, 306 insertions(+), 37 deletions(-) create mode 100644 application/src/main/java/org/thingsboard/server/service/transport/BasicCredentialsValidationResult.java create mode 100644 application/src/test/java/org/thingsboard/server/transport/mqtt/credentials/BasicMqttCredentialsTest.java diff --git a/application/src/main/java/org/thingsboard/server/service/transport/BasicCredentialsValidationResult.java b/application/src/main/java/org/thingsboard/server/service/transport/BasicCredentialsValidationResult.java new file mode 100644 index 0000000000..56d7b776e8 --- /dev/null +++ b/application/src/main/java/org/thingsboard/server/service/transport/BasicCredentialsValidationResult.java @@ -0,0 +1,18 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.service.transport; + +enum BasicCredentialsValidationResult {HASH_MISMATCH, PASSWORD_MISMATCH, VALID} diff --git a/application/src/main/java/org/thingsboard/server/service/transport/DefaultTransportApiService.java b/application/src/main/java/org/thingsboard/server/service/transport/DefaultTransportApiService.java index dc5f6c436d..1cefefd5d1 100644 --- a/application/src/main/java/org/thingsboard/server/service/transport/DefaultTransportApiService.java +++ b/application/src/main/java/org/thingsboard/server/service/transport/DefaultTransportApiService.java @@ -25,7 +25,6 @@ import com.google.protobuf.ByteString; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; -import org.springframework.util.StringUtils; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.cache.ota.OtaPackageDataCache; import org.thingsboard.server.common.data.ApiUsageState; @@ -37,6 +36,7 @@ import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.OtaPackage; import org.thingsboard.server.common.data.OtaPackageInfo; import org.thingsboard.server.common.data.ResourceType; +import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.data.TbResource; import org.thingsboard.server.common.data.TenantProfile; import org.thingsboard.server.common.data.device.credentials.BasicMqttCredentials; @@ -107,6 +107,9 @@ import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import java.util.stream.Collectors; +import static org.thingsboard.server.service.transport.BasicCredentialsValidationResult.PASSWORD_MISMATCH; +import static org.thingsboard.server.service.transport.BasicCredentialsValidationResult.VALID; + /** * Created by ashvayka on 05.10.18. */ @@ -181,71 +184,89 @@ public class DefaultTransportApiService implements TransportApiService { //TODO: Make async and enable caching DeviceCredentials credentials = deviceCredentialsService.findDeviceCredentialsByCredentialsId(credentialsId); if (credentials != null && credentials.getCredentialsType() == credentialsType) { - return getDeviceInfo(credentials.getDeviceId(), credentials); + return getDeviceInfo(credentials); } else { return getEmptyTransportApiResponseFuture(); } } private ListenableFuture validateCredentials(TransportProtos.ValidateBasicMqttCredRequestMsg mqtt) { - DeviceCredentials credentials = null; - if (!StringUtils.isEmpty(mqtt.getUserName())) { - credentials = deviceCredentialsService.findDeviceCredentialsByCredentialsId(mqtt.getUserName()); + DeviceCredentials credentials; + if (StringUtils.isEmpty(mqtt.getUserName())) { + credentials = checkMqttCredentials(mqtt, EncryptionUtil.getSha3Hash(mqtt.getClientId())); if (credentials != null) { - if (credentials.getCredentialsType() == DeviceCredentialsType.ACCESS_TOKEN) { - return getDeviceInfo(credentials.getDeviceId(), credentials); - } else if (credentials.getCredentialsType() == DeviceCredentialsType.MQTT_BASIC) { - if (!checkMqttCredentials(mqtt, credentials)) { - credentials = null; - } - } else { + return getDeviceInfo(credentials); + } else { + return getEmptyTransportApiResponseFuture(); + } + } else { + credentials = deviceCredentialsService.findDeviceCredentialsByCredentialsId( + EncryptionUtil.getSha3Hash("|", mqtt.getClientId(), mqtt.getUserName())); + if (checkIsMqttCredentials(credentials)) { + var validationResult = validateMqttCredentials(mqtt, credentials); + if (VALID.equals(validationResult)) { + return getDeviceInfo(credentials); + } else if (PASSWORD_MISMATCH.equals(validationResult)) { return getEmptyTransportApiResponseFuture(); + } else { + return validateUserNameCredentials(mqtt); } + } else { + return validateUserNameCredentials(mqtt); } - if (credentials == null) { - credentials = checkMqttCredentials(mqtt, EncryptionUtil.getSha3Hash("|", mqtt.getClientId(), mqtt.getUserName())); - } - } - if (credentials == null) { - credentials = checkMqttCredentials(mqtt, EncryptionUtil.getSha3Hash(mqtt.getClientId())); } + } + + private ListenableFuture validateUserNameCredentials(TransportProtos.ValidateBasicMqttCredRequestMsg mqtt) { + DeviceCredentials credentials = deviceCredentialsService.findDeviceCredentialsByCredentialsId(mqtt.getUserName()); if (credentials != null) { - return getDeviceInfo(credentials.getDeviceId(), credentials); - } else { - return getEmptyTransportApiResponseFuture(); + switch (credentials.getCredentialsType()) { + case ACCESS_TOKEN: + return getDeviceInfo(credentials); + case MQTT_BASIC: + if (VALID.equals(validateMqttCredentials(mqtt, credentials))) { + return getDeviceInfo(credentials); + } else { + return getEmptyTransportApiResponseFuture(); + } + } } + return getEmptyTransportApiResponseFuture(); + } + + private static boolean checkIsMqttCredentials(DeviceCredentials credentials) { + return credentials != null && DeviceCredentialsType.MQTT_BASIC.equals(credentials.getCredentialsType()); } private DeviceCredentials checkMqttCredentials(TransportProtos.ValidateBasicMqttCredRequestMsg clientCred, String credId) { - DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByCredentialsId(credId); + return checkMqttCredentials(clientCred, deviceCredentialsService.findDeviceCredentialsByCredentialsId(credId)); + } + + private DeviceCredentials checkMqttCredentials(TransportProtos.ValidateBasicMqttCredRequestMsg clientCred, DeviceCredentials deviceCredentials) { if (deviceCredentials != null && deviceCredentials.getCredentialsType() == DeviceCredentialsType.MQTT_BASIC) { - if (!checkMqttCredentials(clientCred, deviceCredentials)) { - return null; - } else { + if (VALID.equals(validateMqttCredentials(clientCred, deviceCredentials))) { return deviceCredentials; } } return null; } - private boolean checkMqttCredentials(TransportProtos.ValidateBasicMqttCredRequestMsg clientCred, DeviceCredentials deviceCredentials) { + private BasicCredentialsValidationResult validateMqttCredentials(TransportProtos.ValidateBasicMqttCredRequestMsg clientCred, DeviceCredentials deviceCredentials) { BasicMqttCredentials dbCred = JacksonUtil.fromString(deviceCredentials.getCredentialsValue(), BasicMqttCredentials.class); if (!StringUtils.isEmpty(dbCred.getClientId()) && !dbCred.getClientId().equals(clientCred.getClientId())) { - return false; + return BasicCredentialsValidationResult.HASH_MISMATCH; } if (!StringUtils.isEmpty(dbCred.getUserName()) && !dbCred.getUserName().equals(clientCred.getUserName())) { - return false; + return BasicCredentialsValidationResult.HASH_MISMATCH; } if (!StringUtils.isEmpty(dbCred.getPassword())) { if (StringUtils.isEmpty(clientCred.getPassword())) { - return false; + return BasicCredentialsValidationResult.PASSWORD_MISMATCH; } else { - if (!dbCred.getPassword().equals(clientCred.getPassword())) { - return false; - } + return dbCred.getPassword().equals(clientCred.getPassword()) ? VALID : BasicCredentialsValidationResult.PASSWORD_MISMATCH; } } - return true; + return VALID; } private ListenableFuture handle(GetOrCreateDeviceFromGatewayRequestMsg requestMsg) { @@ -437,10 +458,10 @@ public class DefaultTransportApiService implements TransportApiService { .build()); } - private ListenableFuture getDeviceInfo(DeviceId deviceId, DeviceCredentials credentials) { - return Futures.transform(deviceService.findDeviceByIdAsync(TenantId.SYS_TENANT_ID, deviceId), device -> { + private ListenableFuture getDeviceInfo(DeviceCredentials credentials) { + return Futures.transform(deviceService.findDeviceByIdAsync(TenantId.SYS_TENANT_ID, credentials.getDeviceId()), device -> { if (device == null) { - log.trace("[{}] Failed to lookup device by id", deviceId); + log.trace("[{}] Failed to lookup device by id", credentials.getDeviceId()); return getEmptyTransportApiResponse(); } try { @@ -458,7 +479,7 @@ public class DefaultTransportApiService implements TransportApiService { return TransportApiResponseMsg.newBuilder() .setValidateCredResponseMsg(builder.build()).build(); } catch (JsonProcessingException e) { - log.warn("[{}] Failed to lookup device by id", deviceId, e); + log.warn("[{}] Failed to lookup device by id", credentials.getDeviceId(), e); return getEmptyTransportApiResponse(); } }, MoreExecutors.directExecutor()); diff --git a/application/src/test/java/org/thingsboard/server/transport/TransportSqlTestSuite.java b/application/src/test/java/org/thingsboard/server/transport/TransportSqlTestSuite.java index 0fa04d0611..dc5f5917dc 100644 --- a/application/src/test/java/org/thingsboard/server/transport/TransportSqlTestSuite.java +++ b/application/src/test/java/org/thingsboard/server/transport/TransportSqlTestSuite.java @@ -33,6 +33,7 @@ import java.util.Arrays; "org.thingsboard.server.transport.*.attributes.request.sql.*Test", "org.thingsboard.server.transport.*.claim.sql.*Test", "org.thingsboard.server.transport.*.provision.sql.*Test", + "org.thingsboard.server.transport.*.credentials.*Test", "org.thingsboard.server.transport.lwm2m.sql.*Test" }) public class TransportSqlTestSuite { diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/credentials/BasicMqttCredentialsTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/credentials/BasicMqttCredentialsTest.java new file mode 100644 index 0000000000..32ae17e94d --- /dev/null +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/credentials/BasicMqttCredentialsTest.java @@ -0,0 +1,226 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.transport.mqtt.credentials; + +import com.fasterxml.jackson.core.type.TypeReference; +import org.apache.commons.lang3.RandomStringUtils; +import org.eclipse.paho.client.mqttv3.MqttAsyncClient; +import org.eclipse.paho.client.mqttv3.MqttConnectOptions; +import org.eclipse.paho.client.mqttv3.MqttException; +import org.eclipse.paho.client.mqttv3.MqttSecurityException; +import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.thingsboard.common.util.JacksonUtil; +import org.thingsboard.server.common.data.Device; +import org.thingsboard.server.common.data.StringUtils; +import org.thingsboard.server.common.data.Tenant; +import org.thingsboard.server.common.data.User; +import org.thingsboard.server.common.data.device.credentials.BasicMqttCredentials; +import org.thingsboard.server.common.data.device.profile.MqttTopics; +import org.thingsboard.server.common.data.security.Authority; +import org.thingsboard.server.common.data.security.DeviceCredentials; +import org.thingsboard.server.common.data.security.DeviceCredentialsType; +import org.thingsboard.server.dao.service.DaoSqlTest; +import org.thingsboard.server.transport.mqtt.AbstractMqttIntegrationTest; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@DaoSqlTest +public class BasicMqttCredentialsTest extends AbstractMqttIntegrationTest { + + public static final String CLIENT_ID = "ClientId"; + public static final String USER_NAME1 = "UserName1"; + public static final String USER_NAME2 = "UserName2"; + public static final String USER_NAME3 = "UserName3"; + public static final String PASSWORD = "secret"; + + private Device clientIdDevice; + private Device clientIdAndUserNameDevice1; + private Device clientIdAndUserNameAndPasswordDevice2; + private Device clientIdAndUserNameAndPasswordDevice3; + private Device accessTokenDevice; + private Device accessToken2Device; + + + @Before + public void before() throws Exception { + loginSysAdmin(); + + Tenant tenant = new Tenant(); + tenant.setTitle("My tenant"); + savedTenant = doPost("/api/tenant", tenant, Tenant.class); + Assert.assertNotNull(savedTenant); + + tenantAdmin = new User(); + tenantAdmin.setAuthority(Authority.TENANT_ADMIN); + tenantAdmin.setTenantId(savedTenant.getId()); + tenantAdmin.setEmail("tenant" + atomicInteger.getAndIncrement() + "@thingsboard.org"); + tenantAdmin.setFirstName("Joe"); + tenantAdmin.setLastName("Downs"); + + tenantAdmin = createUserAndLogin(tenantAdmin, "testPassword1"); + + BasicMqttCredentials credValue = new BasicMqttCredentials(); + credValue.setClientId(CLIENT_ID); + clientIdDevice = createDevice("clientIdDevice", credValue); + + credValue = new BasicMqttCredentials(); + credValue.setClientId(CLIENT_ID); + credValue.setUserName(USER_NAME1); + clientIdAndUserNameDevice1 = createDevice("clientIdAndUserNameDevice", credValue); + + credValue = new BasicMqttCredentials(); + credValue.setClientId(CLIENT_ID); + credValue.setUserName(USER_NAME2); + credValue.setPassword(PASSWORD); + clientIdAndUserNameAndPasswordDevice2 = createDevice("clientIdAndUserNameAndPasswordDevice", credValue); + + credValue = new BasicMqttCredentials(); + credValue.setClientId(CLIENT_ID); + credValue.setUserName(USER_NAME3); + credValue.setPassword(PASSWORD); + clientIdAndUserNameAndPasswordDevice3 = createDevice("clientIdAndUserNameAndPasswordDevice2", credValue); + + accessTokenDevice = createDevice("accessTokenDevice", USER_NAME1); + accessToken2Device = createDevice("accessToken2Device", USER_NAME2); + } + + @Test + public void testCorrectCredentials() throws Exception { + // Check that correct devices receive telemetry + testTelemetryIsDelivered(accessTokenDevice, getMqttAsyncClient(null, USER_NAME1, null)); + testTelemetryIsDelivered(clientIdDevice, getMqttAsyncClient(CLIENT_ID, null, null)); + testTelemetryIsDelivered(clientIdAndUserNameDevice1, getMqttAsyncClient(CLIENT_ID, USER_NAME1, null)); + testTelemetryIsDelivered(clientIdAndUserNameAndPasswordDevice2, getMqttAsyncClient(CLIENT_ID, USER_NAME2, PASSWORD)); + + // Also correct. Random clientId and password, but matches access token + testTelemetryIsDelivered(accessToken2Device, getMqttAsyncClient(RandomStringUtils.randomAlphanumeric(10), USER_NAME2, RandomStringUtils.randomAlphanumeric(10))); + } + + @Test(expected = MqttSecurityException.class) + public void testCorrectClientIdAndUserNameButWrongPassword() throws Exception { + // Not correct. Correct clientId and username, but wrong password + testTelemetryIsNotDelivered(clientIdAndUserNameAndPasswordDevice3, getMqttAsyncClient(CLIENT_ID, USER_NAME3, "WRONG PASSWORD")); + } + + private void testTelemetryIsDelivered(Device device, MqttAsyncClient client) throws Exception { + testTelemetryIsDelivered(device, client, true); + } + + private void testTelemetryIsNotDelivered(Device device, MqttAsyncClient client) throws Exception { + testTelemetryIsDelivered(device, client, false); + } + + private void testTelemetryIsDelivered(Device device, MqttAsyncClient client, boolean ok) throws Exception { + String randomKey = RandomStringUtils.randomAlphanumeric(10); + List expectedKeys = Arrays.asList(randomKey); + publishMqttMsg(client, JacksonUtil.toString(JacksonUtil.newObjectNode().put(randomKey, true)).getBytes(), MqttTopics.DEVICE_TELEMETRY_TOPIC); + + String deviceId = device.getId().getId().toString(); + + long start = System.currentTimeMillis(); + long end = System.currentTimeMillis() + 5000; + + List actualKeys = null; + while (start <= end) { + actualKeys = doGetAsyncTyped("/api/plugins/telemetry/DEVICE/" + deviceId + "/keys/timeseries", new TypeReference<>() { + }); + if (actualKeys.size() == expectedKeys.size()) { + break; + } + Thread.sleep(100); + start += 100; + } + if (ok) { + assertNotNull(actualKeys); + + Set actualKeySet = new HashSet<>(actualKeys); + Set expectedKeySet = new HashSet<>(expectedKeys); + + assertEquals(expectedKeySet, actualKeySet); + } else { + assertNull(actualKeys); + } + client.disconnect().waitForCompletion(); + } + + @After + public void after() throws Exception { + processAfterTest(); + } + + protected MqttAsyncClient getMqttAsyncClient(String clientId, String username, String password) throws MqttException { + if (StringUtils.isEmpty(clientId)) { + clientId = MqttAsyncClient.generateClientId(); + } + MqttAsyncClient client = new MqttAsyncClient(MQTT_URL, clientId, new MemoryPersistence()); + + MqttConnectOptions options = new MqttConnectOptions(); + if (StringUtils.isNotEmpty(username)) { + options.setUserName(username); + } + if (StringUtils.isNotEmpty(password)) { + options.setPassword(password.toCharArray()); + } + client.connect(options).waitForCompletion(); + return client; + } + + private Device createDevice(String deviceName, BasicMqttCredentials clientIdCredValue) throws Exception { + Device device = new Device(); + device.setName(deviceName); + device.setType("default"); + + device = doPost("/api/device", device, Device.class); + + DeviceCredentials clientIdCred = + doGet("/api/device/" + device.getId().getId().toString() + "/credentials", DeviceCredentials.class); + + clientIdCred.setCredentialsType(DeviceCredentialsType.MQTT_BASIC); + + + clientIdCred.setCredentialsValue(JacksonUtil.toString(clientIdCredValue)); + doPost("/api/device/credentials", clientIdCred).andExpect(status().isOk()); + return device; + } + + private Device createDevice(String deviceName, String accessToken) throws Exception { + Device device = new Device(); + device.setName(deviceName); + device.setType("default"); + + device = doPost("/api/device", device, Device.class); + + DeviceCredentials clientIdCred = + doGet("/api/device/" + device.getId().getId().toString() + "/credentials", DeviceCredentials.class); + + clientIdCred.setCredentialsType(DeviceCredentialsType.ACCESS_TOKEN); + clientIdCred.setCredentialsId(accessToken); + doPost("/api/device/credentials", clientIdCred).andExpect(status().isOk()); + return device; + } +} diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsService.java index 29572bf51a..9afc735213 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsService.java @@ -19,6 +19,8 @@ import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.security.DeviceCredentials; +import java.util.List; + public interface DeviceCredentialsService { DeviceCredentials findDeviceCredentialsByDeviceId(TenantId tenantId, DeviceId deviceId); @@ -32,4 +34,5 @@ public interface DeviceCredentialsService { void formatCredentials(DeviceCredentials deviceCredentials); void deleteDeviceCredentials(TenantId tenantId, DeviceCredentials deviceCredentials); + } From 6d006d16c7522d8c59e1f51f4627c7f47f98430d Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Wed, 24 Nov 2021 10:38:45 +0200 Subject: [PATCH 142/432] Improved rate limits message for MQTT session events --- .../server/common/msg/tools/TbRateLimitsException.java | 1 + .../thingsboard/server/transport/mqtt/MqttTransportHandler.java | 2 +- .../transport/limits/DefaultTransportRateLimitService.java | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/common/message/src/main/java/org/thingsboard/server/common/msg/tools/TbRateLimitsException.java b/common/message/src/main/java/org/thingsboard/server/common/msg/tools/TbRateLimitsException.java index 89b2c7b527..35d5ad63c4 100644 --- a/common/message/src/main/java/org/thingsboard/server/common/msg/tools/TbRateLimitsException.java +++ b/common/message/src/main/java/org/thingsboard/server/common/msg/tools/TbRateLimitsException.java @@ -26,6 +26,7 @@ public class TbRateLimitsException extends RuntimeException { private final EntityType entityType; public TbRateLimitsException(EntityType entityType) { + super(entityType.name() + " rate limits reached!"); this.entityType = entityType; } } diff --git a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportHandler.java b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportHandler.java index 61638052c0..693b47d42f 100644 --- a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportHandler.java +++ b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportHandler.java @@ -951,7 +951,7 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement @Override public void onError(Throwable e) { if (e instanceof TbRateLimitsException) { - log.trace("[{}] Failed to submit session event", sessionId, e); + log.trace("[{}] Failed to submit session event: {}", sessionId, e.getMessage()); } else { log.warn("[{}] Failed to submit session event", sessionId, e); } diff --git a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/limits/DefaultTransportRateLimitService.java b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/limits/DefaultTransportRateLimitService.java index e7d6cddc3c..5ee4064466 100644 --- a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/limits/DefaultTransportRateLimitService.java +++ b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/limits/DefaultTransportRateLimitService.java @@ -57,7 +57,7 @@ public class DefaultTransportRateLimitService implements TransportRateLimitServi @Override public EntityType checkLimits(TenantId tenantId, DeviceId deviceId, int dataPoints) { if (!tenantAllowed.getOrDefault(tenantId, Boolean.TRUE)) { - return EntityType.TENANT; + return EntityType.API_USAGE_STATE; } if (!checkEntityRateLimit(dataPoints, getTenantRateLimits(tenantId))) { return EntityType.TENANT; From 1c81f227b511aa5d5325b2ff537748c23d49d2bf Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Wed, 24 Nov 2021 11:19:58 +0200 Subject: [PATCH 143/432] Correct test class name according to mask in pom.xml --- .../org/thingsboard/server/transport/TransportSqlTestSuite.java | 2 +- .../mqtt/credentials/{ => sql}/BasicMqttCredentialsTest.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename application/src/test/java/org/thingsboard/server/transport/mqtt/credentials/{ => sql}/BasicMqttCredentialsTest.java (99%) diff --git a/application/src/test/java/org/thingsboard/server/transport/TransportSqlTestSuite.java b/application/src/test/java/org/thingsboard/server/transport/TransportSqlTestSuite.java index dc5f5917dc..8df7f22867 100644 --- a/application/src/test/java/org/thingsboard/server/transport/TransportSqlTestSuite.java +++ b/application/src/test/java/org/thingsboard/server/transport/TransportSqlTestSuite.java @@ -33,7 +33,7 @@ import java.util.Arrays; "org.thingsboard.server.transport.*.attributes.request.sql.*Test", "org.thingsboard.server.transport.*.claim.sql.*Test", "org.thingsboard.server.transport.*.provision.sql.*Test", - "org.thingsboard.server.transport.*.credentials.*Test", + "org.thingsboard.server.transport.*.credentials.sql.*Test", "org.thingsboard.server.transport.lwm2m.sql.*Test" }) public class TransportSqlTestSuite { diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/credentials/BasicMqttCredentialsTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/credentials/sql/BasicMqttCredentialsTest.java similarity index 99% rename from application/src/test/java/org/thingsboard/server/transport/mqtt/credentials/BasicMqttCredentialsTest.java rename to application/src/test/java/org/thingsboard/server/transport/mqtt/credentials/sql/BasicMqttCredentialsTest.java index 32ae17e94d..6bb8949f73 100644 --- a/application/src/test/java/org/thingsboard/server/transport/mqtt/credentials/BasicMqttCredentialsTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/credentials/sql/BasicMqttCredentialsTest.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.transport.mqtt.credentials; +package org.thingsboard.server.transport.mqtt.credentials.sql; import com.fasterxml.jackson.core.type.TypeReference; import org.apache.commons.lang3.RandomStringUtils; From 7187ecfdb106f273d19e270129ac304e85dc5c85 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Wed, 24 Nov 2021 12:24:27 +0200 Subject: [PATCH 144/432] Version set to 3.3.3-SNAPSHOT --- application/pom.xml | 2 +- common/actor/pom.xml | 2 +- common/cache/pom.xml | 2 +- common/cluster-api/pom.xml | 2 +- common/coap-server/pom.xml | 2 +- common/dao-api/pom.xml | 2 +- common/data/pom.xml | 2 +- common/edge-api/pom.xml | 2 +- common/message/pom.xml | 2 +- common/pom.xml | 2 +- common/queue/pom.xml | 2 +- common/stats/pom.xml | 2 +- common/transport/coap/pom.xml | 2 +- common/transport/http/pom.xml | 2 +- common/transport/lwm2m/pom.xml | 2 +- common/transport/mqtt/pom.xml | 2 +- common/transport/pom.xml | 2 +- common/transport/snmp/pom.xml | 2 +- common/transport/transport-api/pom.xml | 2 +- common/util/pom.xml | 2 +- dao/pom.xml | 2 +- msa/black-box-tests/pom.xml | 2 +- msa/js-executor/pom.xml | 2 +- msa/pom.xml | 2 +- msa/tb-node/pom.xml | 2 +- msa/tb/pom.xml | 2 +- msa/transport/coap/pom.xml | 2 +- msa/transport/http/pom.xml | 2 +- msa/transport/lwm2m/pom.xml | 2 +- msa/transport/mqtt/pom.xml | 2 +- msa/transport/pom.xml | 2 +- msa/transport/snmp/pom.xml | 2 +- msa/web-ui/pom.xml | 2 +- netty-mqtt/pom.xml | 4 ++-- pom.xml | 2 +- rest-client/pom.xml | 2 +- rule-engine/pom.xml | 2 +- rule-engine/rule-engine-api/pom.xml | 2 +- rule-engine/rule-engine-components/pom.xml | 2 +- tools/pom.xml | 2 +- transport/coap/pom.xml | 2 +- transport/http/pom.xml | 2 +- transport/lwm2m/pom.xml | 2 +- transport/mqtt/pom.xml | 2 +- transport/pom.xml | 2 +- transport/snmp/pom.xml | 2 +- ui-ngx/pom.xml | 2 +- 47 files changed, 48 insertions(+), 48 deletions(-) diff --git a/application/pom.xml b/application/pom.xml index cc3bcef183..beb931d9b0 100644 --- a/application/pom.xml +++ b/application/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT thingsboard application diff --git a/common/actor/pom.xml b/common/actor/pom.xml index 90e7bf22d0..16bd96eedb 100644 --- a/common/actor/pom.xml +++ b/common/actor/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT common org.thingsboard.common diff --git a/common/cache/pom.xml b/common/cache/pom.xml index 1637621273..f5bf91c9f0 100644 --- a/common/cache/pom.xml +++ b/common/cache/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT common org.thingsboard.common diff --git a/common/cluster-api/pom.xml b/common/cluster-api/pom.xml index 4c59e022d4..6a337c414d 100644 --- a/common/cluster-api/pom.xml +++ b/common/cluster-api/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT common org.thingsboard.common diff --git a/common/coap-server/pom.xml b/common/coap-server/pom.xml index 945556c188..a8762a81d2 100644 --- a/common/coap-server/pom.xml +++ b/common/coap-server/pom.xml @@ -22,7 +22,7 @@ 4.0.0 org.thingsboard - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT common org.thingsboard.common diff --git a/common/dao-api/pom.xml b/common/dao-api/pom.xml index b5d26b8781..f861d2fb63 100644 --- a/common/dao-api/pom.xml +++ b/common/dao-api/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT common org.thingsboard.common diff --git a/common/data/pom.xml b/common/data/pom.xml index 1b5c78bcd6..80be41e6a0 100644 --- a/common/data/pom.xml +++ b/common/data/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT common org.thingsboard.common diff --git a/common/edge-api/pom.xml b/common/edge-api/pom.xml index 4223b92d70..482e9d77d8 100644 --- a/common/edge-api/pom.xml +++ b/common/edge-api/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT common org.thingsboard.common diff --git a/common/message/pom.xml b/common/message/pom.xml index 1916aeb254..92c216d7b0 100644 --- a/common/message/pom.xml +++ b/common/message/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT common org.thingsboard.common diff --git a/common/pom.xml b/common/pom.xml index 233046824d..b318d57a4e 100644 --- a/common/pom.xml +++ b/common/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT thingsboard common diff --git a/common/queue/pom.xml b/common/queue/pom.xml index 41937ac079..a43e5c0188 100644 --- a/common/queue/pom.xml +++ b/common/queue/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT common org.thingsboard.common diff --git a/common/stats/pom.xml b/common/stats/pom.xml index 8501fea19a..2af921b251 100644 --- a/common/stats/pom.xml +++ b/common/stats/pom.xml @@ -22,7 +22,7 @@ 4.0.0 org.thingsboard - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT common org.thingsboard.common diff --git a/common/transport/coap/pom.xml b/common/transport/coap/pom.xml index a1e1aaa2b0..26f1f45a0f 100644 --- a/common/transport/coap/pom.xml +++ b/common/transport/coap/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard.common - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT transport org.thingsboard.common.transport diff --git a/common/transport/http/pom.xml b/common/transport/http/pom.xml index 24e3ce2337..2164a5c58e 100644 --- a/common/transport/http/pom.xml +++ b/common/transport/http/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard.common - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT transport org.thingsboard.common.transport diff --git a/common/transport/lwm2m/pom.xml b/common/transport/lwm2m/pom.xml index 6ae5747501..33e7138e33 100644 --- a/common/transport/lwm2m/pom.xml +++ b/common/transport/lwm2m/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard.common - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT transport org.thingsboard.common.transport diff --git a/common/transport/mqtt/pom.xml b/common/transport/mqtt/pom.xml index 5d93b95615..0136730eb3 100644 --- a/common/transport/mqtt/pom.xml +++ b/common/transport/mqtt/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard.common - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT transport org.thingsboard.common.transport diff --git a/common/transport/pom.xml b/common/transport/pom.xml index 113e7b46a9..d82fac0264 100644 --- a/common/transport/pom.xml +++ b/common/transport/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT common org.thingsboard.common diff --git a/common/transport/snmp/pom.xml b/common/transport/snmp/pom.xml index 12576e9a54..7b3535db82 100644 --- a/common/transport/snmp/pom.xml +++ b/common/transport/snmp/pom.xml @@ -21,7 +21,7 @@ org.thingsboard.common - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT transport diff --git a/common/transport/transport-api/pom.xml b/common/transport/transport-api/pom.xml index b66676e61c..df14a28436 100644 --- a/common/transport/transport-api/pom.xml +++ b/common/transport/transport-api/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard.common - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT transport org.thingsboard.common.transport diff --git a/common/util/pom.xml b/common/util/pom.xml index a49b602c19..2109d090b1 100644 --- a/common/util/pom.xml +++ b/common/util/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT common org.thingsboard.common diff --git a/dao/pom.xml b/dao/pom.xml index f490a0e8e5..6a01c08822 100644 --- a/dao/pom.xml +++ b/dao/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT thingsboard dao diff --git a/msa/black-box-tests/pom.xml b/msa/black-box-tests/pom.xml index b642f5a2c5..5a0645c03a 100644 --- a/msa/black-box-tests/pom.xml +++ b/msa/black-box-tests/pom.xml @@ -21,7 +21,7 @@ org.thingsboard - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT msa org.thingsboard.msa diff --git a/msa/js-executor/pom.xml b/msa/js-executor/pom.xml index f08a17987a..5cabaed58a 100644 --- a/msa/js-executor/pom.xml +++ b/msa/js-executor/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT msa org.thingsboard.msa diff --git a/msa/pom.xml b/msa/pom.xml index af70451a1e..024607378c 100644 --- a/msa/pom.xml +++ b/msa/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT thingsboard msa diff --git a/msa/tb-node/pom.xml b/msa/tb-node/pom.xml index 90b8e4ede6..9cf97b4906 100644 --- a/msa/tb-node/pom.xml +++ b/msa/tb-node/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT msa org.thingsboard.msa diff --git a/msa/tb/pom.xml b/msa/tb/pom.xml index f55f5b12e5..841a4edbdf 100644 --- a/msa/tb/pom.xml +++ b/msa/tb/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT msa org.thingsboard.msa diff --git a/msa/transport/coap/pom.xml b/msa/transport/coap/pom.xml index f6e226802a..34b37c6334 100644 --- a/msa/transport/coap/pom.xml +++ b/msa/transport/coap/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard.msa - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT transport org.thingsboard.msa.transport diff --git a/msa/transport/http/pom.xml b/msa/transport/http/pom.xml index b14fa3b82f..0cc5320250 100644 --- a/msa/transport/http/pom.xml +++ b/msa/transport/http/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard.msa - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT transport org.thingsboard.msa.transport diff --git a/msa/transport/lwm2m/pom.xml b/msa/transport/lwm2m/pom.xml index c02dc88e7e..2dd44c4386 100644 --- a/msa/transport/lwm2m/pom.xml +++ b/msa/transport/lwm2m/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard.msa - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT transport org.thingsboard.msa.transport diff --git a/msa/transport/mqtt/pom.xml b/msa/transport/mqtt/pom.xml index 9258221754..d483ef42eb 100644 --- a/msa/transport/mqtt/pom.xml +++ b/msa/transport/mqtt/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard.msa - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT transport org.thingsboard.msa.transport diff --git a/msa/transport/pom.xml b/msa/transport/pom.xml index 3a19267950..06c1d17939 100644 --- a/msa/transport/pom.xml +++ b/msa/transport/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT msa org.thingsboard.msa diff --git a/msa/transport/snmp/pom.xml b/msa/transport/snmp/pom.xml index 7be1e011a2..a30942fe4c 100644 --- a/msa/transport/snmp/pom.xml +++ b/msa/transport/snmp/pom.xml @@ -21,7 +21,7 @@ org.thingsboard.msa transport - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT org.thingsboard.msa.transport diff --git a/msa/web-ui/pom.xml b/msa/web-ui/pom.xml index 0a231344de..2b973afaba 100644 --- a/msa/web-ui/pom.xml +++ b/msa/web-ui/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT msa org.thingsboard.msa diff --git a/netty-mqtt/pom.xml b/netty-mqtt/pom.xml index 93ccb59913..e6c2843b14 100644 --- a/netty-mqtt/pom.xml +++ b/netty-mqtt/pom.xml @@ -19,11 +19,11 @@ 4.0.0 org.thingsboard - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT thingsboard netty-mqtt - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT jar Netty MQTT Client diff --git a/pom.xml b/pom.xml index 7503bcc4c0..7b3dd97ce8 100755 --- a/pom.xml +++ b/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard thingsboard - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT pom Thingsboard diff --git a/rest-client/pom.xml b/rest-client/pom.xml index 87d3b6fa9d..36ec99fab6 100644 --- a/rest-client/pom.xml +++ b/rest-client/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT thingsboard rest-client diff --git a/rule-engine/pom.xml b/rule-engine/pom.xml index 941188b24a..986ac17cae 100644 --- a/rule-engine/pom.xml +++ b/rule-engine/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT thingsboard rule-engine diff --git a/rule-engine/rule-engine-api/pom.xml b/rule-engine/rule-engine-api/pom.xml index 1465ac1fd8..03510ab9ce 100644 --- a/rule-engine/rule-engine-api/pom.xml +++ b/rule-engine/rule-engine-api/pom.xml @@ -22,7 +22,7 @@ 4.0.0 org.thingsboard - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT rule-engine org.thingsboard.rule-engine diff --git a/rule-engine/rule-engine-components/pom.xml b/rule-engine/rule-engine-components/pom.xml index c34d6b3df6..2be6f0cdba 100644 --- a/rule-engine/rule-engine-components/pom.xml +++ b/rule-engine/rule-engine-components/pom.xml @@ -22,7 +22,7 @@ 4.0.0 org.thingsboard - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT rule-engine org.thingsboard.rule-engine diff --git a/tools/pom.xml b/tools/pom.xml index 51c4dd689b..b68e4b94a3 100644 --- a/tools/pom.xml +++ b/tools/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT thingsboard tools diff --git a/transport/coap/pom.xml b/transport/coap/pom.xml index cf54bcb496..cb0bb5e5ee 100644 --- a/transport/coap/pom.xml +++ b/transport/coap/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT transport org.thingsboard.transport diff --git a/transport/http/pom.xml b/transport/http/pom.xml index 4dd04c1932..7b92d5135f 100644 --- a/transport/http/pom.xml +++ b/transport/http/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT transport org.thingsboard.transport diff --git a/transport/lwm2m/pom.xml b/transport/lwm2m/pom.xml index 4730be97bd..1b7ed8f6ca 100644 --- a/transport/lwm2m/pom.xml +++ b/transport/lwm2m/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT transport org.thingsboard.transport diff --git a/transport/mqtt/pom.xml b/transport/mqtt/pom.xml index dc2310f62e..1eac98020b 100644 --- a/transport/mqtt/pom.xml +++ b/transport/mqtt/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT transport org.thingsboard.transport diff --git a/transport/pom.xml b/transport/pom.xml index 9347afe94f..8b19669740 100644 --- a/transport/pom.xml +++ b/transport/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT thingsboard transport diff --git a/transport/snmp/pom.xml b/transport/snmp/pom.xml index 72201e25dd..520c651c32 100644 --- a/transport/snmp/pom.xml +++ b/transport/snmp/pom.xml @@ -21,7 +21,7 @@ org.thingsboard - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT transport diff --git a/ui-ngx/pom.xml b/ui-ngx/pom.xml index 59e85024fd..d071908001 100644 --- a/ui-ngx/pom.xml +++ b/ui-ngx/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.3.2-SNAPSHOT + 3.3.3-SNAPSHOT thingsboard org.thingsboard From a3146b69870210cc4077269ba1ec3b72d7ee5142 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Wed, 24 Nov 2021 12:25:24 +0200 Subject: [PATCH 145/432] Version set to 3.3.3 --- msa/js-executor/package.json | 2 +- msa/web-ui/package.json | 2 +- ui-ngx/package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/msa/js-executor/package.json b/msa/js-executor/package.json index 5c9924dd50..9fe84ffa9f 100644 --- a/msa/js-executor/package.json +++ b/msa/js-executor/package.json @@ -1,7 +1,7 @@ { "name": "thingsboard-js-executor", "private": true, - "version": "3.3.2", + "version": "3.3.3", "description": "ThingsBoard JavaScript Executor Microservice", "main": "server.js", "bin": "server.js", diff --git a/msa/web-ui/package.json b/msa/web-ui/package.json index b984118482..cc98e5f457 100644 --- a/msa/web-ui/package.json +++ b/msa/web-ui/package.json @@ -1,7 +1,7 @@ { "name": "thingsboard-web-ui", "private": true, - "version": "3.3.2", + "version": "3.3.3", "description": "ThingsBoard Web UI Microservice", "main": "server.js", "bin": "server.js", diff --git a/ui-ngx/package.json b/ui-ngx/package.json index 519d31b66c..73d8e8e7b7 100644 --- a/ui-ngx/package.json +++ b/ui-ngx/package.json @@ -1,6 +1,6 @@ { "name": "thingsboard", - "version": "3.3.2", + "version": "3.3.3", "scripts": { "ng": "ng", "start": "node --max_old_space_size=8048 ./node_modules/@angular/cli/bin/ng serve --host 0.0.0.0 --open", From 2e8b9b5cd7b66a6420b87480ea11ed0a1bbdcdc5 Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Wed, 24 Nov 2021 13:03:52 +0200 Subject: [PATCH 146/432] UI: Improvement add/edit location marker/polygon in maps widgets --- pom.xml | 1 + ui-ngx/angular.json | 1 + ui-ngx/package.json | 17 +- .../select-entity-dialog.component.html | 54 ++ .../select-entity-dialog.component.scss | 21 + .../dialogs/select-entity-dialog.component.ts | 56 +++ .../components/widget/lib/maps/leaflet-map.ts | 469 ++++++++++-------- .../components/widget/lib/maps/map-models.ts | 1 + .../components/widget/lib/maps/map-widget2.ts | 130 +---- .../components/widget/lib/maps/markers.scss | 6 +- .../components/widget/lib/maps/markers.ts | 31 +- .../components/widget/lib/maps/polygon.ts | 19 +- .../components/widget/lib/maps/polyline.ts | 12 +- .../widget/lib/maps/providers/google-map.ts | 1 - .../widget/lib/maps/providers/here-map.ts | 1 - .../widget/lib/maps/providers/image-map.ts | 21 +- .../lib/maps/providers/openstreet-map.ts | 1 - .../widget/lib/maps/providers/tencent-map.ts | 1 - .../components/widget/lib/maps/schemes.ts | 6 + .../trip-animation.component.ts | 6 +- .../widget/widget-components.module.ts | 4 +- ui-ngx/src/assets/add_location.svg | 1 - ui-ngx/src/assets/add_polygon.svg | 3 - .../assets/locale/locale.constant-en_US.json | 35 +- ui-ngx/src/assets/shadow.png | Bin 0 -> 712 bytes ui-ngx/src/tsconfig.app.json | 2 +- ...marker.d.ts => leaflet-geoman-extend.d.ts} | 18 +- ui-ngx/tsconfig.json | 3 +- ui-ngx/yarn.lock | 282 +++++++++-- 29 files changed, 758 insertions(+), 445 deletions(-) create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/maps/dialogs/select-entity-dialog.component.html create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/maps/dialogs/select-entity-dialog.component.scss create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/maps/dialogs/select-entity-dialog.component.ts delete mode 100644 ui-ngx/src/assets/add_location.svg delete mode 100644 ui-ngx/src/assets/add_polygon.svg create mode 100644 ui-ngx/src/assets/shadow.png rename ui-ngx/src/typings/{add-marker.d.ts => leaflet-geoman-extend.d.ts} (72%) diff --git a/pom.xml b/pom.xml index 7503bcc4c0..cf348e2f4a 100755 --- a/pom.xml +++ b/pom.xml @@ -830,6 +830,7 @@ src/.browserslistrc **/yarn.lock **/*.raw + **/*.patch **/apache/cassandra/io/** .run/** diff --git a/ui-ngx/angular.json b/ui-ngx/angular.json index a97e65b04c..0d6203c88e 100644 --- a/ui-ngx/angular.json +++ b/ui-ngx/angular.json @@ -79,6 +79,7 @@ "src/app/modules/home/components/widget/lib/maps/markers.scss", "node_modules/leaflet.markercluster/dist/MarkerCluster.css", "node_modules/leaflet.markercluster/dist/MarkerCluster.Default.css", + "node_modules/@geoman-io/leaflet-geoman-free/dist/leaflet-geoman.css", "node_modules/prismjs/themes/prism.css", "node_modules/prismjs/plugins/line-numbers/prism-line-numbers.css" ], diff --git a/ui-ngx/package.json b/ui-ngx/package.json index 519d31b66c..f9ca6d478c 100644 --- a/ui-ngx/package.json +++ b/ui-ngx/package.json @@ -28,6 +28,7 @@ "@date-io/date-fns": "^2.10.11", "@flowjs/flow.js": "^2.14.1", "@flowjs/ngx-flow": "~0.4.6", + "@geoman-io/leaflet-geoman-free": "^2.11.3", "@juggle/resize-observer": "^3.3.1", "@mat-datetimepicker/core": "~6.0.2", "@material-ui/core": "^4.11.4", @@ -57,11 +58,10 @@ "jstree-bootstrap-theme": "^1.0.1", "jszip": "^3.6.0", "leaflet": "^1.7.1", - "leaflet-editable": "^1.2.0", "leaflet-polylinedecorator": "^1.6.0", - "leaflet-providers": "^1.12.0", - "leaflet.gridlayer.googlemutant": "0.10.2", - "leaflet.markercluster": "^1.5.0", + "leaflet-providers": "^1.13.0", + "leaflet.gridlayer.googlemutant": "^0.13.4", + "leaflet.markercluster": "^1.5.3", "material-design-icons": "^3.0.1", "messageformat": "^2.3.0", "moment": "^2.29.1", @@ -113,10 +113,11 @@ "@types/jquery": "^3.5.2", "@types/js-beautify": "^1.13.1", "@types/jstree": "^3.3.40", - "@types/leaflet": "1.5.17", - "@types/leaflet-editable": "^1.2.1", - "@types/leaflet-polylinedecorator": "^1.6.0", - "@types/leaflet.markercluster": "^1.4.4", + "@types/leaflet": "^1.7.6", + "@types/leaflet-polylinedecorator": "^1.6.1", + "@types/leaflet-providers": "^1.2.1", + "@types/leaflet.gridlayer.googlemutant": "^0.4.6", + "@types/leaflet.markercluster": "^1.4.6", "@types/lodash": "^4.14.170", "@types/moment-timezone": "^0.5.30", "@types/mousetrap": "1.6.3", diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/dialogs/select-entity-dialog.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/maps/dialogs/select-entity-dialog.component.html new file mode 100644 index 0000000000..93fa72c84b --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/dialogs/select-entity-dialog.component.html @@ -0,0 +1,54 @@ + +
+ +

widgets.maps.select-entity

+ + +
+ + +
+
+ + entity.entity + + + {{ entity.entityName }} + + + +
widgets.maps.select-entity-hint
+
+
+ + +
+
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/dialogs/select-entity-dialog.component.scss b/ui-ngx/src/app/modules/home/components/widget/lib/maps/dialogs/select-entity-dialog.component.scss new file mode 100644 index 0000000000..b9600d8731 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/dialogs/select-entity-dialog.component.scss @@ -0,0 +1,21 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +:host { + .tb-hint { + margin-top: -1.25em; + max-width: fit-content; + } +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/dialogs/select-entity-dialog.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/dialogs/select-entity-dialog.component.ts new file mode 100644 index 0000000000..58526a4e66 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/dialogs/select-entity-dialog.component.ts @@ -0,0 +1,56 @@ +/// +/// Copyright © 2016-2021 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { Component, Inject } from '@angular/core'; +import { DialogComponent } from '@shared/components/dialog.component'; +import { Store } from '@ngrx/store'; +import { AppState } from '@core/core.state'; +import { Router } from '@angular/router'; +import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; +import { FormBuilder, FormGroup, Validators } from '@angular/forms'; +import { FormattedData } from '@home/components/widget/lib/maps/map-models'; + +export interface SelectEntityDialogData { + entities: FormattedData[]; +} + +@Component({ + selector: 'tb-select-entity-dialog', + templateUrl: './select-entity-dialog.component.html', + styleUrls: ['./select-entity-dialog.component.scss'] +}) +export class SelectEntityDialogComponent extends DialogComponent { + + selectEntityFormGroup: FormGroup; + + constructor(protected store: Store, + protected router: Router, + @Inject(MAT_DIALOG_DATA) public data: SelectEntityDialogData, + public dialogRef: MatDialogRef, + public fb: FormBuilder) { + super(store, router, dialogRef); + + this.selectEntityFormGroup = this.fb.group( + { + entity: ['', Validators.required] + } + ); + } + + save(): void { + this.dialogRef.close(this.selectEntityFormGroup.value.entity); + } +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts index 5120fc8c9e..03249a5307 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts @@ -14,23 +14,15 @@ /// limitations under the License. /// -import L, { - FeatureGroup, - Icon, - LatLngBounds, - LatLngTuple, - markerClusterGroup, - MarkerClusterGroup, - MarkerClusterGroupOptions, Projection -} from 'leaflet'; +import L, { FeatureGroup, Icon, LatLngBounds, LatLngTuple, Projection } from 'leaflet'; import tinycolor from 'tinycolor2'; import 'leaflet-providers'; -import 'leaflet.markercluster/dist/leaflet.markercluster'; +import { MarkerClusterGroup, MarkerClusterGroupOptions } from 'leaflet.markercluster/dist/leaflet.markercluster'; +import '@geoman-io/leaflet-geoman-free'; import { defaultSettings, FormattedData, - MapProviders, MapSettings, MarkerSettings, PolygonSettings, @@ -39,12 +31,10 @@ import { UnitedMapSettings } from './map-models'; import { Marker } from './markers'; -import { Observable, of } from 'rxjs'; +import { forkJoin, Observable, of } from 'rxjs'; import { Polyline } from './polyline'; import { Polygon } from './polygon'; -import { - createTooltip, -} from '@home/components/widget/lib/maps/maps-utils'; +import { createTooltip } from '@home/components/widget/lib/maps/maps-utils'; import { checkLngLat, createLoadingDiv, @@ -54,6 +44,15 @@ import { } from '@home/components/widget/lib/maps/common-maps-utils'; import { WidgetContext } from '@home/models/widget-component.models'; import { deepClone, isDefinedAndNotNull, isEmptyStr, isString } from '@core/utils'; +import { TranslateService } from '@ngx-translate/core'; +import { + SelectEntityDialogComponent, + SelectEntityDialogData +} from '@home/components/widget/lib/maps/dialogs/select-entity-dialog.component'; +import { MatDialog } from '@angular/material/dialog'; +import { AttributeService } from '@core/http/attribute.service'; +import { EntityId } from '@shared/models/id/entity-id'; +import { AttributeScope, DataKeyType, LatestTelemetry } from '@shared/models/telemetry/telemetry.models'; export default abstract class LeafletMap { @@ -78,20 +77,20 @@ export default abstract class LeafletMap { drawRoutes: boolean; showPolygon: boolean; updatePending = false; + editPolygons = false; + selectedEntity: FormattedData; addMarkers: L.Marker[] = []; addPolygons: L.Polygon[] = []; // tslint:disable-next-line:no-string-literal southWest = new L.LatLng(-Projection.SphericalMercator['MAX_LATITUDE'], -180); // tslint:disable-next-line:no-string-literal northEast = new L.LatLng(Projection.SphericalMercator['MAX_LATITUDE'], 180); - mousePositionOnMap: L.LatLng; - addMarker: L.Control; - addPolygon: L.Control; protected constructor(public ctx: WidgetContext, public $container: HTMLElement, options: UnitedMapSettings) { this.options = options; + this.editPolygons = options.showPolygon && options.editablePolygon; } public initSettings(options: MapSettings) { @@ -102,16 +101,28 @@ export default abstract class LeafletMap { removeOutsideVisibleBounds, animate, chunkedLoading, + spiderfyOnMaxZoom, maxClusterRadius, maxZoom }: MapSettings = options; if (useClusterMarkers) { + // disabled marker cluster icon + (L as any).MarkerCluster = (L as any).MarkerCluster.extend({ + options: { pmIgnore: true, ...L.Icon.prototype.options } + }); const clusteringSettings: MarkerClusterGroupOptions = { - spiderfyOnMaxZoom: false, + spiderfyOnMaxZoom, zoomToBoundsOnClick: zoomOnClick, showCoverageOnHover, removeOutsideVisibleBounds, animate, - chunkedLoading + chunkedLoading, + pmIgnore: true, + spiderLegPolylineOptions: { + pmIgnore: true + }, + polygonOptions: { + pmIgnore: true + } }; if (maxClusterRadius && maxClusterRadius > 0) { clusteringSettings.maxClusterRadius = Math.floor(maxClusterRadius); @@ -119,183 +130,165 @@ export default abstract class LeafletMap { if (maxZoom && maxZoom >= 0 && maxZoom < 19) { clusteringSettings.disableClusteringAtZoom = Math.floor(maxZoom); } - this.markersCluster = markerClusterGroup(clusteringSettings); + this.markersCluster = new MarkerClusterGroup(clusteringSettings); } } - addMarkerControl() { - if (this.options.draggableMarker) { - this.map.on('mousemove', (e: L.LeafletMouseEvent) => { - this.mousePositionOnMap = e.latlng; - }); - const dragListener = (e: L.DragEndEvent) => { - if (e.type === 'dragend' && this.mousePositionOnMap) { - const icon = L.icon({ - iconRetinaUrl: 'marker-icon-2x.png', - iconUrl: 'marker-icon.png', - shadowUrl: 'marker-shadow.png', - iconSize: [25, 41], - iconAnchor: [12, 41], - popupAnchor: [1, -34], - tooltipAnchor: [16, -28], - shadowSize: [41, 41] - }); - const customLatLng = this.convertToCustomFormat(this.mousePositionOnMap); - this.mousePositionOnMap.lat = customLatLng[this.options.latKeyName]; - this.mousePositionOnMap.lng = customLatLng[this.options.lngKeyName]; - - const newMarker = L.marker(this.mousePositionOnMap, { icon }).addTo(this.map); - this.addMarkers.push(newMarker); - const datasourcesList = document.createElement('div'); - const header = document.createElement('p'); - header.appendChild(document.createTextNode('Select entity:')); - header.setAttribute('style', 'font-size: 14px; margin: 8px 0'); - datasourcesList.appendChild(header); - this.datasources.forEach(ds => { - const dsItem = document.createElement('p'); - dsItem.appendChild(document.createTextNode(ds.entityName)); - dsItem.setAttribute('style', 'font-size: 14px; margin: 8px 0; cursor: pointer'); - dsItem.onclick = () => { - const updatedEnttity = { ...ds, ...customLatLng }; - this.saveMarkerLocation(updatedEnttity).subscribe(() => { - this.map.removeLayer(newMarker); - const markerIndex = this.addMarkers.indexOf(newMarker); - if (markerIndex > -1) { - this.addMarkers.splice(markerIndex, 1); - } - this.deleteMarker(ds.entityName); - this.createMarker(ds.entityName, updatedEnttity, this.datasources, this.options); - }); - }; - datasourcesList.appendChild(dsItem); - }); - datasourcesList.appendChild(document.createElement('br')); - const deleteBtn = document.createElement('a'); - deleteBtn.appendChild(document.createTextNode('Discard changes')); - deleteBtn.onclick = () => { - this.map.removeLayer(newMarker); - const markerIndex = this.addMarkers.indexOf(newMarker); - if (markerIndex > -1) { - this.addMarkers.splice(markerIndex, 1); - } - }; - datasourcesList.appendChild(deleteBtn); - const popup = L.popup(); - popup.setContent(datasourcesList); - newMarker.bindPopup(popup).openPopup(); - } - this.addMarker.setPosition('topright'); - }; - const addMarker = L.Control.extend({ - onAdd() { - const img = L.DomUtil.create('img') as any; - img.src = `assets/add_location.svg`; - img.style.width = '32px'; - img.style.height = '32px'; - img.title = 'Drag and drop to add marker'; - img.onclick = this.dragMarker; - img.draggable = true; - const draggableImg = new L.Draggable(img); - draggableImg.enable(); - draggableImg.on('dragend', dragListener); - return img; - }, - onRemove() { - }, - dragMarker: this.dragMarker - } as any); - const addMarkerControl = (opts) => { - return new addMarker(opts); - }; - this.addMarker = addMarkerControl({ position: 'topright' }).addTo(this.map); + private selectEntityWithoutLocationDialog(shapes: L.PM.SUPPORTED_SHAPES): Observable { + let entities; + switch (shapes) { + case 'Polygon': + case 'Rectangle': + entities = this.datasources.filter(pData => !this.isValidPolygonPosition(pData)); + break; + case 'Marker': + entities = this.datasources.filter(mData => !this.convertPosition(mData)); + break; + default: + return of(null); + } + if (entities.length === 1) { + return of(entities[0]); + } + const dialog = this.ctx.$injector.get(MatDialog); + return dialog.open(SelectEntityDialogComponent, + { + disableClose: true, + panelClass: ['tb-dialog', 'tb-fullscreen-dialog'], + data: { + entities + } + }).afterClosed(); + } + + private selectEntityWithoutLocation(type: string) { + this.selectEntityWithoutLocationDialog(type.substring(2)).subscribe((data) => { + if (data !== null) { + this.selectedEntity = data; + this.toggleDrawMode(type); + } else { + this.map.pm.Toolbar.toggleButton(type, false); } + }); + } + + private toggleDrawMode(type: string) { + this.map.pm.Draw[type].toggle(); } - addPolygonControl() { - if (this.options.showPolygon && this.options.editablePolygon) { - this.map.on('mousemove', (e: L.LeafletMouseEvent) => { - this.mousePositionOnMap = e.latlng; + addEditControl() { + // Customize edit marker + if (this.options.draggableMarker) { + const actions = [{ + text: L.PM.Utils.getTranslation('actions.cancel'), + onClick: () => this.toggleDrawMode('tbMarker') + }]; + + this.map.pm.Toolbar.copyDrawControl('Marker', { + name: 'tbMarker', + afterClick: () => this.selectEntityWithoutLocation('tbMarker'), + disabled: true, + actions + }); + } + + // Customize edit polygon + if (this.editPolygons) { + const rectangleActions = [ + { + text: L.PM.Utils.getTranslation('actions.cancel'), + onClick: () => this.toggleDrawMode('tbRectangle') + } + ]; + + const polygonActions = [ + 'finish' as const, + 'removeLastVertex' as const, + { + text: L.PM.Utils.getTranslation('actions.cancel'), + onClick: () => this.toggleDrawMode('tbPolygon') + } + ]; + + this.map.pm.Toolbar.copyDrawControl('Rectangle', { + name: 'tbRectangle', + afterClick: () => this.selectEntityWithoutLocation('tbRectangle'), + disabled: true, + actions: rectangleActions + }); + + this.map.pm.Toolbar.copyDrawControl('Polygon', { + name: 'tbPolygon', + afterClick: () => this.selectEntityWithoutLocation('tbPolygon'), + disabled: true, + actions: polygonActions + }); + } + + const translateService = this.ctx.$injector.get(TranslateService); + this.map.pm.setLang('en', translateService.instant('widgets.maps'), 'en'); + this.map.pm.addControls({ + position: 'topleft', + drawMarker: false, + drawCircle: false, + drawCircleMarker: false, + drawRectangle: false, + drawPolyline: false, + drawPolygon: false, + editMode: this.editPolygons, + cutPolygon: this.editPolygons, + rotateMode: this.editPolygons }); - const dragListener = (e: L.DragEndEvent) => { - if (e.type === 'dragend') { - const polygonOffset = this.options.provider === MapProviders.image ? 10 : 0.01; - - const convert = this.convertToCustomFormat(this.mousePositionOnMap, polygonOffset); - this.mousePositionOnMap.lat = convert[this.options.latKeyName]; - this.mousePositionOnMap.lng = convert[this.options.lngKeyName]; - - const latlng1 = this.mousePositionOnMap; - const latlng2 = L.latLng(this.mousePositionOnMap.lat, this.mousePositionOnMap.lng + polygonOffset); - const latlng3 = L.latLng(this.mousePositionOnMap.lat - polygonOffset, this.mousePositionOnMap.lng); - const polygonPoints = [latlng1, latlng2, latlng3]; - - const newPolygon = L.polygon(polygonPoints).addTo(this.map); - this.addPolygons.push(newPolygon); - const datasourcesList = document.createElement('div'); - const customLatLng = {[this.options.polygonKeyName]: this.convertToPolygonFormat(polygonPoints)}; - const header = document.createElement('p'); - header.appendChild(document.createTextNode('Select entity:')); - header.setAttribute('style', 'font-size: 14px; margin: 8px 0'); - datasourcesList.appendChild(header); - this.datasources.forEach(ds => { - const dsItem = document.createElement('p'); - dsItem.appendChild(document.createTextNode(ds.entityName)); - dsItem.setAttribute('style', 'font-size: 14px; margin: 8px 0; cursor: pointer'); - dsItem.onclick = () => { - const updatedEnttity = { ...ds, ...customLatLng }; - this.savePolygonLocation(updatedEnttity).subscribe(() => { - this.map.removeLayer(newPolygon); - const polygonIndex = this.addPolygons.indexOf(newPolygon); - if (polygonIndex > -1) { - this.addPolygons.splice(polygonIndex, 1); - } - this.deletePolygon(ds.entityName); - }); - }; - datasourcesList.appendChild(dsItem); + this.map.on('pm:create', (e) => { + if (e.shape === 'tbMarker') { + // @ts-ignore + this.saveLocation(this.selectedEntity, this.convertToCustomFormat(e.layer.getLatLng())).subscribe(() => { + }); + } else if (e.shape === 'tbRectangle' || e.shape === 'tbPolygon') { + // @ts-ignore + this.saveLocation(this.selectedEntity, this.convertPolygonToCustomFormat(e.layer.getLatLngs()[0])).subscribe(() => { }); - datasourcesList.appendChild(document.createElement('br')); - const deleteBtn = document.createElement('a'); - deleteBtn.appendChild(document.createTextNode('Discard changes')); - deleteBtn.onclick = () => { - this.map.removeLayer(newPolygon); - const polygonIndex = this.addPolygons.indexOf(newPolygon); - if (polygonIndex > -1) { - this.addPolygons.splice(polygonIndex, 1); - } - }; - datasourcesList.appendChild(deleteBtn); - const popup = L.popup(); - popup.setContent(datasourcesList); - newPolygon.bindPopup(popup).openPopup(); } - this.addPolygon.setPosition('topright'); - }; - const addPolygon = L.Control.extend({ - onAdd() { - const img = L.DomUtil.create('img') as any; - img.src = `assets/add_polygon.svg`; - img.style.width = '32px'; - img.style.height = '32px'; - img.title = 'Drag and drop to add Polygon'; - img.onclick = this.dragPolygonVertex; - img.draggable = true; - const draggableImg = new L.Draggable(img); - draggableImg.enable(); - draggableImg.on('dragend', dragListener); - return img; - }, - onRemove() { - }, - dragPolygonVertex: this.dragPolygonVertex - } as any); - const addPolygonControl = (opts) => { - return new addPolygon(opts); - }; - this.addPolygon = addPolygonControl({ position: 'topright' }).addTo(this.map); + // @ts-ignore + e.layer._pmTempLayer = true; + e.layer.remove(); + }); + + this.map.on('pm:cut', (e) => { + // @ts-ignore + e.originalLayer.setLatLngs(e.layer.getLatLngs()); + e.originalLayer.addTo(this.map); + // @ts-ignore + e.originalLayer._pmTempLayer = false; + const iterator = this.polygons.values(); + let result = iterator.next(); + while (!result.done && e.originalLayer !== result.value.leafletPoly) { + result = iterator.next(); + } + // @ts-ignore + e.layer._pmTempLayer = true; + e.layer.remove(); + }); + + this.map.on('pm:remove', (e) => { + if (e.shape === 'Marker') { + const iterator = this.markers.values(); + let result = iterator.next(); + while (!result.done && e.layer !== result.value.leafletMarker) { + result = iterator.next(); + } + this.saveLocation(result.value.data, this.convertToCustomFormat(null)).subscribe(() => {}); + } else if (e.shape === 'Polygon') { + const iterator = this.polygons.values(); + let result = iterator.next(); + while (!result.done && e.layer !== result.value.leafletPoly) { + result = iterator.next(); + } + this.saveLocation(result.value.data, this.convertPolygonToCustomFormat(null)).subscribe(() => {}); + } + }); } - } public setLoading(loading: boolean) { if (this.loading !== loading) { @@ -337,11 +330,10 @@ export default abstract class LeafletMap { if (this.options.disableScrollZooming) { this.map.scrollWheelZoom.disable(); } - if (this.options.draggableMarker) { - this.addMarkerControl(); - } - if (this.options.editablePolygon) { - this.addPolygonControl(); + if (this.options.draggableMarker || this.editPolygons) { + this.addEditControl(); + } else { + this.map.pm.disableDraw(); } if (this.options.useClusterMarkers) { this.map.addLayer(this.markersCluster); @@ -352,12 +344,53 @@ export default abstract class LeafletMap { } } - public saveMarkerLocation(datasource: FormattedData, lat?: number, lng?: number): Observable { - return of(null); - } + private saveLocation(e: FormattedData, values: {[key: string]: any}): Observable { + const attributeService = this.ctx.$injector.get(AttributeService); + const attributes = []; + const timeseries = []; + + const entityId: EntityId = { + entityType: e.$datasource.entityType, + id: e.$datasource.entityId + }; - public savePolygonLocation(datasource: FormattedData, coordinates?: Array<[number, number]>): Observable { - return of(null); + for (const dataKeyName of Object.keys(values)) { + for (const key of e.$datasource.dataKeys) { + if (dataKeyName === key.name) { + const value = { + key: key.name, + value: values[dataKeyName] + }; + if (key.type === DataKeyType.attribute) { + attributes.push(value); + } else if (key.type === DataKeyType.timeseries) { + timeseries.push(value); + } + break; + } + } + } + + const observables: Observable[] = []; + if (timeseries.length) { + observables.push(attributeService.saveEntityTimeseries( + entityId, + LatestTelemetry.LATEST_TELEMETRY, + timeseries + )); + } + if (attributes.length) { + observables.push(attributeService.saveEntityAttributes( + entityId, + AttributeScope.SERVER_SCOPE, + attributes + )); + } + if (observables.length) { + return forkJoin(observables); + } else { + return of(null); + } } createLatLng(lat: number, lng: number): L.LatLng { @@ -441,7 +474,7 @@ export default abstract class LeafletMap { } convertToCustomFormat(position: L.LatLng, offset = 0): object { - position = checkLngLat(position, this.southWest, this.northEast, offset); + position = position ? checkLngLat(position, this.southWest, this.northEast, offset) : {lat: null, lng: null} as L.LatLng; return { [this.options.latKeyName]: position.lat, @@ -455,17 +488,18 @@ export default abstract class LeafletMap { if (point.length) { return this.convertToPolygonFormat(point); } else { - return [point.lat, point.lng]; + const convertPoint = checkLngLat(point, this.southWest, this.northEast); + return [convertPoint.lat, convertPoint.lng]; } }); - } else { - return []; } + return []; } - convertPolygonToCustomFormat(expression: any[][]): object { + convertPolygonToCustomFormat(expression: any[][]): {[key: string]: any} { + const coordinate = expression ? this.convertToPolygonFormat(expression) : null; return { - [this.options.polygonKeyName] : this.convertToPolygonFormat(expression) + [this.options.polygonKeyName]: coordinate }; } @@ -484,7 +518,15 @@ export default abstract class LeafletMap { } this.updateMarkers(formattedData, false); this.updateBoundsInternal(); - if (this.options.draggableMarker || this.options.editablePolygon) { + if (this.options.draggableMarker) { + const foundEntityWithoutLocation = formattedData.some(mData => !this.convertPosition(mData)); + this.map.pm.Toolbar.setButtonDisabled('tbMarker', !foundEntityWithoutLocation); + this.datasources = formattedData; + } + if (this.editPolygons) { + const foundEntityWithoutPolygon = formattedData.some(pData => !this.isValidPolygonPosition(pData)); + this.map.pm.Toolbar.setButtonDisabled('tbPolygon', !foundEntityWithoutPolygon); + this.map.pm.Toolbar.setButtonDisabled('tbRectangle', !foundEntityWithoutPolygon); this.datasources = formattedData; } } else { @@ -577,10 +619,10 @@ export default abstract class LeafletMap { } dragMarker = (e, data = {} as FormattedData) => { - if (e.type !== 'dragend') { + if (e === undefined) { return; } - this.saveMarkerLocation({ ...data, ...this.convertToCustomFormat(e.target._latlng) }).subscribe(); + this.saveLocation(data, this.convertToCustomFormat(e.target._latlng)).subscribe(); } private createMarker(key: string, data: FormattedData, dataSources: FormattedData[], settings: MarkerSettings, @@ -728,11 +770,15 @@ export default abstract class LeafletMap { // Polygon + isValidPolygonPosition(data: FormattedData): boolean { + return data && isDefinedAndNotNull(data[this.options.polygonKeyName]) && !isEmptyStr(data[this.options.polygonKeyName]); + } + updatePolygons(polyData: FormattedData[], updateBounds = true) { const keys: string[] = []; this.polygonsData = deepClone(polyData); polyData.forEach((data: FormattedData) => { - if (data && isDefinedAndNotNull(data[this.options.polygonKeyName]) && !isEmptyStr(data[this.options.polygonKeyName])) { + if (this.isValidPolygonPosition(data)) { if (isString((data[this.options.polygonKeyName]))) { data[this.options.polygonKeyName] = JSON.parse(data[this.options.polygonKeyName]); } @@ -758,15 +804,14 @@ export default abstract class LeafletMap { } dragPolygonVertex = (e?, data = {} as FormattedData) => { - if (e === undefined || (e.type !== 'editable:vertex:dragend' && e.type !== 'editable:vertex:deleted')) { + if (e === undefined) { return; } - if (this.options.provider !== MapProviders.image) { - for (const key of Object.keys(e.layer._latlngs[0])) { - e.layer._latlngs[0][key] = checkLngLat(e.layer._latlngs[0][key], this.southWest, this.northEast); - } + let coordinates = e.layer.getLatLngs(); + if (coordinates.length === 1) { + coordinates = coordinates[0]; } - this.savePolygonLocation({ ...data, ...this.convertPolygonToCustomFormat(e.layer._latlngs) }).subscribe(); + this.saveLocation(data, this.convertPolygonToCustomFormat(coordinates)).subscribe(() => {}); } createPolygon(polyData: FormattedData, dataSources: FormattedData[], settings: PolygonSettings, updateBounds = true) { diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-models.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-models.ts index d9183c1cb6..5b99b792e9 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-models.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-models.ts @@ -57,6 +57,7 @@ export type MapSettings = { showCoverageOnHover: boolean, animate: boolean, maxClusterRadius: number, + spiderfyOnMaxZoom: boolean, chunkedLoading: boolean, removeOutsideVisibleBounds: boolean, useCustomProvider: boolean, diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-widget2.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-widget2.ts index 3ad10a0980..eca27d6532 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-widget2.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-widget2.ts @@ -14,41 +14,23 @@ /// limitations under the License. /// -import { - defaultSettings, - FormattedData, - hereProviders, - MapProviders, - UnitedMapSettings -} from './map-models'; +import { defaultSettings, hereProviders, MapProviders, UnitedMapSettings } from './map-models'; import LeafletMap from './leaflet-map'; import { commonMapSettingsSchema, mapPolygonSchema, - mapProviderSchema, markerClusteringSettingsSchema, markerClusteringSettingsSchemaLeaflet, routeMapSettingsSchema } from './schemes'; import { MapWidgetInterface, MapWidgetStaticInterface } from './map-widget.interface'; -import { - addCondition, - addGroupInfo, - addToSchema, - initSchema, - mergeSchemes -} from '@core/schema-utils'; +import { addCondition, addGroupInfo, addToSchema, initSchema, mergeSchemes } from '@core/schema-utils'; import { WidgetContext } from '@app/modules/home/models/widget-component.models'; import { getDefCenterPosition, getProviderSchema, parseFunction, parseWithTranslation } from './common-maps-utils'; import { Datasource, DatasourceData, JsonSettingsSchema, WidgetActionDescriptor } from '@shared/models/widget.models'; -import { EntityId } from '@shared/models/id/entity-id'; -import { AttributeScope, DataKeyType, LatestTelemetry } from '@shared/models/telemetry/telemetry.models'; -import { AttributeService } from '@core/http/attribute.service'; import { TranslateService } from '@ngx-translate/core'; import { UtilsService } from '@core/services/utils.service'; import { EntityDataPageLink } from '@shared/models/query/query.models'; -import { isDefined } from '@core/utils'; -import { forkJoin, Observable, of } from 'rxjs'; import { providerClass } from '@home/components/widget/lib/maps/providers'; // @dynamic @@ -81,8 +63,6 @@ export class MapWidgetController implements MapWidgetInterface { } parseWithTranslation.setTranslate(this.translate); this.map = new MapClass(this.ctx, $element, this.settings); - this.map.saveMarkerLocation = this.setMarkerLocation; - this.map.savePolygonLocation = this.savePolygonLocation; this.pageLink = { page: 0, pageSize: this.settings.mapPageSize, @@ -178,112 +158,6 @@ export class MapWidgetController implements MapWidgetInterface { }, entityName, null, entityLabel); } - setMarkerLocation = (e: FormattedData, lat?: number, lng?: number) => { - const attributeService = this.ctx.$injector.get(AttributeService); - - const entityId: EntityId = { - entityType: e.$datasource.entityType, - id: e.$datasource.entityId - }; - const attributes = []; - const timeseries = []; - - const latProperties = [this.settings.latKeyName, this.settings.xPosKeyName]; - const lngProperties = [this.settings.lngKeyName, this.settings.yPosKeyName]; - e.$datasource.dataKeys.forEach(key => { - let value; - if (latProperties.includes(key.name)) { - value = { - key: key.name, - value: isDefined(lat) ? lat : e[key.name] - }; - } else if (lngProperties.includes(key.name)) { - value = { - key: key.name, - value: isDefined(lng) ? lng : e[key.name] - }; - } - if (value) { - if (key.type === DataKeyType.attribute) { - attributes.push(value); - } - if (key.type === DataKeyType.timeseries) { - timeseries.push(value); - } - } - }); - const observables: Observable[] = []; - if (timeseries.length) { - observables.push(attributeService.saveEntityTimeseries( - entityId, - LatestTelemetry.LATEST_TELEMETRY, - timeseries - )); - } - if (attributes.length) { - observables.push(attributeService.saveEntityAttributes( - entityId, - AttributeScope.SERVER_SCOPE, - attributes - )); - } - if (observables.length) { - return forkJoin(observables); - } else { - return of(null); - } - } - - savePolygonLocation = (e: FormattedData, coordinates?: Array) => { - const attributeService = this.ctx.$injector.get(AttributeService); - - const entityId: EntityId = { - entityType: e.$datasource.entityType, - id: e.$datasource.entityId - }; - const attributes = []; - const timeseries = []; - - const coordinatesProperties = this.settings.polygonKeyName; - e.$datasource.dataKeys.forEach(key => { - let value; - if (coordinatesProperties === key.name) { - value = { - key: key.name, - value: isDefined(coordinates) ? coordinates : e[key.name] - }; - } - if (value) { - if (key.type === DataKeyType.attribute) { - attributes.push(value); - } - if (key.type === DataKeyType.timeseries) { - timeseries.push(value); - } - } - }); - const observables: Observable[] = []; - if (timeseries.length) { - observables.push(attributeService.saveEntityTimeseries( - entityId, - LatestTelemetry.LATEST_TELEMETRY, - timeseries - )); - } - if (attributes.length) { - observables.push(attributeService.saveEntityAttributes( - entityId, - AttributeScope.SERVER_SCOPE, - attributes - )); - } - if (observables.length) { - return forkJoin(observables); - } else { - return of(null); - } - } - initSettings(settings: UnitedMapSettings, isEditMap?: boolean): UnitedMapSettings { const functionParams = ['data', 'dsData', 'dsIndex']; this.provider = settings.provider || this.mapProvider; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/markers.scss b/ui-ngx/src/app/modules/home/components/widget/lib/maps/markers.scss index 7abf1423c7..147386685c 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/markers.scss +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/markers.scss @@ -29,6 +29,10 @@ box-shadow: none; } -.leaflet-container{ +.leaflet-container { background-color: white; } + +.leaflet-buttons-control-button.pm-disabled { + pointer-events: none; +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/markers.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/markers.ts index cd3f19980f..5550706402 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/markers.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/markers.ts @@ -42,9 +42,7 @@ export class Marker { constructor(private map: LeafletMap, private location: L.LatLng, public settings: MarkerSettings, data?: FormattedData, dataSources?, onDragendListener?) { this.setDataSources(data, dataSources); - this.leafletMarker = L.marker(location, { - draggable: settings.draggableMarker - }); + this.leafletMarker = L.marker(location, {pmIgnore: !settings.draggableMarker}); this.markerOffset = [ isDefined(settings.markerOffsetX) ? settings.markerOffsetX : 0.5, @@ -72,8 +70,8 @@ export class Marker { }); } - if (onDragendListener) { - this.leafletMarker.on('dragend', (e) => onDragendListener(e, this.data)); + if (settings.draggableMarker && onDragendListener) { + this.leafletMarker.on('pm:dragend', (e) => onDragendListener(e, this.data)); } } @@ -199,19 +197,24 @@ export class Marker { createColoredMarkerIcon(color: tinycolor.Instance): { size: number[], icon: Icon } { return { - size: [21, 34], - icon: L.icon({ - iconUrl: 'https://chart.apis.google.com/chart?chst=d_map_pin_letter&chld=%E2%80%A2|' + color.toHex(), - iconSize: [21, 34], - iconAnchor: [21 * this.markerOffset[0], 34 * this.markerOffset[1]], - popupAnchor: [0, -34], - shadowUrl: 'https://chart.apis.google.com/chart?chst=d_map_pin_shadow', - shadowSize: [40, 37], - shadowAnchor: [12, 35] + size: [21, 34], + icon: L.icon({ + iconUrl: this.createColorIconURI(color), + iconSize: [21, 34], + iconAnchor: [21 * this.markerOffset[0], 34 * this.markerOffset[1]], + popupAnchor: [0, -34], + shadowUrl: 'assets/shadow.png', + shadowSize: [40, 37], + shadowAnchor: [12, 35] }) }; } + createColorIconURI(color: tinycolor.Instance): string { + const svg = ``; + return 'data:image/svg+xml;base64,' + btoa(svg); + } + removeMarker() { /* this.map$.subscribe(map => this.leafletMarker.addTo(map))*/ diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/polygon.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/polygon.ts index c7cca2a40b..d87d764d0a 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/polygon.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/polygon.ts @@ -17,7 +17,6 @@ import L, { LatLngExpression, LeafletMouseEvent } from 'leaflet'; import { createTooltip } from './maps-utils'; import { functionValueCalculator, parseWithTranslation, safeExecute } from './common-maps-utils'; -import 'leaflet-editable/src/Leaflet.Editable'; import { FormattedData, PolygonSettings } from './map-models'; export class Polygon { @@ -37,14 +36,12 @@ export class Polygon { color: settings.polygonStrokeColor, weight: settings.polygonStrokeWeight, fillOpacity: settings.polygonOpacity, - opacity: settings.polygonStrokeOpacity + opacity: settings.polygonStrokeOpacity, + pmIgnore: !settings.editablePolygon }).addTo(this.map); - if (settings.editablePolygon) { - this.leafletPoly.enableEdit(this.map); - if (onDragendListener) { - this.leafletPoly.on('editable:vertex:dragend', e => onDragendListener(e, this.data)); - this.leafletPoly.on('editable:vertex:deleted', e => onDragendListener(e, this.data)); - } + + if (settings.editablePolygon && onDragendListener) { + this.leafletPoly.on('pm:edit', (e) => onDragendListener(e, this.data)); } @@ -73,13 +70,7 @@ export class Polygon { updatePolygon(data: FormattedData, dataSources: FormattedData[], settings: PolygonSettings) { this.data = data; this.dataSources = dataSources; - if (settings.editablePolygon) { - this.leafletPoly.disableEdit(); - } this.leafletPoly.setLatLngs(data[this.settings.polygonKeyName]); - if (settings.editablePolygon) { - this.leafletPoly.enableEdit(this.map); - } if (settings.showPolygonTooltip) { this.updateTooltip(this.data); } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/polyline.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/polyline.ts index be319ded3a..895dc15763 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/polyline.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/polyline.ts @@ -14,7 +14,8 @@ /// limitations under the License. /// -import L, { PolylineDecoratorOptions } from 'leaflet'; +// @ts-ignore +import L, { PolylineDecorator, PolylineDecoratorOptions, Symbol } from 'leaflet'; import 'leaflet-polylinedecorator'; import { FormattedData, PolylineSettings } from './map-models'; @@ -23,7 +24,7 @@ import { functionValueCalculator } from '@home/components/widget/lib/maps/common export class Polyline { leafletPoly: L.Polyline; - polylineDecorator: L.PolylineDecorator; + polylineDecorator: PolylineDecorator; dataSources: FormattedData[]; data: FormattedData; @@ -36,7 +37,7 @@ export class Polyline { ).addTo(this.map); if (settings.usePolylineDecorator) { - this.polylineDecorator = L.polylineDecorator(this.leafletPoly, this.getDecoratorSettings(settings)).addTo(this.map); + this.polylineDecorator = new PolylineDecorator(this.leafletPoly, this.getDecoratorSettings(settings)).addTo(this.map); } } @@ -47,7 +48,7 @@ export class Polyline { offset: settings.decoratorOffset, endOffset: settings.endDecoratorOffset, repeat: settings.decoratorRepeat, - symbol: L.Symbol[settings.decoratorSymbol]({ + symbol: Symbol[settings.decoratorSymbol]({ pixelSize: settings.decoratorSymbolSize, polygon: false, pathOptions: { @@ -78,7 +79,8 @@ export class Polyline { opacity: functionValueCalculator(settings.useStrokeOpacityFunction, settings.strokeOpacityFunction, [this.data, this.dataSources, this.data.dsIndex], settings.strokeOpacity), weight: functionValueCalculator(settings.useStrokeWeightFunction, settings.strokeWeightFunction, - [this.data, this.dataSources, this.data.dsIndex], settings.strokeWeight) + [this.data, this.dataSources, this.data.dsIndex], settings.strokeWeight), + pmIgnore: true }; } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/google-map.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/google-map.ts index f3369dd46c..00d9353218 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/google-map.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/google-map.ts @@ -38,7 +38,6 @@ export class GoogleMap extends LeafletMap { this.loadGoogle(() => { const map = L.map($container, { attributionControl: false, - editable: !!options.editablePolygon, tap: L.Browser.safari && L.Browser.mobile }).setView(options?.defaultCenterPosition, options?.defaultZoomLevel || DEFAULT_ZOOM_LEVEL); (L.gridLayer as any).googleMutant({ diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/here-map.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/here-map.ts index e15c897c3b..caac9a78b4 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/here-map.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/here-map.ts @@ -23,7 +23,6 @@ export class HEREMap extends LeafletMap { constructor(ctx: WidgetContext, $container, options: UnitedMapSettings) { super(ctx, $container, options); const map = L.map($container, { - editable: !!options.editablePolygon, tap: L.Browser.safari && L.Browser.mobile }).setView(options?.defaultCenterPosition, options?.defaultZoomLevel || DEFAULT_ZOOM_LEVEL); const tileLayer = (L.tileLayer as any).provider(options.mapProviderHere || 'HERE.normalDay', options.credentials); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/image-map.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/image-map.ts index 272476ea9e..be427f55cf 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/image-map.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/image-map.ts @@ -22,7 +22,6 @@ import { filter, map, mergeMap } from 'rxjs/operators'; import { aspectCache, calculateNewPointCoordinate, - checkLngLat, parseFunction } from '@home/components/widget/lib/maps/common-maps-utils'; import { WidgetContext } from '@home/models/widget-component.models'; @@ -221,7 +220,6 @@ export class ImageMap extends LeafletMap { zoom: 1, crs: L.CRS.Simple, attributionControl: false, - editable: !!this.options.editablePolygon, tap: L.Browser.safari && L.Browser.mobile }); this.updateBounds(updateImage); @@ -263,7 +261,13 @@ export class ImageMap extends LeafletMap { return L.CRS.Simple.latLngToPoint(latLng, maxZoom - 1); } - convertToCustomFormat(position: L.LatLng, offset = 0, width = this.width, height = this.height): object { + convertToCustomFormat(position: L.LatLng, offset = 0, width = this.width, height = this.height): {[key: string]: any} { + if (!position) { + return { + [this.options.xPosKeyName]: null, + [this.options.yPosKeyName]: null + }; + } const point = this.latLngToPoint(position); const customX = calculateNewPointCoordinate(point.x, width); const customY = calculateNewPointCoordinate(point.y, height); @@ -279,13 +283,9 @@ export class ImageMap extends LeafletMap { point.y = height; } - const customLatLng = checkLngLat(this.pointToLatLng(point.x, point.y), this.southWest, this.northEast, offset); - return { [this.options.xPosKeyName]: customX, - [this.options.yPosKeyName]: customY, - [this.options.latKeyName]: customLatLng.lat, - [this.options.lngKeyName]: customLatLng.lng + [this.options.yPosKeyName]: customY }; } @@ -304,9 +304,10 @@ export class ImageMap extends LeafletMap { } } - convertPolygonToCustomFormat(expression: any[][]): object { + convertPolygonToCustomFormat(expression: any[][]): {[key: string]: any} { + const coordinate = expression ? this.convertToPolygonFormat(expression) : null; return { - [this.options.polygonKeyName] : this.convertToPolygonFormat(expression) + [this.options.polygonKeyName]: coordinate }; } } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/openstreet-map.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/openstreet-map.ts index 61312aab23..01eb04ea40 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/openstreet-map.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/openstreet-map.ts @@ -23,7 +23,6 @@ export class OpenStreetMap extends LeafletMap { constructor(ctx: WidgetContext, $container, options: UnitedMapSettings) { super(ctx, $container, options); const map = L.map($container, { - editable: !!options.editablePolygon, tap: L.Browser.safari && L.Browser.mobile }).setView(options?.defaultCenterPosition, options?.defaultZoomLevel || DEFAULT_ZOOM_LEVEL); let tileLayer; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/tencent-map.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/tencent-map.ts index bd34e24331..5e71d92e5d 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/tencent-map.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/tencent-map.ts @@ -25,7 +25,6 @@ export class TencentMap extends LeafletMap { super(ctx, $container, options); const txUrl = 'http://rt{s}.map.gtimg.com/realtimerender?z={z}&x={x}&y={y}&type=vector&style=0'; const map = L.map($container, { - editable: !!options.editablePolygon, tap: L.Browser.safari && L.Browser.mobile }).setView(options?.defaultCenterPosition, options?.defaultZoomLevel || DEFAULT_ZOOM_LEVEL); const txLayer = L.tileLayer(txUrl, { diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/schemes.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/schemes.ts index 4c7e6e61fa..ff52ece929 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/schemes.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/schemes.ts @@ -728,6 +728,11 @@ export const markerClusteringSettingsSchemaLeaflet = type: 'number', default: 80 }, + spiderfyOnMaxZoom: { + title: 'Spiderfy at the max zoom level (to see all cluster markers)', + type: 'boolean', + default: false + }, chunkedLoading: { title: 'Use chunks for adding markers so that the page does not freeze', type: 'boolean', @@ -747,6 +752,7 @@ export const markerClusteringSettingsSchemaLeaflet = 'showCoverageOnHover', 'animate', 'maxClusterRadius', + 'spiderfyOnMaxZoom', 'chunkedLoading', 'removeOutsideVisibleBounds' ] diff --git a/ui-ngx/src/app/modules/home/components/widget/trip-animation/trip-animation.component.ts b/ui-ngx/src/app/modules/home/components/widget/trip-animation/trip-animation.component.ts index b8b1d193e4..dfa630b3ad 100644 --- a/ui-ngx/src/app/modules/home/components/widget/trip-animation/trip-animation.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/trip-animation/trip-animation.component.ts @@ -100,7 +100,10 @@ export class TripAnimationComponent implements OnInit, AfterViewInit, OnDestroy addGroupInfo(schema, 'Path Settings'); addToSchema(schema, addCondition(pointSchema, 'model.showPoints === true', ['showPoints'])); addGroupInfo(schema, 'Path Points Settings'); - addToSchema(schema, addCondition(mapPolygonSchema, 'model.showPolygon === true', ['showPolygon'])); + const mapPolygonSchemaWithoutEdit = mapPolygonSchema; + delete mapPolygonSchemaWithoutEdit.schema.properties.editablePolygon; + mapPolygonSchemaWithoutEdit.form.splice(mapPolygonSchemaWithoutEdit.form.indexOf('editablePolygon'), 1); + addToSchema(schema, addCondition(mapPolygonSchemaWithoutEdit, 'model.showPolygon === true', ['showPolygon'])); addGroupInfo(schema, 'Polygon Settings'); return schema; } @@ -115,6 +118,7 @@ export class TripAnimationComponent implements OnInit, AfterViewInit, OnDestroy rotationAngle: 0 }; this.settings = { ...settings, ...this.ctx.settings }; + this.settings.editablePolygon = false; this.useAnchors = this.settings.showPoints && this.settings.usePointAsAnchor; this.settings.pointAsAnchorFunction = parseFunction(this.settings.pointAsAnchorFunction, ['data', 'dsData', 'dsIndex']); this.settings.tooltipFunction = parseFunction(this.settings.tooltipFunction, ['data', 'dsData', 'dsIndex']); diff --git a/ui-ngx/src/app/modules/home/components/widget/widget-components.module.ts b/ui-ngx/src/app/modules/home/components/widget/widget-components.module.ts index ed9ef23f82..ba692ed122 100644 --- a/ui-ngx/src/app/modules/home/components/widget/widget-components.module.ts +++ b/ui-ngx/src/app/modules/home/components/widget/widget-components.module.ts @@ -41,6 +41,7 @@ import { EdgesOverviewWidgetComponent } from '@home/components/widget/lib/edges- import { JsonInputWidgetComponent } from '@home/components/widget/lib/json-input-widget.component'; import { QrCodeWidgetComponent } from '@home/components/widget/lib/qrcode-widget.component'; import { MarkdownWidgetComponent } from '@home/components/widget/lib/markdown-widget.component'; +import { SelectEntityDialogComponent } from './lib/maps/dialogs/select-entity-dialog.component'; @NgModule({ declarations: @@ -62,7 +63,8 @@ import { MarkdownWidgetComponent } from '@home/components/widget/lib/markdown-wi NavigationCardsWidgetComponent, NavigationCardWidgetComponent, QrCodeWidgetComponent, - MarkdownWidgetComponent + MarkdownWidgetComponent, + SelectEntityDialogComponent ], imports: [ CommonModule, diff --git a/ui-ngx/src/assets/add_location.svg b/ui-ngx/src/assets/add_location.svg deleted file mode 100644 index e3150115b7..0000000000 --- a/ui-ngx/src/assets/add_location.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/ui-ngx/src/assets/add_polygon.svg b/ui-ngx/src/assets/add_polygon.svg deleted file mode 100644 index 098f02c128..0000000000 --- a/ui-ngx/src/assets/add_polygon.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/ui-ngx/src/assets/locale/locale.constant-en_US.json b/ui-ngx/src/assets/locale/locale.constant-en_US.json index bd14f73e27..3ee86c15d6 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -3238,7 +3238,40 @@ "update-timeseries": "Update timeseries", "value": "Value" }, - "invalid-qr-code-text": "Invalid input text for QR code. Input should have a string type" + "invalid-qr-code-text": "Invalid input text for QR code. Input should have a string type", + "maps": { + "select-entity": "Select entity", + "select-entity-hint": "Hint: after selection click at the map to set position", + "tooltips": { + "placeMarker": "Click to place marker", + "firstVertex": "Click to place first point", + "continueLine": "Click to continue drawing", + "finishLine": "Click any existing marker to finish", + "finishPoly": "Click first marker to finish and save", + "finishRect": "Click to finish and save", + "startCircle": "Click to place circle center", + "finishCircle": "Click to finish circle", + "placeCircleMarker": "Click to place circle marker" + }, + "actions": { + "finish": "Finish", + "cancel": "Cancel", + "removeLastVertex": "Remove last point" + }, + "buttonTitles": { + "drawMarkerButton": "Create marker", + "drawPolyButton": "Create polygon", + "drawLineButton": "Create Polyline", + "drawCircleButton": "Create Circle", + "drawRectButton": "Create rectangle", + "editButton": "Edit mode", + "dragButton": "Drag-drop mode", + "cutButton": "Cut polygon area", + "deleteButton": "Remove", + "drawCircleMarkerButton": "Create circle marker", + "rotateButton": "Rotate polygon" + } + } }, "icon": { "icon": "Icon", diff --git a/ui-ngx/src/assets/shadow.png b/ui-ngx/src/assets/shadow.png new file mode 100644 index 0000000000000000000000000000000000000000..fc2f271799dbf1ec2055dd532952cd9c1adff6e2 GIT binary patch literal 712 zcmV;(0yq7MP)DPwCqqps>CHM?|!y z5@-i@Vt4v!5yADje^sQdo^bOC^;Sfmh}zGz6)FojnqV^tv={r*cILGSt(t3BBS9AO z0W0~ti0G(R)AS8Eg+17hgE)}3J;AD7))r+^6)BvvvVn@`S<%g901LQ79X2D<-iwOS zvn-;wB+~j_L~*HeL9c+71lg64dqos?C_f1*_@dP$AMhSuSG&1az$t7I9XgX>+xmd3 z;~ie(C0^ipo?BJD0*-0TyU7IZR&T4RCZhEa57M6DW4A@U02VW9QEQkMgSB{r{7KCO z`-)cycOOsjCim&8UI3Rx5r4w0Nby#!L0r6VJJm?AH+Y2Gc#?a}Ya7OE1thxbvlt7T zL_KcFIbmU zqDb49JZ^`piO#%=OSmf@YE3E&SWCFN=;{r5zKO>;hx4ND2BLmG7ACZ6u_5a74$k7D zXn=vKAHcd+Cy(JK&fuB>q_k6I0V|?G4vTNV>o_Ig>VriKl?80#D2|A+a~hWi4b`r) ufX8rL)ZHmu7&y@ybwZ@`IIX7+?Kac^0000 Date: Wed, 24 Nov 2021 19:18:40 +0200 Subject: [PATCH 147/432] lwm2m - trust Certificate - ok --- .../TbLwM2MDtlsCertificateVerifier.java | 54 ++++++++++++++++--- 1 file changed, 48 insertions(+), 6 deletions(-) diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MDtlsCertificateVerifier.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MDtlsCertificateVerifier.java index e3bfe986c3..2251701e23 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MDtlsCertificateVerifier.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MDtlsCertificateVerifier.java @@ -29,6 +29,7 @@ import org.eclipse.californium.scandium.dtls.HandshakeResultHandler; import org.eclipse.californium.scandium.dtls.x509.NewAdvancedCertificateVerifier; import org.eclipse.californium.scandium.dtls.x509.StaticCertificateVerifier; import org.eclipse.californium.scandium.util.ServerNames; +import org.eclipse.leshan.core.util.SecurityUtil; import org.eclipse.leshan.server.security.NonUniqueSecurityInfoException; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; @@ -56,6 +57,7 @@ import java.security.cert.CertificateNotYetValidException; import java.security.cert.X509Certificate; import java.util.Arrays; import java.util.List; +import java.util.Optional; import static org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mTypeServer.CLIENT; @@ -114,13 +116,28 @@ public class TbLwM2MDtlsCertificateVerifier implements NewAdvancedCertificateVer cert.checkValidity(); } + + TbLwM2MSecurityInfo securityInfo = null; + // verify if trust + if (config.getTrustSslCredentials().getTrustedCertificates().length > 0) { + if (searchIssuer(cert, config.getTrustSslCredentials().getTrustedCertificates()) != null) { + String [] dns = cert.getSubjectX500Principal().getName().split(","); + Optional cn = (Arrays.stream(dns).filter(dn -> dn.contains("CN="))).findFirst(); + if (cn.isPresent() && cn.get().length()>3){ + String endpoint = cn.get().split("=")[1]; + securityInfo = securityInfoValidator.getEndpointSecurityInfoByCredentialsId(endpoint, CLIENT); + } + } + } + // if not trust or cert trust securityInfo == null String strCert = SslUtil.getCertificateString(cert); String sha3Hash = EncryptionUtil.getSha3Hash(strCert); - TbLwM2MSecurityInfo securityInfo; - try { - securityInfo = securityInfoValidator.getEndpointSecurityInfoByCredentialsId(sha3Hash, CLIENT); - } catch (LwM2MAuthException e) { - securityInfo = null; + if (securityInfo == null) { + try { + securityInfo = securityInfoValidator.getEndpointSecurityInfoByCredentialsId(sha3Hash, CLIENT); + } catch (LwM2MAuthException e) { + log.trace("Failed find security info: {}", sha3Hash, e); + } } ValidateDeviceCredentialsResponse msg = securityInfo != null ? securityInfo.getMsg() : null; if (msg != null && org.thingsboard.server.common.data.StringUtils.isNotEmpty(msg.getCredentials())) { @@ -131,7 +148,7 @@ public class TbLwM2MDtlsCertificateVerifier implements NewAdvancedCertificateVer X509ClientCredential config = (X509ClientCredential) credentials.getClient(); String certBody = config.getCert(); String endpoint = config.getEndpoint(); - if (strCert.equals(certBody)) { + if (certBody.isEmpty() || strCert.equals(certBody)) { x509CredentialsFound = true; DeviceProfile deviceProfile = msg.getDeviceProfile(); if (msg.hasDeviceInfo() && deviceProfile != null) { @@ -179,4 +196,29 @@ public class TbLwM2MDtlsCertificateVerifier implements NewAdvancedCertificateVer public void setResultHandler(HandshakeResultHandler resultHandler) { } + + private static X509Certificate searchIssuer(X509Certificate certificate, X509Certificate[] certificates) { + X500Principal subject = certificate.getIssuerX500Principal(); + for (int index = 0; index < certificates.length; ++index) { + X509Certificate trust = certificates[index]; + if (trust != null && subject.equals(trust.getIssuerX500Principal())) { + if (verifyCertificate(certificate)) { + return certificate; + } + } + } + return null; + } + + private static boolean verifyCertificate(X509Certificate certificate) { + try { + // date + certificate.checkValidity(); + // Validate X509. + SecurityUtil.certificate.decode(certificate.getEncoded()); + return true; + } catch (Exception e) { + return false; + } + } } From 132ace407c16fe1b51223b79148c35be72c38fa9 Mon Sep 17 00:00:00 2001 From: van-vanich Date: Thu, 25 Nov 2021 15:23:54 +0200 Subject: [PATCH 148/432] fix issue with forgotten license and fix the old test, which doesn't work because of a new feature --- .../server/dao/service/BaseEntityServiceTest.java | 8 ++++++++ .../dao/sql/query/EntityKeyMappingTest.java | 15 +++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseEntityServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseEntityServiceTest.java index e58191b60d..9140c457e6 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseEntityServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseEntityServiceTest.java @@ -1307,6 +1307,14 @@ public abstract class BaseEntityServiceTest extends AbstractServiceTest { notEqualStrings.add(operationName); containsStrings.add(operationName); break; + case IN: + notEqualStrings.add(operationName); + notContainsStrings.add(operationName); + break; + case NOT_IN: + notEqualStrings.add(operationName); + notContainsStrings.add(operationName); + break; } } diff --git a/dao/src/test/java/org/thingsboard/server/dao/sql/query/EntityKeyMappingTest.java b/dao/src/test/java/org/thingsboard/server/dao/sql/query/EntityKeyMappingTest.java index c914bce1c1..01b41121e4 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/sql/query/EntityKeyMappingTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/sql/query/EntityKeyMappingTest.java @@ -1,3 +1,18 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.thingsboard.server.dao.sql.query; import org.junit.Assert; From 0c499014d45b2dab7ec6784d983cb45147ab7428 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Thu, 25 Nov 2021 16:56:50 +0200 Subject: [PATCH 149/432] lwm2m - trust certificate, add get value by key from Subject Name --- .../lwm2m/secure/TbLwM2MDtlsCertificateVerifier.java | 10 +++------- .../transport/config/ssl/AbstractSslCredentials.java | 12 ++++++++++++ .../common/transport/config/ssl/SslCredentials.java | 1 + 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MDtlsCertificateVerifier.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MDtlsCertificateVerifier.java index 2251701e23..77d3aada6b 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MDtlsCertificateVerifier.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MDtlsCertificateVerifier.java @@ -35,6 +35,7 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.DeviceProfile; +import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MSecurityMode; import org.thingsboard.server.common.data.device.credentials.lwm2m.X509ClientCredential; import org.thingsboard.server.common.msg.EncryptionUtil; @@ -57,7 +58,6 @@ import java.security.cert.CertificateNotYetValidException; import java.security.cert.X509Certificate; import java.util.Arrays; import java.util.List; -import java.util.Optional; import static org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mTypeServer.CLIENT; @@ -121,12 +121,8 @@ public class TbLwM2MDtlsCertificateVerifier implements NewAdvancedCertificateVer // verify if trust if (config.getTrustSslCredentials().getTrustedCertificates().length > 0) { if (searchIssuer(cert, config.getTrustSslCredentials().getTrustedCertificates()) != null) { - String [] dns = cert.getSubjectX500Principal().getName().split(","); - Optional cn = (Arrays.stream(dns).filter(dn -> dn.contains("CN="))).findFirst(); - if (cn.isPresent() && cn.get().length()>3){ - String endpoint = cn.get().split("=")[1]; - securityInfo = securityInfoValidator.getEndpointSecurityInfoByCredentialsId(endpoint, CLIENT); - } + String endpoint = config.getTrustSslCredentials().getValueFromSubjectNameByKey(cert.getSubjectX500Principal().getName(), "CN"); + securityInfo = StringUtils.isNotEmpty(endpoint) ? securityInfoValidator.getEndpointSecurityInfoByCredentialsId(endpoint, CLIENT) : null; } } // if not trust or cert trust securityInfo == null diff --git a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/config/ssl/AbstractSslCredentials.java b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/config/ssl/AbstractSslCredentials.java index 792d46b475..8043396e8d 100644 --- a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/config/ssl/AbstractSslCredentials.java +++ b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/config/ssl/AbstractSslCredentials.java @@ -31,9 +31,11 @@ import java.security.UnrecoverableEntryException; import java.security.UnrecoverableKeyException; import java.security.cert.Certificate; import java.security.cert.X509Certificate; +import java.util.Arrays; import java.util.Collections; import java.util.Enumeration; import java.util.HashSet; +import java.util.Optional; import java.util.Set; public abstract class AbstractSslCredentials implements SslCredentials { @@ -113,6 +115,7 @@ public abstract class AbstractSslCredentials implements SslCredentials { return this.trusts; } + @Override public TrustManagerFactory createTrustManagerFactory() throws NoSuchAlgorithmException, KeyStoreException { TrustManagerFactory tmFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); @@ -127,6 +130,15 @@ public abstract class AbstractSslCredentials implements SslCredentials { return kmf; } + + @Override + public String getValueFromSubjectNameByKey(String subjectName, String key) { + String[] dns = subjectName.split(","); + Optional cn = (Arrays.stream(dns).filter(dn -> dn.contains(key + "="))).findFirst(); + String value = cn.isPresent() ? cn.get().replace(key + "=", "") : null; + return StringUtils.isNotEmpty(value) ? value : null; + } + protected abstract boolean canUse(); protected abstract KeyStore loadKeyStore(boolean isPrivateKeyRequired, char[] keyPasswordArray) throws IOException, GeneralSecurityException; diff --git a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/config/ssl/SslCredentials.java b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/config/ssl/SslCredentials.java index c6207b877d..49152960fc 100644 --- a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/config/ssl/SslCredentials.java +++ b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/config/ssl/SslCredentials.java @@ -49,4 +49,5 @@ public interface SslCredentials { KeyManagerFactory createKeyManagerFactory() throws NoSuchAlgorithmException, UnrecoverableKeyException, KeyStoreException; + String getValueFromSubjectNameByKey(String subjectName, String key); } From a12771ecfb114f6069a8a427380dd6ad72659d97 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Thu, 25 Nov 2021 18:05:23 +0200 Subject: [PATCH 150/432] lwm2m - trust certificate, fix bug X509_TrustLwM2MIntegrationTest --- .../lwm2m/security/AbstractSecurityLwM2MIntegrationTest.java | 2 +- .../transport/lwm2m/secure/TbLwM2MDtlsCertificateVerifier.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/AbstractSecurityLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/AbstractSecurityLwM2MIntegrationTest.java index 046f0558cb..ea30b43436 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/AbstractSecurityLwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/AbstractSecurityLwM2MIntegrationTest.java @@ -161,7 +161,7 @@ public abstract class AbstractSecurityLwM2MIntegrationTest extends AbstractLwM2M rootCAX509Cert = (X509Certificate) serverKeyStore.getCertificate("rootCA"); serverX509Cert = (X509Certificate) serverKeyStore.getCertificate("server"); serverX509CertSelfSigned = (X509Certificate) serverKeyStore.getCertificate("server_self_signed"); - trustedCertificates[0] = rootCAX509Cert; + trustedCertificates[0] = serverX509Cert; } catch (GeneralSecurityException | IOException e) { throw new RuntimeException(e); } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MDtlsCertificateVerifier.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MDtlsCertificateVerifier.java index 77d3aada6b..5daf639f29 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MDtlsCertificateVerifier.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MDtlsCertificateVerifier.java @@ -144,7 +144,7 @@ public class TbLwM2MDtlsCertificateVerifier implements NewAdvancedCertificateVer X509ClientCredential config = (X509ClientCredential) credentials.getClient(); String certBody = config.getCert(); String endpoint = config.getEndpoint(); - if (certBody.isEmpty() || strCert.equals(certBody)) { + if (StringUtils.isBlank(certBody) || strCert.equals(certBody)) { x509CredentialsFound = true; DeviceProfile deviceProfile = msg.getDeviceProfile(); if (msg.hasDeviceInfo() && deviceProfile != null) { From 19ab4f498a1a78fe72ec345a7f910a0dc9b92f5e Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Fri, 26 Nov 2021 11:12:31 +0200 Subject: [PATCH 151/432] lwm2m - info about previous update Ota --- .../server/ota/DefaultLwM2MOtaUpdateService.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/DefaultLwM2MOtaUpdateService.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/DefaultLwM2MOtaUpdateService.java index 050929c470..66903d8812 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/DefaultLwM2MOtaUpdateService.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/DefaultLwM2MOtaUpdateService.java @@ -399,12 +399,12 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl log.debug("[{}] Starting update to [{}{}] using binary", client.getEndpoint(), fwInfo.getTargetName(), fwInfo.getTargetVersion()); startUpdateUsingBinary(client, fwInfo); } - } else if (fwInfo.updateState != null) { - log.debug("[{}] failed to process firmware update: [{}]. Previous update failed.", client.getEndpoint(), fwInfo); - logService.log(client, "Failed to process firmware update: " + fwInfo + ". Previous update failed."); + } else if (fwInfo.getResult() != null && fwInfo.getResult().getCode() > 1) { + log.trace("[{}] Previous update failed. [{}]", client.getEndpoint(), fwInfo); + logService.log(client, "Previous update firmware failed. Result: " + fwInfo.getResult().name()); } } catch (Exception e) { - log.info("[{}] failed to update client: {}", client.getEndpoint(), fwInfo, e); + log.error("[{}] failed to update client: {}", client.getEndpoint(), fwInfo, e); sendStateUpdateToTelemetry(client, fwInfo, OtaPackageUpdateStatus.FAILED, "Internal server error: " + e.getMessage()); } } @@ -427,9 +427,9 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl startUpdateUsingBinary(client, swInfo); } } - } else if (swInfo.updateState != null) { - log.debug("[{}] failed to update client: [{}], previous update failed.", client.getEndpoint(), swInfo); - logService.log(client, "Failed to process software update: " + swInfo + ". Previous update failed."); + } else if (swInfo.getResult() != null && swInfo.getResult().code >= 50) { + log.trace("[{}] Previous update failed. [{}]", client.getEndpoint(), swInfo); + logService.log(client, "Previous update software failed. Result: " + swInfo.getResult().name()); } } catch (Exception e) { log.info("[{}] failed to update client: {}", client.getEndpoint(), swInfo, e); From d17f70494f1b0ad78f96656a9305105d15f401dc Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Fri, 26 Nov 2021 12:41:04 +0200 Subject: [PATCH 152/432] UI: Fixed open dashboard state in separate dialog showed a blank dialog --- .../src/app/modules/home/components/widget/widget.component.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/ui-ngx/src/app/modules/home/components/widget/widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/widget.component.ts index 8aaf9eb603..05d8686d46 100644 --- a/ui-ngx/src/app/modules/home/components/widget/widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/widget.component.ts @@ -1419,6 +1419,7 @@ export class WidgetComponent extends PageComponent implements OnInit, AfterViewI height: dialogHeight } }); + this.cd.markForCheck(); } private elementClick($event: Event) { From eda4e0f76181b9282d71256b42fa1a51cc614ab0 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Fri, 26 Nov 2021 13:47:07 +0200 Subject: [PATCH 153/432] Fixed right layout and state name propagation in mobile mode, skip popover/dialog dashboard changes. --- .../dashboard-page.component.ts | 26 ++++++++++--------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.ts b/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.ts index 534d22834a..37ef5e0429 100644 --- a/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.ts +++ b/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.ts @@ -345,24 +345,26 @@ export class DashboardPageComponent extends PageComponent implements IDashboardC this.runChangeDetection(); } )); - this.rxSubscriptions.push(this.route.queryParamMap.subscribe( - (paramMap) => { - if (paramMap.has('reload')) { - this.dashboardCtx.aliasController.updateAliases(); - setTimeout(() => { - this.mobileService.handleDashboardStateName(this.dashboardCtx.stateController.getCurrentStateName()); - this.mobileService.onDashboardLoaded(this.layouts.right.show, this.isRightLayoutOpened); - }); + if (this.syncStateWithQueryParam) { + this.rxSubscriptions.push(this.route.queryParamMap.subscribe( + (paramMap) => { + if (paramMap.has('reload')) { + this.dashboardCtx.aliasController.updateAliases(); + setTimeout(() => { + this.mobileService.handleDashboardStateName(this.dashboardCtx.stateController.getCurrentStateName()); + this.mobileService.onDashboardLoaded(this.layouts.right.show, this.isRightLayoutOpened); + }); + } } - } - )); + )); + } this.rxSubscriptions.push(this.breakpointObserver .observe(MediaBreakpoints['gt-sm']) .subscribe((state: BreakpointState) => { this.isMobile = !state.matches; } )); - if (this.isMobileApp) { + if (this.isMobileApp && this.syncStateWithQueryParam) { this.mobileService.registerToggleLayoutFunction(() => { setTimeout(() => { this.toggleLayouts(); @@ -464,7 +466,7 @@ export class DashboardPageComponent extends PageComponent implements IDashboardC } ngOnDestroy(): void { - if (this.isMobileApp) { + if (this.isMobileApp && this.syncStateWithQueryParam) { this.mobileService.unregisterToggleLayoutFunction(); } this.rxSubscriptions.forEach((subscription) => { From 79251adb3ae65e0dab93d8cd56533e561ac0caa1 Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Fri, 26 Nov 2021 16:01:21 +0200 Subject: [PATCH 154/432] UI: Revert code for backward-compatible after having updated editors in maps widgets --- .../components/widget/lib/maps/leaflet-map.ts | 57 +----------- .../components/widget/lib/maps/map-widget2.ts | 93 ++++++++++++++++++- ui-ngx/yarn.lock | 2 +- 3 files changed, 97 insertions(+), 55 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts index 03249a5307..5db9db2e9e 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts @@ -31,7 +31,7 @@ import { UnitedMapSettings } from './map-models'; import { Marker } from './markers'; -import { forkJoin, Observable, of } from 'rxjs'; +import { Observable, of } from 'rxjs'; import { Polyline } from './polyline'; import { Polygon } from './polygon'; import { createTooltip } from '@home/components/widget/lib/maps/maps-utils'; @@ -50,9 +50,6 @@ import { SelectEntityDialogData } from '@home/components/widget/lib/maps/dialogs/select-entity-dialog.component'; import { MatDialog } from '@angular/material/dialog'; -import { AttributeService } from '@core/http/attribute.service'; -import { EntityId } from '@shared/models/id/entity-id'; -import { AttributeScope, DataKeyType, LatestTelemetry } from '@shared/models/telemetry/telemetry.models'; export default abstract class LeafletMap { @@ -85,6 +82,9 @@ export default abstract class LeafletMap { southWest = new L.LatLng(-Projection.SphericalMercator['MAX_LATITUDE'], -180); // tslint:disable-next-line:no-string-literal northEast = new L.LatLng(Projection.SphericalMercator['MAX_LATITUDE'], 180); + saveLocation: (e: FormattedData, values: {[key: string]: any}) => Observable; + saveMarkerLocation: (e: FormattedData, lat?: number, lng?: number) => Observable; + savePolygonLocation: (e: FormattedData, coordinates?: Array) => Observable; protected constructor(public ctx: WidgetContext, public $container: HTMLElement, @@ -344,55 +344,6 @@ export default abstract class LeafletMap { } } - private saveLocation(e: FormattedData, values: {[key: string]: any}): Observable { - const attributeService = this.ctx.$injector.get(AttributeService); - const attributes = []; - const timeseries = []; - - const entityId: EntityId = { - entityType: e.$datasource.entityType, - id: e.$datasource.entityId - }; - - for (const dataKeyName of Object.keys(values)) { - for (const key of e.$datasource.dataKeys) { - if (dataKeyName === key.name) { - const value = { - key: key.name, - value: values[dataKeyName] - }; - if (key.type === DataKeyType.attribute) { - attributes.push(value); - } else if (key.type === DataKeyType.timeseries) { - timeseries.push(value); - } - break; - } - } - } - - const observables: Observable[] = []; - if (timeseries.length) { - observables.push(attributeService.saveEntityTimeseries( - entityId, - LatestTelemetry.LATEST_TELEMETRY, - timeseries - )); - } - if (attributes.length) { - observables.push(attributeService.saveEntityAttributes( - entityId, - AttributeScope.SERVER_SCOPE, - attributes - )); - } - if (observables.length) { - return forkJoin(observables); - } else { - return of(null); - } - } - createLatLng(lat: number, lng: number): L.LatLng { return L.latLng(lat, lng); } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-widget2.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-widget2.ts index eca27d6532..21c576eeb1 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-widget2.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-widget2.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { defaultSettings, hereProviders, MapProviders, UnitedMapSettings } from './map-models'; +import { defaultSettings, FormattedData, hereProviders, MapProviders, UnitedMapSettings } from './map-models'; import LeafletMap from './leaflet-map'; import { commonMapSettingsSchema, @@ -32,6 +32,12 @@ import { TranslateService } from '@ngx-translate/core'; import { UtilsService } from '@core/services/utils.service'; import { EntityDataPageLink } from '@shared/models/query/query.models'; import { providerClass } from '@home/components/widget/lib/maps/providers'; +import { isDefined } from '@core/utils'; +import L from 'leaflet'; +import { forkJoin, Observable, of } from 'rxjs'; +import { AttributeService } from '@core/http/attribute.service'; +import { EntityId } from '@shared/models/id/entity-id'; +import { AttributeScope, DataKeyType, LatestTelemetry } from '@shared/models/telemetry/telemetry.models'; // @dynamic export class MapWidgetController implements MapWidgetInterface { @@ -63,6 +69,10 @@ export class MapWidgetController implements MapWidgetInterface { } parseWithTranslation.setTranslate(this.translate); this.map = new MapClass(this.ctx, $element, this.settings); + (this.ctx as any).mapInstance = this.map; + this.map.saveMarkerLocation = this.setMarkerLocation; + this.map.savePolygonLocation = this.savePolygonLocation; + this.map.saveLocation = this.saveLocation; this.pageLink = { page: 0, pageSize: this.settings.mapPageSize, @@ -158,6 +168,86 @@ export class MapWidgetController implements MapWidgetInterface { }, entityName, null, entityLabel); } + setMarkerLocation(e: FormattedData, lat?: number, lng?: number) { + let markerValue; + if (isDefined(lat) && isDefined(lng)) { + const point = lat != null && lng !== null ? L.latLng(lat, lng) : null; + markerValue = this.map.convertToCustomFormat(point); + } else if (this.settings.mapProvider !== MapProviders.image) { + markerValue = { + [this.settings.latKeyName]: e[this.settings.latKeyName], + [this.settings.lngKeyName]: e[this.settings.lngKeyName], + }; + } else { + markerValue = { + [this.settings.xPosKeyName]: e[this.settings.xPosKeyName], + [this.settings.yPosKeyName]: e[this.settings.yPosKeyName], + }; + } + return this.saveLocation(e, markerValue); + } + + savePolygonLocation(e: FormattedData, coordinates?: Array) { + let polygonValue; + if (isDefined(coordinates)) { + polygonValue = this.map.convertToPolygonFormat(coordinates); + } else { + polygonValue = { + [this.settings.polygonKeyName]: e[this.settings.polygonKeyName] + }; + } + return this.saveLocation(e, polygonValue); + } + + saveLocation(e: FormattedData, values: {[key: string]: any}): Observable { + const attributeService = this.ctx.$injector.get(AttributeService); + const attributes = []; + const timeseries = []; + + const entityId: EntityId = { + entityType: e.$datasource.entityType, + id: e.$datasource.entityId + }; + + for (const dataKeyName of Object.keys(values)) { + for (const key of e.$datasource.dataKeys) { + if (dataKeyName === key.name) { + const value = { + key: key.name, + value: values[dataKeyName] + }; + if (key.type === DataKeyType.attribute) { + attributes.push(value); + } else if (key.type === DataKeyType.timeseries) { + timeseries.push(value); + } + break; + } + } + } + + const observables: Observable[] = []; + if (timeseries.length) { + observables.push(attributeService.saveEntityTimeseries( + entityId, + LatestTelemetry.LATEST_TELEMETRY, + timeseries + )); + } + if (attributes.length) { + observables.push(attributeService.saveEntityAttributes( + entityId, + AttributeScope.SERVER_SCOPE, + attributes + )); + } + if (observables.length) { + return forkJoin(observables); + } else { + return of(null); + } + } + initSettings(settings: UnitedMapSettings, isEditMap?: boolean): UnitedMapSettings { const functionParams = ['data', 'dsData', 'dsIndex']; this.provider = settings.provider || this.mapProvider; @@ -209,6 +299,7 @@ export class MapWidgetController implements MapWidgetInterface { } destroy() { + (this.ctx as any).mapInstance = null; if (this.map) { this.map.remove(); } diff --git a/ui-ngx/yarn.lock b/ui-ngx/yarn.lock index 046e100cd1..36eb458108 100644 --- a/ui-ngx/yarn.lock +++ b/ui-ngx/yarn.lock @@ -6444,7 +6444,7 @@ leaflet-rotatedmarker@^0.2.0: resolved "https://registry.yarnpkg.com/leaflet-rotatedmarker/-/leaflet-rotatedmarker-0.2.0.tgz#4467f49f98d1bfd56959bd9c6705203dd2601277" integrity sha1-RGf0n5jRv9VpWb2cZwUgPdJgEnc= -leaflet.gridlayer.googlemutant@0.13.4: +leaflet.gridlayer.googlemutant@^0.13.4: version "0.13.4" resolved "https://registry.yarnpkg.com/leaflet.gridlayer.googlemutant/-/leaflet.gridlayer.googlemutant-0.13.4.tgz#0add37d240c70c999e1f1d341208e6fea2372c40" integrity sha512-oC6xUSFJ9HP4WIupXakgiYckdBHuHQeSaxTXsVlcvcpfsuYoJ/HFIrz1bmK4Qr/qKO4fY1MDM6AoewU7Bph8ZQ== From 5d4579ce288bcd6750b9a8a82e80f94d757c26ed Mon Sep 17 00:00:00 2001 From: ArtemDzhereleiko Date: Fri, 26 Nov 2021 17:00:51 +0200 Subject: [PATCH 155/432] UI: New control widget Persistent table --- .../widget_bundles/control_widgets.json | 18 + .../server/controller/RpcV2Controller.java | 11 +- .../server/dao/rpc/RpcService.java | 2 + .../server/dao/rpc/BaseRpcService.java | 10 +- .../thingsboard/server/dao/rpc/RpcDao.java | 4 +- .../server/dao/sql/rpc/JpaRpcDao.java | 7 +- .../server/dao/sql/rpc/RpcRepository.java | 2 + ui-ngx/src/app/core/api/widget-api.models.ts | 14 +- .../src/app/core/api/widget-subscription.ts | 23 +- ui-ngx/src/app/core/http/device.service.ts | 13 +- .../rpc/persistent-add-dialog.component.html | 92 ++++ .../rpc/persistent-add-dialog.component.scss | 30 ++ .../rpc/persistent-add-dialog.component.ts | 77 +++ .../persistent-details-dialog.component.html | 118 +++++ .../persistent-details-dialog.component.scss | 33 ++ .../persistent-details-dialog.component.ts | 151 ++++++ .../persistent-filter-panel.component.html | 44 ++ .../persistent-filter-panel.component.scss | 36 ++ .../rpc/persistent-filter-panel.component.ts | 71 +++ .../lib/rpc/persistent-table.component.html | 125 +++++ .../lib/rpc/persistent-table.component.scss | 52 ++ .../lib/rpc/persistent-table.component.ts | 476 ++++++++++++++++++ .../widget/lib/rpc/rpc-widgets.module.ts | 15 +- .../home/models/widget-component.models.ts | 10 +- .../json-object-view.component.html | 22 + .../json-object-view.component.scss | 27 + .../components/json-object-view.component.ts | 166 ++++++ ui-ngx/src/app/shared/models/rpc.models.ts | 51 +- ui-ngx/src/app/shared/shared.module.ts | 3 + .../assets/locale/locale.constant-en_US.json | 44 +- .../assets/locale/locale.constant-ru_RU.json | 41 ++ .../assets/locale/locale.constant-uk_UA.json | 41 ++ 32 files changed, 1805 insertions(+), 24 deletions(-) create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-add-dialog.component.html create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-add-dialog.component.scss create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-add-dialog.component.ts create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-details-dialog.component.html create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-details-dialog.component.scss create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-details-dialog.component.ts create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-filter-panel.component.html create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-filter-panel.component.scss create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-filter-panel.component.ts create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-table.component.html create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-table.component.scss create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-table.component.ts create mode 100644 ui-ngx/src/app/shared/components/json-object-view.component.html create mode 100644 ui-ngx/src/app/shared/components/json-object-view.component.scss create mode 100644 ui-ngx/src/app/shared/components/json-object-view.component.ts diff --git a/application/src/main/data/json/system/widget_bundles/control_widgets.json b/application/src/main/data/json/system/widget_bundles/control_widgets.json index f1e3eaa1fe..73a1ef633d 100644 --- a/application/src/main/data/json/system/widget_bundles/control_widgets.json +++ b/application/src/main/data/json/system/widget_bundles/control_widgets.json @@ -149,6 +149,24 @@ "dataKeySettingsSchema": "{}\n", "defaultConfig": "{\"showTitle\":false,\"backgroundColor\":\"#e6e7e8\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"styleButton\":{\"isRaised\":true,\"isPrimary\":false},\"entityParameters\":\"{}\",\"entityAttributeType\":\"SERVER_SCOPE\",\"buttonText\":\"Update device attribute\"},\"title\":\"Update device attribute\",\"dropShadow\":true,\"enableFullscreen\":false,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"useDashboardTimewindow\":true,\"showLegend\":false,\"actions\":{},\"targetDeviceAliases\":[]}" } + }, + { + "alias": "persistent_table", + "name": "Persistent table", + "image": "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjAwIiBoZWlnaHQ9IjE2MCIgdmlld0JveD0iMCAwIDIwMCAxNjAiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxwYXRoIGQ9Ik0yMDAgMEgwVjE2MEgyMDBWMFoiIGZpbGw9IndoaXRlIi8+CjxwYXRoIGQ9Ik0yMDAgMTIwSDBWMTIxSDIwMFYxMjBaIiBmaWxsPSIjRTBFMEUwIi8+CjxwYXRoIGQ9Ik0yMDAgODBIMFY4MUgyMDBWODBaIiBmaWxsPSIjRTBFMEUwIi8+CjxwYXRoIGQ9Ik0yMDAgMzlIMFY0MEgyMDBWMzlaIiBmaWxsPSIjRTBFMEUwIi8+CjxwYXRoIGQ9Ik0xNS42Njg1IDE5Ljk4NjhIMTQuMTUzOFYyM0gxMi43OTQ5VjE1LjE3OTdIMTUuNTQ0OUMxNi40NDczIDE1LjE3OTcgMTcuMTQzNyAxNS4zODIgMTcuNjM0MyAxNS43ODY2QzE4LjEyNDggMTYuMTkxMiAxOC4zNzAxIDE2Ljc3NjcgMTguMzcwMSAxNy41NDNDMTguMzcwMSAxOC4wNjU4IDE4LjI0MyAxOC41MDQ0IDE3Ljk4ODggMTguODU4OUMxNy43MzgxIDE5LjIwOTggMTcuMzg3MiAxOS40ODAxIDE2LjkzNiAxOS42Njk5TDE4LjY5MjQgMjIuOTMwMlYyM0gxNy4yMzY4TDE1LjY2ODUgMTkuOTg2OFpNMTQuMTUzOCAxOC44OTY1SDE1LjU1MDNDMTYuMDA4NiAxOC44OTY1IDE2LjM2NjcgMTguNzgxOSAxNi42MjQ1IDE4LjU1MjdDMTYuODgyMyAxOC4zMiAxNy4wMTEyIDE4LjAwMzEgMTcuMDExMiAxNy42MDIxQzE3LjAxMTIgMTcuMTgzMSAxNi44OTEzIDE2Ljg1OSAxNi42NTE0IDE2LjYyOTlDMTYuNDE1IDE2LjQwMDcgMTYuMDYwNSAxNi4yODI2IDE1LjU4NzkgMTYuMjc1NEgxNC4xNTM4VjE4Ljg5NjVaIiBmaWxsPSJibGFjayIgZmlsbC1vcGFjaXR5PSIwLjg3Ii8+CjxwYXRoIGQ9Ik0yMS4wMTgxIDIwLjA5NDJWMjNIMTkuNjU5MlYxNS4xNzk3SDIyLjY1MDlDMjMuNTI0NiAxNS4xNzk3IDI0LjIxNzQgMTUuNDA3MSAyNC43Mjk1IDE1Ljg2MThDMjUuMjQ1MSAxNi4zMTY2IDI1LjUwMjkgMTYuOTE4MSAyNS41MDI5IDE3LjY2NjVDMjUuNTAyOSAxOC40MzI4IDI1LjI1MDUgMTkuMDI5IDI0Ljc0NTYgMTkuNDU1MUMyNC4yNDQzIDE5Ljg4MTIgMjMuNTQwNyAyMC4wOTQyIDIyLjYzNDggMjAuMDk0MkgyMS4wMTgxWk0yMS4wMTgxIDE5LjAwMzlIMjIuNjUwOUMyMy4xMzQzIDE5LjAwMzkgMjMuNTAzMSAxOC44OTExIDIzLjc1NzMgMTguNjY1NUMyNC4wMTE2IDE4LjQzNjQgMjQuMTM4NyAxOC4xMDY5IDI0LjEzODcgMTcuNjc3MkMyNC4xMzg3IDE3LjI1NDcgMjQuMDA5OCAxNi45MTgxIDIzLjc1MiAxNi42Njc1QzIzLjQ5NDEgMTYuNDEzMiAyMy4xMzk2IDE2LjI4MjYgMjIuNjg4NSAxNi4yNzU0SDIxLjAxODFWMTkuMDAzOVoiIGZpbGw9ImJsYWNrIiBmaWxsLW9wYWNpdHk9IjAuODciLz4KPHBhdGggZD0iTTMyLjY2MjYgMjAuNDU0MUMzMi41ODM4IDIxLjI4ODQgMzIuMjc1OSAyMS45NDAxIDMxLjczODggMjIuNDA5MkMzMS4yMDE3IDIyLjg3NDcgMzAuNDg3MyAyMy4xMDc0IDI5LjU5NTcgMjMuMTA3NEMyOC45NzI3IDIzLjEwNzQgMjguNDIzIDIyLjk2MDYgMjcuOTQ2OCAyMi42NjdDMjcuNDc0MSAyMi4zNjk4IDI3LjEwODkgMjEuOTQ5MSAyNi44NTExIDIxLjQwNDhDMjYuNTkzMyAyMC44NjA1IDI2LjQ1OSAyMC4yMjg1IDI2LjQ0ODIgMTkuNTA4OFYxOC43NzgzQzI2LjQ0ODIgMTguMDQwNyAyNi41Nzg5IDE3LjM5MDggMjYuODQwMyAxNi44Mjg2QzI3LjEwMTcgMTYuMjY2NCAyNy40NzU5IDE1LjgzMzIgMjcuOTYyOSAxNS41Mjg4QzI4LjQ1MzUgMTUuMjI0NCAyOS4wMTkyIDE1LjA3MjMgMjkuNjYwMiAxNS4wNzIzQzMwLjUyMzEgMTUuMDcyMyAzMS4yMTc4IDE1LjMwNjggMzEuNzQ0MSAxNS43NzU5QzMyLjI3MDUgMTYuMjQ1IDMyLjU3NjcgMTYuOTA3NCAzMi42NjI2IDE3Ljc2MzJIMzEuMzA5MUMzMS4yNDQ2IDE3LjIwMSAzMS4wNzk5IDE2Ljc5NjQgMzAuODE0OSAxNi41NDkzQzMwLjU1MzUgMTYuMjk4NyAzMC4xNjg2IDE2LjE3MzMgMjkuNjYwMiAxNi4xNzMzQzI5LjA2OTMgMTYuMTczMyAyOC42MTQ2IDE2LjM5IDI4LjI5NTkgMTYuODIzMkMyNy45ODA4IDE3LjI1MjkgMjcuODE5NyAxNy44ODQ5IDI3LjgxMjUgMTguNzE5MlYxOS40MTIxQzI3LjgxMjUgMjAuMjU3MiAyNy45NjI5IDIwLjkwMTcgMjguMjYzNyAyMS4zNDU3QzI4LjU2OCAyMS43ODk3IDI5LjAxMiAyMi4wMTE3IDI5LjU5NTcgMjIuMDExN0MzMC4xMjkyIDIyLjAxMTcgMzAuNTMwMyAyMS44OTE4IDMwLjc5ODggMjEuNjUxOUMzMS4wNjc0IDIxLjQxMTkgMzEuMjM3NSAyMS4wMTI3IDMxLjMwOTEgMjAuNDU0MUgzMi42NjI2WiIgZmlsbD0iYmxhY2siIGZpbGwtb3BhY2l0eT0iMC44NyIvPgo8cGF0aCBkPSJNMzguMDU1MiAyM0gzNi43MDE3VjE1LjE3OTdIMzguMDU1MlYyM1oiIGZpbGw9ImJsYWNrIiBmaWxsLW9wYWNpdHk9IjAuODciLz4KPHBhdGggZD0iTTM5LjcyNTYgMjNWMTUuMTc5N0g0Mi4wMzUyQzQyLjcyNjIgMTUuMTc5NyA0My4zMzg1IDE1LjMzMzcgNDMuODcyMSAxNS42NDE2QzQ0LjQwOTIgMTUuOTQ5NSA0NC44MjQ1IDE2LjM4NjQgNDUuMTE4MiAxNi45NTIxQzQ1LjQxMTggMTcuNTE3OSA0NS41NTg2IDE4LjE2NiA0NS41NTg2IDE4Ljg5NjVWMTkuMjg4NkM0NS41NTg2IDIwLjAyOTggNDUuNDEgMjAuNjgxNSA0NS4xMTI4IDIxLjI0MzdDNDQuODE5MiAyMS44MDU4IDQ0LjM5ODQgMjIuMjM5MSA0My44NTA2IDIyLjU0MzVDNDMuMzA2MyAyMi44NDc4IDQyLjY4MTUgMjMgNDEuOTc2MSAyM0gzOS43MjU2Wk00MS4wODQ1IDE2LjI3NTRWMjEuOTE1SDQxLjk3MDdDNDIuNjgzMyAyMS45MTUgNDMuMjI5MyAyMS42OTMgNDMuNjA4OSAyMS4yNDlDNDMuOTkyIDIwLjgwMTQgNDQuMTg3MiAyMC4xNjA1IDQ0LjE5NDMgMTkuMzI2MlYxOC44OTExQzQ0LjE5NDMgMTguMDQyNSA0NC4wMDk5IDE3LjM5NDQgNDMuNjQxMSAxNi45NDY4QzQzLjI3MjMgMTYuNDk5MiA0Mi43MzcgMTYuMjc1NCA0Mi4wMzUyIDE2LjI3NTRINDEuMDg0NVoiIGZpbGw9ImJsYWNrIiBmaWxsLW9wYWNpdHk9IjAuODciLz4KPHBhdGggZD0iTTYxLjU1NjYgMTUuMTc5N0w2My44MTI1IDIxLjE3MzhMNjYuMDYzIDE1LjE3OTdINjcuODE5M1YyM0g2Ni40NjU4VjIwLjQyMTlMNjYuNjAwMSAxNi45NzM2TDY0LjI5MDUgMjNINjMuMzE4NEw2MS4wMTQyIDE2Ljk3OUw2MS4xNDg0IDIwLjQyMTlWMjNINTkuNzk0OVYxNS4xNzk3SDYxLjU1NjZaIiBmaWxsPSJibGFjayIgZmlsbC1vcGFjaXR5PSIwLjg3Ii8+CjxwYXRoIGQ9Ik03MS44NjM4IDIzLjEwNzRDNzEuMDM2NiAyMy4xMDc0IDcwLjM2NTIgMjIuODQ3OCA2OS44NDk2IDIyLjMyODZDNjkuMzM3NiAyMS44MDU4IDY5LjA4MTUgMjEuMTExMiA2OS4wODE1IDIwLjI0NDZWMjAuMDgzNUM2OS4wODE1IDE5LjUwMzQgNjkuMTkyNSAxOC45ODYgNjkuNDE0NiAxOC41MzEyQzY5LjY0MDEgMTguMDcyOSA2OS45NTUyIDE3LjcxNjYgNzAuMzU5OSAxNy40NjI0QzcwLjc2NDUgMTcuMjA4MiA3MS4yMTU3IDE3LjA4MTEgNzEuNzEzNCAxNy4wODExQzcyLjUwNDcgMTcuMDgxMSA3My4xMTUyIDE3LjMzMzUgNzMuNTQ0OSAxNy44Mzg0QzczLjk3ODIgMTguMzQzMyA3NC4xOTQ4IDE5LjA1NzYgNzQuMTk0OCAxOS45ODE0VjIwLjUwNzhINzAuMzk3NUM3MC40MzY4IDIwLjk4NzYgNzAuNTk2MiAyMS4zNjcyIDcwLjg3NTUgMjEuNjQ2NUM3MS4xNTg0IDIxLjkyNTggNzEuNTEyOSAyMi4wNjU0IDcxLjkzOSAyMi4wNjU0QzcyLjUzNjkgMjIuMDY1NCA3My4wMjM5IDIxLjgyMzcgNzMuMzk5OSAyMS4zNDAzTDc0LjEwMzUgMjIuMDExN0M3My44NzA4IDIyLjM1OSA3My41NTkyIDIyLjYyOTQgNzMuMTY4OSAyMi44MjI4QzcyLjc4MjIgMjMuMDEyNSA3Mi4zNDcyIDIzLjEwNzQgNzEuODYzOCAyMy4xMDc0Wk03MS43MDggMTguMTI4NEM3MS4zNDk5IDE4LjEyODQgNzEuMDU5OSAxOC4yNTM3IDcwLjgzNzkgMTguNTA0NEM3MC42MTk1IDE4Ljc1NSA3MC40Nzk4IDE5LjEwNDIgNzAuNDE4OSAxOS41NTE4SDcyLjkwNThWMTkuNDU1MUM3Mi44NzcxIDE5LjAxODIgNzIuNzYwNyAxOC42ODg4IDcyLjU1NjYgMTguNDY2OEM3Mi4zNTI1IDE4LjI0MTIgNzIuMDY5NyAxOC4xMjg0IDcxLjcwOCAxOC4xMjg0WiIgZmlsbD0iYmxhY2siIGZpbGwtb3BhY2l0eT0iMC44NyIvPgo8cGF0aCBkPSJNNzguNDcwMiAyMS40MjA5Qzc4LjQ3MDIgMjEuMTg4MiA3OC4zNzM1IDIxLjAxMDkgNzguMTgwMiAyMC44ODkyQzc3Ljk5MDQgMjAuNzY3NCA3Ny42NzM1IDIwLjY2IDc3LjIyOTUgMjAuNTY2OUM3Ni43ODU1IDIwLjQ3MzggNzYuNDE0OSAyMC4zNTU2IDc2LjExNzcgMjAuMjEyNEM3NS40NjYgMTkuODk3MyA3NS4xNDAxIDE5LjQ0MDggNzUuMTQwMSAxOC44NDI4Qzc1LjE0MDEgMTguMzQxNSA3NS4zNTE0IDE3LjkyMjUgNzUuNzczOSAxNy41ODU5Qzc2LjE5NjUgMTcuMjQ5MyA3Ni43MzM2IDE3LjA4MTEgNzcuMzg1MyAxNy4wODExQzc4LjA3OTkgMTcuMDgxMSA3OC42NDAzIDE3LjI1MjkgNzkuMDY2NCAxNy41OTY3Qzc5LjQ5NjEgMTcuOTQwNCA3OS43MTA5IDE4LjM4NjIgNzkuNzEwOSAxOC45MzQxSDc4LjQwNThDNzguNDA1OCAxOC42ODM0IDc4LjMxMjcgMTguNDc1NyA3OC4xMjY1IDE4LjMxMUM3Ny45NDAzIDE4LjE0MjcgNzcuNjkzMiAxOC4wNTg2IDc3LjM4NTMgMTguMDU4NkM3Ny4wOTg4IDE4LjA1ODYgNzYuODY0MyAxOC4xMjQ4IDc2LjY4MTYgMTguMjU3M0M3Ni41MDI2IDE4LjM4OTggNzYuNDEzMSAxOC41NjcxIDc2LjQxMzEgMTguNzg5MUM3Ni40MTMxIDE4Ljk4OTYgNzYuNDk3MiAxOS4xNDUzIDc2LjY2NTUgMTkuMjU2M0M3Ni44MzM4IDE5LjM2NzQgNzcuMTc0IDE5LjQ4MDEgNzcuNjg2IDE5LjU5NDdDNzguMTk4MSAxOS43MDU3IDc4LjU5OTEgMTkuODQgNzguODg5MiAxOS45OTc2Qzc5LjE4MjggMjAuMTUxNSA3OS4zOTk0IDIwLjMzNzcgNzkuNTM5MSAyMC41NTYyQzc5LjY4MjMgMjAuNzc0NiA3OS43NTM5IDIxLjAzOTYgNzkuNzUzOSAyMS4zNTExQzc5Ljc1MzkgMjEuODczOSA3OS41MzczIDIyLjI5ODIgNzkuMTA0IDIyLjYyNEM3OC42NzA3IDIyLjk0NjMgNzguMTAzMiAyMy4xMDc0IDc3LjQwMTQgMjMuMTA3NEM3Ni45MjUxIDIzLjEwNzQgNzYuNTAwOCAyMy4wMjE1IDc2LjEyODQgMjIuODQ5NkM3NS43NTYgMjIuNjc3NyA3NS40NjYgMjIuNDQxNCA3NS4yNTgzIDIyLjE0MDZDNzUuMDUwNiAyMS44Mzk4IDc0Ljk0NjggMjEuNTE1OCA3NC45NDY4IDIxLjE2ODVINzYuMjE0NEM3Ni4yMzIzIDIxLjQ3NjQgNzYuMzQ4NiAyMS43MTQ1IDc2LjU2MzUgMjEuODgyOEM3Ni43NzgzIDIyLjA0NzUgNzcuMDYzIDIyLjEyOTkgNzcuNDE3NSAyMi4xMjk5Qzc3Ljc2MTIgMjIuMTI5OSA3OC4wMjI2IDIyLjA2NTQgNzguMjAxNyAyMS45MzY1Qzc4LjM4MDcgMjEuODA0IDc4LjQ3MDIgMjEuNjMyMiA3OC40NzAyIDIxLjQyMDlaIiBmaWxsPSJibGFjayIgZmlsbC1vcGFjaXR5PSIwLjg3Ii8+CjxwYXRoIGQ9Ik04NC4xNTI4IDIxLjQyMDlDODQuMTUyOCAyMS4xODgyIDg0LjA1NjIgMjEuMDEwOSA4My44NjI4IDIwLjg4OTJDODMuNjczIDIwLjc2NzQgODMuMzU2MSAyMC42NiA4Mi45MTIxIDIwLjU2NjlDODIuNDY4MSAyMC40NzM4IDgyLjA5NzUgMjAuMzU1NiA4MS44MDAzIDIwLjIxMjRDODEuMTQ4NiAxOS44OTczIDgwLjgyMjggMTkuNDQwOCA4MC44MjI4IDE4Ljg0MjhDODAuODIyOCAxOC4zNDE1IDgxLjAzNCAxNy45MjI1IDgxLjQ1NjUgMTcuNTg1OUM4MS44NzkxIDE3LjI0OTMgODIuNDE2MiAxNy4wODExIDgzLjA2NzkgMTcuMDgxMUM4My43NjI1IDE3LjA4MTEgODQuMzIyOSAxNy4yNTI5IDg0Ljc0OSAxNy41OTY3Qzg1LjE3ODcgMTcuOTQwNCA4NS4zOTM2IDE4LjM4NjIgODUuMzkzNiAxOC45MzQxSDg0LjA4ODRDODQuMDg4NCAxOC42ODM0IDgzLjk5NTMgMTguNDc1NyA4My44MDkxIDE4LjMxMUM4My42MjI5IDE4LjE0MjcgODMuMzc1OCAxOC4wNTg2IDgzLjA2NzkgMTguMDU4NkM4Mi43ODE0IDE4LjA1ODYgODIuNTQ2OSAxOC4xMjQ4IDgyLjM2NDMgMTguMjU3M0M4Mi4xODUyIDE4LjM4OTggODIuMDk1NyAxOC41NjcxIDgyLjA5NTcgMTguNzg5MUM4Mi4wOTU3IDE4Ljk4OTYgODIuMTc5OSAxOS4xNDUzIDgyLjM0ODEgMTkuMjU2M0M4Mi41MTY0IDE5LjM2NzQgODIuODU2NiAxOS40ODAxIDgzLjM2ODcgMTkuNTk0N0M4My44ODA3IDE5LjcwNTcgODQuMjgxNyAxOS44NCA4NC41NzE4IDE5Ljk5NzZDODQuODY1NCAyMC4xNTE1IDg1LjA4MiAyMC4zMzc3IDg1LjIyMTcgMjAuNTU2MkM4NS4zNjQ5IDIwLjc3NDYgODUuNDM2NSAyMS4wMzk2IDg1LjQzNjUgMjEuMzUxMUM4NS40MzY1IDIxLjg3MzkgODUuMjE5OSAyMi4yOTgyIDg0Ljc4NjYgMjIuNjI0Qzg0LjM1MzQgMjIuOTQ2MyA4My43ODU4IDIzLjEwNzQgODMuMDg0IDIzLjEwNzRDODIuNjA3NyAyMy4xMDc0IDgyLjE4MzQgMjMuMDIxNSA4MS44MTEgMjIuODQ5NkM4MS40Mzg2IDIyLjY3NzcgODEuMTQ4NiAyMi40NDE0IDgwLjk0MDkgMjIuMTQwNkM4MC43MzMyIDIxLjgzOTggODAuNjI5NCAyMS41MTU4IDgwLjYyOTQgMjEuMTY4NUg4MS44OTdDODEuOTE0OSAyMS40NzY0IDgyLjAzMTIgMjEuNzE0NSA4Mi4yNDYxIDIxLjg4MjhDODIuNDYwOSAyMi4wNDc1IDgyLjc0NTYgMjIuMTI5OSA4My4xMDAxIDIyLjEyOTlDODMuNDQzOCAyMi4xMjk5IDgzLjcwNTIgMjIuMDY1NCA4My44ODQzIDIxLjkzNjVDODQuMDYzMyAyMS44MDQgODQuMTUyOCAyMS42MzIyIDg0LjE1MjggMjEuNDIwOVoiIGZpbGw9ImJsYWNrIiBmaWxsLW9wYWNpdHk9IjAuODciLz4KPHBhdGggZD0iTTkwLjA1MDMgMjNDODkuOTkzIDIyLjg4OSA4OS45NDI5IDIyLjcwODIgODkuODk5OSAyMi40NTc1Qzg5LjQ4NDUgMjIuODkwOCA4OC45NzYxIDIzLjEwNzQgODguMzc0NSAyMy4xMDc0Qzg3Ljc5MDkgMjMuMTA3NCA4Ny4zMTQ2IDIyLjk0MDkgODYuOTQ1OCAyMi42MDc5Qzg2LjU3NyAyMi4yNzQ5IDg2LjM5MjYgMjEuODYzMSA4Ni4zOTI2IDIxLjM3MjZDODYuMzkyNiAyMC43NTMxIDg2LjYyMTcgMjAuMjc4NiA4Ny4wODAxIDE5Ljk0OTJDODcuNTQyIDE5LjYxNjIgODguMjAwOCAxOS40NDk3IDg5LjA1NjYgMTkuNDQ5N0g4OS44NTY5VjE5LjA2ODRDODkuODU2OSAxOC43Njc2IDg5Ljc3MjggMTguNTI3NyA4OS42MDQ1IDE4LjM0ODZDODkuNDM2MiAxOC4xNjYgODkuMTgwMiAxOC4wNzQ3IDg4LjgzNjQgMTguMDc0N0M4OC41MzkyIDE4LjA3NDcgODguMjk1NyAxOC4xNDk5IDg4LjEwNiAxOC4zMDAzQzg3LjkxNjIgMTguNDQ3MSA4Ny44MjEzIDE4LjYzNTEgODcuODIxMyAxOC44NjQzSDg2LjUxNjFDODYuNTE2MSAxOC41NDU2IDg2LjYyMTcgMTguMjQ4NCA4Ni44MzMgMTcuOTcyN0M4Ny4wNDQzIDE3LjY5MzQgODcuMzMwNyAxNy40NzQ5IDg3LjY5MjQgMTcuMzE3NEM4OC4wNTc2IDE3LjE1OTggODguNDY0IDE3LjA4MTEgODguOTExNiAxNy4wODExQzg5LjU5MiAxNy4wODExIDkwLjEzNDQgMTcuMjUyOSA5MC41MzkxIDE3LjU5NjdDOTAuOTQzNyAxNy45MzY4IDkxLjE1MTQgMTguNDE2NyA5MS4xNjIxIDE5LjAzNjFWMjEuNjU3MkM5MS4xNjIxIDIyLjE4IDkxLjIzNTUgMjIuNTk3MiA5MS4zODIzIDIyLjkwODdWMjNIOTAuMDUwM1pNODguNjE2MiAyMi4wNjAxQzg4Ljg3NCAyMi4wNjAxIDg5LjExNTcgMjEuOTk3NCA4OS4zNDEzIDIxLjg3MjFDODkuNTcwNSAyMS43NDY3IDg5Ljc0MjQgMjEuNTc4NSA4OS44NTY5IDIxLjM2NzJWMjAuMjcxNUg4OS4xNTMzQzg4LjY2OTkgMjAuMjcxNSA4OC4zMDY1IDIwLjM1NTYgODguMDYzIDIwLjUyMzlDODcuODE5NSAyMC42OTIyIDg3LjY5NzggMjAuOTMwMyA4Ny42OTc4IDIxLjIzODNDODcuNjk3OCAyMS40ODg5IDg3Ljc4MDEgMjEuNjg5NSA4Ny45NDQ4IDIxLjgzOThDODguMTEzMSAyMS45ODY3IDg4LjMzNjkgMjIuMDYwMSA4OC42MTYyIDIyLjA2MDFaIiBmaWxsPSJibGFjayIgZmlsbC1vcGFjaXR5PSIwLjg3Ii8+CjxwYXRoIGQ9Ik05Mi4zMDA4IDIwLjA1MTNDOTIuMzAwOCAxOS4xNDg5IDkyLjUxMiAxOC40MjkyIDkyLjkzNDYgMTcuODkyMUM5My4zNjA3IDE3LjM1MTQgOTMuOTI0NiAxNy4wODExIDk0LjYyNjUgMTcuMDgxMUM5NS4yODg5IDE3LjA4MTEgOTUuODA5OSAxNy4zMTIgOTYuMTg5NSAxNy43NzM5TDk2LjI0ODUgMTcuMTg4NUg5Ny40MjQ4VjIyLjgyMjhDOTcuNDI0OCAyMy41ODU0IDk3LjE4NjcgMjQuMTg3IDk2LjcxMDQgMjQuNjI3NEM5Ni4yMzc4IDI1LjA2NzkgOTUuNTk4NiAyNS4yODgxIDk0Ljc5MyAyNS4yODgxQzk0LjM2NjkgMjUuMjg4MSA5My45NDk3IDI1LjE5ODYgOTMuNTQxNSAyNS4wMTk1QzkzLjEzNjkgMjQuODQ0MSA5Mi44Mjg5IDI0LjYxMzEgOTIuNjE3NyAyNC4zMjY3TDkzLjIzNTQgMjMuNTQyNUM5My42MzY0IDI0LjAxODcgOTQuMTMwNSAyNC4yNTY4IDk0LjcxNzggMjQuMjU2OEM5NS4xNTEgMjQuMjU2OCA5NS40OTMgMjQuMTM4NyA5NS43NDM3IDIzLjkwMjNDOTUuOTk0MyAyMy42Njk2IDk2LjExOTYgMjMuMzI1OCA5Ni4xMTk2IDIyLjg3MTFWMjIuNDc5Qzk1Ljc0MzcgMjIuODk3OSA5NS4yNDI0IDIzLjEwNzQgOTQuNjE1NyAyMy4xMDc0QzkzLjkzNTQgMjMuMTA3NCA5My4zNzg2IDIyLjgzNzEgOTIuOTQ1MyAyMi4yOTY0QzkyLjUxNTYgMjEuNzU1NyA5Mi4zMDA4IDIxLjAwNzMgOTIuMzAwOCAyMC4wNTEzWk05My42MDA2IDIwLjE2NDFDOTMuNjAwNiAyMC43NDc3IDkzLjcxODggMjEuMjA3OCA5My45NTUxIDIxLjU0NDRDOTQuMTk1IDIxLjg3NzQgOTQuNTI2MiAyMi4wNDM5IDk0Ljk0ODcgMjIuMDQzOUM5NS40NzUxIDIyLjA0MzkgOTUuODY1NCAyMS44MTg0IDk2LjExOTYgMjEuMzY3MlYxOC44MTA1Qzk1Ljg3MjYgMTguMzcwMSA5NS40ODU4IDE4LjE0OTkgOTQuOTU5NSAxOC4xNDk5Qzk0LjUyOTggMTguMTQ5OSA5NC4xOTUgMTguMzIgOTMuOTU1MSAxOC42NjAyQzkzLjcxODggMTkuMDAwMyA5My42MDA2IDE5LjUwMTYgOTMuNjAwNiAyMC4xNjQxWiIgZmlsbD0iYmxhY2siIGZpbGwtb3BhY2l0eT0iMC44NyIvPgo8cGF0aCBkPSJNMTAxLjMzIDIzLjEwNzRDMTAwLjUwMiAyMy4xMDc0IDk5LjgzMTEgMjIuODQ3OCA5OS4zMTU0IDIyLjMyODZDOTguODAzNCAyMS44MDU4IDk4LjU0NzQgMjEuMTExMiA5OC41NDc0IDIwLjI0NDZWMjAuMDgzNUM5OC41NDc0IDE5LjUwMzQgOTguNjU4NCAxOC45ODYgOTguODgwNCAxOC41MzEyQzk5LjEwNiAxOC4wNzI5IDk5LjQyMTEgMTcuNzE2NiA5OS44MjU3IDE3LjQ2MjRDMTAwLjIzIDE3LjIwODIgMTAwLjY4MSAxNy4wODExIDEwMS4xNzkgMTcuMDgxMUMxMDEuOTcxIDE3LjA4MTEgMTAyLjU4MSAxNy4zMzM1IDEwMy4wMTEgMTcuODM4NEMxMDMuNDQ0IDE4LjM0MzMgMTAzLjY2MSAxOS4wNTc2IDEwMy42NjEgMTkuOTgxNFYyMC41MDc4SDk5Ljg2MzNDOTkuOTAyNyAyMC45ODc2IDEwMC4wNjIgMjEuMzY3MiAxMDAuMzQxIDIxLjY0NjVDMTAwLjYyNCAyMS45MjU4IDEwMC45NzkgMjIuMDY1NCAxMDEuNDA1IDIyLjA2NTRDMTAyLjAwMyAyMi4wNjU0IDEwMi40OSAyMS44MjM3IDEwMi44NjYgMjEuMzQwM0wxMDMuNTY5IDIyLjAxMTdDMTAzLjMzNyAyMi4zNTkgMTAzLjAyNSAyMi42Mjk0IDEwMi42MzUgMjIuODIyOEMxMDIuMjQ4IDIzLjAxMjUgMTAxLjgxMyAyMy4xMDc0IDEwMS4zMyAyMy4xMDc0Wk0xMDEuMTc0IDE4LjEyODRDMTAwLjgxNiAxOC4xMjg0IDEwMC41MjYgMTguMjUzNyAxMDAuMzA0IDE4LjUwNDRDMTAwLjA4NSAxOC43NTUgOTkuOTQ1NiAxOS4xMDQyIDk5Ljg4NDggMTkuNTUxOEgxMDIuMzcyVjE5LjQ1NTFDMTAyLjM0MyAxOS4wMTgyIDEwMi4yMjcgMTguNjg4OCAxMDIuMDIyIDE4LjQ2NjhDMTAxLjgxOCAxOC4yNDEyIDEwMS41MzUgMTguMTI4NCAxMDEuMTc0IDE4LjEyODRaIiBmaWxsPSJibGFjayIgZmlsbC1vcGFjaXR5PSIwLjg3Ii8+CjxwYXRoIGQ9Ik0xMDkuMDUzIDE1Ljc3NTlWMTcuMTg4NUgxMTAuMDc5VjE4LjE1NTNIMTA5LjA1M1YyMS4zOTk0QzEwOS4wNTMgMjEuNjIxNCAxMDkuMDk2IDIxLjc4MjYgMTA5LjE4MiAyMS44ODI4QzEwOS4yNzIgMjEuOTc5NSAxMDkuNDI5IDIyLjAyNzggMTA5LjY1NSAyMi4wMjc4QzEwOS44MDUgMjIuMDI3OCAxMDkuOTU3IDIyLjAwOTkgMTEwLjExMSAyMS45NzQxVjIyLjk4MzlDMTA5LjgxNCAyMy4wNjYyIDEwOS41MjggMjMuMTA3NCAxMDkuMjUyIDIzLjEwNzRDMTA4LjI0OSAyMy4xMDc0IDEwNy43NDggMjIuNTU0MiAxMDcuNzQ4IDIxLjQ0NzhWMTguMTU1M0gxMDYuNzkyVjE3LjE4ODVIMTA3Ljc0OFYxNS43NzU5SDEwOS4wNTNaIiBmaWxsPSJibGFjayIgZmlsbC1vcGFjaXR5PSIwLjg3Ii8+CjxwYXRoIGQ9Ik0xMTMuMTE0IDIxLjEzMDlMMTE0LjI5NSAxNy4xODg1SDExNS42ODdMMTEzLjM3NyAyMy44ODA5QzExMy4wMjIgMjQuODU4NCAxMTIuNDIxIDI1LjM0NzIgMTExLjU3MiAyNS4zNDcyQzExMS4zODIgMjUuMzQ3MiAxMTEuMTczIDI1LjMxNDkgMTEwLjk0NCAyNS4yNTA1VjI0LjI0MDdMMTExLjE5MSAyNC4yNTY4QzExMS41MiAyNC4yNTY4IDExMS43NjcgMjQuMTk2IDExMS45MzIgMjQuMDc0MkMxMTIuMSAyMy45NTYxIDExMi4yMzMgMjMuNzU1NSAxMTIuMzMgMjMuNDcyN0wxMTIuNTE4IDIyLjk3MzFMMTEwLjQ3NyAxNy4xODg1SDExMS44ODRMMTEzLjExNCAyMS4xMzA5WiIgZmlsbD0iYmxhY2siIGZpbGwtb3BhY2l0eT0iMC44NyIvPgo8cGF0aCBkPSJNMTIxLjUzIDIwLjE1MzNDMTIxLjUzIDIxLjA1MjEgMTIxLjMyNiAyMS43NyAxMjAuOTE4IDIyLjMwNzFDMTIwLjUxIDIyLjg0MDcgMTE5Ljk2MiAyMy4xMDc0IDExOS4yNzQgMjMuMTA3NEMxMTguNjM3IDIzLjEwNzQgMTE4LjEyNyAyMi44OTc5IDExNy43NDQgMjIuNDc5VjI1LjIzNDRIMTE2LjQzOFYxNy4xODg1SDExNy42NDJMMTE3LjY5NSAxNy43NzkzQzExOC4wNzggMTcuMzEzOCAxMTguNTk5IDE3LjA4MTEgMTE5LjI1OCAxNy4wODExQzExOS45NjcgMTcuMDgxMSAxMjAuNTIyIDE3LjM0NiAxMjAuOTIzIDE3Ljg3NkMxMjEuMzI4IDE4LjQwMjMgMTIxLjUzIDE5LjEzNDYgMTIxLjUzIDIwLjA3MjhWMjAuMTUzM1pNMTIwLjIzIDIwLjA0MDVDMTIwLjIzIDE5LjQ2MDQgMTIwLjExNCAxOS4wMDAzIDExOS44ODEgMTguNjYwMkMxMTkuNjUyIDE4LjMyIDExOS4zMjMgMTguMTQ5OSAxMTguODkzIDE4LjE0OTlDMTE4LjM2IDE4LjE0OTkgMTE3Ljk3NiAxOC4zNzAxIDExNy43NDQgMTguODEwNVYyMS4zODg3QzExNy45OCAyMS44Mzk4IDExOC4zNjcgMjIuMDY1NCAxMTguOTA0IDIyLjA2NTRDMTE5LjMxOSAyMi4wNjU0IDExOS42NDMgMjEuODk4OSAxMTkuODc2IDIxLjU2NTlDMTIwLjExMiAyMS4yMjkzIDEyMC4yMyAyMC43MjA5IDEyMC4yMyAyMC4wNDA1WiIgZmlsbD0iYmxhY2siIGZpbGwtb3BhY2l0eT0iMC44NyIvPgo8cGF0aCBkPSJNMTI1LjE5OSAyMy4xMDc0QzEyNC4zNzIgMjMuMTA3NCAxMjMuNyAyMi44NDc4IDEyMy4xODUgMjIuMzI4NkMxMjIuNjczIDIxLjgwNTggMTIyLjQxNyAyMS4xMTEyIDEyMi40MTcgMjAuMjQ0NlYyMC4wODM1QzEyMi40MTcgMTkuNTAzNCAxMjIuNTI4IDE4Ljk4NiAxMjIuNzUgMTguNTMxMkMxMjIuOTc1IDE4LjA3MjkgMTIzLjI5IDE3LjcxNjYgMTIzLjY5NSAxNy40NjI0QzEyNC4wOTkgMTcuMjA4MiAxMjQuNTUxIDE3LjA4MTEgMTI1LjA0OCAxNy4wODExQzEyNS44NCAxNy4wODExIDEyNi40NSAxNy4zMzM1IDEyNi44OCAxNy44Mzg0QzEyNy4zMTMgMTguMzQzMyAxMjcuNTMgMTkuMDU3NiAxMjcuNTMgMTkuOTgxNFYyMC41MDc4SDEyMy43MzJDMTIzLjc3MiAyMC45ODc2IDEyMy45MzEgMjEuMzY3MiAxMjQuMjEgMjEuNjQ2NUMxMjQuNDkzIDIxLjkyNTggMTI0Ljg0OCAyMi4wNjU0IDEyNS4yNzQgMjIuMDY1NEMxMjUuODcyIDIyLjA2NTQgMTI2LjM1OSAyMS44MjM3IDEyNi43MzUgMjEuMzQwM0wxMjcuNDM4IDIyLjAxMTdDMTI3LjIwNiAyMi4zNTkgMTI2Ljg5NCAyMi42Mjk0IDEyNi41MDQgMjIuODIyOEMxMjYuMTE3IDIzLjAxMjUgMTI1LjY4MiAyMy4xMDc0IDEyNS4xOTkgMjMuMTA3NFpNMTI1LjA0MyAxOC4xMjg0QzEyNC42ODUgMTguMTI4NCAxMjQuMzk1IDE4LjI1MzcgMTI0LjE3MyAxOC41MDQ0QzEyMy45NTQgMTguNzU1IDEyMy44MTUgMTkuMTA0MiAxMjMuNzU0IDE5LjU1MThIMTI2LjI0MVYxOS40NTUxQzEyNi4yMTIgMTkuMDE4MiAxMjYuMDk2IDE4LjY4ODggMTI1Ljg5MiAxOC40NjY4QzEyNS42ODggMTguMjQxMiAxMjUuNDA1IDE4LjEyODQgMTI1LjA0MyAxOC4xMjg0WiIgZmlsbD0iYmxhY2siIGZpbGwtb3BhY2l0eT0iMC44NyIvPgo8cGF0aCBkPSJNMTQ0Ljg4MiAyMC45ODU4QzE0NC44ODIgMjAuNjQyMSAxNDQuNzYxIDIwLjM3NzEgMTQ0LjUxNyAyMC4xOTA5QzE0NC4yNzcgMjAuMDA0NyAxNDMuODQyIDE5LjgxNjcgMTQzLjIxMiAxOS42MjdDMTQyLjU4MiAxOS40MzcyIDE0Mi4wOCAxOS4yMjU5IDE0MS43MDggMTguOTkzMkMxNDAuOTk1IDE4LjU0NTYgMTQwLjYzOSAxNy45NjE5IDE0MC42MzkgMTcuMjQyMkMxNDAuNjM5IDE2LjYxMiAxNDAuODk1IDE2LjA5MjggMTQxLjQwNyAxNS42ODQ2QzE0MS45MjMgMTUuMjc2NCAxNDIuNTkxIDE1LjA3MjMgMTQzLjQxMSAxNS4wNzIzQzE0My45NTUgMTUuMDcyMyAxNDQuNDQgMTUuMTcyNSAxNDQuODY2IDE1LjM3M0MxNDUuMjkyIDE1LjU3MzYgMTQ1LjYyNyAxNS44NiAxNDUuODcxIDE2LjIzMjRDMTQ2LjExNCAxNi42MDEyIDE0Ni4yMzYgMTcuMDExMiAxNDYuMjM2IDE3LjQ2MjRIMTQ0Ljg4MkMxNDQuODgyIDE3LjA1NDIgMTQ0Ljc1MyAxNi43MzU1IDE0NC40OTYgMTYuNTA2M0MxNDQuMjQxIDE2LjI3MzYgMTQzLjg3NiAxNi4xNTcyIDE0My40IDE2LjE1NzJDMTQyLjk1NiAxNi4xNTcyIDE0Mi42MSAxNi4yNTIxIDE0Mi4zNjMgMTYuNDQxOUMxNDIuMTIgMTYuNjMxNyAxNDEuOTk4IDE2Ljg5NjYgMTQxLjk5OCAxNy4yMzY4QzE0MS45OTggMTcuNTIzMyAxNDIuMTMxIDE3Ljc2MzIgMTQyLjM5NiAxNy45NTY1QzE0Mi42NiAxOC4xNDYzIDE0My4wOTcgMTguMzMyNSAxNDMuNzA2IDE4LjUxNTFDMTQ0LjMxNSAxOC42OTQyIDE0NC44MDQgMTguOTAwMSAxNDUuMTcyIDE5LjEzMjhDMTQ1LjU0MSAxOS4zNjIgMTQ1LjgxMiAxOS42MjcgMTQ1Ljk4MyAxOS45Mjc3QzE0Ni4xNTUgMjAuMjI0OSAxNDYuMjQxIDIwLjU3NDEgMTQ2LjI0MSAyMC45NzUxQzE0Ni4yNDEgMjEuNjI2OCAxNDUuOTkxIDIyLjE0NiAxNDUuNDg5IDIyLjUzMjdDMTQ0Ljk5MiAyMi45MTU5IDE0NC4zMTUgMjMuMTA3NCAxNDMuNDU5IDIzLjEwNzRDMTQyLjg5MyAyMy4xMDc0IDE0Mi4zNzIgMjMuMDAzNiAxNDEuODk2IDIyLjc5NTlDMTQxLjQyMyAyMi41ODQ2IDE0MS4wNTUgMjIuMjk0NiAxNDAuNzkgMjEuOTI1OEMxNDAuNTI4IDIxLjU1NyAxNDAuMzk3IDIxLjEyNzMgMTQwLjM5NyAyMC42MzY3SDE0MS43NTZDMTQxLjc1NiAyMS4wODA3IDE0MS45MDMgMjEuNDI0NSAxNDIuMTk3IDIxLjY2OEMxNDIuNDkgMjEuOTExNSAxNDIuOTExIDIyLjAzMzIgMTQzLjQ1OSAyMi4wMzMyQzE0My45MzIgMjIuMDMzMiAxNDQuMjg2IDIxLjkzODMgMTQ0LjUyMiAyMS43NDg1QzE0NC43NjIgMjEuNTU1MiAxNDQuODgyIDIxLjMwMDkgMTQ0Ljg4MiAyMC45ODU4WiIgZmlsbD0iYmxhY2siIGZpbGwtb3BhY2l0eT0iMC44NyIvPgo8cGF0aCBkPSJNMTQ4Ljk0MyAxNS43NzU5VjE3LjE4ODVIMTQ5Ljk2OVYxOC4xNTUzSDE0OC45NDNWMjEuMzk5NEMxNDguOTQzIDIxLjYyMTQgMTQ4Ljk4NiAyMS43ODI2IDE0OS4wNzIgMjEuODgyOEMxNDkuMTYxIDIxLjk3OTUgMTQ5LjMxOSAyMi4wMjc4IDE0OS41NDQgMjIuMDI3OEMxNDkuNjk1IDIyLjAyNzggMTQ5Ljg0NyAyMi4wMDk5IDE1MC4wMDEgMjEuOTc0MVYyMi45ODM5QzE0OS43MDQgMjMuMDY2MiAxNDkuNDE3IDIzLjEwNzQgMTQ5LjE0MiAyMy4xMDc0QzE0OC4xMzkgMjMuMTA3NCAxNDcuNjM4IDIyLjU1NDIgMTQ3LjYzOCAyMS40NDc4VjE4LjE1NTNIMTQ2LjY4MlYxNy4xODg1SDE0Ny42MzhWMTUuNzc1OUgxNDguOTQzWiIgZmlsbD0iYmxhY2siIGZpbGwtb3BhY2l0eT0iMC44NyIvPgo8cGF0aCBkPSJNMTU0LjQ0MyAyM0MxNTQuMzg2IDIyLjg4OSAxNTQuMzM1IDIyLjcwODIgMTU0LjI5MiAyMi40NTc1QzE1My44NzcgMjIuODkwOCAxNTMuMzY5IDIzLjEwNzQgMTUyLjc2NyAyMy4xMDc0QzE1Mi4xODMgMjMuMTA3NCAxNTEuNzA3IDIyLjk0MDkgMTUxLjMzOCAyMi42MDc5QzE1MC45NyAyMi4yNzQ5IDE1MC43ODUgMjEuODYzMSAxNTAuNzg1IDIxLjM3MjZDMTUwLjc4NSAyMC43NTMxIDE1MS4wMTQgMjAuMjc4NiAxNTEuNDczIDE5Ljk0OTJDMTUxLjkzNSAxOS42MTYyIDE1Mi41OTMgMTkuNDQ5NyAxNTMuNDQ5IDE5LjQ0OTdIMTU0LjI1VjE5LjA2ODRDMTU0LjI1IDE4Ljc2NzYgMTU0LjE2NSAxOC41Mjc3IDE1My45OTcgMTguMzQ4NkMxNTMuODI5IDE4LjE2NiAxNTMuNTczIDE4LjA3NDcgMTUzLjIyOSAxOC4wNzQ3QzE1Mi45MzIgMTguMDc0NyAxNTIuNjg4IDE4LjE0OTkgMTUyLjQ5OSAxOC4zMDAzQzE1Mi4zMDkgMTguNDQ3MSAxNTIuMjE0IDE4LjYzNTEgMTUyLjIxNCAxOC44NjQzSDE1MC45MDlDMTUwLjkwOSAxOC41NDU2IDE1MS4wMTQgMTguMjQ4NCAxNTEuMjI2IDE3Ljk3MjdDMTUxLjQzNyAxNy42OTM0IDE1MS43MjMgMTcuNDc0OSAxNTIuMDg1IDE3LjMxNzRDMTUyLjQ1IDE3LjE1OTggMTUyLjg1NyAxNy4wODExIDE1My4zMDQgMTcuMDgxMUMxNTMuOTg1IDE3LjA4MTEgMTU0LjUyNyAxNy4yNTI5IDE1NC45MzIgMTcuNTk2N0MxNTUuMzM2IDE3LjkzNjggMTU1LjU0NCAxOC40MTY3IDE1NS41NTUgMTkuMDM2MVYyMS42NTcyQzE1NS41NTUgMjIuMTggMTU1LjYyOCAyMi41OTcyIDE1NS43NzUgMjIuOTA4N1YyM0gxNTQuNDQzWk0xNTMuMDA5IDIyLjA2MDFDMTUzLjI2NyAyMi4wNjAxIDE1My41MDggMjEuOTk3NCAxNTMuNzM0IDIxLjg3MjFDMTUzLjk2MyAyMS43NDY3IDE1NC4xMzUgMjEuNTc4NSAxNTQuMjUgMjEuMzY3MlYyMC4yNzE1SDE1My41NDZDMTUzLjA2MiAyMC4yNzE1IDE1Mi42OTkgMjAuMzU1NiAxNTIuNDU2IDIwLjUyMzlDMTUyLjIxMiAyMC42OTIyIDE1Mi4wOSAyMC45MzAzIDE1Mi4wOSAyMS4yMzgzQzE1Mi4wOSAyMS40ODg5IDE1Mi4xNzMgMjEuNjg5NSAxNTIuMzM3IDIxLjgzOThDMTUyLjUwNiAyMS45ODY3IDE1Mi43MjkgMjIuMDYwMSAxNTMuMDA5IDIyLjA2MDFaIiBmaWxsPSJibGFjayIgZmlsbC1vcGFjaXR5PSIwLjg3Ii8+CjxwYXRoIGQ9Ik0xNTguNTU3IDE1Ljc3NTlWMTcuMTg4NUgxNTkuNTgzVjE4LjE1NTNIMTU4LjU1N1YyMS4zOTk0QzE1OC41NTcgMjEuNjIxNCAxNTguNiAyMS43ODI2IDE1OC42ODYgMjEuODgyOEMxNTguNzc2IDIxLjk3OTUgMTU4LjkzMyAyMi4wMjc4IDE1OS4xNTkgMjIuMDI3OEMxNTkuMzA5IDIyLjAyNzggMTU5LjQ2MSAyMi4wMDk5IDE1OS42MTUgMjEuOTc0MVYyMi45ODM5QzE1OS4zMTggMjMuMDY2MiAxNTkuMDMyIDIzLjEwNzQgMTU4Ljc1NiAyMy4xMDc0QzE1Ny43NTMgMjMuMTA3NCAxNTcuMjUyIDIyLjU1NDIgMTU3LjI1MiAyMS40NDc4VjE4LjE1NTNIMTU2LjI5NlYxNy4xODg1SDE1Ny4yNTJWMTUuNzc1OUgxNTguNTU3WiIgZmlsbD0iYmxhY2siIGZpbGwtb3BhY2l0eT0iMC44NyIvPgo8cGF0aCBkPSJNMTY0LjEwNSAyMi40MzA3QzE2My43MjIgMjIuODgxOCAxNjMuMTc4IDIzLjEwNzQgMTYyLjQ3MyAyMy4xMDc0QzE2MS44NDIgMjMuMTA3NCAxNjEuMzY0IDIyLjkyMyAxNjEuMDM5IDIyLjU1NDJDMTYwLjcxNiAyMi4xODU0IDE2MC41NTUgMjEuNjUxOSAxNjAuNTU1IDIwLjk1MzZWMTcuMTg4NUgxNjEuODZWMjAuOTM3NUMxNjEuODYgMjEuNjc1MSAxNjIuMTY3IDIyLjA0MzkgMTYyLjc3OSAyMi4wNDM5QzE2My40MTMgMjIuMDQzOSAxNjMuODQgMjEuODE2NiAxNjQuMDYyIDIxLjM2MThWMTcuMTg4NUgxNjUuMzY4VjIzSDE2NC4xMzhMMTY0LjEwNSAyMi40MzA3WiIgZmlsbD0iYmxhY2siIGZpbGwtb3BhY2l0eT0iMC44NyIvPgo8cGF0aCBkPSJNMTY5Ljk1NSAyMS40MjA5QzE2OS45NTUgMjEuMTg4MiAxNjkuODU4IDIxLjAxMDkgMTY5LjY2NSAyMC44ODkyQzE2OS40NzUgMjAuNzY3NCAxNjkuMTU4IDIwLjY2IDE2OC43MTQgMjAuNTY2OUMxNjguMjcgMjAuNDczOCAxNjcuODk5IDIwLjM1NTYgMTY3LjYwMiAyMC4yMTI0QzE2Ni45NSAxOS44OTczIDE2Ni42MjUgMTkuNDQwOCAxNjYuNjI1IDE4Ljg0MjhDMTY2LjYyNSAxOC4zNDE1IDE2Ni44MzYgMTcuOTIyNSAxNjcuMjU4IDE3LjU4NTlDMTY3LjY4MSAxNy4yNDkzIDE2OC4yMTggMTcuMDgxMSAxNjguODcgMTcuMDgxMUMxNjkuNTY0IDE3LjA4MTEgMTcwLjEyNSAxNy4yNTI5IDE3MC41NTEgMTcuNTk2N0MxNzAuOTggMTcuOTQwNCAxNzEuMTk1IDE4LjM4NjIgMTcxLjE5NSAxOC45MzQxSDE2OS44OUMxNjkuODkgMTguNjgzNCAxNjkuNzk3IDE4LjQ3NTcgMTY5LjYxMSAxOC4zMTFDMTY5LjQyNSAxOC4xNDI3IDE2OS4xNzggMTguMDU4NiAxNjguODcgMTguMDU4NkMxNjguNTgzIDE4LjA1ODYgMTY4LjM0OSAxOC4xMjQ4IDE2OC4xNjYgMTguMjU3M0MxNjcuOTg3IDE4LjM4OTggMTY3Ljg5NyAxOC41NjcxIDE2Ny44OTcgMTguNzg5MUMxNjcuODk3IDE4Ljk4OTYgMTY3Ljk4MiAxOS4xNDUzIDE2OC4xNSAxOS4yNTYzQzE2OC4zMTggMTkuMzY3NCAxNjguNjU4IDE5LjQ4MDEgMTY5LjE3IDE5LjU5NDdDMTY5LjY4MiAxOS43MDU3IDE3MC4wODMgMTkuODQgMTcwLjM3NCAxOS45OTc2QzE3MC42NjcgMjAuMTUxNSAxNzAuODg0IDIwLjMzNzcgMTcxLjAyMyAyMC41NTYyQzE3MS4xNjcgMjAuNzc0NiAxNzEuMjM4IDIxLjAzOTYgMTcxLjIzOCAyMS4zNTExQzE3MS4yMzggMjEuODczOSAxNzEuMDIyIDIyLjI5ODIgMTcwLjU4OCAyMi42MjRDMTcwLjE1NSAyMi45NDYzIDE2OS41ODggMjMuMTA3NCAxNjguODg2IDIzLjEwNzRDMTY4LjQxIDIzLjEwNzQgMTY3Ljk4NSAyMy4wMjE1IDE2Ny42MTMgMjIuODQ5NkMxNjcuMjQgMjIuNjc3NyAxNjYuOTUgMjIuNDQxNCAxNjYuNzQzIDIyLjE0MDZDMTY2LjUzNSAyMS44Mzk4IDE2Ni40MzEgMjEuNTE1OCAxNjYuNDMxIDIxLjE2ODVIMTY3LjY5OUMxNjcuNzE3IDIxLjQ3NjQgMTY3LjgzMyAyMS43MTQ1IDE2OC4wNDggMjEuODgyOEMxNjguMjYzIDIyLjA0NzUgMTY4LjU0NyAyMi4xMjk5IDE2OC45MDIgMjIuMTI5OUMxNjkuMjQ2IDIyLjEyOTkgMTY5LjUwNyAyMi4wNjU0IDE2OS42ODYgMjEuOTM2NUMxNjkuODY1IDIxLjgwNCAxNjkuOTU1IDIxLjYzMjIgMTY5Ljk1NSAyMS40MjA5WiIgZmlsbD0iYmxhY2siIGZpbGwtb3BhY2l0eT0iMC44NyIvPgo8cGF0aCBkPSJNMTIuNzczNCA2My40NzlDMTIuNzczNCA2My4zMDcxIDEyLjgyMzYgNjMuMTYzOSAxMi45MjM4IDYzLjA0OTNDMTMuMDI3NyA2Mi45MzQ3IDEzLjE4MTYgNjIuODc3NCAxMy4zODU3IDYyLjg3NzRDMTMuNTg5OCA2Mi44Nzc0IDEzLjc0MzggNjIuOTM0NyAxMy44NDc3IDYzLjA0OTNDMTMuOTU1MSA2My4xNjM5IDE0LjAwODggNjMuMzA3MSAxNC4wMDg4IDYzLjQ3OUMxNC4wMDg4IDYzLjY0MzcgMTMuOTU1MSA2My43ODE2IDEzLjg0NzcgNjMuODkyNkMxMy43NDM4IDY0LjAwMzYgMTMuNTg5OCA2NC4wNTkxIDEzLjM4NTcgNjQuMDU5MUMxMy4xODE2IDY0LjA1OTEgMTMuMDI3NyA2NC4wMDM2IDEyLjkyMzggNjMuODkyNkMxMi44MjM2IDYzLjc4MTYgMTIuNzczNCA2My42NDM3IDEyLjc3MzQgNjMuNDc5WiIgZmlsbD0iYmxhY2siIGZpbGwtb3BhY2l0eT0iMC44NyIvPgo8cGF0aCBkPSJNMTUuNjczOCA2My40NzlDMTUuNjczOCA2My4zMDcxIDE1LjcyNCA2My4xNjM5IDE1LjgyNDIgNjMuMDQ5M0MxNS45MjgxIDYyLjkzNDcgMTYuMDgyIDYyLjg3NzQgMTYuMjg2MSA2Mi44Nzc0QzE2LjQ5MDIgNjIuODc3NCAxNi42NDQyIDYyLjkzNDcgMTYuNzQ4IDYzLjA0OTNDMTYuODU1NSA2My4xNjM5IDE2LjkwOTIgNjMuMzA3MSAxNi45MDkyIDYzLjQ3OUMxNi45MDkyIDYzLjY0MzcgMTYuODU1NSA2My43ODE2IDE2Ljc0OCA2My44OTI2QzE2LjY0NDIgNjQuMDAzNiAxNi40OTAyIDY0LjA1OTEgMTYuMjg2MSA2NC4wNTkxQzE2LjA4MiA2NC4wNTkxIDE1LjkyODEgNjQuMDAzNiAxNS44MjQyIDYzLjg5MjZDMTUuNzI0IDYzLjc4MTYgMTUuNjczOCA2My42NDM3IDE1LjY3MzggNjMuNDc5WiIgZmlsbD0iYmxhY2siIGZpbGwtb3BhY2l0eT0iMC44NyIvPgo8cGF0aCBkPSJNMjAuODgzOCA2My4yOTY0QzIxLjIzODMgNjMuMjk2NCAyMS41NDggNjMuMTg5IDIxLjgxMyA2Mi45NzQxQzIyLjA3OCA2Mi43NTkzIDIyLjIyNDggNjIuNDkwNyAyMi4yNTM0IDYyLjE2ODVIMjMuMTkzNEMyMy4xNzU1IDYyLjUwMTUgMjMuMDYwOSA2Mi44MTg0IDIyLjg0OTYgNjMuMTE5MUMyMi42MzgzIDYzLjQxOTkgMjIuMzU1NSA2My42NTk4IDIyLjAwMSA2My44Mzg5QzIxLjY1MDEgNjQuMDE3OSAyMS4yNzc3IDY0LjEwNzQgMjAuODgzOCA2NC4xMDc0QzIwLjA5MjQgNjQuMTA3NCAxOS40NjIyIDYzLjg0NDIgMTguOTkzMiA2My4zMTc5QzE4LjUyNzcgNjIuNzg3OSAxOC4yOTQ5IDYyLjA2NDYgMTguMjk0OSA2MS4xNDc5VjYwLjk4MTRDMTguMjk0OSA2MC40MTU3IDE4LjM5ODggNTkuOTEyNiAxOC42MDY0IDU5LjQ3MjJDMTguODE0MSA1OS4wMzE3IDE5LjExMTMgNTguNjg5OCAxOS40OTggNTguNDQ2M0MxOS44ODgzIDU4LjIwMjggMjAuMzQ4NSA1OC4wODExIDIwLjg3ODQgNTguMDgxMUMyMS41MzAxIDU4LjA4MTEgMjIuMDcwOCA1OC4yNzYyIDIyLjUwMDUgNTguNjY2NUMyMi45MzM4IDU5LjA1NjggMjMuMTY0NyA1OS41NjM1IDIzLjE5MzQgNjAuMTg2NUgyMi4yNTM0QzIyLjIyNDggNTkuODEwNSAyMi4wODE1IDU5LjUwMjYgMjEuODIzNyA1OS4yNjI3QzIxLjU2OTUgNTkuMDE5MiAyMS4yNTQ0IDU4Ljg5NzUgMjAuODc4NCA1OC44OTc1QzIwLjM3MzUgNTguODk3NSAxOS45ODE0IDU5LjA4MDEgMTkuNzAyMSA1OS40NDUzQzE5LjQyNjQgNTkuODA3IDE5LjI4ODYgNjAuMzMxNSAxOS4yODg2IDYxLjAxOVY2MS4yMDdDMTkuMjg4NiA2MS44NzY2IDE5LjQyNjQgNjIuMzkyMyAxOS43MDIxIDYyLjc1MzlDMTkuOTc3OSA2My4xMTU2IDIwLjM3MTcgNjMuMjk2NCAyMC44ODM4IDYzLjI5NjRaIiBmaWxsPSJibGFjayIgZmlsbC1vcGFjaXR5PSIwLjg3Ii8+CjxwYXRoIGQ9Ik0yNC4wNDc0IDYxLjA0MDVDMjQuMDQ3NCA2MC40NzEyIDI0LjE1ODQgNTkuOTU5MSAyNC4zODA0IDU5LjUwNDRDMjQuNjA2IDU5LjA0OTYgMjQuOTE3NSA1OC42OTg3IDI1LjMxNDkgNTguNDUxN0MyNS43MTYgNTguMjA0NiAyNi4xNzI1IDU4LjA4MTEgMjYuNjg0NiA1OC4wODExQzI3LjQ3NTkgNTguMDgxMSAyOC4xMTUxIDU4LjM1NSAyOC42MDIxIDU4LjkwMjhDMjkuMDkyNiA1OS40NTA3IDI5LjMzNzkgNjAuMTc5NCAyOS4zMzc5IDYxLjA4ODlWNjEuMTU4N0MyOS4zMzc5IDYxLjcyNDQgMjkuMjI4NyA2Mi4yMzI5IDI5LjAxMDMgNjIuNjg0MUMyOC43OTU0IDYzLjEzMTcgMjguNDg1NyA2My40ODA4IDI4LjA4MTEgNjMuNzMxNEMyNy42OCA2My45ODIxIDI3LjIxODEgNjQuMTA3NCAyNi42OTUzIDY0LjEwNzRDMjUuOTA3NiA2NC4xMDc0IDI1LjI2ODQgNjMuODMzNSAyNC43Nzc4IDYzLjI4NTZDMjQuMjkwOSA2Mi43Mzc4IDI0LjA0NzQgNjIuMDEyNyAyNC4wNDc0IDYxLjExMDRWNjEuMDQwNVpNMjUuMDQ2NCA2MS4xNTg3QzI1LjA0NjQgNjEuODAzMiAyNS4xOTUgNjIuMzIwNiAyNS40OTIyIDYyLjcxMDlDMjUuNzkzIDYzLjEwMTIgMjYuMTk0IDYzLjI5NjQgMjYuNjk1MyA2My4yOTY0QzI3LjIwMDIgNjMuMjk2NCAyNy42MDEyIDYzLjA5OTQgMjcuODk4NCA2Mi43MDU2QzI4LjE5NTYgNjIuMzA4MSAyOC4zNDQyIDYxLjc1MzEgMjguMzQ0MiA2MS4wNDA1QzI4LjM0NDIgNjAuNDAzMiAyOC4xOTIxIDU5Ljg4NzUgMjcuODg3NyA1OS40OTM3QzI3LjU4NjkgNTkuMDk2MiAyNy4xODU5IDU4Ljg5NzUgMjYuNjg0NiA1OC44OTc1QzI2LjE5NCA1OC44OTc1IDI1Ljc5ODMgNTkuMDkyNiAyNS40OTc2IDU5LjQ4MjlDMjUuMTk2OCA1OS44NzMyIDI1LjA0NjQgNjAuNDMxOCAyNS4wNDY0IDYxLjE1ODdaIiBmaWxsPSJibGFjayIgZmlsbC1vcGFjaXR5PSIwLjg3Ii8+CjxwYXRoIGQ9Ik0zNC42NzY4IDYxLjM3MzVIMzUuNzYxN1Y2Mi4xODQ2SDM0LjY3NjhWNjRIMzMuNjc3N1Y2Mi4xODQ2SDMwLjExNjdWNjEuNTk5MUwzMy42MTg3IDU2LjE3OTdIMzQuNjc2OFY2MS4zNzM1Wk0zMS4yNDQ2IDYxLjM3MzVIMzMuNjc3N1Y1Ny41Mzg2TDMzLjU1OTYgNTcuNzUzNEwzMS4yNDQ2IDYxLjM3MzVaIiBmaWxsPSJibGFjayIgZmlsbC1vcGFjaXR5PSIwLjg3Ii8+CjxwYXRoIGQ9Ik0zNy43ODY2IDU4LjE4ODVWNjQuNjcxNEMzNy43ODY2IDY1Ljc4ODYgMzcuMjc5OSA2Ni4zNDcyIDM2LjI2NjYgNjYuMzQ3MkMzNi4wNDgyIDY2LjM0NzIgMzUuODQ1OSA2Ni4zMTQ5IDM1LjY1OTcgNjYuMjUwNVY2NS40NTU2QzM1Ljc3NDMgNjUuNDg0MiAzNS45MjQ2IDY1LjQ5ODUgMzYuMTEwOCA2NS40OTg1QzM2LjMzMjggNjUuNDk4NSAzNi41MDExIDY1LjQzNzcgMzYuNjE1NyA2NS4zMTU5QzM2LjczMzkgNjUuMTk3OCAzNi43OTMgNjQuOTkwMSAzNi43OTMgNjQuNjkyOVY1OC4xODg1SDM3Ljc4NjZaTTM2LjY5MDkgNTYuNjQ3QzM2LjY5MDkgNTYuNDg5NCAzNi43MzkzIDU2LjM1NTEgMzYuODM1OSA1Ni4yNDQxQzM2LjkzNjIgNTYuMTI5NiAzNy4wODEyIDU2LjA3MjMgMzcuMjcxIDU2LjA3MjNDMzcuNDY0NCA1Ni4wNzIzIDM3LjYxMTIgNTYuMTI3OCAzNy43MTE0IDU2LjIzODhDMzcuODExNyA1Ni4zNDk4IDM3Ljg2MTggNTYuNDg1OCAzNy44NjE4IDU2LjY0N0MzNy44NjE4IDU2LjgwODEgMzcuODExNyA1Ni45NDI0IDM3LjcxMTQgNTcuMDQ5OEMzNy42MTEyIDU3LjE1NzIgMzcuNDY0NCA1Ny4yMTA5IDM3LjI3MSA1Ny4yMTA5QzM3LjA3NzYgNTcuMjEwOSAzNi45MzI2IDU3LjE1NzIgMzYuODM1OSA1Ny4wNDk4QzM2LjczOTMgNTYuOTQyNCAzNi42OTA5IDU2LjgwODEgMzYuNjkwOSA1Ni42NDdaIiBmaWxsPSJibGFjayIgZmlsbC1vcGFjaXR5PSIwLjg3Ii8+CjxwYXRoIGQ9Ik00Mi45ODA1IDYzLjQyNTNDNDIuNTkzOCA2My44OCA0Mi4wMjYyIDY0LjEwNzQgNDEuMjc3OCA2NC4xMDc0QzQwLjY1ODQgNjQuMTA3NCA0MC4xODU3IDYzLjkyODQgMzkuODU5OSA2My41NzAzQzM5LjUzNzYgNjMuMjA4NyAzOS4zNzQ3IDYyLjY3NTEgMzkuMzcxMSA2MS45Njk3VjU4LjE4ODVINDAuMzY0N1Y2MS45NDI5QzQwLjM2NDcgNjIuODIzNyA0MC43MjI4IDYzLjI2NDIgNDEuNDM5IDYzLjI2NDJDNDIuMTk4MSA2My4yNjQyIDQyLjcwMyA2Mi45ODEzIDQyLjk1MzYgNjIuNDE1NVY1OC4xODg1SDQzLjk0NzNWNjRINDMuMDAyTDQyLjk4MDUgNjMuNDI1M1oiIGZpbGw9ImJsYWNrIiBmaWxsLW9wYWNpdHk9IjAuODciLz4KPHBhdGggZD0iTTY1LjMxMSA1Ny4wMjgzSDYyLjc5NzRWNjRINjEuNzcxNVY1Ny4wMjgzSDU5LjI2MzJWNTYuMTc5N0g2NS4zMTFWNTcuMDI4M1oiIGZpbGw9ImJsYWNrIiBmaWxsLW9wYWNpdHk9IjAuODciLz4KPHBhdGggZD0iTTcxLjE0OTQgNjIuNjMwNEw3Mi4yNjY2IDU4LjE4ODVINzMuMjYwM0w3MS41Njg0IDY0SDcwLjc2MjdMNjkuMzUwMSA1OS41OTU3TDY3Ljk3NTEgNjRINjcuMTY5NEw2NS40ODI5IDU4LjE4ODVINjYuNDcxMkw2Ny42MTUyIDYyLjUzOTFMNjguOTY4OCA1OC4xODg1SDY5Ljc2OUw3MS4xNDk0IDYyLjYzMDRaIiBmaWxsPSJibGFjayIgZmlsbC1vcGFjaXR5PSIwLjg3Ii8+CjxwYXRoIGQ9Ik03NC4wMTIyIDYxLjA0MDVDNzQuMDEyMiA2MC40NzEyIDc0LjEyMzIgNTkuOTU5MSA3NC4zNDUyIDU5LjUwNDRDNzQuNTcwOCA1OS4wNDk2IDc0Ljg4MjMgNTguNjk4NyA3NS4yNzk4IDU4LjQ1MTdDNzUuNjgwOCA1OC4yMDQ2IDc2LjEzNzQgNTguMDgxMSA3Ni42NDk0IDU4LjA4MTFDNzcuNDQwOCA1OC4wODExIDc4LjA3OTkgNTguMzU1IDc4LjU2NjkgNTguOTAyOEM3OS4wNTc1IDU5LjQ1MDcgNzkuMzAyNyA2MC4xNzk0IDc5LjMwMjcgNjEuMDg4OVY2MS4xNTg3Qzc5LjMwMjcgNjEuNzI0NCA3OS4xOTM1IDYyLjIzMjkgNzguOTc1MSA2Mi42ODQxQzc4Ljc2MDMgNjMuMTMxNyA3OC40NTA1IDYzLjQ4MDggNzguMDQ1OSA2My43MzE0Qzc3LjY0NDkgNjMuOTgyMSA3Ny4xODI5IDY0LjEwNzQgNzYuNjYwMiA2NC4xMDc0Qzc1Ljg3MjQgNjQuMTA3NCA3NS4yMzMyIDYzLjgzMzUgNzQuNzQyNyA2My4yODU2Qzc0LjI1NTcgNjIuNzM3OCA3NC4wMTIyIDYyLjAxMjcgNzQuMDEyMiA2MS4xMTA0VjYxLjA0MDVaTTc1LjAxMTIgNjEuMTU4N0M3NS4wMTEyIDYxLjgwMzIgNzUuMTU5OCA2Mi4zMjA2IDc1LjQ1NyA2Mi43MTA5Qzc1Ljc1NzggNjMuMTAxMiA3Ni4xNTg5IDYzLjI5NjQgNzYuNjYwMiA2My4yOTY0Qzc3LjE2NSA2My4yOTY0IDc3LjU2NjEgNjMuMDk5NCA3Ny44NjMzIDYyLjcwNTZDNzguMTYwNSA2Mi4zMDgxIDc4LjMwOTEgNjEuNzUzMSA3OC4zMDkxIDYxLjA0MDVDNzguMzA5MSA2MC40MDMyIDc4LjE1NjkgNTkuODg3NSA3Ny44NTI1IDU5LjQ5MzdDNzcuNTUxOCA1OS4wOTYyIDc3LjE1MDcgNTguODk3NSA3Ni42NDk0IDU4Ljg5NzVDNzYuMTU4OSA1OC44OTc1IDc1Ljc2MzIgNTkuMDkyNiA3NS40NjI0IDU5LjQ4MjlDNzUuMTYxNiA1OS44NzMyIDc1LjAxMTIgNjAuNDMxOCA3NS4wMTEyIDYxLjE1ODdaIiBmaWxsPSJibGFjayIgZmlsbC1vcGFjaXR5PSIwLjg3Ii8+CjxwYXRoIGQ9Ik04Mi42MTY3IDYxLjA4MzVINzkuOTk1NlY2MC4yNzI1SDgyLjYxNjdWNjEuMDgzNVoiIGZpbGw9ImJsYWNrIiBmaWxsLW9wYWNpdHk9IjAuODciLz4KPHBhdGggZD0iTTg4LjczNDQgNjIuNjMwNEw4OS44NTE2IDU4LjE4ODVIOTAuODQ1Mkw4OS4xNTMzIDY0SDg4LjM0NzdMODYuOTM1MSA1OS41OTU3TDg1LjU2MDEgNjRIODQuNzU0NEw4My4wNjc5IDU4LjE4ODVIODQuMDU2Mkw4NS4yMDAyIDYyLjUzOTFMODYuNTUzNyA1OC4xODg1SDg3LjM1NEw4OC43MzQ0IDYyLjYzMDRaIiBmaWxsPSJibGFjayIgZmlsbC1vcGFjaXR5PSIwLjg3Ii8+CjxwYXRoIGQ9Ik05NS40NDgyIDY0Qzk1LjM5MSA2My44ODU0IDk1LjM0NDQgNjMuNjgxMyA5NS4zMDg2IDYzLjM4NzdDOTQuODQ2NyA2My44Njc1IDk0LjI5NTIgNjQuMTA3NCA5My42NTQzIDY0LjEwNzRDOTMuMDgxNCA2NC4xMDc0IDkyLjYxMDUgNjMuOTQ2MyA5Mi4yNDE3IDYzLjYyNEM5MS44NzY1IDYzLjI5ODIgOTEuNjkzOCA2Mi44ODY0IDkxLjY5MzggNjIuMzg4N0M5MS42OTM4IDYxLjc4MzUgOTEuOTIzIDYxLjMxNDUgOTIuMzgxMyA2MC45ODE0QzkyLjg0MzMgNjAuNjQ0OSA5My40OTE0IDYwLjQ3NjYgOTQuMzI1NyA2MC40NzY2SDk1LjI5MjVWNjAuMDJDOTUuMjkyNSA1OS42NzI3IDk1LjE4ODYgNTkuMzk3IDk0Ljk4MSA1OS4xOTI5Qzk0Ljc3MzMgNTguOTg1MiA5NC40NjcxIDU4Ljg4MTMgOTQuMDYyNSA1OC44ODEzQzkzLjcwOCA1OC44ODEzIDkzLjQxMDggNTguOTcwOSA5My4xNzA5IDU5LjE0OTlDOTIuOTMxIDU5LjMyODkgOTIuODExIDU5LjU0NTYgOTIuODExIDU5Ljc5OThIOTEuODEyQzkxLjgxMiA1OS41MDk4IDkxLjkxNDEgNTkuMjMwNSA5Mi4xMTgyIDU4Ljk2MTlDOTIuMzI1OCA1OC42ODk4IDkyLjYwNTEgNTguNDc0OSA5Mi45NTYxIDU4LjMxNzRDOTMuMzEwNSA1OC4xNTk4IDkzLjY5OTEgNTguMDgxMSA5NC4xMjE2IDU4LjA4MTFDOTQuNzkxMiA1OC4wODExIDk1LjMxNTggNTguMjQ5MyA5NS42OTUzIDU4LjU4NTlDOTYuMDc0OSA1OC45MTg5IDk2LjI3MTggNTkuMzc5MSA5Ni4yODYxIDU5Ljk2NjNWNjIuNjQxMUM5Ni4yODYxIDYzLjE3NDYgOTYuMzU0MiA2My41OTkgOTYuNDkwMiA2My45MTQxVjY0SDk1LjQ0ODJaTTkzLjc5OTMgNjMuMjQyN0M5NC4xMTA4IDYzLjI0MjcgOTQuNDA2MiA2My4xNjIxIDk0LjY4NTUgNjMuMDAxQzk0Ljk2NDggNjIuODM5OCA5NS4xNjcyIDYyLjYzMDQgOTUuMjkyNSA2Mi4zNzI2VjYxLjE4MDJIOTQuNTEzN0M5My4yOTYyIDYxLjE4MDIgOTIuNjg3NSA2MS41MzY1IDkyLjY4NzUgNjIuMjQ5QzkyLjY4NzUgNjIuNTYwNSA5Mi43OTEzIDYyLjgwNCA5Mi45OTkgNjIuOTc5NUM5My4yMDY3IDYzLjE1NDkgOTMuNDczNSA2My4yNDI3IDkzLjc5OTMgNjMuMjQyN1oiIGZpbGw9ImJsYWNrIiBmaWxsLW9wYWNpdHk9IjAuODciLz4KPHBhdGggZD0iTTk5LjY1OTIgNjIuNTQ0NEwxMDEuMDEzIDU4LjE4ODVIMTAyLjA3Nkw5OS43Mzk3IDY0Ljg5N0M5OS4zNzgxIDY1Ljg2MzggOTguODAzNCA2Ni4zNDcyIDk4LjAxNTYgNjYuMzQ3Mkw5Ny44Mjc2IDY2LjMzMTFMOTcuNDU3IDY2LjI2MTJWNjUuNDU1Nkw5Ny43MjU2IDY1LjQ3NzFDOTguMDYyMiA2NS40NzcxIDk4LjMyMzYgNjUuNDA5IDk4LjUwOTggNjUuMjcyOUM5OC42OTk1IDY1LjEzNjkgOTguODU1MyA2NC44ODggOTguOTc3MSA2NC41MjY0TDk5LjE5NzMgNjMuOTM1NUw5Ny4xMjQgNTguMTg4NUg5OC4yMDlMOTkuNjU5MiA2Mi41NDQ0WiIgZmlsbD0iYmxhY2siIGZpbGwtb3BhY2l0eT0iMC44NyIvPgo8cGF0aCBkPSJNNjUuOTIzMyAxMDAuMzQyQzY1LjkyMzMgMTAxLjEwOSA2NS43OTQ0IDEwMS43NzggNjUuNTM2NiAxMDIuMzUxQzY1LjI3ODggMTAyLjkyIDY0LjkxMzYgMTAzLjM1NSA2NC40NDA5IDEwMy42NTZDNjMuOTY4MyAxMDMuOTU3IDYzLjQxNjggMTA0LjEwNyA2Mi43ODY2IDEwNC4xMDdDNjIuMTcwNyAxMDQuMTA3IDYxLjYyNDcgMTAzLjk1NyA2MS4xNDg0IDEwMy42NTZDNjAuNjcyMiAxMDMuMzUyIDYwLjMwMTYgMTAyLjkyIDYwLjAzNjYgMTAyLjM2MkM1OS43NzUyIDEwMS44IDU5LjY0MSAxMDEuMTUgNTkuNjMzOCAxMDAuNDEyVjk5Ljg0ODFDNTkuNjMzOCA5OS4wOTYyIDU5Ljc2NDUgOTguNDMyIDYwLjAyNTkgOTcuODU1NUM2MC4yODczIDk3LjI3OSA2MC42NTYxIDk2LjgzODUgNjEuMTMyMyA5Ni41MzQyQzYxLjYxMjEgOTYuMjI2MiA2Mi4xNiA5Ni4wNzIzIDYyLjc3NTkgOTYuMDcyM0M2My40MDI1IDk2LjA3MjMgNjMuOTUzOSA5Ni4yMjQ0IDY0LjQzMDIgOTYuNTI4OEM2NC45MSA5Ni44Mjk2IDY1LjI3ODggOTcuMjY4MiA2NS41MzY2IDk3Ljg0NDdDNjUuNzk0NCA5OC40MTc2IDY1LjkyMzMgOTkuMDg1NCA2NS45MjMzIDk5Ljg0ODFWMTAwLjM0MlpNNjQuODk3NSA5OS44Mzc0QzY0Ljg5NzUgOTguOTEgNjQuNzExMyA5OC4xOTkyIDY0LjMzODkgOTcuNzA1MUM2My45NjY1IDk3LjIwNzQgNjMuNDQ1NSA5Ni45NTg1IDYyLjc3NTkgOTYuOTU4NUM2Mi4xMjQyIDk2Ljk1ODUgNjEuNjEwNCA5Ny4yMDc0IDYxLjIzNDQgOTcuNzA1MUM2MC44NjIgOTguMTk5MiA2MC42NzA0IDk4Ljg4NjcgNjAuNjU5NyA5OS43Njc2VjEwMC4zNDJDNjAuNjU5NyAxMDEuMjQxIDYwLjg0NzcgMTAxLjk0OCA2MS4yMjM2IDEwMi40NjRDNjEuNjAzMiAxMDIuOTc2IDYyLjEyNDIgMTAzLjIzMiA2Mi43ODY2IDEwMy4yMzJDNjMuNDUyNiAxMDMuMjMyIDYzLjk2ODMgMTAyLjk5IDY0LjMzMzUgMTAyLjUwN0M2NC42OTg3IDEwMi4wMiA2NC44ODY3IDEwMS4zMjMgNjQuODk3NSAxMDAuNDE3Vjk5LjgzNzRaIiBmaWxsPSJibGFjayIgZmlsbC1vcGFjaXR5PSIwLjg3Ii8+CjxwYXRoIGQ9Ik02OC4yNTQ0IDk4LjE4ODVMNjguMjg2NiA5OC45MTg5QzY4LjczMDYgOTguMzYwNCA2OS4zMTA3IDk4LjA4MTEgNzAuMDI2OSA5OC4wODExQzcxLjI1NSA5OC4wODExIDcxLjg3NDUgOTguNzczOSA3MS44ODUzIDEwMC4xNlYxMDRINzAuODkxNlYxMDAuMTU0QzcwLjg4OCA5OS43MzU0IDcwLjc5MTMgOTkuNDI1NiA3MC42MDE2IDk5LjIyNTFDNzAuNDE1NCA5OS4wMjQ2IDcwLjEyMzUgOTguOTI0MyA2OS43MjYxIDk4LjkyNDNDNjkuNDAzOCA5OC45MjQzIDY5LjEyMDkgOTkuMDEwMyA2OC44Nzc0IDk5LjE4MjFDNjguNjM0IDk5LjM1NCA2OC40NDQyIDk5LjU3OTYgNjguMzA4MSA5OS44NTg5VjEwNEg2Ny4zMTQ1Vjk4LjE4ODVINjguMjU0NFoiIGZpbGw9ImJsYWNrIiBmaWxsLW9wYWNpdHk9IjAuODciLz4KPHBhdGggZD0iTTc1Ljc5NTQgMTA0LjEwN0M3NS4wMDc2IDEwNC4xMDcgNzQuMzY2NyAxMDMuODUgNzMuODcyNiAxMDMuMzM0QzczLjM3ODQgMTAyLjgxNSA3My4xMzEzIDEwMi4xMjIgNzMuMTMxMyAxMDEuMjU1VjEwMS4wNzNDNzMuMTMxMyAxMDAuNDk2IDczLjI0MDYgOTkuOTgyNCA3My40NTkgOTkuNTMxMkM3My42ODEgOTkuMDc2NSA3My45ODg5IDk4LjcyMiA3NC4zODI4IDk4LjQ2NzhDNzQuNzgwMyA5OC4yMSA3NS4yMSA5OC4wODExIDc1LjY3MTkgOTguMDgxMUM3Ni40Mjc0IDk4LjA4MTEgNzcuMDE0NiA5OC4zMjk5IDc3LjQzMzYgOTguODI3NkM3Ny44NTI1IDk5LjMyNTQgNzguMDYyIDEwMC4wMzggNzguMDYyIDEwMC45NjVWMTAxLjM3OUg3NC4xMjVDNzQuMTM5MyAxMDEuOTUyIDc0LjMwNTggMTAyLjQxNiA3NC42MjQ1IDEwMi43N0M3NC45NDY4IDEwMy4xMjEgNzUuMzU1IDEwMy4yOTYgNzUuODQ5MSAxMDMuMjk2Qzc2LjIgMTAzLjI5NiA3Ni40OTcyIDEwMy4yMjUgNzYuNzQwNyAxMDMuMDgyQzc2Ljk4NDIgMTAyLjkzOCA3Ny4xOTczIDEwMi43NDkgNzcuMzc5OSAxMDIuNTEyTDc3Ljk4NjggMTAyLjk4NUM3Ny40OTk4IDEwMy43MzMgNzYuNzY5NCAxMDQuMTA3IDc1Ljc5NTQgMTA0LjEwN1pNNzUuNjcxOSA5OC44OTc1Qzc1LjI3MDggOTguODk3NSA3NC45MzQyIDk5LjA0NDMgNzQuNjYyMSA5OS4zMzc5Qzc0LjM5IDk5LjYyNzkgNzQuMjIxNyAxMDAuMDM2IDc0LjE1NzIgMTAwLjU2Mkg3Ny4wNjg0VjEwMC40ODdDNzcuMDM5NyA5OS45ODI0IDc2LjkwMzYgOTkuNTkyMSA3Ni42NjAyIDk5LjMxNjRDNzYuNDE2NyA5OS4wMzcxIDc2LjA4NzIgOTguODk3NSA3NS42NzE5IDk4Ljg5NzVaIiBmaWxsPSJibGFjayIgZmlsbC1vcGFjaXR5PSIwLjg3Ii8+CjxwYXRoIGQ9Ik04MS4yODQ3IDEwMS4wODNINzguNjYzNlYxMDAuMjcySDgxLjI4NDdWMTAxLjA4M1oiIGZpbGw9ImJsYWNrIiBmaWxsLW9wYWNpdHk9IjAuODciLz4KPHBhdGggZD0iTTg3LjQwMjMgMTAyLjYzTDg4LjUxOTUgOTguMTg4NUg4OS41MTMyTDg3LjgyMTMgMTA0SDg3LjAxNTZMODUuNjAzIDk5LjU5NTdMODQuMjI4IDEwNEg4My40MjI0TDgxLjczNTggOTguMTg4NUg4Mi43MjQxTDgzLjg2ODIgMTAyLjUzOUw4NS4yMjE3IDk4LjE4ODVIODYuMDIyTDg3LjQwMjMgMTAyLjYzWiIgZmlsbD0iYmxhY2siIGZpbGwtb3BhY2l0eT0iMC44NyIvPgo8cGF0aCBkPSJNOTQuMTE2MiAxMDRDOTQuMDU4OSAxMDMuODg1IDk0LjAxMjQgMTAzLjY4MSA5My45NzY2IDEwMy4zODhDOTMuNTE0NiAxMDMuODY4IDkyLjk2MzIgMTA0LjEwNyA5Mi4zMjIzIDEwNC4xMDdDOTEuNzQ5MyAxMDQuMTA3IDkxLjI3ODUgMTAzLjk0NiA5MC45MDk3IDEwMy42MjRDOTAuNTQ0NCAxMDMuMjk4IDkwLjM2MTggMTAyLjg4NiA5MC4zNjE4IDEwMi4zODlDOTAuMzYxOCAxMDEuNzg0IDkwLjU5MSAxMDEuMzE0IDkxLjA0OTMgMTAwLjk4MUM5MS41MTEyIDEwMC42NDUgOTIuMTU5MyAxMDAuNDc3IDkyLjk5MzcgMTAwLjQ3N0g5My45NjA0VjEwMC4wMkM5My45NjA0IDk5LjY3MjcgOTMuODU2NiA5OS4zOTcgOTMuNjQ4OSA5OS4xOTI5QzkzLjQ0MTIgOTguOTg1MiA5My4xMzUxIDk4Ljg4MTMgOTIuNzMwNSA5OC44ODEzQzkyLjM3NiA5OC44ODEzIDkyLjA3ODggOTguOTcwOSA5MS44Mzg5IDk5LjE0OTlDOTEuNTk5IDk5LjMyODkgOTEuNDc5IDk5LjU0NTYgOTEuNDc5IDk5Ljc5OThIOTAuNDhDOTAuNDggOTkuNTA5OCA5MC41ODIgOTkuMjMwNSA5MC43ODYxIDk4Ljk2MTlDOTAuOTkzOCA5OC42ODk4IDkxLjI3MzEgOTguNDc0OSA5MS42MjQgOTguMzE3NEM5MS45Nzg1IDk4LjE1OTggOTIuMzY3IDk4LjA4MTEgOTIuNzg5NiA5OC4wODExQzkzLjQ1OTEgOTguMDgxMSA5My45ODM3IDk4LjI0OTMgOTQuMzYzMyA5OC41ODU5Qzk0Ljc0MjggOTguOTE4OSA5NC45Mzk4IDk5LjM3OTEgOTQuOTU0MSA5OS45NjYzVjEwMi42NDFDOTQuOTU0MSAxMDMuMTc1IDk1LjAyMjEgMTAzLjU5OSA5NS4xNTgyIDEwMy45MTRWMTA0SDk0LjExNjJaTTkyLjQ2NzMgMTAzLjI0M0M5Mi43Nzg4IDEwMy4yNDMgOTMuMDc0MiAxMDMuMTYyIDkzLjM1MzUgMTAzLjAwMUM5My42MzI4IDEwMi44NCA5My44MzUxIDEwMi42MyA5My45NjA0IDEwMi4zNzNWMTAxLjE4SDkzLjE4MTZDOTEuOTY0MiAxMDEuMTggOTEuMzU1NSAxMDEuNTM2IDkxLjM1NTUgMTAyLjI0OUM5MS4zNTU1IDEwMi41NjEgOTEuNDU5MyAxMDIuODA0IDkxLjY2NyAxMDIuOTc5QzkxLjg3NDcgMTAzLjE1NSA5Mi4xNDE0IDEwMy4yNDMgOTIuNDY3MyAxMDMuMjQzWiIgZmlsbD0iYmxhY2siIGZpbGwtb3BhY2l0eT0iMC44NyIvPgo8cGF0aCBkPSJNOTguMzI3MSAxMDIuNTQ0TDk5LjY4MDcgOTguMTg4NUgxMDAuNzQ0TDk4LjQwNzcgMTA0Ljg5N0M5OC4wNDYxIDEwNS44NjQgOTcuNDcxNCAxMDYuMzQ3IDk2LjY4MzYgMTA2LjM0N0w5Ni40OTU2IDEwNi4zMzFMOTYuMTI1IDEwNi4yNjFWMTA1LjQ1Nkw5Ni4zOTM2IDEwNS40NzdDOTYuNzMwMSAxMDUuNDc3IDk2Ljk5MTUgMTA1LjQwOSA5Ny4xNzc3IDEwNS4yNzNDOTcuMzY3NSAxMDUuMTM3IDk3LjUyMzMgMTA0Ljg4OCA5Ny42NDUgMTA0LjUyNkw5Ny44NjUyIDEwMy45MzZMOTUuNzkyIDk4LjE4ODVIOTYuODc3TDk4LjMyNzEgMTAyLjU0NFoiIGZpbGw9ImJsYWNrIiBmaWxsLW9wYWNpdHk9IjAuODciLz4KPHBhdGggZD0iTTY1LjkyMzMgMTQwLjM0MkM2NS45MjMzIDE0MS4xMDkgNjUuNzk0NCAxNDEuNzc4IDY1LjUzNjYgMTQyLjM1MUM2NS4yNzg4IDE0Mi45MiA2NC45MTM2IDE0My4zNTUgNjQuNDQwOSAxNDMuNjU2QzYzLjk2ODMgMTQzLjk1NyA2My40MTY4IDE0NC4xMDcgNjIuNzg2NiAxNDQuMTA3QzYyLjE3MDcgMTQ0LjEwNyA2MS42MjQ3IDE0My45NTcgNjEuMTQ4NCAxNDMuNjU2QzYwLjY3MjIgMTQzLjM1MiA2MC4zMDE2IDE0Mi45MiA2MC4wMzY2IDE0Mi4zNjJDNTkuNzc1MiAxNDEuOCA1OS42NDEgMTQxLjE1IDU5LjYzMzggMTQwLjQxMlYxMzkuODQ4QzU5LjYzMzggMTM5LjA5NiA1OS43NjQ1IDEzOC40MzIgNjAuMDI1OSAxMzcuODU1QzYwLjI4NzMgMTM3LjI3OSA2MC42NTYxIDEzNi44MzkgNjEuMTMyMyAxMzYuNTM0QzYxLjYxMjEgMTM2LjIyNiA2Mi4xNiAxMzYuMDcyIDYyLjc3NTkgMTM2LjA3MkM2My40MDI1IDEzNi4wNzIgNjMuOTUzOSAxMzYuMjI0IDY0LjQzMDIgMTM2LjUyOUM2NC45MSAxMzYuODMgNjUuMjc4OCAxMzcuMjY4IDY1LjUzNjYgMTM3Ljg0NUM2NS43OTQ0IDEzOC40MTggNjUuOTIzMyAxMzkuMDg1IDY1LjkyMzMgMTM5Ljg0OFYxNDAuMzQyWk02NC44OTc1IDEzOS44MzdDNjQuODk3NSAxMzguOTEgNjQuNzExMyAxMzguMTk5IDY0LjMzODkgMTM3LjcwNUM2My45NjY1IDEzNy4yMDcgNjMuNDQ1NSAxMzYuOTU4IDYyLjc3NTkgMTM2Ljk1OEM2Mi4xMjQyIDEzNi45NTggNjEuNjEwNCAxMzcuMjA3IDYxLjIzNDQgMTM3LjcwNUM2MC44NjIgMTM4LjE5OSA2MC42NzA0IDEzOC44ODcgNjAuNjU5NyAxMzkuNzY4VjE0MC4zNDJDNjAuNjU5NyAxNDEuMjQxIDYwLjg0NzcgMTQxLjk0OCA2MS4yMjM2IDE0Mi40NjRDNjEuNjAzMiAxNDIuOTc2IDYyLjEyNDIgMTQzLjIzMiA2Mi43ODY2IDE0My4yMzJDNjMuNDUyNiAxNDMuMjMyIDYzLjk2ODMgMTQyLjk5IDY0LjMzMzUgMTQyLjUwN0M2NC42OTg3IDE0Mi4wMiA2NC44ODY3IDE0MS4zMjMgNjQuODk3NSAxNDAuNDE3VjEzOS44MzdaIiBmaWxsPSJibGFjayIgZmlsbC1vcGFjaXR5PSIwLjg3Ii8+CjxwYXRoIGQ9Ik02OC4yNTQ0IDEzOC4xODhMNjguMjg2NiAxMzguOTE5QzY4LjczMDYgMTM4LjM2IDY5LjMxMDcgMTM4LjA4MSA3MC4wMjY5IDEzOC4wODFDNzEuMjU1IDEzOC4wODEgNzEuODc0NSAxMzguNzc0IDcxLjg4NTMgMTQwLjE2VjE0NEg3MC44OTE2VjE0MC4xNTRDNzAuODg4IDEzOS43MzUgNzAuNzkxMyAxMzkuNDI2IDcwLjYwMTYgMTM5LjIyNUM3MC40MTU0IDEzOS4wMjUgNzAuMTIzNSAxMzguOTI0IDY5LjcyNjEgMTM4LjkyNEM2OS40MDM4IDEzOC45MjQgNjkuMTIwOSAxMzkuMDEgNjguODc3NCAxMzkuMTgyQzY4LjYzNCAxMzkuMzU0IDY4LjQ0NDIgMTM5LjU4IDY4LjMwODEgMTM5Ljg1OVYxNDRINjcuMzE0NVYxMzguMTg4SDY4LjI1NDRaIiBmaWxsPSJibGFjayIgZmlsbC1vcGFjaXR5PSIwLjg3Ii8+CjxwYXRoIGQ9Ik03NS43OTU0IDE0NC4xMDdDNzUuMDA3NiAxNDQuMTA3IDc0LjM2NjcgMTQzLjg1IDczLjg3MjYgMTQzLjMzNEM3My4zNzg0IDE0Mi44MTUgNzMuMTMxMyAxNDIuMTIyIDczLjEzMTMgMTQxLjI1NVYxNDEuMDczQzczLjEzMTMgMTQwLjQ5NiA3My4yNDA2IDEzOS45ODIgNzMuNDU5IDEzOS41MzFDNzMuNjgxIDEzOS4wNzYgNzMuOTg4OSAxMzguNzIyIDc0LjM4MjggMTM4LjQ2OEM3NC43ODAzIDEzOC4yMSA3NS4yMSAxMzguMDgxIDc1LjY3MTkgMTM4LjA4MUM3Ni40Mjc0IDEzOC4wODEgNzcuMDE0NiAxMzguMzMgNzcuNDMzNiAxMzguODI4Qzc3Ljg1MjUgMTM5LjMyNSA3OC4wNjIgMTQwLjAzOCA3OC4wNjIgMTQwLjk2NVYxNDEuMzc5SDc0LjEyNUM3NC4xMzkzIDE0MS45NTIgNzQuMzA1OCAxNDIuNDE2IDc0LjYyNDUgMTQyLjc3Qzc0Ljk0NjggMTQzLjEyMSA3NS4zNTUgMTQzLjI5NiA3NS44NDkxIDE0My4yOTZDNzYuMiAxNDMuMjk2IDc2LjQ5NzIgMTQzLjIyNSA3Ni43NDA3IDE0My4wODJDNzYuOTg0MiAxNDIuOTM4IDc3LjE5NzMgMTQyLjc0OSA3Ny4zNzk5IDE0Mi41MTJMNzcuOTg2OCAxNDIuOTg1Qzc3LjQ5OTggMTQzLjczMyA3Ni43Njk0IDE0NC4xMDcgNzUuNzk1NCAxNDQuMTA3Wk03NS42NzE5IDEzOC44OTdDNzUuMjcwOCAxMzguODk3IDc0LjkzNDIgMTM5LjA0NCA3NC42NjIxIDEzOS4zMzhDNzQuMzkgMTM5LjYyOCA3NC4yMjE3IDE0MC4wMzYgNzQuMTU3MiAxNDAuNTYySDc3LjA2ODRWMTQwLjQ4N0M3Ny4wMzk3IDEzOS45ODIgNzYuOTAzNiAxMzkuNTkyIDc2LjY2MDIgMTM5LjMxNkM3Ni40MTY3IDEzOS4wMzcgNzYuMDg3MiAxMzguODk3IDc1LjY3MTkgMTM4Ljg5N1oiIGZpbGw9ImJsYWNrIiBmaWxsLW9wYWNpdHk9IjAuODciLz4KPHBhdGggZD0iTTgxLjI4NDcgMTQxLjA4M0g3OC42NjM2VjE0MC4yNzJIODEuMjg0N1YxNDEuMDgzWiIgZmlsbD0iYmxhY2siIGZpbGwtb3BhY2l0eT0iMC44NyIvPgo8cGF0aCBkPSJNODcuNDAyMyAxNDIuNjNMODguNTE5NSAxMzguMTg4SDg5LjUxMzJMODcuODIxMyAxNDRIODcuMDE1Nkw4NS42MDMgMTM5LjU5Nkw4NC4yMjggMTQ0SDgzLjQyMjRMODEuNzM1OCAxMzguMTg4SDgyLjcyNDFMODMuODY4MiAxNDIuNTM5TDg1LjIyMTcgMTM4LjE4OEg4Ni4wMjJMODcuNDAyMyAxNDIuNjNaIiBmaWxsPSJibGFjayIgZmlsbC1vcGFjaXR5PSIwLjg3Ii8+CjxwYXRoIGQ9Ik05NC4xMTYyIDE0NEM5NC4wNTg5IDE0My44ODUgOTQuMDEyNCAxNDMuNjgxIDkzLjk3NjYgMTQzLjM4OEM5My41MTQ2IDE0My44NjggOTIuOTYzMiAxNDQuMTA3IDkyLjMyMjMgMTQ0LjEwN0M5MS43NDkzIDE0NC4xMDcgOTEuMjc4NSAxNDMuOTQ2IDkwLjkwOTcgMTQzLjYyNEM5MC41NDQ0IDE0My4yOTggOTAuMzYxOCAxNDIuODg2IDkwLjM2MTggMTQyLjM4OUM5MC4zNjE4IDE0MS43ODQgOTAuNTkxIDE0MS4zMTQgOTEuMDQ5MyAxNDAuOTgxQzkxLjUxMTIgMTQwLjY0NSA5Mi4xNTkzIDE0MC40NzcgOTIuOTkzNyAxNDAuNDc3SDkzLjk2MDRWMTQwLjAyQzkzLjk2MDQgMTM5LjY3MyA5My44NTY2IDEzOS4zOTcgOTMuNjQ4OSAxMzkuMTkzQzkzLjQ0MTIgMTM4Ljk4NSA5My4xMzUxIDEzOC44ODEgOTIuNzMwNSAxMzguODgxQzkyLjM3NiAxMzguODgxIDkyLjA3ODggMTM4Ljk3MSA5MS44Mzg5IDEzOS4xNUM5MS41OTkgMTM5LjMyOSA5MS40NzkgMTM5LjU0NiA5MS40NzkgMTM5LjhIOTAuNDhDOTAuNDggMTM5LjUxIDkwLjU4MiAxMzkuMjMgOTAuNzg2MSAxMzguOTYyQzkwLjk5MzggMTM4LjY5IDkxLjI3MzEgMTM4LjQ3NSA5MS42MjQgMTM4LjMxN0M5MS45Nzg1IDEzOC4xNiA5Mi4zNjcgMTM4LjA4MSA5Mi43ODk2IDEzOC4wODFDOTMuNDU5MSAxMzguMDgxIDkzLjk4MzcgMTM4LjI0OSA5NC4zNjMzIDEzOC41ODZDOTQuNzQyOCAxMzguOTE5IDk0LjkzOTggMTM5LjM3OSA5NC45NTQxIDEzOS45NjZWMTQyLjY0MUM5NC45NTQxIDE0My4xNzUgOTUuMDIyMSAxNDMuNTk5IDk1LjE1ODIgMTQzLjkxNFYxNDRIOTQuMTE2MlpNOTIuNDY3MyAxNDMuMjQzQzkyLjc3ODggMTQzLjI0MyA5My4wNzQyIDE0My4xNjIgOTMuMzUzNSAxNDMuMDAxQzkzLjYzMjggMTQyLjg0IDkzLjgzNTEgMTQyLjYzIDkzLjk2MDQgMTQyLjM3M1YxNDEuMThIOTMuMTgxNkM5MS45NjQyIDE0MS4xOCA5MS4zNTU1IDE0MS41MzYgOTEuMzU1NSAxNDIuMjQ5QzkxLjM1NTUgMTQyLjU2MSA5MS40NTkzIDE0Mi44MDQgOTEuNjY3IDE0Mi45NzlDOTEuODc0NyAxNDMuMTU1IDkyLjE0MTQgMTQzLjI0MyA5Mi40NjczIDE0My4yNDNaIiBmaWxsPSJibGFjayIgZmlsbC1vcGFjaXR5PSIwLjg3Ii8+CjxwYXRoIGQ9Ik05OC4zMjcxIDE0Mi41NDRMOTkuNjgwNyAxMzguMTg4SDEwMC43NDRMOTguNDA3NyAxNDQuODk3Qzk4LjA0NjEgMTQ1Ljg2NCA5Ny40NzE0IDE0Ni4zNDcgOTYuNjgzNiAxNDYuMzQ3TDk2LjQ5NTYgMTQ2LjMzMUw5Ni4xMjUgMTQ2LjI2MVYxNDUuNDU2TDk2LjM5MzYgMTQ1LjQ3N0M5Ni43MzAxIDE0NS40NzcgOTYuOTkxNSAxNDUuNDA5IDk3LjE3NzcgMTQ1LjI3M0M5Ny4zNjc1IDE0NS4xMzcgOTcuNTIzMyAxNDQuODg4IDk3LjY0NSAxNDQuNTI2TDk3Ljg2NTIgMTQzLjkzNkw5NS43OTIgMTM4LjE4OEg5Ni44NzdMOTguMzI3MSAxNDIuNTQ0WiIgZmlsbD0iYmxhY2siIGZpbGwtb3BhY2l0eT0iMC44NyIvPgo8cGF0aCBkPSJNMTIuNzczNCAxMDMuNDc5QzEyLjc3MzQgMTAzLjMwNyAxMi44MjM2IDEwMy4xNjQgMTIuOTIzOCAxMDMuMDQ5QzEzLjAyNzcgMTAyLjkzNSAxMy4xODE2IDEwMi44NzcgMTMuMzg1NyAxMDIuODc3QzEzLjU4OTggMTAyLjg3NyAxMy43NDM4IDEwMi45MzUgMTMuODQ3NyAxMDMuMDQ5QzEzLjk1NTEgMTAzLjE2NCAxNC4wMDg4IDEwMy4zMDcgMTQuMDA4OCAxMDMuNDc5QzE0LjAwODggMTAzLjY0NCAxMy45NTUxIDEwMy43ODIgMTMuODQ3NyAxMDMuODkzQzEzLjc0MzggMTA0LjAwNCAxMy41ODk4IDEwNC4wNTkgMTMuMzg1NyAxMDQuMDU5QzEzLjE4MTYgMTA0LjA1OSAxMy4wMjc3IDEwNC4wMDQgMTIuOTIzOCAxMDMuODkzQzEyLjgyMzYgMTAzLjc4MiAxMi43NzM0IDEwMy42NDQgMTIuNzczNCAxMDMuNDc5WiIgZmlsbD0iYmxhY2siIGZpbGwtb3BhY2l0eT0iMC44NyIvPgo8cGF0aCBkPSJNMTUuNjczOCAxMDMuNDc5QzE1LjY3MzggMTAzLjMwNyAxNS43MjQgMTAzLjE2NCAxNS44MjQyIDEwMy4wNDlDMTUuOTI4MSAxMDIuOTM1IDE2LjA4MiAxMDIuODc3IDE2LjI4NjEgMTAyLjg3N0MxNi40OTAyIDEwMi44NzcgMTYuNjQ0MiAxMDIuOTM1IDE2Ljc0OCAxMDMuMDQ5QzE2Ljg1NTUgMTAzLjE2NCAxNi45MDkyIDEwMy4zMDcgMTYuOTA5MiAxMDMuNDc5QzE2LjkwOTIgMTAzLjY0NCAxNi44NTU1IDEwMy43ODIgMTYuNzQ4IDEwMy44OTNDMTYuNjQ0MiAxMDQuMDA0IDE2LjQ5MDIgMTA0LjA1OSAxNi4yODYxIDEwNC4wNTlDMTYuMDgyIDEwNC4wNTkgMTUuOTI4MSAxMDQuMDA0IDE1LjgyNDIgMTAzLjg5M0MxNS43MjQgMTAzLjc4MiAxNS42NzM4IDEwMy42NDQgMTUuNjczOCAxMDMuNDc5WiIgZmlsbD0iYmxhY2siIGZpbGwtb3BhY2l0eT0iMC44NyIvPgo8cGF0aCBkPSJNMTguMjg5NiAxMDEuMDQxQzE4LjI4OTYgMTAwLjQ3MSAxOC40MDA2IDk5Ljk1OTEgMTguNjIyNiA5OS41MDQ0QzE4Ljg0ODEgOTkuMDQ5NiAxOS4xNTk3IDk4LjY5ODcgMTkuNTU3MSA5OC40NTE3QzE5Ljk1ODIgOTguMjA0NiAyMC40MTQ3IDk4LjA4MTEgMjAuOTI2OCA5OC4wODExQzIxLjcxODEgOTguMDgxMSAyMi4zNTczIDk4LjM1NSAyMi44NDQyIDk4LjkwMjhDMjMuMzM0OCA5OS40NTA3IDIzLjU4MDEgMTAwLjE3OSAyMy41ODAxIDEwMS4wODlWMTAxLjE1OUMyMy41ODAxIDEwMS43MjQgMjMuNDcwOSAxMDIuMjMzIDIzLjI1MjQgMTAyLjY4NEMyMy4wMzc2IDEwMy4xMzIgMjIuNzI3OSAxMDMuNDgxIDIyLjMyMzIgMTAzLjczMUMyMS45MjIyIDEwMy45ODIgMjEuNDYwMyAxMDQuMTA3IDIwLjkzNzUgMTA0LjEwN0MyMC4xNDk3IDEwNC4xMDcgMTkuNTEwNiAxMDMuODMzIDE5LjAyIDEwMy4yODZDMTguNTMzIDEwMi43MzggMTguMjg5NiAxMDIuMDEzIDE4LjI4OTYgMTAxLjExVjEwMS4wNDFaTTE5LjI4ODYgMTAxLjE1OUMxOS4yODg2IDEwMS44MDMgMTkuNDM3MiAxMDIuMzIxIDE5LjczNDQgMTAyLjcxMUMyMC4wMzUyIDEwMy4xMDEgMjAuNDM2MiAxMDMuMjk2IDIwLjkzNzUgMTAzLjI5NkMyMS40NDI0IDEwMy4yOTYgMjEuODQzNCAxMDMuMDk5IDIyLjE0MDYgMTAyLjcwNkMyMi40Mzc4IDEwMi4zMDggMjIuNTg2NCAxMDEuNzUzIDIyLjU4NjQgMTAxLjA0MUMyMi41ODY0IDEwMC40MDMgMjIuNDM0MiA5OS44ODc1IDIyLjEyOTkgOTkuNDkzN0MyMS44MjkxIDk5LjA5NjIgMjEuNDI4MSA5OC44OTc1IDIwLjkyNjggOTguODk3NUMyMC40MzYyIDk4Ljg5NzUgMjAuMDQwNSA5OS4wOTI2IDE5LjczOTcgOTkuNDgyOUMxOS40MzkgOTkuODczMiAxOS4yODg2IDEwMC40MzIgMTkuMjg4NiAxMDEuMTU5WiIgZmlsbD0iYmxhY2siIGZpbGwtb3BhY2l0eT0iMC44NyIvPgo8cGF0aCBkPSJNMjYuMTY4OSA5OS42MDY0SDI2LjkxNTVDMjcuMzg0NiA5OS41OTkzIDI3Ljc1MzQgOTkuNDc1NyAyOC4wMjIgOTkuMjM1OEMyOC4yOTA1IDk4Ljk5NTkgMjguNDI0OCA5OC42NzE5IDI4LjQyNDggOTguMjYzN0MyOC40MjQ4IDk3LjM0NyAyNy45NjgzIDk2Ljg4ODcgMjcuMDU1MiA5Ni44ODg3QzI2LjYyNTUgOTYuODg4NyAyNi4yODE3IDk3LjAxMjIgMjYuMDIzOSA5Ny4yNTkzQzI1Ljc2OTcgOTcuNTAyOCAyNS42NDI2IDk3LjgyNjggMjUuNjQyNiA5OC4yMzE0SDI0LjY0ODlDMjQuNjQ4OSA5Ny42MTIgMjQuODc0NSA5Ny4wOTgxIDI1LjMyNTcgOTYuNjg5OUMyNS43ODA0IDk2LjI3ODIgMjYuMzU2OSA5Ni4wNzIzIDI3LjA1NTIgOTYuMDcyM0MyNy43OTI4IDk2LjA3MjMgMjguMzcxMSA5Ni4yNjc0IDI4Ljc5IDk2LjY1NzdDMjkuMjA5IDk3LjA0OCAyOS40MTg1IDk3LjU5MDUgMjkuNDE4NSA5OC4yODUyQzI5LjQxODUgOTguNjI1MyAyOS4zMDc1IDk4Ljk1NDggMjkuMDg1NCA5OS4yNzM0QzI4Ljg2NyA5OS41OTIxIDI4LjU2OCA5OS44MzAyIDI4LjE4ODUgOTkuOTg3OEMyOC42MTgyIDEwMC4xMjQgMjguOTQ5NCAxMDAuMzQ5IDI5LjE4MjEgMTAwLjY2NUMyOS40MTg1IDEwMC45OCAyOS41MzY2IDEwMS4zNjUgMjkuNTM2NiAxMDEuODE5QzI5LjUzNjYgMTAyLjUyMSAyOS4zMDc1IDEwMy4wNzggMjguODQ5MSAxMDMuNDlDMjguMzkwOCAxMDMuOTAyIDI3Ljc5NDYgMTA0LjEwNyAyNy4wNjA1IDEwNC4xMDdDMjYuMzI2NSAxMDQuMTA3IDI1LjcyODUgMTAzLjkwOSAyNS4yNjY2IDEwMy41MTFDMjQuODA4MyAxMDMuMTE0IDI0LjU3OTEgMTAyLjU4OSAyNC41NzkxIDEwMS45MzhIMjUuNTc4MUMyNS41NzgxIDEwMi4zNDkgMjUuNzEyNCAxMDIuNjc5IDI1Ljk4MSAxMDIuOTI2QzI2LjI0OTUgMTAzLjE3MyAyNi42MDk0IDEwMy4yOTYgMjcuMDYwNSAxMDMuMjk2QzI3LjU0MDQgMTAzLjI5NiAyNy45MDc0IDEwMy4xNzEgMjguMTYxNiAxMDIuOTJDMjguNDE1OSAxMDIuNjcgMjguNTQzIDEwMi4zMSAyOC41NDMgMTAxLjg0MUMyOC41NDMgMTAxLjM4NiAyOC40MDMzIDEwMS4wMzcgMjguMTI0IDEwMC43OTNDMjcuODQ0NyAxMDAuNTUgMjcuNDQxOSAxMDAuNDI1IDI2LjkxNTUgMTAwLjQxN0gyNi4xNjg5Vjk5LjYwNjRaIiBmaWxsPSJibGFjayIgZmlsbC1vcGFjaXR5PSIwLjg3Ii8+CjxwYXRoIGQ9Ik0zMC43NjEyIDEwMS4wNDZDMzAuNzYxMiAxMDAuMTU0IDMwLjk3MjUgOTkuNDM4MiAzMS4zOTUgOTguODk3NUMzMS44MTc1IDk4LjM1MzIgMzIuMzcwOCA5OC4wODExIDMzLjA1NDcgOTguMDgxMUMzMy43MzUgOTguMDgxMSAzNC4yNzM5IDk4LjMxMzggMzQuNjcxNCA5OC43NzkzVjk1Ljc1SDM1LjY2NVYxMDRIMzQuNzUyTDM0LjcwMzYgMTAzLjM3N0MzNC4zMDYyIDEwMy44NjQgMzMuNzUyOSAxMDQuMTA3IDMzLjA0MzkgMTA0LjEwN0MzMi4zNzA4IDEwNC4xMDcgMzEuODIxMSAxMDMuODMyIDMxLjM5NSAxMDMuMjhDMzAuOTcyNSAxMDIuNzI5IDMwLjc2MTIgMTAyLjAwOSAzMC43NjEyIDEwMS4xMjFWMTAxLjA0NlpNMzEuNzU0OSAxMDEuMTU5QzMxLjc1NDkgMTAxLjgxOCAzMS44OTEgMTAyLjMzMyAzMi4xNjMxIDEwMi43MDZDMzIuNDM1MiAxMDMuMDc4IDMyLjgxMTIgMTAzLjI2NCAzMy4yOTEgMTAzLjI2NEMzMy45MjEyIDEwMy4yNjQgMzQuMzgxMyAxMDIuOTgxIDM0LjY3MTQgMTAyLjQxNlY5OS43NDYxQzM0LjM3NDIgOTkuMTk4MiAzMy45MTc2IDk4LjkyNDMgMzMuMzAxOCA5OC45MjQzQzMyLjgxNDggOTguOTI0MyAzMi40MzUyIDk5LjExMjMgMzIuMTYzMSA5OS40ODgzQzMxLjg5MSA5OS44NjQzIDMxLjc1NDkgMTAwLjQyMSAzMS43NTQ5IDEwMS4xNTlaIiBmaWxsPSJibGFjayIgZmlsbC1vcGFjaXR5PSIwLjg3Ii8+CjxwYXRoIGQ9Ik00MC4wMjEgOTkuMDgwMUMzOS44NzA2IDk5LjA1NSAzOS43MDc3IDk5LjA0MjUgMzkuNTMyMiA5OS4wNDI1QzM4Ljg4MDUgOTkuMDQyNSAzOC40MzgzIDk5LjMyIDM4LjIwNTYgOTkuODc1VjEwNEgzNy4yMTE5Vjk4LjE4ODVIMzguMTc4N0wzOC4xOTQ4IDk4Ljg1OTlDMzguNTIwNyA5OC4zNDA3IDM4Ljk4MjYgOTguMDgxMSAzOS41ODA2IDk4LjA4MTFDMzkuNzczOSA5OC4wODExIDM5LjkyMDcgOTguMTA2MSA0MC4wMjEgOTguMTU2MlY5OS4wODAxWiIgZmlsbD0iYmxhY2siIGZpbGwtb3BhY2l0eT0iMC44NyIvPgo8cGF0aCBkPSJNNDEuODc5NCA5OC4xODg1TDQxLjkxMTYgOTguOTE4OUM0Mi4zNTU2IDk4LjM2MDQgNDIuOTM1NyA5OC4wODExIDQzLjY1MTkgOTguMDgxMUM0NC44OCA5OC4wODExIDQ1LjQ5OTUgOTguNzczOSA0NS41MTAzIDEwMC4xNlYxMDRINDQuNTE2NlYxMDAuMTU0QzQ0LjUxMyA5OS43MzU0IDQ0LjQxNjMgOTkuNDI1NiA0NC4yMjY2IDk5LjIyNTFDNDQuMDQwNCA5OS4wMjQ2IDQzLjc0ODUgOTguOTI0MyA0My4zNTExIDk4LjkyNDNDNDMuMDI4OCA5OC45MjQzIDQyLjc0NTkgOTkuMDEwMyA0Mi41MDI0IDk5LjE4MjFDNDIuMjU5IDk5LjM1NCA0Mi4wNjkyIDk5LjU3OTYgNDEuOTMzMSA5OS44NTg5VjEwNEg0MC45Mzk1Vjk4LjE4ODVINDEuODc5NFoiIGZpbGw9ImJsYWNrIiBmaWxsLW9wYWNpdHk9IjAuODciLz4KPHBhdGggZD0iTTEyLjc3MzQgMTQzLjQ3OUMxMi43NzM0IDE0My4zMDcgMTIuODIzNiAxNDMuMTY0IDEyLjkyMzggMTQzLjA0OUMxMy4wMjc3IDE0Mi45MzUgMTMuMTgxNiAxNDIuODc3IDEzLjM4NTcgMTQyLjg3N0MxMy41ODk4IDE0Mi44NzcgMTMuNzQzOCAxNDIuOTM1IDEzLjg0NzcgMTQzLjA0OUMxMy45NTUxIDE0My4xNjQgMTQuMDA4OCAxNDMuMzA3IDE0LjAwODggMTQzLjQ3OUMxNC4wMDg4IDE0My42NDQgMTMuOTU1MSAxNDMuNzgyIDEzLjg0NzcgMTQzLjg5M0MxMy43NDM4IDE0NC4wMDQgMTMuNTg5OCAxNDQuMDU5IDEzLjM4NTcgMTQ0LjA1OUMxMy4xODE2IDE0NC4wNTkgMTMuMDI3NyAxNDQuMDA0IDEyLjkyMzggMTQzLjg5M0MxMi44MjM2IDE0My43ODIgMTIuNzczNCAxNDMuNjQ0IDEyLjc3MzQgMTQzLjQ3OVoiIGZpbGw9ImJsYWNrIiBmaWxsLW9wYWNpdHk9IjAuODciLz4KPHBhdGggZD0iTTE1LjY3MzggMTQzLjQ3OUMxNS42NzM4IDE0My4zMDcgMTUuNzI0IDE0My4xNjQgMTUuODI0MiAxNDMuMDQ5QzE1LjkyODEgMTQyLjkzNSAxNi4wODIgMTQyLjg3NyAxNi4yODYxIDE0Mi44NzdDMTYuNDkwMiAxNDIuODc3IDE2LjY0NDIgMTQyLjkzNSAxNi43NDggMTQzLjA0OUMxNi44NTU1IDE0My4xNjQgMTYuOTA5MiAxNDMuMzA3IDE2LjkwOTIgMTQzLjQ3OUMxNi45MDkyIDE0My42NDQgMTYuODU1NSAxNDMuNzgyIDE2Ljc0OCAxNDMuODkzQzE2LjY0NDIgMTQ0LjAwNCAxNi40OTAyIDE0NC4wNTkgMTYuMjg2MSAxNDQuMDU5QzE2LjA4MiAxNDQuMDU5IDE1LjkyODEgMTQ0LjAwNCAxNS44MjQyIDE0My44OTNDMTUuNzI0IDE0My43ODIgMTUuNjczOCAxNDMuNjQ0IDE1LjY3MzggMTQzLjQ3OVoiIGZpbGw9ImJsYWNrIiBmaWxsLW9wYWNpdHk9IjAuODciLz4KPHBhdGggZD0iTTIxLjM2MTggMTM5LjA4QzIxLjIxMTQgMTM5LjA1NSAyMS4wNDg1IDEzOS4wNDIgMjAuODczIDEzOS4wNDJDMjAuMjIxNCAxMzkuMDQyIDE5Ljc3OTEgMTM5LjMyIDE5LjU0NjQgMTM5Ljg3NVYxNDRIMTguNTUyN1YxMzguMTg4SDE5LjUxOTVMMTkuNTM1NiAxMzguODZDMTkuODYxNSAxMzguMzQxIDIwLjMyMzQgMTM4LjA4MSAyMC45MjE0IDEzOC4wODFDMjEuMTE0NyAxMzguMDgxIDIxLjI2MTYgMTM4LjEwNiAyMS4zNjE4IDEzOC4xNTZWMTM5LjA4WiIgZmlsbD0iYmxhY2siIGZpbGwtb3BhY2l0eT0iMC44NyIvPgo8cGF0aCBkPSJNMjQuMjk0NCAxNDIuNjUyTDI1LjczMzkgMTM4LjE4OEgyNi43NDlMMjQuNjY1IDE0NEgyMy45MDc3TDIxLjgwMjIgMTM4LjE4OEgyMi44MTc0TDI0LjI5NDQgMTQyLjY1MloiIGZpbGw9ImJsYWNrIiBmaWxsLW9wYWNpdHk9IjAuODciLz4KPHBhdGggZD0iTTMxLjQxMTEgMTQwLjU2MkMzMS4yMDM1IDE0MC44MSAzMC45NTQ2IDE0MS4wMDggMzAuNjY0NiAxNDEuMTU5QzMwLjM3ODEgMTQxLjMwOSAzMC4wNjMgMTQxLjM4NCAyOS43MTkyIDE0MS4zODRDMjkuMjY4MSAxNDEuMzg0IDI4Ljg3NDIgMTQxLjI3MyAyOC41Mzc2IDE0MS4wNTFDMjguMjA0NiAxNDAuODI5IDI3Ljk0NjggMTQwLjUxOCAyNy43NjQyIDE0MC4xMTdDMjcuNTgxNSAxMzkuNzEyIDI3LjQ5MDIgMTM5LjI2NiAyNy40OTAyIDEzOC43NzlDMjcuNDkwMiAxMzguMjU3IDI3LjU4ODcgMTM3Ljc4NiAyNy43ODU2IDEzNy4zNjdDMjcuOTg2MiAxMzYuOTQ4IDI4LjI2OSAxMzYuNjI3IDI4LjYzNDMgMTM2LjQwNUMyOC45OTk1IDEzNi4xODMgMjkuNDI1NiAxMzYuMDcyIDI5LjkxMjYgMTM2LjA3MkMzMC42ODYgMTM2LjA3MiAzMS4yOTQ4IDEzNi4zNjIgMzEuNzM4OCAxMzYuOTQyQzMyLjE4NjQgMTM3LjUxOSAzMi40MTAyIDEzOC4zMDcgMzIuNDEwMiAxMzkuMzA2VjEzOS41OTZDMzIuNDEwMiAxNDEuMTE4IDMyLjEwOTQgMTQyLjIyOSAzMS41MDc4IDE0Mi45MzFDMzAuOTA2MiAxNDMuNjI5IDI5Ljk5ODUgMTQzLjk4NyAyOC43ODQ3IDE0NC4wMDVIMjguNTkxM1YxNDMuMTY3SDI4LjgwMDhDMjkuNjIwOCAxNDMuMTUzIDMwLjI1MSAxNDIuOTQgMzAuNjkxNCAxNDIuNTI4QzMxLjEzMTggMTQyLjExMyAzMS4zNzE3IDE0MS40NTggMzEuNDExMSAxNDAuNTYyWk0yOS44ODA0IDE0MC41NjJDMzAuMjEzNCAxNDAuNTYyIDMwLjUxOTUgMTQwLjQ2IDMwLjc5ODggMTQwLjI1NkMzMS4wODE3IDE0MC4wNTIgMzEuMjg3NiAxMzkuOCAzMS40MTY1IDEzOS40OTlWMTM5LjEwMkMzMS40MTY1IDEzOC40NSAzMS4yNzUxIDEzNy45MiAzMC45OTIyIDEzNy41MTJDMzAuNzA5MyAxMzcuMTA0IDMwLjM1MTIgMTM2Ljg5OSAyOS45MTggMTM2Ljg5OUMyOS40ODExIDEzNi44OTkgMjkuMTMwMiAxMzcuMDY4IDI4Ljg2NTIgMTM3LjQwNEMyOC42MDAzIDEzNy43MzcgMjguNDY3OCAxMzguMTc4IDI4LjQ2NzggMTM4LjcyNkMyOC40Njc4IDEzOS4yNTkgMjguNTk0OSAxMzkuNyAyOC44NDkxIDE0MC4wNDdDMjkuMTA2OSAxNDAuMzkxIDI5LjQ1MDcgMTQwLjU2MiAyOS44ODA0IDE0MC41NjJaIiBmaWxsPSJibGFjayIgZmlsbC1vcGFjaXR5PSIwLjg3Ii8+CjxwYXRoIGQ9Ik0zNS41MDM5IDE0MS4zMDlMMzQuODgwOSAxNDEuOTU5VjE0NEgzMy44ODcyVjEzNS43NUgzNC44ODA5VjE0MC43NEwzNS40MTI2IDE0MC4xMDFMMzcuMjIyNyAxMzguMTg4SDM4LjQzMTJMMzYuMTY5OSAxNDAuNjE2TDM4LjY5NDMgMTQ0SDM3LjUyODhMMzUuNTAzOSAxNDEuMzA5WiIgZmlsbD0iYmxhY2siIGZpbGwtb3BhY2l0eT0iMC44NyIvPgo8cGF0aCBkPSJNNDEuNzYxMiAxNDQuMTA3QzQwLjk3MzUgMTQ0LjEwNyA0MC4zMzI1IDE0My44NSAzOS44Mzg0IDE0My4zMzRDMzkuMzQ0MiAxNDIuODE1IDM5LjA5NzIgMTQyLjEyMiAzOS4wOTcyIDE0MS4yNTVWMTQxLjA3M0MzOS4wOTcyIDE0MC40OTYgMzkuMjA2NCAxMzkuOTgyIDM5LjQyNDggMTM5LjUzMUMzOS42NDY4IDEzOS4wNzYgMzkuOTU0OCAxMzguNzIyIDQwLjM0ODYgMTM4LjQ2OEM0MC43NDYxIDEzOC4yMSA0MS4xNzU4IDEzOC4wODEgNDEuNjM3NyAxMzguMDgxQzQyLjM5MzIgMTM4LjA4MSA0Mi45ODA1IDEzOC4zMyA0My4zOTk0IDEzOC44MjhDNDMuODE4NCAxMzkuMzI1IDQ0LjAyNzggMTQwLjAzOCA0NC4wMjc4IDE0MC45NjVWMTQxLjM3OUg0MC4wOTA4QzQwLjEwNTEgMTQxLjk1MiA0MC4yNzE2IDE0Mi40MTYgNDAuNTkwMyAxNDIuNzdDNDAuOTEyNiAxNDMuMTIxIDQxLjMyMDggMTQzLjI5NiA0MS44MTQ5IDE0My4yOTZDNDIuMTY1OSAxNDMuMjk2IDQyLjQ2MzEgMTQzLjIyNSA0Mi43MDY1IDE0My4wODJDNDIuOTUgMTQyLjkzOCA0My4xNjMxIDE0Mi43NDkgNDMuMzQ1NyAxNDIuNTEyTDQzLjk1MjYgMTQyLjk4NUM0My40NjU3IDE0My43MzMgNDIuNzM1MiAxNDQuMTA3IDQxLjc2MTIgMTQ0LjEwN1pNNDEuNjM3NyAxMzguODk3QzQxLjIzNjcgMTM4Ljg5NyA0MC45MDAxIDEzOS4wNDQgNDAuNjI3OSAxMzkuMzM4QzQwLjM1NTggMTM5LjYyOCA0MC4xODc1IDE0MC4wMzYgNDAuMTIzIDE0MC41NjJINDMuMDM0MlYxNDAuNDg3QzQzLjAwNTUgMTM5Ljk4MiA0Mi44Njk1IDEzOS41OTIgNDIuNjI2IDEzOS4zMTZDNDIuMzgyNSAxMzkuMDM3IDQyLjA1MzEgMTM4Ljg5NyA0MS42Mzc3IDEzOC44OTdaIiBmaWxsPSJibGFjayIgZmlsbC1vcGFjaXR5PSIwLjg3Ii8+CjxwYXRoIGQ9Ik0xNDYuNDQ1IDU3LjI3NTRIMTQ0LjAwN1Y2NEgxNDIuNjU5VjU3LjI3NTRIMTQwLjI0MlY1Ni4xNzk3SDE0Ni40NDVWNTcuMjc1NFoiIGZpbGw9IiNGRkE1MDAiLz4KPHBhdGggZD0iTTE0OC43MzkgNjRIMTQ3LjQzNFY1OC4xODg1SDE0OC43MzlWNjRaTTE0Ny4zNTMgNTYuNjc5MkMxNDcuMzUzIDU2LjQ3ODcgMTQ3LjQxNiA1Ni4zMTIyIDE0Ny41NDEgNTYuMTc5N0MxNDcuNjcgNTYuMDQ3MiAxNDcuODUzIDU1Ljk4MSAxNDguMDg5IDU1Ljk4MUMxNDguMzI1IDU1Ljk4MSAxNDguNTA4IDU2LjA0NzIgMTQ4LjYzNyA1Ni4xNzk3QzE0OC43NjYgNTYuMzEyMiAxNDguODMgNTYuNDc4NyAxNDguODMgNTYuNjc5MkMxNDguODMgNTYuODc2MSAxNDguNzY2IDU3LjA0MDkgMTQ4LjYzNyA1Ny4xNzMzQzE0OC41MDggNTcuMzAyMiAxNDguMzI1IDU3LjM2NjcgMTQ4LjA4OSA1Ny4zNjY3QzE0Ny44NTMgNTcuMzY2NyAxNDcuNjcgNTcuMzAyMiAxNDcuNTQxIDU3LjE3MzNDMTQ3LjQxNiA1Ny4wNDA5IDE0Ny4zNTMgNTYuODc2MSAxNDcuMzUzIDU2LjY3OTJaIiBmaWxsPSIjRkZBNTAwIi8+CjxwYXRoIGQ9Ik0xNTEuMzkyIDU4LjE4ODVMMTUxLjQzIDU4Ljc5NTRDMTUxLjgzOCA1OC4zMTkyIDE1Mi4zOTYgNTguMDgxMSAxNTMuMTA1IDU4LjA4MTFDMTUzLjg4MiA1OC4wODExIDE1NC40MTQgNTguMzc4MyAxNTQuNzAxIDU4Ljk3MjdDMTU1LjEyMyA1OC4zNzgzIDE1NS43MTggNTguMDgxMSAxNTYuNDg0IDU4LjA4MTFDMTU3LjEyNSA1OC4wODExIDE1Ny42MDEgNTguMjU4MyAxNTcuOTEzIDU4LjYxMjhDMTU4LjIyOCA1OC45NjczIDE1OC4zODkgNTkuNDkwMSAxNTguMzk2IDYwLjE4MTJWNjRIMTU3LjA5MVY2MC4yMTg4QzE1Ny4wOTEgNTkuODQ5OSAxNTcuMDEgNTkuNTc5NiAxNTYuODQ5IDU5LjQwNzdDMTU2LjY4OCA1OS4yMzU4IDE1Ni40MjEgNTkuMTQ5OSAxNTYuMDQ5IDU5LjE0OTlDMTU1Ljc1MiA1OS4xNDk5IDE1NS41MDggNTkuMjMwNSAxNTUuMzE4IDU5LjM5MTZDMTU1LjEzMiA1OS41NDkyIDE1NS4wMDEgNTkuNzU2OCAxNTQuOTI2IDYwLjAxNDZMMTU0LjkzMiA2NEgxNTMuNjI2VjYwLjE3NThDMTUzLjYwOSA1OS40OTE5IDE1My4yNTkgNTkuMTQ5OSAxNTIuNTc5IDU5LjE0OTlDMTUyLjA1NiA1OS4xNDk5IDE1MS42ODYgNTkuMzYzIDE1MS40NjcgNTkuNzg5MVY2NEgxNTAuMTYyVjU4LjE4ODVIMTUxLjM5MloiIGZpbGw9IiNGRkE1MDAiLz4KPHBhdGggZD0iTTE2Mi4yOTUgNjQuMTA3NEMxNjEuNDY4IDY0LjEwNzQgMTYwLjc5NyA2My44NDc4IDE2MC4yODEgNjMuMzI4NkMxNTkuNzY5IDYyLjgwNTggMTU5LjUxMyA2Mi4xMTEyIDE1OS41MTMgNjEuMjQ0NlY2MS4wODM1QzE1OS41MTMgNjAuNTAzNCAxNTkuNjI0IDU5Ljk4NiAxNTkuODQ2IDU5LjUzMTJDMTYwLjA3MiA1OS4wNzI5IDE2MC4zODcgNTguNzE2NiAxNjAuNzkyIDU4LjQ2MjRDMTYxLjE5NiA1OC4yMDgyIDE2MS42NDcgNTguMDgxMSAxNjIuMTQ1IDU4LjA4MTFDMTYyLjkzNiA1OC4wODExIDE2My41NDcgNTguMzMzNSAxNjMuOTc3IDU4LjgzODRDMTY0LjQxIDU5LjM0MzMgMTY0LjYyNiA2MC4wNTc2IDE2NC42MjYgNjAuOTgxNFY2MS41MDc4SDE2MC44MjlDMTYwLjg2OCA2MS45ODc2IDE2MS4wMjggNjIuMzY3MiAxNjEuMzA3IDYyLjY0NjVDMTYxLjU5IDYyLjkyNTggMTYxLjk0NCA2My4wNjU0IDE2Mi4zNzEgNjMuMDY1NEMxNjIuOTY5IDYzLjA2NTQgMTYzLjQ1NiA2Mi44MjM3IDE2My44MzIgNjIuMzQwM0wxNjQuNTM1IDYzLjAxMTdDMTY0LjMwMiA2My4zNTkgMTYzLjk5MSA2My42Mjk0IDE2My42MDEgNjMuODIyOEMxNjMuMjE0IDY0LjAxMjUgMTYyLjc3OSA2NC4xMDc0IDE2Mi4yOTUgNjQuMTA3NFpNMTYyLjE0IDU5LjEyODRDMTYxLjc4MiA1OS4xMjg0IDE2MS40OTIgNTkuMjUzNyAxNjEuMjcgNTkuNTA0NEMxNjEuMDUxIDU5Ljc1NSAxNjAuOTExIDYwLjEwNDIgMTYwLjg1MSA2MC41NTE4SDE2My4zMzdWNjAuNDU1MUMxNjMuMzA5IDYwLjAxODIgMTYzLjE5MiA1OS42ODg4IDE2Mi45ODggNTkuNDY2OEMxNjIuNzg0IDU5LjI0MTIgMTYyLjUwMSA1OS4xMjg0IDE2Mi4xNCA1OS4xMjg0WiIgZmlsbD0iI0ZGQTUwMCIvPgo8cGF0aCBkPSJNMTY1LjQgNjEuMDQwNUMxNjUuNCA2MC40NzEyIDE2NS41MTMgNTkuOTU5MSAxNjUuNzM4IDU5LjUwNDRDMTY1Ljk2NCA1OS4wNDYxIDE2Ni4yODEgNTguNjk1MSAxNjYuNjg5IDU4LjQ1MTdDMTY3LjA5NyA1OC4yMDQ2IDE2Ny41NjYgNTguMDgxMSAxNjguMDk2IDU4LjA4MTFDMTY4Ljg4IDU4LjA4MTEgMTY5LjUxNiA1OC4zMzM1IDE3MC4wMDMgNTguODM4NEMxNzAuNDkzIDU5LjM0MzMgMTcwLjc1OCA2MC4wMTI5IDE3MC43OTggNjAuODQ3MkwxNzAuODAzIDYxLjE1MzNDMTcwLjgwMyA2MS43MjYyIDE3MC42OTIgNjIuMjM4MyAxNzAuNDcgNjIuNjg5NUMxNzAuMjUyIDYzLjE0MDYgMTY5LjkzNyA2My40ODk3IDE2OS41MjUgNjMuNzM2OEMxNjkuMTE3IDYzLjk4MzkgMTY4LjY0NCA2NC4xMDc0IDE2OC4xMDcgNjQuMTA3NEMxNjcuMjg3IDY0LjEwNzQgMTY2LjYzIDYzLjgzNTMgMTY2LjEzNiA2My4yOTFDMTY1LjY0NSA2Mi43NDMyIDE2NS40IDYyLjAxNDUgMTY1LjQgNjEuMTA1VjYxLjA0MDVaTTE2Ni43MDUgNjEuMTUzM0MxNjYuNzA1IDYxLjc1MTMgMTY2LjgyOSA2Mi4yMjA0IDE2Ny4wNzYgNjIuNTYwNUMxNjcuMzIzIDYyLjg5NzEgMTY3LjY2NyA2My4wNjU0IDE2OC4xMDcgNjMuMDY1NEMxNjguNTQ3IDYzLjA2NTQgMTY4Ljg4OSA2Mi44OTM2IDE2OS4xMzMgNjIuNTQ5OEMxNjkuMzggNjIuMjA2MSAxNjkuNTAzIDYxLjcwMyAxNjkuNTAzIDYxLjA0MDVDMTY5LjUwMyA2MC40NTMzIDE2OS4zNzYgNTkuOTg3OCAxNjkuMTIyIDU5LjY0NEMxNjguODcxIDU5LjMwMDMgMTY4LjUyOSA1OS4xMjg0IDE2OC4wOTYgNTkuMTI4NEMxNjcuNjcgNTkuMTI4NCAxNjcuMzMyIDU5LjI5ODUgMTY3LjA4MSA1OS42Mzg3QzE2Ni44MyA1OS45NzUzIDE2Ni43MDUgNjAuNDgwMSAxNjYuNzA1IDYxLjE1MzNaIiBmaWxsPSIjRkZBNTAwIi8+CjxwYXRoIGQ9Ik0xNzUuNDI4IDYzLjQzMDdDMTc1LjA0NSA2My44ODE4IDE3NC41IDY0LjEwNzQgMTczLjc5NSA2NC4xMDc0QzE3My4xNjUgNjQuMTA3NCAxNzIuNjg3IDYzLjkyMyAxNzIuMzYxIDYzLjU1NDJDMTcyLjAzOSA2My4xODU0IDE3MS44NzcgNjIuNjUxOSAxNzEuODc3IDYxLjk1MzZWNTguMTg4NUgxNzMuMTgzVjYxLjkzNzVDMTczLjE4MyA2Mi42NzUxIDE3My40ODkgNjMuMDQzOSAxNzQuMTAxIDYzLjA0MzlDMTc0LjczNSA2My4wNDM5IDE3NS4xNjMgNjIuODE2NiAxNzUuMzg1IDYyLjM2MThWNTguMTg4NUgxNzYuNjlWNjRIMTc1LjQ2TDE3NS40MjggNjMuNDMwN1oiIGZpbGw9IiNGRkE1MDAiLz4KPHBhdGggZD0iTTE3OS42NTUgNTYuNzc1OVY1OC4xODg1SDE4MC42ODFWNTkuMTU1M0gxNzkuNjU1VjYyLjM5OTRDMTc5LjY1NSA2Mi42MjE0IDE3OS42OTggNjIuNzgyNiAxNzkuNzg0IDYyLjg4MjhDMTc5Ljg3MyA2Mi45Nzk1IDE4MC4wMzEgNjMuMDI3OCAxODAuMjU2IDYzLjAyNzhDMTgwLjQwNyA2My4wMjc4IDE4MC41NTkgNjMuMDA5OSAxODAuNzEzIDYyLjk3NDFWNjMuOTgzOUMxODAuNDE2IDY0LjA2NjIgMTgwLjEyOSA2NC4xMDc0IDE3OS44NTQgNjQuMTA3NEMxNzguODUxIDY0LjEwNzQgMTc4LjM1IDYzLjU1NDIgMTc4LjM1IDYyLjQ0NzhWNTkuMTU1M0gxNzcuMzk0VjU4LjE4ODVIMTc4LjM1VjU2Ljc3NTlIMTc5LjY1NVoiIGZpbGw9IiNGRkE1MDAiLz4KPHBhdGggZD0iTTE0NS4zMDEgMTAwLjY4NkgxNDIuMTU0VjEwNEgxNDAuNzk1Vjk2LjE3OTdIMTQ1Ljc2M1Y5Ny4yNzU0SDE0Mi4xNTRWOTkuNjAxMUgxNDUuMzAxVjEwMC42ODZaIiBmaWxsPSIjRkYzRTNFIi8+CjxwYXRoIGQ9Ik0xNTAuMDA2IDEwNEMxNDkuOTQ5IDEwMy44ODkgMTQ5Ljg5OSAxMDMuNzA4IDE0OS44NTYgMTAzLjQ1OEMxNDkuNDQxIDEwMy44OTEgMTQ4LjkzMiAxMDQuMTA3IDE0OC4zMzEgMTA0LjEwN0MxNDcuNzQ3IDEwNC4xMDcgMTQ3LjI3MSAxMDMuOTQxIDE0Ni45MDIgMTAzLjYwOEMxNDYuNTMzIDEwMy4yNzUgMTQ2LjM0OSAxMDIuODYzIDE0Ni4zNDkgMTAyLjM3M0MxNDYuMzQ5IDEwMS43NTMgMTQ2LjU3OCAxMDEuMjc5IDE0Ny4wMzYgMTAwLjk0OUMxNDcuNDk4IDEwMC42MTYgMTQ4LjE1NyAxMDAuNDUgMTQ5LjAxMyAxMDAuNDVIMTQ5LjgxM1YxMDAuMDY4QzE0OS44MTMgOTkuNzY3NiAxNDkuNzI5IDk5LjUyNzcgMTQ5LjU2MSA5OS4zNDg2QzE0OS4zOTIgOTkuMTY2IDE0OS4xMzYgOTkuMDc0NyAxNDguNzkyIDk5LjA3NDdDMTQ4LjQ5NSA5OS4wNzQ3IDE0OC4yNTIgOTkuMTQ5OSAxNDguMDYyIDk5LjMwMDNDMTQ3Ljg3MiA5OS40NDcxIDE0Ny43NzcgOTkuNjM1MSAxNDcuNzc3IDk5Ljg2NDNIMTQ2LjQ3MkMxNDYuNDcyIDk5LjU0NTYgMTQ2LjU3OCA5OS4yNDg0IDE0Ni43ODkgOTguOTcyN0MxNDcgOTguNjkzNCAxNDcuMjg3IDk4LjQ3NDkgMTQ3LjY0OCA5OC4zMTc0QzE0OC4wMTQgOTguMTU5OCAxNDguNDIgOTguMDgxMSAxNDguODY4IDk4LjA4MTFDMTQ5LjU0OCA5OC4wODExIDE1MC4wOSA5OC4yNTI5IDE1MC40OTUgOTguNTk2N0MxNTAuOSA5OC45MzY4IDE1MS4xMDcgOTkuNDE2NyAxNTEuMTE4IDEwMC4wMzZWMTAyLjY1N0MxNTEuMTE4IDEwMy4xOCAxNTEuMTkyIDEwMy41OTcgMTUxLjMzOCAxMDMuOTA5VjEwNEgxNTAuMDA2Wk0xNDguNTcyIDEwMy4wNkMxNDguODMgMTAzLjA2IDE0OS4wNzIgMTAyLjk5NyAxNDkuMjk3IDEwMi44NzJDMTQ5LjUyNyAxMDIuNzQ3IDE0OS42OTggMTAyLjU3OCAxNDkuODEzIDEwMi4zNjdWMTAxLjI3MUgxNDkuMTA5QzE0OC42MjYgMTAxLjI3MSAxNDguMjYzIDEwMS4zNTYgMTQ4LjAxOSAxMDEuNTI0QzE0Ny43NzYgMTAxLjY5MiAxNDcuNjU0IDEwMS45MyAxNDcuNjU0IDEwMi4yMzhDMTQ3LjY1NCAxMDIuNDg5IDE0Ny43MzYgMTAyLjY4OSAxNDcuOTAxIDEwMi44NEMxNDguMDY5IDEwMi45ODcgMTQ4LjI5MyAxMDMuMDYgMTQ4LjU3MiAxMDMuMDZaIiBmaWxsPSIjRkYzRTNFIi8+CjxwYXRoIGQ9Ik0xNTMuODc0IDEwNEgxNTIuNTY4Vjk4LjE4ODVIMTUzLjg3NFYxMDRaTTE1Mi40ODggOTYuNjc5MkMxNTIuNDg4IDk2LjQ3ODcgMTUyLjU1IDk2LjMxMjIgMTUyLjY3NiA5Ni4xNzk3QzE1Mi44MDUgOTYuMDQ3MiAxNTIuOTg3IDk1Ljk4MSAxNTMuMjI0IDk1Ljk4MUMxNTMuNDYgOTUuOTgxIDE1My42NDMgOTYuMDQ3MiAxNTMuNzcxIDk2LjE3OTdDMTUzLjkgOTYuMzEyMiAxNTMuOTY1IDk2LjQ3ODcgMTUzLjk2NSA5Ni42NzkyQzE1My45NjUgOTYuODc2MSAxNTMuOSA5Ny4wNDA5IDE1My43NzEgOTcuMTczM0MxNTMuNjQzIDk3LjMwMjIgMTUzLjQ2IDk3LjM2NjcgMTUzLjIyNCA5Ny4zNjY3QzE1Mi45ODcgOTcuMzY2NyAxNTIuODA1IDk3LjMwMjIgMTUyLjY3NiA5Ny4xNzMzQzE1Mi41NSA5Ny4wNDA5IDE1Mi40ODggOTYuODc2MSAxNTIuNDg4IDk2LjY3OTJaIiBmaWxsPSIjRkYzRTNFIi8+CjxwYXRoIGQ9Ik0xNTYuNjg4IDEwNEgxNTUuMzgzVjk1Ljc1SDE1Ni42ODhWMTA0WiIgZmlsbD0iI0ZGM0UzRSIvPgo8cGF0aCBkPSJNMTYwLjY3MyAxMDQuMTA3QzE1OS44NDYgMTA0LjEwNyAxNTkuMTc1IDEwMy44NDggMTU4LjY1OSAxMDMuMzI5QzE1OC4xNDcgMTAyLjgwNiAxNTcuODkxIDEwMi4xMTEgMTU3Ljg5MSAxMDEuMjQ1VjEwMS4wODNDMTU3Ljg5MSAxMDAuNTAzIDE1OC4wMDIgOTkuOTg2IDE1OC4yMjQgOTkuNTMxMkMxNTguNDUgOTkuMDcyOSAxNTguNzY1IDk4LjcxNjYgMTU5LjE2OSA5OC40NjI0QzE1OS41NzQgOTguMjA4MiAxNjAuMDI1IDk4LjA4MTEgMTYwLjUyMyA5OC4wODExQzE2MS4zMTQgOTguMDgxMSAxNjEuOTI1IDk4LjMzMzUgMTYyLjM1NCA5OC44Mzg0QzE2Mi43ODggOTkuMzQzMyAxNjMuMDA0IDEwMC4wNTggMTYzLjAwNCAxMDAuOTgxVjEwMS41MDhIMTU5LjIwN0MxNTkuMjQ2IDEwMS45ODggMTU5LjQwNiAxMDIuMzY3IDE1OS42ODUgMTAyLjY0NkMxNTkuOTY4IDEwMi45MjYgMTYwLjMyMiAxMDMuMDY1IDE2MC43NDkgMTAzLjA2NUMxNjEuMzQ3IDEwMy4wNjUgMTYxLjgzMyAxMDIuODI0IDE2Mi4yMDkgMTAyLjM0TDE2Mi45MTMgMTAzLjAxMkMxNjIuNjggMTAzLjM1OSAxNjIuMzY5IDEwMy42MjkgMTYxLjk3OSAxMDMuODIzQzE2MS41OTIgMTA0LjAxMyAxNjEuMTU3IDEwNC4xMDcgMTYwLjY3MyAxMDQuMTA3Wk0xNjAuNTE4IDk5LjEyODRDMTYwLjE2IDk5LjEyODQgMTU5Ljg2OSA5OS4yNTM3IDE1OS42NDcgOTkuNTA0NEMxNTkuNDI5IDk5Ljc1NSAxNTkuMjg5IDEwMC4xMDQgMTU5LjIyOSAxMDAuNTUySDE2MS43MTVWMTAwLjQ1NUMxNjEuNjg3IDEwMC4wMTggMTYxLjU3IDk5LjY4ODggMTYxLjM2NiA5OS40NjY4QzE2MS4xNjIgOTkuMjQxMiAxNjAuODc5IDk5LjEyODQgMTYwLjUxOCA5OS4xMjg0WiIgZmlsbD0iI0ZGM0UzRSIvPgo8cGF0aCBkPSJNMTYzLjc3OCAxMDEuMDUxQzE2My43NzggMTAwLjE1NiAxNjMuOTg2IDk5LjQzODIgMTY0LjQwMSA5OC44OTc1QzE2NC44MTYgOTguMzUzMiAxNjUuMzczIDk4LjA4MTEgMTY2LjA3MSA5OC4wODExQzE2Ni42ODcgOTguMDgxMSAxNjcuMTg1IDk4LjI5NTkgMTY3LjU2NCA5OC43MjU2Vjk1Ljc1SDE2OC44N1YxMDRIMTY3LjY4OEwxNjcuNjI0IDEwMy4zOThDMTY3LjIzMyAxMDMuODcxIDE2Ni43MTIgMTA0LjEwNyAxNjYuMDYxIDEwNC4xMDdDMTY1LjM4IDEwNC4xMDcgMTY0LjgyOSAxMDMuODMzIDE2NC40MDYgMTAzLjI4NkMxNjMuOTg3IDEwMi43MzggMTYzLjc3OCAxMDEuOTkzIDE2My43NzggMTAxLjA1MVpNMTY1LjA4MyAxMDEuMTY0QzE2NS4wODMgMTAxLjc1NSAxNjUuMTk2IDEwMi4yMTcgMTY1LjQyMSAxMDIuNTVDMTY1LjY1MSAxMDIuODc5IDE2NS45NzUgMTAzLjA0NCAxNjYuMzk0IDEwMy4wNDRDMTY2LjkyNyAxMDMuMDQ0IDE2Ny4zMTcgMTAyLjgwNiAxNjcuNTY0IDEwMi4zM1Y5OS44NDgxQzE2Ny4zMjUgOTkuMzgyNiAxNjYuOTM4IDk5LjE0OTkgMTY2LjQwNCA5OS4xNDk5QzE2NS45ODIgOTkuMTQ5OSAxNjUuNjU2IDk5LjMxODIgMTY1LjQyNyA5OS42NTQ4QzE2NS4xOTggOTkuOTg3OCAxNjUuMDgzIDEwMC40OTEgMTY1LjA4MyAxMDEuMTY0WiIgZmlsbD0iI0ZGM0UzRSIvPgo8cGF0aCBkPSJNMTQwLjc5NSAxNDRWMTM2LjE4SDE0My4xMDRDMTQzLjc5NiAxMzYuMTggMTQ0LjQwOCAxMzYuMzM0IDE0NC45NDEgMTM2LjY0MkMxNDUuNDc5IDEzNi45NSAxNDUuODk0IDEzNy4zODYgMTQ2LjE4OCAxMzcuOTUyQzE0Ni40ODEgMTM4LjUxOCAxNDYuNjI4IDEzOS4xNjYgMTQ2LjYyOCAxMzkuODk2VjE0MC4yODlDMTQ2LjYyOCAxNDEuMDMgMTQ2LjQ3OSAxNDEuNjgxIDE0Ni4xODIgMTQyLjI0NEMxNDUuODg5IDE0Mi44MDYgMTQ1LjQ2OCAxNDMuMjM5IDE0NC45MiAxNDMuNTQzQzE0NC4zNzYgMTQzLjg0OCAxNDMuNzUxIDE0NCAxNDMuMDQ1IDE0NEgxNDAuNzk1Wk0xNDIuMTU0IDEzNy4yNzVWMTQyLjkxNUgxNDMuMDRDMTQzLjc1MyAxNDIuOTE1IDE0NC4yOTkgMTQyLjY5MyAxNDQuNjc4IDE0Mi4yNDlDMTQ1LjA2MSAxNDEuODAxIDE0NS4yNTcgMTQxLjE2IDE0NS4yNjQgMTQwLjMyNlYxMzkuODkxQzE0NS4yNjQgMTM5LjA0MiAxNDUuMDc5IDEzOC4zOTQgMTQ0LjcxIDEzNy45NDdDMTQ0LjM0MiAxMzcuNDk5IDE0My44MDYgMTM3LjI3NSAxNDMuMTA0IDEzNy4yNzVIMTQyLjE1NFoiIGZpbGw9IiM0Q0FGNTAiLz4KPHBhdGggZD0iTTE1MC40MTUgMTQ0LjEwN0MxNDkuNTg3IDE0NC4xMDcgMTQ4LjkxNiAxNDMuODQ4IDE0OC40IDE0My4zMjlDMTQ3Ljg4OCAxNDIuODA2IDE0Ny42MzIgMTQyLjExMSAxNDcuNjMyIDE0MS4yNDVWMTQxLjA4M0MxNDcuNjMyIDE0MC41MDMgMTQ3Ljc0MyAxMzkuOTg2IDE0Ny45NjUgMTM5LjUzMUMxNDguMTkxIDEzOS4wNzMgMTQ4LjUwNiAxMzguNzE3IDE0OC45MTEgMTM4LjQ2MkMxNDkuMzE1IDEzOC4yMDggMTQ5Ljc2NiAxMzguMDgxIDE1MC4yNjQgMTM4LjA4MUMxNTEuMDU2IDEzOC4wODEgMTUxLjY2NiAxMzguMzMzIDE1Mi4wOTYgMTM4LjgzOEMxNTIuNTI5IDEzOS4zNDMgMTUyLjc0NiAxNDAuMDU4IDE1Mi43NDYgMTQwLjk4MVYxNDEuNTA4SDE0OC45NDhDMTQ4Ljk4OCAxNDEuOTg4IDE0OS4xNDcgMTQyLjM2NyAxNDkuNDI2IDE0Mi42NDZDMTQ5LjcwOSAxNDIuOTI2IDE1MC4wNjQgMTQzLjA2NSAxNTAuNDkgMTQzLjA2NUMxNTEuMDg4IDE0My4wNjUgMTUxLjU3NSAxNDIuODI0IDE1MS45NTEgMTQyLjM0TDE1Mi42NTQgMTQzLjAxMkMxNTIuNDIyIDE0My4zNTkgMTUyLjExIDE0My42MjkgMTUxLjcyIDE0My44MjNDMTUxLjMzMyAxNDQuMDEzIDE1MC44OTggMTQ0LjEwNyAxNTAuNDE1IDE0NC4xMDdaTTE1MC4yNTkgMTM5LjEyOEMxNDkuOTAxIDEzOS4xMjggMTQ5LjYxMSAxMzkuMjU0IDE0OS4zODkgMTM5LjUwNEMxNDkuMTcgMTM5Ljc1NSAxNDkuMDMxIDE0MC4xMDQgMTQ4Ljk3IDE0MC41NTJIMTUxLjQ1N1YxNDAuNDU1QzE1MS40MjggMTQwLjAxOCAxNTEuMzEyIDEzOS42ODkgMTUxLjEwNyAxMzkuNDY3QzE1MC45MDMgMTM5LjI0MSAxNTAuNjIgMTM5LjEyOCAxNTAuMjU5IDEzOS4xMjhaIiBmaWxsPSIjNENBRjUwIi8+CjxwYXRoIGQ9Ik0xNTUuMTUyIDE0NEgxNTMuODQ3VjEzNS43NUgxNTUuMTUyVjE0NFoiIGZpbGw9IiM0Q0FGNTAiLz4KPHBhdGggZD0iTTE1Ny45NjYgMTQ0SDE1Ni42NjFWMTM4LjE4OEgxNTcuOTY2VjE0NFpNMTU2LjU4MSAxMzYuNjc5QzE1Ni41ODEgMTM2LjQ3OSAxNTYuNjQzIDEzNi4zMTIgMTU2Ljc2OSAxMzYuMThDMTU2Ljg5NyAxMzYuMDQ3IDE1Ny4wOCAxMzUuOTgxIDE1Ny4zMTYgMTM1Ljk4MUMxNTcuNTUzIDEzNS45ODEgMTU3LjczNSAxMzYuMDQ3IDE1Ny44NjQgMTM2LjE4QzE1Ny45OTMgMTM2LjMxMiAxNTguMDU4IDEzNi40NzkgMTU4LjA1OCAxMzYuNjc5QzE1OC4wNTggMTM2Ljg3NiAxNTcuOTkzIDEzNy4wNDEgMTU3Ljg2NCAxMzcuMTczQzE1Ny43MzUgMTM3LjMwMiAxNTcuNTUzIDEzNy4zNjcgMTU3LjMxNiAxMzcuMzY3QzE1Ny4wOCAxMzcuMzY3IDE1Ni44OTcgMTM3LjMwMiAxNTYuNzY5IDEzNy4xNzNDMTU2LjY0MyAxMzcuMDQxIDE1Ni41ODEgMTM2Ljg3NiAxNTYuNTgxIDEzNi42NzlaIiBmaWxsPSIjNENBRjUwIi8+CjxwYXRoIGQ9Ik0xNjEuNDQxIDE0Mi4zNDZMMTYyLjY3MSAxMzguMTg4SDE2NC4wMkwxNjIuMDA1IDE0NEgxNjAuODcyTDE1OC44NDIgMTM4LjE4OEgxNjAuMTk1TDE2MS40NDEgMTQyLjM0NloiIGZpbGw9IiM0Q0FGNTAiLz4KPHBhdGggZD0iTTE2Ny4zMjMgMTQ0LjEwN0MxNjYuNDk2IDE0NC4xMDcgMTY1LjgyNCAxNDMuODQ4IDE2NS4zMDkgMTQzLjMyOUMxNjQuNzk3IDE0Mi44MDYgMTY0LjU0MSAxNDIuMTExIDE2NC41NDEgMTQxLjI0NVYxNDEuMDgzQzE2NC41NDEgMTQwLjUwMyAxNjQuNjUyIDEzOS45ODYgMTY0Ljg3NCAxMzkuNTMxQzE2NS4wOTkgMTM5LjA3MyAxNjUuNDE0IDEzOC43MTcgMTY1LjgxOSAxMzguNDYyQzE2Ni4yMjMgMTM4LjIwOCAxNjYuNjc1IDEzOC4wODEgMTY3LjE3MiAxMzguMDgxQzE2Ny45NjQgMTM4LjA4MSAxNjguNTc0IDEzOC4zMzMgMTY5LjAwNCAxMzguODM4QzE2OS40MzcgMTM5LjM0MyAxNjkuNjU0IDE0MC4wNTggMTY5LjY1NCAxNDAuOTgxVjE0MS41MDhIMTY1Ljg1NkMxNjUuODk2IDE0MS45ODggMTY2LjA1NSAxNDIuMzY3IDE2Ni4zMzQgMTQyLjY0NkMxNjYuNjE3IDE0Mi45MjYgMTY2Ljk3MiAxNDMuMDY1IDE2Ny4zOTggMTQzLjA2NUMxNjcuOTk2IDE0My4wNjUgMTY4LjQ4MyAxNDIuODI0IDE2OC44NTkgMTQyLjM0TDE2OS41NjIgMTQzLjAxMkMxNjkuMzMgMTQzLjM1OSAxNjkuMDE4IDE0My42MjkgMTY4LjYyOCAxNDMuODIzQzE2OC4yNDEgMTQ0LjAxMyAxNjcuODA2IDE0NC4xMDcgMTY3LjMyMyAxNDQuMTA3Wk0xNjcuMTY3IDEzOS4xMjhDMTY2LjgwOSAxMzkuMTI4IDE2Ni41MTkgMTM5LjI1NCAxNjYuMjk3IDEzOS41MDRDMTY2LjA3OCAxMzkuNzU1IDE2NS45MzkgMTQwLjEwNCAxNjUuODc4IDE0MC41NTJIMTY4LjM2NVYxNDAuNDU1QzE2OC4zMzYgMTQwLjAxOCAxNjguMjIgMTM5LjY4OSAxNjguMDE2IDEzOS40NjdDMTY3LjgxMiAxMzkuMjQxIDE2Ny41MjkgMTM5LjEyOCAxNjcuMTY3IDEzOS4xMjhaIiBmaWxsPSIjNENBRjUwIi8+CjxwYXRoIGQ9Ik0xNzMuNzE0IDEzOS4zODFDMTczLjU0MiAxMzkuMzUyIDE3My4zNjUgMTM5LjMzOCAxNzMuMTgzIDEzOS4zMzhDMTcyLjU4NSAxMzkuMzM4IDE3Mi4xODIgMTM5LjU2NyAxNzEuOTc0IDE0MC4wMjVWMTQ0SDE3MC42NjlWMTM4LjE4OEgxNzEuOTE1TDE3MS45NDcgMTM4LjgzOEMxNzIuMjYyIDEzOC4zMzMgMTcyLjY5OSAxMzguMDgxIDE3My4yNTggMTM4LjA4MUMxNzMuNDQ0IDEzOC4wODEgMTczLjU5OCAxMzguMTA2IDE3My43MiAxMzguMTU2TDE3My43MTQgMTM5LjM4MVoiIGZpbGw9IiM0Q0FGNTAiLz4KPHBhdGggZD0iTTE3Ni45OTEgMTQ0LjEwN0MxNzYuMTY0IDE0NC4xMDcgMTc1LjQ5MiAxNDMuODQ4IDE3NC45NzcgMTQzLjMyOUMxNzQuNDY1IDE0Mi44MDYgMTc0LjIwOCAxNDIuMTExIDE3NC4yMDggMTQxLjI0NVYxNDEuMDgzQzE3NC4yMDggMTQwLjUwMyAxNzQuMzE5IDEzOS45ODYgMTc0LjU0MiAxMzkuNTMxQzE3NC43NjcgMTM5LjA3MyAxNzUuMDgyIDEzOC43MTcgMTc1LjQ4NyAxMzguNDYyQzE3NS44OTEgMTM4LjIwOCAxNzYuMzQzIDEzOC4wODEgMTc2Ljg0IDEzOC4wODFDMTc3LjYzMiAxMzguMDgxIDE3OC4yNDIgMTM4LjMzMyAxNzguNjcyIDEzOC44MzhDMTc5LjEwNSAxMzkuMzQzIDE3OS4zMjIgMTQwLjA1OCAxNzkuMzIyIDE0MC45ODFWMTQxLjUwOEgxNzUuNTI0QzE3NS41NjQgMTQxLjk4OCAxNzUuNzIzIDE0Mi4zNjcgMTc2LjAwMiAxNDIuNjQ2QzE3Ni4yODUgMTQyLjkyNiAxNzYuNjQgMTQzLjA2NSAxNzcuMDY2IDE0My4wNjVDMTc3LjY2NCAxNDMuMDY1IDE3OC4xNTEgMTQyLjgyNCAxNzguNTI3IDE0Mi4zNEwxNzkuMjMgMTQzLjAxMkMxNzguOTk4IDE0My4zNTkgMTc4LjY4NiAxNDMuNjI5IDE3OC4yOTYgMTQzLjgyM0MxNzcuOTA5IDE0NC4wMTMgMTc3LjQ3NCAxNDQuMTA3IDE3Ni45OTEgMTQ0LjEwN1pNMTc2LjgzNSAxMzkuMTI4QzE3Ni40NzcgMTM5LjEyOCAxNzYuMTg3IDEzOS4yNTQgMTc1Ljk2NSAxMzkuNTA0QzE3NS43NDYgMTM5Ljc1NSAxNzUuNjA3IDE0MC4xMDQgMTc1LjU0NiAxNDAuNTUySDE3OC4wMzNWMTQwLjQ1NUMxNzguMDA0IDE0MC4wMTggMTc3Ljg4OCAxMzkuNjg5IDE3Ny42ODQgMTM5LjQ2N0MxNzcuNDc5IDEzOS4yNDEgMTc3LjE5NyAxMzkuMTI4IDE3Ni44MzUgMTM5LjEyOFoiIGZpbGw9IiM0Q0FGNTAiLz4KPHBhdGggZD0iTTE4MC4wOTUgMTQxLjA1MUMxODAuMDk1IDE0MC4xNTYgMTgwLjMwMyAxMzkuNDM4IDE4MC43MTggMTM4Ljg5N0MxODEuMTM0IDEzOC4zNTMgMTgxLjY5IDEzOC4wODEgMTgyLjM4OSAxMzguMDgxQzE4My4wMDUgMTM4LjA4MSAxODMuNTAyIDEzOC4yOTYgMTgzLjg4MiAxMzguNzI2VjEzNS43NUgxODUuMTg3VjE0NEgxODQuMDA1TDE4My45NDEgMTQzLjM5OEMxODMuNTUxIDE0My44NzEgMTgzLjAzIDE0NC4xMDcgMTgyLjM3OCAxNDQuMTA3QzE4MS42OTggMTQ0LjEwNyAxODEuMTQ2IDE0My44MzMgMTgwLjcyNCAxNDMuMjg2QzE4MC4zMDUgMTQyLjczOCAxODAuMDk1IDE0MS45OTMgMTgwLjA5NSAxNDEuMDUxWk0xODEuNCAxNDEuMTY0QzE4MS40IDE0MS43NTUgMTgxLjUxMyAxNDIuMjE3IDE4MS43MzkgMTQyLjU1QzE4MS45NjggMTQyLjg3OSAxODIuMjkyIDE0My4wNDQgMTgyLjcxMSAxNDMuMDQ0QzE4My4yNDQgMTQzLjA0NCAxODMuNjM1IDE0Mi44MDYgMTgzLjg4MiAxNDIuMzNWMTM5Ljg0OEMxODMuNjQyIDEzOS4zODMgMTgzLjI1NSAxMzkuMTUgMTgyLjcyMiAxMzkuMTVDMTgyLjI5OSAxMzkuMTUgMTgxLjk3MyAxMzkuMzE4IDE4MS43NDQgMTM5LjY1NUMxODEuNTE1IDEzOS45ODggMTgxLjQgMTQwLjQ5MSAxODEuNCAxNDEuMTY0WiIgZmlsbD0iIzRDQUY1MCIvPgo8cGF0aCBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGNsaXAtcnVsZT0iZXZlbm9kZCIgZD0iTTE5NiAxSDRDMi4zNDMxNCAxIDEgMi4zNDMxNCAxIDRWMTU2QzEgMTU3LjY1NyAyLjM0MzE0IDE1OSA0IDE1OUgxOTZDMTk3LjY1NyAxNTkgMTk5IDE1Ny42NTcgMTk5IDE1NlY0QzE5OSAyLjM0MzE1IDE5Ny42NTcgMSAxOTYgMVpNNCAwSDE5NkMxOTguMjA5IDAgMjAwIDEuNzkwODYgMjAwIDRWMTU2QzIwMCAxNTguMjA5IDE5OC4yMDkgMTYwIDE5NiAxNjBINEMxLjc5MDg2IDE2MCAwIDE1OC4yMDkgMCAxNTZWNEMwIDEuNzkwODYgMS43OTA4NiAwIDQgMFoiIGZpbGw9IiNFMEUwRTAiLz4KPC9zdmc+Cg==", + "description": "Displays Persistent RPC requests that match selected alias and filter with the ability of pagination and sending persistent RPC requests.", + "descriptor": { + "type": "rpc", + "sizeX": 7.5, + "sizeY": 4, + "resources": [], + "templateHtml": "", + "templateCss": "", + "controllerScript": "self.onInit = function() {\n}\n\nself.onResize = function() {\n}\n\nself.onDestroy = function() {\n}\n", + "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"PersistentTableSettings\",\n \"properties\": {\n \"enableStickyHeader\": {\n \"title\": \"Always display header\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"enableFilter\": {\n \"title\": \"Enable filter\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"allowSendRequest\": {\n \"title\": \"Allow send RPC request\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"enableStickyAction\": {\n \"title\": \"Always display actions column\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"displayDetails\": {\n \"title\": \"Display request details\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"allowDelete\": {\n \"title\": \"Allow delete request\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"displayPagination\": {\n \"title\": \"Display pagination\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"defaultPageSize\": {\n \"title\": \"Default page size\",\n \"type\": \"number\",\n \"default\": 10\n },\n \"defaultSortOrder\": {\n \"title\": \"Default sort order\",\n \"type\": \"string\",\n \"default\": \"-createdTime\"\n },\n \"displayColumns\": {\n \"title\": \"Columns for display\",\n \"type\": \"array\",\n \"minItems\": 1\n }\n },\n \"required\": [\"displayColumns\"]\n },\n \"uiSchema\": {\n \"type\": \"VerticalLayout\",\n \"elements\": [\n {\n \"type\": \"Control\",\n \"scope\": \"#/schema/properties/enableStickyHeader\"\n },\n {\n \"type\": \"Control\",\n \"scope\": \"#/schema/properties/enableFilter\"\n }\n ]\n },\n \"form\": [\n [\n \"enableStickyHeader\",\n \"enableFilter\",\n \"allowSendRequest\",\n \"enableStickyAction\",\n \"displayDetails\",\n \"allowDelete\",\n \"displayPagination\",\n \"defaultPageSize\",\n \"defaultSortOrder\"\n ],\n [\n {\n \"key\": \"displayColumns\",\n \"type\": \"rc-select\",\n \"multiple\": true,\n \"default\": [\"rpcId\", \"messageType\", \"status\", \"method\", \"createdTime\", \"expirationTime\"],\n \"items\": [\n {\n \"value\": \"rpcId\",\n \"label\": \"RPC ID\"\n },\n {\n \"value\": \"messageType\",\n \"label\": \"Message type\"\n },\n {\n \"value\": \"status\",\n \"label\": \"Status\"\n },\n {\n \"value\": \"method\",\n \"label\": \"Method\"\n },\n {\n \"value\": \"createdTime\",\n \"label\": \"Created time\"\n },\n {\n \"value\": \"expirationTime\",\n \"label\": \"Expiration time\"\n }\n ]\n }\n ]\n ],\n \"groupInfoes\": [{\n \"formIndex\": 0,\n \"GroupTitle\": \"General settings\"\n }, {\n \"formIndex\": 1,\n \"GroupTitle\": \"Columns settings\"\n }]\n}", + "dataKeySettingsSchema": "{}\n", + "defaultConfig": "{\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"enableStickyAction\":true,\"enableFilter\":true,\"displayPagination\":true,\"defaultPageSize\":10,\"enableStickyHeader\":true,\"displayColumns\":[\"rpcId\",\"messageType\",\"status\",\"method\",\"createdTime\",\"expirationTime\"],\"displayDetails\":true,\"defaultSortOrder\":\"-createdTime\",\"allowSendRequest\":true,\"allowDelete\":true},\"title\":\"Persistent table\",\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400,\"padding\":\"5px 10px\"},\"targetDeviceAliasIds\":[]}" + } } ] } \ No newline at end of file diff --git a/application/src/main/java/org/thingsboard/server/controller/RpcV2Controller.java b/application/src/main/java/org/thingsboard/server/controller/RpcV2Controller.java index 389a767cdf..844795593c 100644 --- a/application/src/main/java/org/thingsboard/server/controller/RpcV2Controller.java +++ b/application/src/main/java/org/thingsboard/server/controller/RpcV2Controller.java @@ -177,8 +177,8 @@ public class RpcV2Controller extends AbstractRpcController { @RequestParam int pageSize, @ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true) @RequestParam int page, - @ApiParam(value = "Status of the RPC", required = true, allowableValues = RPC_STATUS_ALLOWABLE_VALUES) - @RequestParam RpcStatus rpcStatus, + @ApiParam(value = "Status of the RPC", allowableValues = RPC_STATUS_ALLOWABLE_VALUES) + @RequestParam(required = false) RpcStatus rpcStatus, @ApiParam(value = RPC_TEXT_SEARCH_DESCRIPTION) @RequestParam(required = false) String textSearch, @ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = RPC_SORT_PROPERTY_ALLOWABLE_VALUES) @@ -194,7 +194,12 @@ public class RpcV2Controller extends AbstractRpcController { accessValidator.validate(getCurrentUser(), Operation.RPC_CALL, deviceId, new HttpValidationCallback(response, new FutureCallback<>() { @Override public void onSuccess(@Nullable DeferredResult result) { - PageData rpcCalls = rpcService.findAllByDeviceIdAndStatus(tenantId, deviceId, rpcStatus, pageLink); + PageData rpcCalls; + if (rpcStatus != null) { + rpcCalls = rpcService.findAllByDeviceIdAndStatus(tenantId, deviceId, rpcStatus, pageLink); + } else { + rpcCalls = rpcService.findAllByDeviceId(tenantId, deviceId, pageLink); + } response.setResult(new ResponseEntity<>(rpcCalls, HttpStatus.OK)); } diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/rpc/RpcService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/rpc/RpcService.java index 4bdb1a169d..46b82077a3 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/rpc/RpcService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/rpc/RpcService.java @@ -35,5 +35,7 @@ public interface RpcService { ListenableFuture findRpcByIdAsync(TenantId tenantId, RpcId id); + PageData findAllByDeviceId(TenantId tenantId, DeviceId deviceId, PageLink pageLink); + PageData findAllByDeviceIdAndStatus(TenantId tenantId, DeviceId deviceId, RpcStatus rpcStatus, PageLink pageLink); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/rpc/BaseRpcService.java b/dao/src/main/java/org/thingsboard/server/dao/rpc/BaseRpcService.java index 02b4bbe433..a5538f56d7 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/rpc/BaseRpcService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/rpc/BaseRpcService.java @@ -82,7 +82,15 @@ public class BaseRpcService implements RpcService { log.trace("Executing findAllByDeviceIdAndStatus, tenantId [{}], deviceId [{}], rpcStatus [{}], pageLink [{}]", tenantId, deviceId, rpcStatus, pageLink); validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validatePageLink(pageLink); - return rpcDao.findAllByDeviceId(tenantId, deviceId, rpcStatus, pageLink); + return rpcDao.findAllByDeviceIdAndStatus(tenantId, deviceId, rpcStatus, pageLink); + } + + @Override + public PageData findAllByDeviceId(TenantId tenantId, DeviceId deviceId, PageLink pageLink) { + log.trace("Executing findAllByDeviceIdAndStatus, tenantId [{}], deviceId [{}], pageLink [{}]", tenantId, deviceId, pageLink); + validateId(tenantId, INCORRECT_TENANT_ID + tenantId); + validatePageLink(pageLink); + return rpcDao.findAllByDeviceId(tenantId, deviceId, pageLink); } private PaginatedRemover tenantRpcRemover = diff --git a/dao/src/main/java/org/thingsboard/server/dao/rpc/RpcDao.java b/dao/src/main/java/org/thingsboard/server/dao/rpc/RpcDao.java index 63af784dbb..3f34db3907 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/rpc/RpcDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/rpc/RpcDao.java @@ -24,7 +24,9 @@ import org.thingsboard.server.common.data.rpc.RpcStatus; import org.thingsboard.server.dao.Dao; public interface RpcDao extends Dao { - PageData findAllByDeviceId(TenantId tenantId, DeviceId deviceId, RpcStatus rpcStatus, PageLink pageLink); + PageData findAllByDeviceId(TenantId tenantId, DeviceId deviceId, PageLink pageLink); + + PageData findAllByDeviceIdAndStatus(TenantId tenantId, DeviceId deviceId, RpcStatus rpcStatus, PageLink pageLink); PageData findAllRpcByTenantId(TenantId tenantId, PageLink pageLink); diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/rpc/JpaRpcDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/rpc/JpaRpcDao.java index 221ef17361..6791de4122 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/rpc/JpaRpcDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/rpc/JpaRpcDao.java @@ -50,7 +50,12 @@ public class JpaRpcDao extends JpaAbstractDao implements RpcDao } @Override - public PageData findAllByDeviceId(TenantId tenantId, DeviceId deviceId, RpcStatus rpcStatus, PageLink pageLink) { + public PageData findAllByDeviceId(TenantId tenantId, DeviceId deviceId, PageLink pageLink) { + return DaoUtil.toPageData(rpcRepository.findAllByTenantIdAndDeviceId(tenantId.getId(), deviceId.getId(), DaoUtil.toPageable(pageLink))); + } + + @Override + public PageData findAllByDeviceIdAndStatus(TenantId tenantId, DeviceId deviceId, RpcStatus rpcStatus, PageLink pageLink) { return DaoUtil.toPageData(rpcRepository.findAllByTenantIdAndDeviceIdAndStatus(tenantId.getId(), deviceId.getId(), rpcStatus, DaoUtil.toPageable(pageLink))); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/rpc/RpcRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/rpc/RpcRepository.java index 76b67b3823..0ca33dbb2e 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/rpc/RpcRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/rpc/RpcRepository.java @@ -26,6 +26,8 @@ import org.thingsboard.server.dao.model.sql.RpcEntity; import java.util.UUID; public interface RpcRepository extends CrudRepository { + Page findAllByTenantIdAndDeviceId(UUID tenantId, UUID deviceId, Pageable pageable); + Page findAllByTenantIdAndDeviceIdAndStatus(UUID tenantId, UUID deviceId, RpcStatus status, Pageable pageable); Page findAllByTenantId(UUID tenantId, Pageable pageable); diff --git a/ui-ngx/src/app/core/api/widget-api.models.ts b/ui-ngx/src/app/core/api/widget-api.models.ts index d053efb601..c0bab56e4e 100644 --- a/ui-ngx/src/app/core/api/widget-api.models.ts +++ b/ui-ngx/src/app/core/api/widget-api.models.ts @@ -55,6 +55,8 @@ import { TranslateService } from '@ngx-translate/core'; import { AlarmDataService } from '@core/api/alarm-data.service'; import { IDashboardController } from '@home/components/dashboard-page/dashboard-page.models'; import { PopoverPlacement } from '@shared/components/popover.models'; +import { PageLink } from '@shared/models/page/page-link'; +import { PersistentRpc, RpcStatus } from '@shared/models/rpc.models'; export interface TimewindowFunctions { onUpdateTimewindow: (startTimeMs: number, endTimeMs: number, interval?: number) => void; @@ -71,9 +73,9 @@ export interface WidgetSubscriptionApi { export interface RpcApi { sendOneWayCommand: (method: string, params?: any, timeout?: number, persistent?: boolean, - persistentPollingInterval?: number, requestUUID?: string) => Observable; + persistentPollingInterval?: number, retries?: number, additionalInfo?: any, requestUUID?: string) => Observable; sendTwoWayCommand: (method: string, params?: any, timeout?: number, persistent?: boolean, - persistentPollingInterval?: number, requestUUID?: string) => Observable; + persistentPollingInterval?: number, retries?: number, additionalInfo?: any, requestUUID?: string) => Observable; completedCommand: () => void; } @@ -287,6 +289,8 @@ export interface IWidgetSubscription { comparisonEnabled?: boolean; comparisonTimeWindow?: WidgetTimewindow; + persistentRequests?: PageData; + alarms?: PageData; alarmSource?: Datasource; @@ -313,11 +317,13 @@ export interface IWidgetSubscription { updateTimewindowConfig(newTimewindow: Timewindow): void; sendOneWayCommand(method: string, params?: any, timeout?: number, persistent?: boolean, - persistentPollingInterval?: number, requestUUID?: string): Observable; + persistentPollingInterval?: number, retries?: number, additionalInfo?: any, requestUUID?: string): Observable; sendTwoWayCommand(method: string, params?: any, timeout?: number, persistent?: boolean, - persistentPollingInterval?: number, requestUUID?: string): Observable; + persistentPollingInterval?: number, retries?: number, additionalInfo?: any, requestUUID?: string): Observable; clearRpcError(): void; + subscribeForPersistentRequests(pageLink: PageLink, keyFileter: RpcStatus): Observable; + subscribe(): void; subscribeAllForPaginatedData(pageLink: EntityDataPageLink, diff --git a/ui-ngx/src/app/core/api/widget-subscription.ts b/ui-ngx/src/app/core/api/widget-subscription.ts index 21f95a9158..c548b0fbab 100644 --- a/ui-ngx/src/app/core/api/widget-subscription.ts +++ b/ui-ngx/src/app/core/api/widget-subscription.ts @@ -70,6 +70,7 @@ import { import { distinct, filter, map, switchMap, takeUntil } from 'rxjs/operators'; import { AlarmDataListener } from '@core/api/alarm-data.service'; import { RpcStatus } from '@shared/models/rpc.models'; +import { PageLink } from '@shared/models/page/page-link'; const moment = moment_; @@ -656,13 +657,13 @@ export class WidgetSubscription implements IWidgetSubscription { } sendOneWayCommand(method: string, params?: any, timeout?: number, persistent?: boolean, - persistentPollingInterval?: number, requestUUID?: string): Observable { - return this.sendCommand(true, method, params, timeout, persistent, persistentPollingInterval, requestUUID); + persistentPollingInterval?: number, retries?: number, additionalInfo?: any, requestUUID?: string): Observable { + return this.sendCommand(true, method, params, timeout, persistent, persistentPollingInterval, retries, additionalInfo, requestUUID); } sendTwoWayCommand(method: string, params?: any, timeout?: number, persistent?: boolean, - persistentPollingInterval?: number, requestUUID?: string): Observable { - return this.sendCommand(false, method, params, timeout, persistent, persistentPollingInterval, requestUUID); + persistentPollingInterval?: number, retries?: number, additionalInfo?: any, requestUUID?: string): Observable { + return this.sendCommand(false, method, params, timeout, persistent, persistentPollingInterval, retries, additionalInfo, requestUUID); } clearRpcError(): void { @@ -679,7 +680,8 @@ export class WidgetSubscription implements IWidgetSubscription { } sendCommand(oneWayElseTwoWay: boolean, method: string, params?: any, timeout?: number, - persistent?: boolean, persistentPollingInterval?: number, requestUUID?: string): Observable { + persistent?: boolean, persistentPollingInterval?: number, retries?: number, + additionalInfo?: any, requestUUID?: string): Observable { if (!this.rpcEnabled) { return throwError(new Error('Rpc disabled!')); } else { @@ -692,6 +694,8 @@ export class WidgetSubscription implements IWidgetSubscription { method, params, persistent, + retries, + additionalInfo, requestUUID }; if (timeout && timeout > 0) { @@ -777,6 +781,15 @@ export class WidgetSubscription implements IWidgetSubscription { } } + subscribeForPersistentRequests(pageLink: PageLink, keyFilter: RpcStatus): Observable { + if (!this.rpcEnabled) { + return throwError(new Error('Rpc disabled!')); + } else if (!this.targetDeviceId) { + return throwError(new Error('Target device is not set!')); + } + return this.ctx.deviceService.getPersistedRpcRequests(this.targetDeviceId, pageLink, keyFilter); + } + private extractRejectionErrorText(rejection: HttpErrorResponse) { let error = null; if (rejection.error) { diff --git a/ui-ngx/src/app/core/http/device.service.ts b/ui-ngx/src/app/core/http/device.service.ts index c8ea7e65ff..9b5119d317 100644 --- a/ui-ngx/src/app/core/http/device.service.ts +++ b/ui-ngx/src/app/core/http/device.service.ts @@ -31,7 +31,7 @@ import { import { EntitySubtype } from '@app/shared/models/entity-type.models'; import { AuthService } from '@core/auth/auth.service'; import { BulkImportRequest, BulkImportResult } from '@home/components/import-export/import-export.models'; -import { PersistentRpc } from '@shared/models/rpc.models'; +import { PersistentRpc, RpcStatus } from '@shared/models/rpc.models'; @Injectable({ providedIn: 'root' @@ -143,6 +143,17 @@ export class DeviceService { return this.http.get(`/api/rpc/persistent/${rpcId}`, defaultHttpOptionsFromConfig(config)); } + public deletePersistedRpc(rpcId: string, config?: RequestConfig) { + return this.http.delete(`/api/rpc/persistent/${rpcId}`, defaultHttpOptionsFromConfig(config)); + } + + public getPersistedRpcRequests(deviceId: string, pageLink: PageLink, + keyFilter: RpcStatus, config?: RequestConfig): Observable> { + const rpcStatus = keyFilter ? '&rpcStatus=' + keyFilter : ''; + return this.http.get>(`/api/rpc/persistent/device/${deviceId}${pageLink.toQuery()}${rpcStatus}`, + defaultHttpOptionsFromConfig(config)); + } + public findByQuery(query: DeviceSearchQuery, config?: RequestConfig): Observable> { return this.http.post>('/api/devices', query, defaultHttpOptionsFromConfig(config)); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-add-dialog.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-add-dialog.component.html new file mode 100644 index 0000000000..7e0ae3056f --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-add-dialog.component.html @@ -0,0 +1,92 @@ + +
+ +

{{ 'widgets.persistent-table.add-title' | translate }}

+ + +
+ + +
+
+
+
+ + {{ 'widgets.persistent-table.message-types.' + persistentFormGroup.get('oneWayElseTwoWay').value | translate }} + +
+
+ + widgets.persistent-table.method + + + {{'widgets.persistent-table.method-error' | translate}} + + + {{'widgets.persistent-table.white-space-error' | translate}} + + + + widgets.persistent-table.retries + + +
+
+ + +
+ + + + widgets.persistent-table.additional-info + + + + + + + +
+
+
+
+ + +
+ +
+
+
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-add-dialog.component.scss b/ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-add-dialog.component.scss new file mode 100644 index 0000000000..e450fa4a09 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-add-dialog.component.scss @@ -0,0 +1,30 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +:host { + .add-dialog ::ng-deep { + + .params-json-editor, + .additional-json-editor { + .tb-json-object-panel { + margin: 0 0 16px; + } + + .mat-expansion-panel-body { + padding-bottom: 0 !important; + } + } + } +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-add-dialog.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-add-dialog.component.ts new file mode 100644 index 0000000000..c4e87c5e6b --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-add-dialog.component.ts @@ -0,0 +1,77 @@ +/// +/// Copyright © 2016-2021 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { Component, OnInit } from '@angular/core'; +import { DialogComponent } from '@shared/components/dialog.component'; +import { Store } from '@ngrx/store'; +import { AppState } from '@core/core.state'; +import { Router } from '@angular/router'; +import { MatDialogRef } from '@angular/material/dialog'; +import { FormBuilder, FormGroup, Validators } from '@angular/forms'; +import { RequestData } from '@shared/models/rpc.models'; + +@Component({ + selector: 'tb-persistent-add-dialog', + templateUrl: './persistent-add-dialog.component.html', + styleUrls: ['./persistent-add-dialog.component.scss'] +}) + +export class PersistentAddDialogComponent extends DialogComponent implements OnInit { + + public persistentFormGroup: FormGroup; + + private requestData: RequestData = { + persistentUpdated: false + }; + + constructor(protected store: Store, + protected router: Router, + public dialogRef: MatDialogRef, + private fb: FormBuilder) { + super(store, router, dialogRef); + + this.persistentFormGroup = this.fb.group( + { + method: ['', [Validators.required, Validators.pattern(/^\S+$/)]], + oneWayElseTwoWay: [false], + retries: [null, [Validators.pattern(/^-?[0-9]+$/), Validators.min(0)]], + params: [{}], + additionalInfo: [{}] + } + ); + } + + save() { + if (this.persistentFormGroup.valid) { + this.requestData = { + persistentUpdated: true, + method: this.persistentFormGroup.get('method').value, + oneWayElseTwoWay: this.persistentFormGroup.get('oneWayElseTwoWay').value, + params: this.persistentFormGroup.get('params').value, + additionalInfo: this.persistentFormGroup.get('additionalInfo').value, + retries: this.persistentFormGroup.get('retries').value + }; + this.close(); + } + } + + ngOnInit(): void { + } + + close(): void { + this.dialogRef.close(this.requestData); + } +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-details-dialog.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-details-dialog.component.html new file mode 100644 index 0000000000..3a9451db67 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-details-dialog.component.html @@ -0,0 +1,118 @@ + +
+ +

{{ persistentFormGroup.get('rpcId').value }}

+ + +
+ + +
+
+
+
+ + widgets.persistent-table.created-time + + + + widgets.persistent-table.expiration-time + + +
+
+ + widgets.persistent-table.message-type + + + + widgets.persistent-table.status + + + + widgets.persistent-table.method + + + + widgets.persistent-table.retries + + +
+ + + + + + {{ 'widgets.persistent-table.response' | translate }} + + + + + + + + {{ 'widgets.persistent-table.params' | translate }} + + + + + + + + + + {{ 'widgets.persistent-table.additional-info' | translate }} + + + + + + + + +
+
+
+ + +
+ +
+
+
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-details-dialog.component.scss b/ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-details-dialog.component.scss new file mode 100644 index 0000000000..ec456d5d9e --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-details-dialog.component.scss @@ -0,0 +1,33 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +:host { + .rpc-dialog ::ng-deep { + .mat-expansion-panel-body { + padding-bottom: 0 !important; + } + + .tb-json-object-panel { + margin: 0 0 16px 0; + } + } + .tb-audit-log-response-data { + width: 100%; + min-width: 400px; + height: 100%; + min-height: 100px; + border: 1px solid #c0c0c0; + } +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-details-dialog.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-details-dialog.component.ts new file mode 100644 index 0000000000..552175b905 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-details-dialog.component.ts @@ -0,0 +1,151 @@ +/// +/// Copyright © 2016-2021 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { Component, ElementRef, Inject, OnInit, ViewChild } from '@angular/core'; +import { DialogComponent } from '@shared/components/dialog.component'; +import { Store } from '@ngrx/store'; +import { AppState } from '@core/core.state'; +import { Router } from '@angular/router'; +import { DatePipe } from '@angular/common'; +import { TranslateService } from '@ngx-translate/core'; +import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; +import { FormBuilder, FormGroup } from '@angular/forms'; +import { DeviceService } from '@core/http/device.service'; +import { + PersistentRpc, + rpcStatusColors, + RpcStatus, + rpcStatusTranslation +} from '@shared/models/rpc.models'; +import { isDefinedAndNotNull } from '@core/utils'; +import { NULL_UUID } from '@shared/models/id/has-uuid'; +import { DialogService } from '@core/services/dialog.service'; + +export interface PersistentDetailsDialogData { + persistentRequest: PersistentRpc; + allowDelete: boolean; +} + +@Component({ + selector: 'tb-persistent-details-dialog', + templateUrl: './persistent-details-dialog.component.html', + styleUrls: ['./persistent-details-dialog.component.scss'] +}) + +export class PersistentDetailsDialogComponent extends DialogComponent implements OnInit { + + @ViewChild('responseDataEditor', {static: true}) + responseDataEditorElmRef: ElementRef; + + public persistentFormGroup: FormGroup; + public rpcStatusColorsMap = rpcStatusColors; + public rpcStatus = RpcStatus; + public allowDelete: boolean; + + private persistentUpdated = false; + private responseData: string; + + constructor(protected store: Store, + protected router: Router, + private datePipe: DatePipe, + private translate: TranslateService, + @Inject(MAT_DIALOG_DATA) public data: PersistentDetailsDialogData, + public dialogRef: MatDialogRef, + private dialogService: DialogService, + private deviceService: DeviceService, + private fb: FormBuilder) { + super(store, router, dialogRef); + + this.allowDelete = data.allowDelete; + + this.persistentFormGroup = this.fb.group( + { + rpcId: [''], + createdTime: [''], + expirationTime: [''], + messageType: [''], + status: [''], + method: [''], + params: [''], + retries: [''], + response: [''], + additionalInfo: [null] + } + ); + this.loadPersistentFields(data.persistentRequest); + this.responseData = JSON.stringify(data.persistentRequest.response, null, 2); + } + + loadPersistentFields(request: PersistentRpc) { + this.persistentFormGroup.get('rpcId') + .patchValue(this.translate.instant('widgets.persistent-table.details-title') + request.id.id); + this.persistentFormGroup.get('createdTime') + .patchValue(this.datePipe.transform(request.createdTime, 'yyyy-MM-dd HH:mm:ss')); + this.persistentFormGroup.get('expirationTime') + .patchValue(this.datePipe.transform(request.expirationTime, 'yyyy-MM-dd HH:mm:ss')); + this.persistentFormGroup.get('messageType') + .patchValue(this.translate.instant('widgets.persistent-table.message-types.' + request.request.oneway) + ); + this.persistentFormGroup.get('status') + .patchValue(this.translate.instant(rpcStatusTranslation.get(request.status))); + this.persistentFormGroup.get('method') + .patchValue(request.request.body.method); + if (isDefinedAndNotNull(request.request.retries)) { + this.persistentFormGroup.get('retries') + .patchValue(request.request.retries); + } + if (isDefinedAndNotNull(request.response)) { + this.persistentFormGroup.get('response') + .patchValue(request.response); + } + if (isDefinedAndNotNull(request.request.body.params)) { + this.persistentFormGroup.get('params') + .patchValue(JSON.parse(request.request.body.params)); + } + if (isDefinedAndNotNull(request.additionalInfo)) { + this.persistentFormGroup.get('additionalInfo') + .patchValue(request.additionalInfo); + } + } + + ngOnInit(): void { + } + + close(): void { + this.dialogRef.close(this.persistentUpdated); + } + + deleteRpcRequest() { + const persistentRpc = this.data.persistentRequest; + if (persistentRpc && persistentRpc.id && persistentRpc.id.id !== NULL_UUID) { + this.dialogService.confirm( + this.translate.instant('widgets.persistent-table.delete-request-title'), + this.translate.instant('widgets.persistent-table.delete-request-text'), + this.translate.instant('action.no'), + this.translate.instant('action.yes') + ).subscribe((res) => { + if (res) { + if (res) { + this.deviceService.deletePersistedRpc(persistentRpc.id.id).subscribe(() => { + this.persistentUpdated = true; + this.close(); + }); + } + } + }); + } + } +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-filter-panel.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-filter-panel.component.html new file mode 100644 index 0000000000..ffbcab5749 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-filter-panel.component.html @@ -0,0 +1,44 @@ + +
+ + widgets.persistent-table.rpc-status-list + + + {{ 'widgets.persistent-table.rpc-search-status-all' | translate }} + + + {{ rpcSearchStatusTranslationMap.get(searchStatus) | translate }} + + + +
+ + +
+
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-filter-panel.component.scss b/ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-filter-panel.component.scss new file mode 100644 index 0000000000..63f832d78c --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-filter-panel.component.scss @@ -0,0 +1,36 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +:host { + width: 100%; + height: 100%; + min-width: 300px; + overflow: hidden; + background: #fff; + border-radius: 4px; + box-shadow: + 0 7px 8px -4px rgba(0, 0, 0, .2), + 0 13px 19px 2px rgba(0, 0, 0, .14), + 0 5px 24px 4px rgba(0, 0, 0, .12); + + .mat-content { + overflow: hidden; + background-color: #fff; + } + + .mat-padding { + padding: 16px; + } +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-filter-panel.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-filter-panel.component.ts new file mode 100644 index 0000000000..d60c80ac43 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-filter-panel.component.ts @@ -0,0 +1,71 @@ +/// +/// Copyright © 2016-2021 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { Component, Inject, InjectionToken } from '@angular/core'; +import { FormBuilder, FormGroup } from '@angular/forms'; +import { OverlayRef } from '@angular/cdk/overlay'; +import { RpcStatus, rpcStatusTranslation } from '@shared/models/rpc.models'; + +export const PERSISTENT_FILTER_PANEL_DATA = new InjectionToken('AlarmFilterPanelData'); + +export interface PersistentFilterPanelData { + rpcStatus: RpcStatus; +} + +@Component({ + selector: 'tb-persistent-filter-panel', + templateUrl: './persistent-filter-panel.component.html', + styleUrls: ['./persistent-filter-panel.component.scss'] +}) +export class PersistentFilterPanelComponent { + + public persistentFilterFormGroup: FormGroup; + public result: PersistentFilterPanelData; + public rpcSearchStatusTranslationMap = rpcStatusTranslation; + + public persistentSearchStatuses = [ + RpcStatus.QUEUED, + RpcStatus.SENT, + RpcStatus.DELIVERED, + RpcStatus.SUCCESSFUL, + RpcStatus.TIMEOUT, + RpcStatus.EXPIRED, + RpcStatus.FAILED + ]; + + constructor(@Inject(PERSISTENT_FILTER_PANEL_DATA) + public data: PersistentFilterPanelData, + public overlayRef: OverlayRef, + private fb: FormBuilder) { + this.persistentFilterFormGroup = this.fb.group( + { + rpcStatus: this.data.rpcStatus + } + ); + } + + update() { + this.result = { + rpcStatus: this.persistentFilterFormGroup.get('rpcStatus').value + }; + this.overlayRef.dispose(); + } + + cancel() { + this.overlayRef.dispose(); + } +} + diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-table.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-table.component.html new file mode 100644 index 0000000000..c4fc2428be --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-table.component.html @@ -0,0 +1,125 @@ + +
+
+
+ + + + {{ 'widgets.persistent-table.rpc-id' | translate }} + + + {{ column.id.id }} + + + + + {{ 'widgets.persistent-table.created-time' | translate }} + + + {{ column.createdTime | date:'yyyy-MM-dd HH:mm:ss' }} + + + + + {{ 'widgets.persistent-table.expiration-time' | translate }} + + + {{ column.expirationTime | date:'yyyy-MM-dd HH:mm:ss' }} + + + + + {{ 'widgets.persistent-table.status' | translate }} + + + {{ rpcStatusTranslation.get(column.status) | translate }} + + + + + {{ 'widgets.persistent-table.message-type' | translate }} + + + {{ 'widgets.persistent-table.message-types.' + column.request.oneway | translate }} + + + + + {{ 'widgets.persistent-table.method' | translate }} + + + {{ column.request.body.method }} + + + + + + +
+ + + +
+
+ + + + + + +
+
+
+ + +
+ {{ noDataDisplayMessageText }} + {{ 'common.loading' | translate }} +
+ + +
+
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-table.component.scss b/ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-table.component.scss new file mode 100644 index 0000000000..ec079f54cb --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-table.component.scss @@ -0,0 +1,52 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +:host { + width: 100%; + height: 100%; + .tb-table-widget { + .table-container { + position: relative; + } + + .mat-table { + .mat-row { + &.invisible { + visibility: hidden; + } + } + } + + span.no-data-found { + position: absolute; + top: 60px; + bottom: 0; + left: 0; + right: 0; + } + + .column-id { + min-width: 250px; + max-width: 250px; + width: 250px; + } + + .column-time { + min-width: 120px; + max-width: 120px; + width: 120px; + } + } +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-table.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-table.component.ts new file mode 100644 index 0000000000..8f5ccab14b --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-table.component.ts @@ -0,0 +1,476 @@ +/// +/// Copyright © 2016-2021 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { + Component, + ElementRef, + Injector, + Input, + OnInit, + StaticProvider, + ViewChild, + ViewContainerRef +} from '@angular/core'; +import { PageComponent } from '@shared/components/page.component'; +import { Store } from '@ngrx/store'; +import { AppState } from '@core/core.state'; +import { WidgetContext } from '@home/models/widget-component.models'; +import { WidgetConfig } from '@shared/models/widget.models'; +import { IWidgetSubscription } from '@core/api/widget-api.models'; +import { BehaviorSubject, merge, Observable, of, ReplaySubject } from 'rxjs'; +import { catchError, map, tap } from 'rxjs/operators'; +import { + constructTableCssString, noDataMessage, + TableCellButtonActionDescriptor, + TableWidgetSettings +} from '@home/components/widget/lib/table-widget.models'; +import cssjs from '@core/css/css'; +import { UtilsService } from '@core/services/utils.service'; +import { TranslateService } from '@ngx-translate/core'; +import { hashCode, isDefined, isNumber } from '@core/utils'; +import { CollectionViewer, DataSource } from '@angular/cdk/collections'; +import { emptyPageData, PageData } from '@shared/models/page/page-data'; +import { + PersistentRpc, + PersistentRpcData, RequestData, + RpcStatus, + rpcStatusColors, rpcStatusTranslation +} from '@shared/models/rpc.models'; +import { PageLink } from '@shared/models/page/page-link'; +import { Direction, SortOrder, sortOrderFromString } from '@shared/models/page/sort-order'; +import { MatPaginator } from '@angular/material/paginator'; +import { MatSort } from '@angular/material/sort'; +import { NULL_UUID } from '@shared/models/id/has-uuid'; +import { DialogService } from '@core/services/dialog.service'; +import { DeviceService } from '@core/http/device.service'; +import { MatDialog } from '@angular/material/dialog'; +import { + PersistentDetailsDialogComponent, + PersistentDetailsDialogData +} from '@home/components/widget/lib/rpc/persistent-details-dialog.component'; +import { ConnectedPosition, Overlay, OverlayConfig, OverlayRef } from '@angular/cdk/overlay'; +import { ComponentPortal } from '@angular/cdk/portal'; +import { + PERSISTENT_FILTER_PANEL_DATA, PersistentFilterPanelComponent, PersistentFilterPanelData +} from '@home/components/widget/lib/rpc/persistent-filter-panel.component'; +import { PersistentAddDialogComponent } from '@home/components/widget/lib/rpc/persistent-add-dialog.component'; + +interface PersistentTableWidgetSettings extends TableWidgetSettings { + defaultSortOrder: string; + defaultPageSize: number; + displayPagination: boolean; + enableStickyAction: boolean; + enableStickyHeader: boolean; + enableFilter: boolean; + displayColumns: string[]; + displayDetails: boolean; + allowDelete: boolean; + allowSendRequest: boolean; +} + +interface PersistentTableWidgetActionDescriptor extends TableCellButtonActionDescriptor { + details?: boolean; + delete?: boolean; +} + +@Component({ + selector: 'tb-persistent-table-widget', + templateUrl: './persistent-table.component.html', + styleUrls: ['./persistent-table.component.scss' , '../table-widget.scss'] +}) + +export class PersistentTableComponent extends PageComponent implements OnInit { + + @Input() + ctx: WidgetContext; + + @ViewChild(MatPaginator) paginator: MatPaginator; + @ViewChild(MatSort) sort: MatSort; + + private settings: PersistentTableWidgetSettings; + private widgetConfig: WidgetConfig; + private subscription: IWidgetSubscription; + private enableFilterAction = true; + private allowSendRequest = true; + private defaultPageSize = 10; + private defaultSortOrder = '-createdTime'; + private rpcStatusFilter: RpcStatus | null = null; + private displayDetails = true; + private allowDelete = true; + private displayTableColumns: string[]; + + public persistentDatasource: PersistentDatasource; + public noDataDisplayMessageText: string; + public rpcStatusColor = rpcStatusColors; + public rpcStatusTranslation = rpcStatusTranslation; + public displayPagination = true; + public enableStickyHeader = true; + public enableStickyAction = true; + public pageLink: PageLink; + public pageSizeOptions; + public actionCellButtonAction: PersistentTableWidgetActionDescriptor[] = []; + public displayedColumns: string[]; + + constructor(protected store: Store, + private elementRef: ElementRef, + private overlay: Overlay, + private viewContainerRef: ViewContainerRef, + private utils: UtilsService, + private translate: TranslateService, + private dialogService: DialogService, + private deviceService: DeviceService, + private dialog: MatDialog) { + super(store); + } + + ngOnInit() { + this.ctx.$scope.persistentTableWidget = this; + this.settings = this.ctx.settings; + this.widgetConfig = this.ctx.widgetConfig; + this.subscription = this.ctx.defaultSubscription; + this.initializeConfig(); + this.ctx.updateWidgetParams(); + } + + ngAfterViewInit(): void { + if (this.displayPagination) { + this.sort.sortChange.subscribe(() => this.paginator.pageIndex = 0); + } + ((this.displayPagination ? merge(this.sort.sortChange, this.paginator.page) : this.sort.sortChange) as Observable) + .pipe( + tap(() => this.updateData()) + ) + .subscribe(); + this.updateData(); + } + + private initializeConfig() { + + this.displayPagination = isDefined(this.settings.displayPagination) ? this.settings.displayPagination : true; + this.enableStickyHeader = isDefined(this.settings.enableStickyHeader) ? this.settings.enableStickyHeader : true; + this.displayTableColumns = isDefined(this.settings.displayColumns) ? this.settings.displayColumns : []; + this.enableStickyAction = isDefined(this.settings.enableStickyAction) ? this.settings.enableStickyAction : true; + this.enableFilterAction = isDefined(this.settings.enableFilter) ? this.settings.enableFilter : true; + this.displayDetails = isDefined(this.settings.displayDetails) ? this.settings.displayDetails : true; + this.allowDelete = isDefined(this.settings.allowDelete) ? this.settings.allowDelete : true; + this.allowSendRequest = isDefined(this.settings.allowSendRequest) ? this.settings.allowSendRequest : true; + + this.noDataDisplayMessageText = + noDataMessage(this.widgetConfig.noDataDisplayMessage, 'widgets.persistent-table.no-request-prompt', this.utils, this.translate); + + this.displayedColumns = [...this.displayTableColumns]; + + const pageSize = this.settings.defaultPageSize; + if (isDefined(pageSize) && isNumber(pageSize) && pageSize > 0) { + this.defaultPageSize = pageSize; + } + this.pageSizeOptions = [this.defaultPageSize, this.defaultPageSize * 2, this.defaultPageSize * 3]; + if (this.settings.defaultSortOrder && this.settings.defaultSortOrder.length) { + this.defaultSortOrder = this.settings.defaultSortOrder; + } + const sortOrder: SortOrder = sortOrderFromString(this.defaultSortOrder); + this.pageLink = new PageLink(this.defaultPageSize, 0, null, sortOrder); + this.pageLink.pageSize = this.displayPagination ? this.defaultPageSize : 1024; + + + this.ctx.widgetActions = [ + { + name: 'widgets.persistent-table.add', + show: this.allowSendRequest, + icon: 'add', + onAction: $event => this.addPersistentRpcRequest($event) + }, + { + name: 'widgets.persistent-table.refresh', + show: true, + icon: 'refresh', + onAction: () => this.reloadPersistentRequests() + }, + { + name: 'widgets.persistent-table.filter', + show: this.enableFilterAction, + icon: 'filter_list', + onAction: $event => this.editFilter($event) + } + ]; + + if (this.settings.displayDetails) { + this.actionCellButtonAction.push( + { + displayName: this.translate.instant('widgets.persistent-table.details'), + icon: 'more_horiz', + details: true + } as PersistentTableWidgetActionDescriptor + ); + } + if (this.settings.allowDelete) { + this.actionCellButtonAction.push( + { + displayName: this.translate.instant('widgets.persistent-table.delete'), + icon: 'delete', + delete: true + } as PersistentTableWidgetActionDescriptor + ); + } + if (this.actionCellButtonAction.length) { + this.displayedColumns.push('actions'); + } + + this.persistentDatasource = new PersistentDatasource(this.translate, this.subscription); + + const cssString = constructTableCssString(this.widgetConfig); + const cssParser = new cssjs(); + cssParser.testMode = false; + const namespace = 'persistent-table-' + hashCode(cssString); + cssParser.cssPreviewNamespace = namespace; + cssParser.createStyleElement(namespace, cssString); + $(this.elementRef.nativeElement).addClass(namespace); + } + + private updateData() { + if (this.displayPagination) { + this.pageLink.page = this.paginator.pageIndex; + this.pageLink.pageSize = this.paginator.pageSize; + } else { + this.pageLink.page = 0; + } + if (this.settings.defaultSortOrder && this.settings.defaultSortOrder.length) { + this.defaultSortOrder = this.utils.customTranslation(this.settings.defaultSortOrder, this.settings.defaultSortOrder); + } + this.pageLink.sortOrder.property = this.sort.active; + this.pageLink.sortOrder.direction = Direction[this.sort.direction.toUpperCase()]; + this.persistentDatasource.loadPersistent(this.pageLink, this.rpcStatusFilter); + this.ctx.detectChanges(); + } + + public onDataUpdated() { + this.ctx.detectChanges(); + } + + reloadPersistentRequests() { + if (this.displayPagination) { + this.paginator.pageIndex = 0; + } + this.updateData(); + } + + deleteRpcRequest($event: Event, persistentRpc: PersistentRpc) { + if ($event) { + $event.stopPropagation(); + } + if (persistentRpc && persistentRpc.id && persistentRpc.id.id !== NULL_UUID) { + this.dialogService.confirm( + this.translate.instant('widgets.persistent-table.delete-request-title'), + this.translate.instant('widgets.persistent-table.delete-request-text'), + this.translate.instant('action.no'), + this.translate.instant('action.yes') + ).subscribe((res) => { + if (res) { + if (res) { + this.deviceService.deletePersistedRpc(persistentRpc.id.id).subscribe(() => { + this.reloadPersistentRequests(); + }); + } + } + }); + } + } + + openRequestDetails($event: Event, persistentRpc: PersistentRpc) { + if ($event) { + $event.stopPropagation(); + } + if (persistentRpc && persistentRpc.id && persistentRpc.id.id !== NULL_UUID) { + this.dialog.open + (PersistentDetailsDialogComponent, + { + disableClose: true, + panelClass: ['tb-dialog', 'tb-fullscreen-dialog'], + data: { + persistentRequest: persistentRpc, + allowDelete: this.allowDelete + } + }).afterClosed().subscribe( + (res) => { + if (res) { + this.reloadPersistentRequests(); + } + } + ); + } + } + + addPersistentRpcRequest($event: Event){ + if ($event) { + $event.stopPropagation(); + } + this.dialog.open + (PersistentAddDialogComponent, + { + disableClose: true, + panelClass: ['tb-dialog', 'tb-fullscreen-dialog'] + }).afterClosed().subscribe( + (requestData) => { + if (requestData.persistentUpdated) { + this.sendRequests(requestData); + } + } + ); + } + + private sendRequests(requestData: RequestData) { + let commandPromise; + if (requestData.oneWayElseTwoWay) { + commandPromise = this.ctx.controlApi.sendOneWayCommand( + requestData.method, + requestData.params, null, + true, null, + requestData.retries, + requestData.additionalInfo + ); + } else { + commandPromise = this.ctx.controlApi.sendTwoWayCommand( + requestData.method, + requestData.params, + null, + true, null, + requestData.retries, + requestData.additionalInfo + ); + } + commandPromise.subscribe( + () => { + this.reloadPersistentRequests(); + } + ); + } + + public onActionButtonClick($event: Event, persistentRpc: PersistentRpc, actionDescriptor: PersistentTableWidgetActionDescriptor) { + if (actionDescriptor.details) { + this.openRequestDetails($event, persistentRpc); + } + if (actionDescriptor.delete) { + this.deleteRpcRequest($event, persistentRpc); + } + } + + private editFilter($event: Event) { + if ($event) { + $event.stopPropagation(); + } + const target = $event.target || $event.srcElement || $event.currentTarget; + const config = new OverlayConfig(); + config.backdropClass = 'cdk-overlay-transparent-backdrop'; + config.hasBackdrop = true; + const connectedPosition: ConnectedPosition = { + originX: 'end', + originY: 'bottom', + overlayX: 'end', + overlayY: 'top' + }; + config.positionStrategy = this.overlay.position().flexibleConnectedTo(target as HTMLElement) + .withPositions([connectedPosition]); + + const overlayRef = this.overlay.create(config); + overlayRef.backdropClick().subscribe(() => { + overlayRef.dispose(); + }); + const providers: StaticProvider[] = [ + { + provide: PERSISTENT_FILTER_PANEL_DATA, + useValue: { + rpcStatus: this.rpcStatusFilter + } as PersistentFilterPanelData + }, + { + provide: OverlayRef, + useValue: overlayRef + } + ]; + const injector = Injector.create({parent: this.viewContainerRef.injector, providers}); + const componentRef = overlayRef.attach(new ComponentPortal(PersistentFilterPanelComponent, + this.viewContainerRef, injector)); + componentRef.onDestroy(() => { + if (componentRef.instance.result) { + const result = componentRef.instance.result; + this.rpcStatusFilter = result.rpcStatus; + this.reloadPersistentRequests(); + } + }); + this.ctx.detectChanges(); + } +} + +class PersistentDatasource implements DataSource { + + private persistentSubject = new BehaviorSubject([]); + private pageDataSubject = new BehaviorSubject>(emptyPageData()); + + public dataLoading = true; + public pageData$ = this.pageDataSubject.asObservable(); + + constructor(private translate: TranslateService, + private subscription: IWidgetSubscription) { + } + + connect(collectionViewer: CollectionViewer): Observable> { + return this.persistentSubject.asObservable(); + } + + disconnect(collectionViewer: CollectionViewer): void { + this.persistentSubject.complete(); + this.pageDataSubject.complete(); + } + + reset() { + const pageData = emptyPageData(); + this.persistentSubject.next(pageData.data); + this.pageDataSubject.next(pageData); + } + + loadPersistent(pageLink: PageLink, keyFilter: RpcStatus) { + this.dataLoading = true; + + const result = new ReplaySubject>(); + this.fetchEntities(pageLink, keyFilter).pipe( + catchError(() => of(emptyPageData())), + ).subscribe( + (pageData) => { + this.persistentSubject.next(pageData.data); + this.pageDataSubject.next(pageData); + result.next(pageData); + this.dataLoading = false; + } + ); + return result; + } + + fetchEntities(pageLink: PageLink, keyFilter: RpcStatus): Observable> { + return this.subscription.subscribeForPersistentRequests(pageLink, keyFilter); + } + + isEmpty(): Observable { + return this.persistentSubject.pipe( + map((requests) => !requests.length) + ); + } + + total(): Observable { + return this.pageDataSubject.pipe( + map((pageData) => pageData.totalElements) + ); + } +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/rpc/rpc-widgets.module.ts b/ui-ngx/src/app/modules/home/components/widget/lib/rpc/rpc-widgets.module.ts index 330429ce10..a4da8f4b82 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/rpc/rpc-widgets.module.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/rpc/rpc-widgets.module.ts @@ -21,6 +21,10 @@ import { LedIndicatorComponent } from '@home/components/widget/lib/rpc/led-indic import { RoundSwitchComponent } from '@home/components/widget/lib/rpc/round-switch.component'; import { SwitchComponent } from '@home/components/widget/lib/rpc/switch.component'; import { KnobComponent } from '@home/components/widget/lib/rpc/knob.component'; +import { PersistentTableComponent } from '@home/components/widget/lib/rpc/persistent-table.component'; +import { PersistentDetailsDialogComponent } from '@home/components/widget/lib/rpc/persistent-details-dialog.component'; +import { PersistentFilterPanelComponent } from '@home/components/widget/lib/rpc/persistent-filter-panel.component'; +import { PersistentAddDialogComponent } from '@home/components/widget/lib/rpc/persistent-add-dialog.component'; @NgModule({ declarations: @@ -28,7 +32,11 @@ import { KnobComponent } from '@home/components/widget/lib/rpc/knob.component'; LedIndicatorComponent, RoundSwitchComponent, SwitchComponent, - KnobComponent + KnobComponent, + PersistentTableComponent, + PersistentDetailsDialogComponent, + PersistentAddDialogComponent, + PersistentFilterPanelComponent ], imports: [ CommonModule, @@ -38,7 +46,10 @@ import { KnobComponent } from '@home/components/widget/lib/rpc/knob.component'; LedIndicatorComponent, RoundSwitchComponent, SwitchComponent, - KnobComponent + KnobComponent, + PersistentTableComponent, + PersistentDetailsDialogComponent, + PersistentAddDialogComponent ] }) export class RpcWidgetsModule { } diff --git a/ui-ngx/src/app/modules/home/models/widget-component.models.ts b/ui-ngx/src/app/modules/home/models/widget-component.models.ts index 2a530c8b4e..f63f53d032 100644 --- a/ui-ngx/src/app/modules/home/models/widget-component.models.ts +++ b/ui-ngx/src/app/modules/home/models/widget-component.models.ts @@ -196,16 +196,18 @@ export class WidgetContext { }; controlApi: RpcApi = { - sendOneWayCommand: (method, params, timeout, persistent, requestUUID) => { + sendOneWayCommand: (method, params, timeout, persistent, + retries, additionalInfo, requestUUID) => { if (this.defaultSubscription) { - return this.defaultSubscription.sendOneWayCommand(method, params, timeout, persistent, requestUUID); + return this.defaultSubscription.sendOneWayCommand(method, params, timeout, persistent, retries, additionalInfo, requestUUID); } else { return of(null); } }, - sendTwoWayCommand: (method, params, timeout, persistent, requestUUID) => { + sendTwoWayCommand: (method, params, timeout, persistent, + retries, additionalInfo, requestUUID) => { if (this.defaultSubscription) { - return this.defaultSubscription.sendTwoWayCommand(method, params, timeout, persistent, requestUUID); + return this.defaultSubscription.sendTwoWayCommand(method, params, timeout, persistent, retries, additionalInfo, requestUUID); } else { return of(null); } diff --git a/ui-ngx/src/app/shared/components/json-object-view.component.html b/ui-ngx/src/app/shared/components/json-object-view.component.html new file mode 100644 index 0000000000..379c557b44 --- /dev/null +++ b/ui-ngx/src/app/shared/components/json-object-view.component.html @@ -0,0 +1,22 @@ + +
+ + +
+
diff --git a/ui-ngx/src/app/shared/components/json-object-view.component.scss b/ui-ngx/src/app/shared/components/json-object-view.component.scss new file mode 100644 index 0000000000..2b754b0ef2 --- /dev/null +++ b/ui-ngx/src/app/shared/components/json-object-view.component.scss @@ -0,0 +1,27 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +:host { + #tb-json-view { + width: 100%; + height: 100%; + margin-bottom: 16px; + border: 1px solid #c0c0c0; + + &:not(.fill-height) { + min-height: 100px; + } + } +} diff --git a/ui-ngx/src/app/shared/components/json-object-view.component.ts b/ui-ngx/src/app/shared/components/json-object-view.component.ts new file mode 100644 index 0000000000..5ce00b0189 --- /dev/null +++ b/ui-ngx/src/app/shared/components/json-object-view.component.ts @@ -0,0 +1,166 @@ +/// +/// Copyright © 2016-2021 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { Component, ElementRef, forwardRef, Input, OnInit, Renderer2, ViewChild } from '@angular/core'; +import { NG_VALUE_ACCESSOR } from '@angular/forms'; +import { Ace } from 'ace-builds'; +import { coerceBooleanProperty } from '@angular/cdk/coercion'; +import { Store } from '@ngrx/store'; +import { AppState } from '@core/core.state'; +import { RafService } from '@core/services/raf.service'; +import { isDefinedAndNotNull, isUndefined } from '@core/utils'; +import { getAce } from '@shared/models/ace/ace.models'; + +@Component({ + selector: 'tb-json-object-view', + templateUrl: './json-object-view.component.html', + styleUrls: ['./json-object-view.component.scss'], + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => JsonObjectViewComponent), + multi: true + } + ] +}) +export class JsonObjectViewComponent implements OnInit { + + @ViewChild('jsonViewer', {static: true}) + jsonViewerElmRef: ElementRef; + + private jsonViewer: Ace.Editor; + private viewerElement: Ace.Editor; + private propagateChange = null; + private modelValue: any; + private contentValue: string; + + @Input() label: string; + + @Input() fillHeight: boolean; + + @Input() editorStyle: { [klass: string]: any }; + + @Input() sort: (key: string, value: any) => any; + + private widthValue: boolean; + + get autoWidth(): boolean { + return this.widthValue; + } + + @Input() + set autoWidth(value: boolean) { + this.widthValue = coerceBooleanProperty(value); + } + + private heigthValue: boolean; + + get autoHeight(): boolean { + return this.heigthValue; + } + + @Input() + set autoHeight(value: boolean) { + this.heigthValue = coerceBooleanProperty(value); + } + + constructor(public elementRef: ElementRef, + protected store: Store, + private raf: RafService, + private renderer: Renderer2) { + } + + ngOnInit(): void { + this.viewerElement = this.jsonViewerElmRef.nativeElement; + let editorOptions: Partial = { + mode: 'ace/mode/java', + theme: 'ace/theme/github', + showGutter: false, + showPrintMargin: false, + readOnly: true + }; + + const advancedOptions = { + enableSnippets: false, + enableBasicAutocompletion: false, + enableLiveAutocompletion: false + }; + + editorOptions = {...editorOptions, ...advancedOptions}; + getAce().subscribe( + (ace) => { + this.jsonViewer = ace.edit(this.viewerElement, editorOptions); + this.jsonViewer.session.setUseWrapMode(false); + this.jsonViewer.setValue(this.contentValue ? this.contentValue : '', -1); + if (this.contentValue && (this.widthValue || this.heigthValue)) { + this.updateEditorSize(this.viewerElement, this.contentValue, this.jsonViewer); + } + } + ); + } + + updateEditorSize(editorElement: any, content: string, editor: Ace.Editor) { + let newHeight = 200; + let newWidth = 600; + if (content && content.length > 0) { + const lines = content.split('\n'); + newHeight = 17 * lines.length + 17; + let maxLineLength = 0; + lines.forEach((row) => { + const line = row.replace(/\t/g, ' ').replace(/\n/g, ''); + const lineLength = line.length; + maxLineLength = Math.max(maxLineLength, lineLength); + }); + newWidth = 8 * maxLineLength + 16; + } + if (this.heigthValue) { + // this.renderer.setStyle(editorElement, 'minHeight', newHeight.toString() + 'px'); + this.renderer.setStyle(editorElement, 'height', newHeight.toString() + 'px'); + } + if (this.widthValue) { + this.renderer.setStyle(editorElement, 'width', newWidth.toString() + 'px'); + } + editor.resize(); + } + registerOnChange(fn: any): void { + this.propagateChange = fn; + } + + registerOnTouched(fn: any): void { + } + + writeValue(value: any): void { + this.modelValue = value; + this.contentValue = ''; + try { + if (isDefinedAndNotNull(this.modelValue)) { + this.contentValue = JSON.stringify(this.modelValue, isUndefined(this.sort) ? undefined : + (key, objectValue) => { + return this.sort(key, objectValue); + }, 2); + } + } catch (e) { + // + } + if (this.jsonViewer) { + this.jsonViewer.setValue(this.contentValue ? this.contentValue : '', -1); + if (this.contentValue && (this.widthValue || this.heigthValue)) { + this.updateEditorSize(this.viewerElement, this.contentValue, this.jsonViewer); + } + } + } + +} diff --git a/ui-ngx/src/app/shared/models/rpc.models.ts b/ui-ngx/src/app/shared/models/rpc.models.ts index 75ac132394..61a94a401e 100644 --- a/ui-ngx/src/app/shared/models/rpc.models.ts +++ b/ui-ngx/src/app/shared/models/rpc.models.ts @@ -17,15 +17,42 @@ import { TenantId } from '@shared/models/id/tenant-id'; import { RpcId } from '@shared/models/id/rpc-id'; import { DeviceId } from '@shared/models/id/device-id'; +import { TableCellButtonActionDescriptor } from '@home/components/widget/lib/table-widget.models'; export enum RpcStatus { QUEUED = 'QUEUED', DELIVERED = 'DELIVERED', SUCCESSFUL = 'SUCCESSFUL', TIMEOUT = 'TIMEOUT', - FAILED = 'FAILED' + FAILED = 'FAILED', + SENT = 'SENT', + EXPIRED = 'EXPIRED' } +export const rpcStatusColors = new Map( + [ + [RpcStatus.QUEUED, 'black'], + [RpcStatus.DELIVERED, 'green'], + [RpcStatus.SUCCESSFUL, 'green'], + [RpcStatus.TIMEOUT, 'orange'], + [RpcStatus.FAILED, 'red'], + [RpcStatus.SENT, 'green'], + [RpcStatus.EXPIRED, 'red'] + ] +); + +export const rpcStatusTranslation = new Map( + [ + [RpcStatus.QUEUED, 'widgets.persistent-table.rpc-status.QUEUED'], + [RpcStatus.DELIVERED, 'widgets.persistent-table.rpc-status.DELIVERED'], + [RpcStatus.SUCCESSFUL, 'widgets.persistent-table.rpc-status.SUCCESSFUL'], + [RpcStatus.TIMEOUT, 'widgets.persistent-table.rpc-status.TIMEOUT'], + [RpcStatus.FAILED, 'widgets.persistent-table.rpc-status.FAILED'], + [RpcStatus.SENT, 'widgets.persistent-table.rpc-status.SENT'], + [RpcStatus.EXPIRED, 'widgets.persistent-table.rpc-status.EXPIRED'] + ] +); + export interface PersistentRpc { id: RpcId; createdTime: number; @@ -34,7 +61,29 @@ export interface PersistentRpc { response: any; request: { id: string; + oneway: boolean; + body: { + method: string; + params: string; + }; + retries: null | number; }; deviceId: DeviceId; tenantId: TenantId; + additionalInfo?: string; +} + +export interface PersistentRpcData extends PersistentRpc { + actionCellButtons?: TableCellButtonActionDescriptor[]; + hasActions?: boolean; +} + +export interface RequestData { + persistentUpdated: boolean; + method?: string; + oneWayElseTwoWay?: boolean; + persistentPollingInterval?: number; + retries?: number; + params?: object; + additionalInfo?: object; } diff --git a/ui-ngx/src/app/shared/shared.module.ts b/ui-ngx/src/app/shared/shared.module.ts index 90b80393dd..3941dd902a 100644 --- a/ui-ngx/src/app/shared/shared.module.ts +++ b/ui-ngx/src/app/shared/shared.module.ts @@ -94,6 +94,7 @@ import { SocialSharePanelComponent } from '@shared/components/socialshare-panel. import { RelationTypeAutocompleteComponent } from '@shared/components/relation/relation-type-autocomplete.component'; import { EntityListSelectComponent } from '@shared/components/entity/entity-list-select.component'; import { JsonObjectEditComponent } from '@shared/components/json-object-edit.component'; +import { JsonObjectViewComponent, } from '@shared/components/json-object-view.component'; import { FooterFabButtonsComponent } from '@shared/components/footer-fab-buttons.component'; import { CircularProgressDirective } from '@shared/components/circular-progress.directive'; import { @@ -231,6 +232,7 @@ export function MarkedOptionsFactory(markedOptionsService: MarkedOptionsService) RelationTypeAutocompleteComponent, SocialSharePanelComponent, JsonObjectEditComponent, + JsonObjectViewComponent, JsonContentComponent, JsFuncComponent, FabTriggerDirective, @@ -376,6 +378,7 @@ export function MarkedOptionsFactory(markedOptionsService: MarkedOptionsService) RelationTypeAutocompleteComponent, SocialSharePanelComponent, JsonObjectEditComponent, + JsonObjectViewComponent, JsonContentComponent, JsFuncComponent, FabTriggerDirective, diff --git a/ui-ngx/src/assets/locale/locale.constant-en_US.json b/ui-ngx/src/assets/locale/locale.constant-en_US.json index bd14f73e27..79f8e18030 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -3238,7 +3238,49 @@ "update-timeseries": "Update timeseries", "value": "Value" }, - "invalid-qr-code-text": "Invalid input text for QR code. Input should have a string type" + "invalid-qr-code-text": "Invalid input text for QR code. Input should have a string type", + "persistent-table": { + "rpc-id": "RPC ID", + "message-type": "Message type", + "method": "Method", + "params": "Params", + "created-time": "Created time", + "expiration-time": "Expiration time", + "retries": "Retries", + "status": "Status", + "filter": "Filter", + "refresh": "Refresh", + "add": "Add RPC request", + "details": "Details", + "delete": "Delete", + "delete-request-title": "Delete Persistent RPC request", + "delete-request-text": "Are you sure you want to delete request?", + "details-title": "Details RPC ID: ", + "additional-info": "Additional info", + "response": "Response", + "any-status": "Any status", + "rpc-status-list": "RPC status list", + "no-request-prompt": "No request to display", + "send-request": "Send request", + "add-title": "Create Persistent RPC request", + "method-error": "Method is required.", + "timeout-error": "Min timeout value is 5000 (5 seconds).", + "white-space-error": "White space is not allowed.", + "rpc-status": { + "QUEUED": "QUEUED", + "SENT": "SENT", + "DELIVERED": "DELIVERED", + "SUCCESSFUL": "SUCCESSFUL", + "TIMEOUT": "TIMEOUT", + "EXPIRED": "EXPIRED", + "FAILED": "FAILED" + }, + "rpc-search-status-all": "ALL", + "message-types": { + "false": "Two-way", + "true": "One-way" + } + } }, "icon": { "icon": "Icon", diff --git a/ui-ngx/src/assets/locale/locale.constant-ru_RU.json b/ui-ngx/src/assets/locale/locale.constant-ru_RU.json index 66d99281bb..dfc5226d6d 100644 --- a/ui-ngx/src/assets/locale/locale.constant-ru_RU.json +++ b/ui-ngx/src/assets/locale/locale.constant-ru_RU.json @@ -1787,6 +1787,47 @@ "update-attribute": "Обновить атрибут", "update-timeseries": "Обновить телеметрию", "value": "Значение" + }, + "persistent-table": { + "rpc-id": "RPC ID", + "message-type": "Тип сообщения", + "method": "Метод", + "params": "Параметры", + "created-time": "Время создания", + "expiration-time": "Время жизни", + "retries": "Повторные попытки", + "status": "Статус", + "filter": "Фильтр", + "refresh": "Обновить", + "add": "Добавить RPC запрос", + "details": "Детали", + "delete": "Удалить", + "delete-request-title": "Удалить RPC запрос", + "delete-request-text": "Вы точно хотите удалить RPC запрос?", + "details-title": "Детали RPC ID: ", + "additional-info": "Дополнительная информация", + "response": "Ответ", + "any-status": "Любой статус", + "rpc-status-list": "Список RPC статусов", + "no-request-prompt": "Запросы не найдены", + "send-request": "Отправить запрос", + "add-title": "Добавить новый RPC запрос", + "method-error": "Метод обязателен.", + "white-space-error": "Пробелы не допускаются.", + "rpc-status": { + "QUEUED": "В ОЧЕРЕДИ", + "SENT": "ОТПРАВЛЕННО", + "DELIVERED": "ДОСТАВЛЕННО", + "SUCCESSFUL": "УСПЕШНО", + "TIMEOUT": "ВРЕМЯ ИСТЕКЛО", + "EXPIRED": "ПРОСРОЧЕНО", + "FAILED": "НЕУДАЧНО" + }, + "rpc-search-status-all": "ВСЕ", + "message-types": { + "false": "Двусторонний", + "true": "Односторонний" + } } }, "icon": { diff --git a/ui-ngx/src/assets/locale/locale.constant-uk_UA.json b/ui-ngx/src/assets/locale/locale.constant-uk_UA.json index 43691918dd..be31aa7375 100644 --- a/ui-ngx/src/assets/locale/locale.constant-uk_UA.json +++ b/ui-ngx/src/assets/locale/locale.constant-uk_UA.json @@ -2359,6 +2359,47 @@ "update-attribute": "Оновити атрибут", "update-timeseries": "Оновити телеметрію", "value": "Значення" + }, + "persistent-table": { + "rpc-id": "RPC ID", + "message-type": "Тип повідомлення", + "method": "Метод", + "params": "Параметри", + "created-time": "Час створення", + "expiration-time": "Час життя", + "retries": "Повторні спроби", + "status": "Статус", + "filter": "Фільтр", + "refresh": "Оновити", + "add": "Додати RPC запит", + "details": "Деталі", + "delete": "Видалити", + "delete-request-title": "Видалити RPC запит", + "delete-request-text": "Ви впевнені, що хочете видалити RPC запит?", + "details-title": "Деталі RPC ID: ", + "additional-info": "Додаткова інформація", + "response": "Відповідь", + "any-status": "Будь-який статус", + "rpc-status-list": "Список RPC статусів", + "no-request-prompt": "Запитів не знайдено", + "send-request": "Відправити запит", + "add-title": "Додати новий RPC запит", + "method-error": "Необхідно вказати метод.", + "white-space-error": "Пробіли не допускаються.", + "rpc-status": { + "QUEUED": "В ЧЕРЗІ", + "SENT": "ВІДПРАВЛЕНО", + "DELIVERED": "ДОСТАВЛЕННО", + "SUCCESSFUL": "УСПІШНО", + "TIMEOUT": "ЧАС МИНУВ", + "EXPIRED": "ПРОСРОЧЕНО", + "FAILED": "НЕ ВДАЛО" + }, + "rpc-search-status-all": "ВСІ", + "message-types": { + "false": "Двусторонній", + "true": "Односторонній" + } } }, "white-labeling": { From f9aab73e92c3ef917da0b6898a95f627182eafe9 Mon Sep 17 00:00:00 2001 From: Sergey Tarnavskiy Date: Fri, 26 Nov 2021 17:53:06 +0200 Subject: [PATCH 156/432] Added new option for including Bootstrap Serer updates --- ...2mDeviceProfileTransportConfiguration.java | 1 + .../dao/device/DeviceProfileServiceImpl.java | 4 ++ ...2m-bootstrap-config-servers.component.html | 2 +- ...wm2m-bootstrap-config-servers.component.ts | 22 ++++++++- ...ile-transport-configuration.component.html | 6 ++- ...ofile-transport-configuration.component.ts | 46 ++++++++++++++++++- .../lwm2m/lwm2m-profile-config.models.ts | 1 + .../assets/locale/locale.constant-en_US.json | 3 ++ 8 files changed, 80 insertions(+), 5 deletions(-) diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/Lwm2mDeviceProfileTransportConfiguration.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/Lwm2mDeviceProfileTransportConfiguration.java index 0c1441f031..08ad7acf5a 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/Lwm2mDeviceProfileTransportConfiguration.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/Lwm2mDeviceProfileTransportConfiguration.java @@ -29,6 +29,7 @@ public class Lwm2mDeviceProfileTransportConfiguration implements DeviceProfileTr private static final long serialVersionUID = 6257277825459600068L; private TelemetryMappingConfiguration observeAttr; + private boolean bootstrapServerUpdateEnable; private List bootstrap; private OtherConfiguration clientLwM2mSettings; diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java index fc901abd35..a9bc2401c4 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java @@ -709,12 +709,16 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D private void validateLwm2mServersConfigOfBootstrapForClient(List lwM2MBootstrapServersConfigurations) { Set uris = new HashSet<>(); + Set shortServerIds = new HashSet<>(); for (LwM2MBootstrapServerCredential bootstrapServerCredential : lwM2MBootstrapServersConfigurations) { AbstractLwM2MBootstrapServerCredential serverConfig = (AbstractLwM2MBootstrapServerCredential) bootstrapServerCredential; String server = serverConfig.isBootstrapServerIs() ? "Bootstrap Server" : "LwM2M Server" + " shortServerId: " + serverConfig.getShortServerId() + ":"; if (serverConfig.getShortServerId() < 1 || serverConfig.getShortServerId() > 65534) { throw new DeviceCredentialsValidationException(server + " ShortServerId must not be less than 1 and more than 65534!"); } + if (!shortServerIds.add(serverConfig.getShortServerId())){ + throw new DeviceCredentialsValidationException(server + " \"Short server Id\" value = " + serverConfig.getShortServerId() + ". This value must be a unique value for all servers!"); + }; String uri = serverConfig.getHost() + ":" + serverConfig.getPort(); if (!uris.add(uri)){ throw new DeviceCredentialsValidationException(server + " \"Host + port\" value = " + uri + ". This value must be a unique value for all servers!"); diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-bootstrap-config-servers.component.html b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-bootstrap-config-servers.component.html index cd00d1661a..ebd80ef558 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-bootstrap-config-servers.component.html +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-bootstrap-config-servers.component.html @@ -32,7 +32,7 @@
diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-bootstrap-config-servers.component.ts b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-bootstrap-config-servers.component.ts index a4bf5d4958..9230195efe 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-bootstrap-config-servers.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-bootstrap-config-servers.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, forwardRef, Input, OnInit } from '@angular/core'; +import { ChangeDetectorRef, Component, forwardRef, Input, OnInit } from '@angular/core'; import { AbstractControl, ControlValueAccessor, @@ -57,6 +57,15 @@ export class Lwm2mBootstrapConfigServersComponent implements OnInit, ControlValu @Input() disabled: boolean; + public isBootstrapServerUpdateEnableValue: boolean; + @Input() + set isBootstrapServerUpdateEnable(value: boolean) { + this.isBootstrapServerUpdateEnableValue = value; + if (!value) { + this.removeBootstrapServerConfig(); + } + } + private valueChangeSubscription: Subscription = null; private propagateChange = (v: any) => { }; @@ -138,7 +147,7 @@ export class Lwm2mBootstrapConfigServersComponent implements OnInit, ControlValu } addServerConfig(): void { - const addDialogObs = this.isBootstrapAdded() ? of(false) : + const addDialogObs = (this.isBootstrapAdded() || !this.isBootstrapServerUpdateEnableValue) ? of(false) : this.matDialog.open(Lwm2mBootstrapAddConfigServerDialogComponent, { disableClose: true, panelClass: ['tb-dialog', 'tb-fullscreen-dialog'] @@ -178,6 +187,15 @@ export class Lwm2mBootstrapConfigServersComponent implements OnInit, ControlValu return false; } + private removeBootstrapServerConfig(): void { + if (this.bootstrapConfigServersFormGroup) { + const bootstrapServerIndex = this.serverConfigsFromArray().getRawValue().findIndex(server => server.bootstrapServerIs === true); + if (bootstrapServerIndex !== -1) { + this.serverConfigsFromArray().removeAt(bootstrapServerIndex); + } + } + } + private updateModel() { const serverConfigs: Array = this.serverConfigsFromArray().value; this.propagateChange(serverConfigs); diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.html b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.html index 20cbd63168..05643ae497 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.html +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.html @@ -33,8 +33,12 @@
+ + {{ 'device-profile.lwm2m.include-bootstrap-server' | translate }} +
- +
diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts index d16a0eafca..d8fc933fdb 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts @@ -52,6 +52,8 @@ import _ from 'lodash'; import { Subject } from 'rxjs'; import { takeUntil } from 'rxjs/operators'; import { Lwm2mSecurityType } from '@shared/models/lwm2m-security-config.models'; +import { DialogService } from '@core/services/dialog.service'; +import { TranslateService } from '@ngx-translate/core'; @Component({ selector: 'tb-profile-lwm2m-device-transport-configuration', @@ -72,6 +74,7 @@ import { Lwm2mSecurityType } from '@shared/models/lwm2m-security-config.models'; export class Lwm2mDeviceProfileTransportConfigurationComponent implements ControlValueAccessor, Validator, OnDestroy { public disabled = false; + public isBootstrapServerUpdateEnable: boolean; private requiredValue: boolean; private destroy$ = new Subject(); @@ -94,12 +97,15 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro private propagateChange = (v: any) => { } - constructor(private fb: FormBuilder, + constructor(public translate: TranslateService, + private fb: FormBuilder, private cd: ChangeDetectorRef, + private dialogService: DialogService, private deviceProfileService: DeviceProfileService) { this.lwm2mDeviceProfileFormGroup = this.fb.group({ objectIds: [null], observeAttrTelemetry: [null], + bootstrapServerUpdateEnable: [false], bootstrap: [[]], clientLwM2mSettings: this.fb.group({ clientOnlyObserveAfterConnect: [1, []], @@ -114,6 +120,7 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro compositeOperationsSupport: [false] }) }); + this.lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.fwUpdateStrategy').valueChanges.pipe( takeUntil(this.destroy$) ).subscribe((fwStrategy) => { @@ -125,6 +132,7 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro .reset(DEFAULT_FW_UPDATE_RESOURCE, {emitEvent: false}); } }); + this.lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.swUpdateStrategy').valueChanges.pipe( takeUntil(this.destroy$) ).subscribe((swStrategy) => { @@ -136,6 +144,39 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro .reset(DEFAULT_SW_UPDATE_RESOURCE, {emitEvent: false}); } }); + + this.lwm2mDeviceProfileFormGroup.get('bootstrapServerUpdateEnable').valueChanges.pipe( + takeUntil(this.destroy$) + ).subscribe((value) => { + if (!value) { + const bootstrap = this.lwm2mDeviceProfileFormGroup.get('bootstrap').value; + const bootstrapResultArray = bootstrap.filter(server => server.bootstrapServerIs === true); + if (bootstrapResultArray.length) { + this.dialogService.confirm( + this.translate.instant('device-profile.lwm2m.bootstrap-update-title'), + this.translate.instant('device-profile.lwm2m.bootstrap-update-text'), + this.translate.instant('action.no'), + this.translate.instant('action.yes'), + ).pipe( + takeUntil(this.destroy$) + ).subscribe((result) => { + if (result) { + this.isBootstrapServerUpdateEnable = value; + } else { + this.lwm2mDeviceProfileFormGroup.patchValue({ + bootstrapServerUpdateEnable: true + }, {emitEvent: true}); + } + this.cd.markForCheck(); + }); + } else { + this.isBootstrapServerUpdateEnable = value; + } + } else { + this.isBootstrapServerUpdateEnable = value; + } + }); + this.lwm2mDeviceProfileFormGroup.valueChanges.pipe( takeUntil(this.destroy$) ).subscribe((value) => { @@ -217,6 +258,7 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro objectIds: value, observeAttrTelemetry: this.getObserveAttrTelemetryObjects(value), bootstrap: this.configurationValue.bootstrap, + bootstrapServerUpdateEnable: this.configurationValue.bootstrapServerUpdateEnable || false, clientLwM2mSettings: { clientOnlyObserveAfterConnect: this.configurationValue.clientLwM2mSettings.clientOnlyObserveAfterConnect, fwUpdateStrategy: this.configurationValue.clientLwM2mSettings.fwUpdateStrategy || 1, @@ -232,6 +274,7 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro } }, {emitEvent: false}); + this.isBootstrapServerUpdateEnable = this.configurationValue.bootstrapServerUpdateEnable || false; if (!this.disabled) { this.lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.powerMode').updateValueAndValidity({onlySelf: true}); this.lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.fwUpdateStrategy').updateValueAndValidity({onlySelf: true}); @@ -261,6 +304,7 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro } this.configurationValue.bootstrap = config.bootstrap; this.configurationValue.clientLwM2mSettings = config.clientLwM2mSettings; + this.configurationValue.bootstrapServerUpdateEnable = config.bootstrapServerUpdateEnable; this.updateModel(); } diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-profile-config.models.ts b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-profile-config.models.ts index 543c000e12..56ae00c5a9 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-profile-config.models.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-profile-config.models.ts @@ -148,6 +148,7 @@ export interface ServerSecurityConfigInfo extends ServerSecurityConfig { export interface Lwm2mProfileConfigModels { clientLwM2mSettings: ClientLwM2mSettings; observeAttr: ObservableAttributes; + bootstrapServerUpdateEnable: boolean; bootstrap: Array; } diff --git a/ui-ngx/src/assets/locale/locale.constant-en_US.json b/ui-ngx/src/assets/locale/locale.constant-en_US.json index 7bdc11c479..b9ca3a3ad7 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -1348,6 +1348,9 @@ "binding-tooltip": "Tis is the list in the\"binding\" resource of the LwM2M server object - /1/x/7.\nIndicates the supported binding modes in the LwM2M Client.\nThis value SHOULD be the same as the value in the “Supported Binding and Modes” resource in the Device Object (/3/0/16).\nWhile multiple transports are supported, only one transport binding can be used during the entire Transport Session.\nAs an example, when UDP and SMS are both supported, the LwM2M Client and the LwM2M Server can choose to communicate either over UDP or SMS during the entire Transport Session.", "bootstrap-server": "Bootstrap Server", "lwm2m-server": "LwM2M Server", + "include-bootstrap-server": "Include Bootstrap Server updates", + "bootstrap-update-title": "You already have configured Bootstrap Server. Are you sure you want to exclude the updates?", + "bootstrap-update-text": "Be careful, after the confirmation the Bootstrap Server configuration data will become unrecoverable.", "server-host": "Host", "server-host-required": "Host is required.", "server-port": "Port", From 4117d9c558cc3573972ba7e81b791d58c5c965c2 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Fri, 26 Nov 2021 23:08:32 +0200 Subject: [PATCH 157/432] lwm2m - includes bootstrap update --- .../store/LwM2MConfigurationChecker.java | 83 +++++++++++++++++++ .../LwM2MInMemoryBootstrapConfigStore.java | 24 +++++- 2 files changed, 106 insertions(+), 1 deletion(-) create mode 100644 common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MConfigurationChecker.java diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MConfigurationChecker.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MConfigurationChecker.java new file mode 100644 index 0000000000..d27ec707c2 --- /dev/null +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MConfigurationChecker.java @@ -0,0 +1,83 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.transport.lwm2m.bootstrap.store; + +import org.eclipse.leshan.server.bootstrap.BootstrapConfig; +import org.eclipse.leshan.server.bootstrap.ConfigurationChecker; +import org.eclipse.leshan.server.bootstrap.InvalidConfigurationException; +import java.util.Map; + +public class LwM2MConfigurationChecker extends ConfigurationChecker { + + @Override + public void verify(BootstrapConfig config) throws InvalidConfigurationException { + // check security configurations + for (Map.Entry e : config.security.entrySet()) { + BootstrapConfig.ServerSecurity sec = e.getValue(); + + // checks security config + switch (sec.securityMode) { + case NO_SEC: + checkNoSec(sec); + break; + case PSK: + checkPSK(sec); + break; + case RPK: + checkRPK(sec); + break; + case X509: + checkX509(sec); + break; + case EST: + throw new InvalidConfigurationException("EST is not currently supported.", e); + } + + validateMandatoryField(sec); + } + + // does each server have a corresponding security entry? + validateOneSecurityByServer(config); + } + + protected void validateOneSecurityByServer(BootstrapConfig config) throws InvalidConfigurationException { + for (Map.Entry e : config.servers.entrySet()) { + BootstrapConfig.ServerConfig srvCfg = e.getValue(); + + // shortId checks + if (srvCfg.shortId == 0) { + throw new InvalidConfigurationException("short ID must not be 0"); + } + + // look for security entry + BootstrapConfig.ServerSecurity security = getSecurityEntry(config, srvCfg.shortId); + + if (security == null) { + throw new InvalidConfigurationException("no security entry for server instance: " + e.getKey()); + } + } + } + + protected static BootstrapConfig.ServerSecurity getSecurityEntry(BootstrapConfig config, int shortId) { + for (Map.Entry es : config.security.entrySet()) { + if (es.getValue().serverId == shortId) { + return es.getValue(); + } + } + return null; + } + +} \ No newline at end of file diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MInMemoryBootstrapConfigStore.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MInMemoryBootstrapConfigStore.java index 2fa470a58e..485a8946f7 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MInMemoryBootstrapConfigStore.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MInMemoryBootstrapConfigStore.java @@ -19,6 +19,7 @@ import lombok.extern.slf4j.Slf4j; import org.eclipse.leshan.core.request.Identity; import org.eclipse.leshan.server.bootstrap.BootstrapConfig; import org.eclipse.leshan.server.bootstrap.BootstrapSession; +import org.eclipse.leshan.server.bootstrap.ConfigurationChecker; import org.eclipse.leshan.server.bootstrap.InMemoryBootstrapConfigStore; import org.eclipse.leshan.server.bootstrap.InvalidConfigurationException; import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; @@ -36,6 +37,7 @@ public class LwM2MInMemoryBootstrapConfigStore extends InMemoryBootstrapConfigSt private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock(); private final Lock readLock = readWriteLock.readLock(); private final Lock writeLock = readWriteLock.writeLock(); + protected final ConfigurationChecker configChecker = new LwM2MConfigurationChecker(); @Override public BootstrapConfig get(String endpoint, Identity deviceIdentity, BootstrapSession session) { @@ -73,6 +75,26 @@ public class LwM2MInMemoryBootstrapConfigStore extends InMemoryBootstrapConfigSt } public void addToStore(String endpoint, BootstrapConfig config) throws InvalidConfigurationException { - super.add(endpoint, config); + + configChecker.verify(config); + // Check PSK identity uniqueness for bootstrap server: + PskByServer pskToAdd = getBootstrapPskIdentity(config); + if (pskToAdd != null) { + BootstrapConfig existingConfig = bootstrapByPskId.get(pskToAdd); + if (existingConfig != null) { + // check if this config will be replace by the new one. + BootstrapConfig previousConfig = bootstrapByEndpoint.get(endpoint); + if (previousConfig != existingConfig) { + throw new InvalidConfigurationException( + "Psk identity [%s] already used for this bootstrap server [%s]", pskToAdd.identity, + pskToAdd.serverUrl); + } + } + } + + bootstrapByEndpoint.put(endpoint, config); + if (pskToAdd != null) { + bootstrapByPskId.put(pskToAdd, config); + } } } From 5ce9264d070bf2cbbd04ce7160bb2d13dfb2dacb Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Sat, 27 Nov 2021 00:35:07 +0200 Subject: [PATCH 158/432] lwm2m - delete config bootstrap server if need --- .../store/LwM2MBootstrapSecurityStore.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MBootstrapSecurityStore.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MBootstrapSecurityStore.java index 5c1669fcf3..74e5061166 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MBootstrapSecurityStore.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MBootstrapSecurityStore.java @@ -24,6 +24,7 @@ import org.eclipse.leshan.server.security.SecurityInfo; import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.stereotype.Service; import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MSecurityMode; +import org.thingsboard.server.common.data.device.profile.Lwm2mDeviceProfileTransportConfiguration; import org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap.AbstractLwM2MBootstrapServerCredential; import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.transport.lwm2m.bootstrap.secure.LwM2MBootstrapConfig; @@ -36,6 +37,7 @@ import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportServerHelper; import java.util.Collections; import java.util.Iterator; import java.util.Map; +import java.util.Optional; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicBoolean; @@ -75,6 +77,18 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore { BootstrapConfig bsConfigNew = store.getBootstrapConfig(); if (bsConfigNew != null) { try { + boolean bootstrapServerUpdateEnable = ((Lwm2mDeviceProfileTransportConfiguration)store.getDeviceProfile().getProfileData().getTransportConfiguration()).isBootstrapServerUpdateEnable(); + if (!bootstrapServerUpdateEnable) { + Optional> securities = bsConfigNew.security.entrySet().stream().filter(sec -> ((BootstrapConfig.ServerSecurity)sec.getValue()).bootstrapServer==true).findAny(); + if (securities.isPresent()) { + bsConfigNew.security.entrySet().remove(securities.get()); + int serverSortId = securities.get().getValue().serverId; + Optional> serverConfigs = bsConfigNew.servers.entrySet().stream().filter(serv -> ((BootstrapConfig.ServerConfig)serv.getValue()).shortId==serverSortId).findAny(); + if (serverConfigs.isPresent()) { + bsConfigNew.servers.entrySet().remove(serverConfigs.get()); + } + } + } for (String config : bootstrapConfigStore.getAll().keySet()) { if (config.equals(endPoint)) { bootstrapConfigStore.remove(config); From f49f99fac58f07cdc91fa690b3e38bbd1710be41 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Sat, 27 Nov 2021 09:09:38 +0200 Subject: [PATCH 159/432] lwm2m - config bootstrap server if need add validation Bootstrap Server Update Enable --- .../server/dao/device/DeviceProfileServiceImpl.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java index a9bc2401c4..18a8a1ecde 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java @@ -420,7 +420,8 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D } } else if (transportConfiguration instanceof Lwm2mDeviceProfileTransportConfiguration) { List lwM2MBootstrapServersConfigurations = ((Lwm2mDeviceProfileTransportConfiguration) transportConfiguration).getBootstrap(); - validateLwm2mServersConfigOfBootstrapForClient(lwM2MBootstrapServersConfigurations); + validateLwm2mServersConfigOfBootstrapForClient(lwM2MBootstrapServersConfigurations, + ((Lwm2mDeviceProfileTransportConfiguration) transportConfiguration).isBootstrapServerUpdateEnable()); for (LwM2MBootstrapServerCredential bootstrapServerCredential : lwM2MBootstrapServersConfigurations) { validateLwm2mServersCredentialOfBootstrapForClient(bootstrapServerCredential); } @@ -707,11 +708,14 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D } } - private void validateLwm2mServersConfigOfBootstrapForClient(List lwM2MBootstrapServersConfigurations) { + private void validateLwm2mServersConfigOfBootstrapForClient(List lwM2MBootstrapServersConfigurations, boolean isBootstrapServerUpdateEnable) { Set uris = new HashSet<>(); Set shortServerIds = new HashSet<>(); for (LwM2MBootstrapServerCredential bootstrapServerCredential : lwM2MBootstrapServersConfigurations) { AbstractLwM2MBootstrapServerCredential serverConfig = (AbstractLwM2MBootstrapServerCredential) bootstrapServerCredential; + if (!isBootstrapServerUpdateEnable && serverConfig.isBootstrapServerIs()) { + throw new DeviceCredentialsValidationException("Bootstrap config must not include \"Bootstrap Server\". \"Include Bootstrap Server updates\" is " + isBootstrapServerUpdateEnable + "." ); + } String server = serverConfig.isBootstrapServerIs() ? "Bootstrap Server" : "LwM2M Server" + " shortServerId: " + serverConfig.getShortServerId() + ":"; if (serverConfig.getShortServerId() < 1 || serverConfig.getShortServerId() > 65534) { throw new DeviceCredentialsValidationException(server + " ShortServerId must not be less than 1 and more than 65534!"); From 947fbc3abfd471a4977e9f6da09562e0ff80e6d0 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Sun, 28 Nov 2021 20:03:16 +0200 Subject: [PATCH 160/432] lwm2m - fix bug tests --- .../server/transport/lwm2m/AbstractLwM2MIntegrationTest.java | 1 + .../server/transport/lwm2m/ota/sql/OtaLwM2MIntegrationTest.java | 1 + .../transport/lwm2m/rpc/AbstractRpcLwM2MIntegrationTest.java | 1 + 3 files changed, 3 insertions(+) diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/AbstractLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/AbstractLwM2MIntegrationTest.java index 7c8e8e64ab..cb276b3fdc 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/AbstractLwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/AbstractLwM2MIntegrationTest.java @@ -82,6 +82,7 @@ public abstract class AbstractLwM2MIntegrationTest extends AbstractWebsocketTest " ],\n" + " \"attributeLwm2m\": {}\n" + " },\n" + + " \"bootstrapServerUpdateEnable\": true,\n" + " \"bootstrap\": [\n" + " {\n" + " \"host\": \"0.0.0.0\",\n" + diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/ota/sql/OtaLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/ota/sql/OtaLwM2MIntegrationTest.java index ae1ef48235..903750663a 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/ota/sql/OtaLwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/ota/sql/OtaLwM2MIntegrationTest.java @@ -92,6 +92,7 @@ public class OtaLwM2MIntegrationTest extends AbstractOtaLwM2MIntegrationTest { " ],\n" + " \"attributeLwm2m\": {}\n" + " },\n" + + " \"bootstrapServerUpdateEnable\": true,\n" + " \"bootstrap\": [\n" + " {\n" + " \"host\": \"0.0.0.0\",\n" + diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/AbstractRpcLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/AbstractRpcLwM2MIntegrationTest.java index 6f4a520295..95878b74d1 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/AbstractRpcLwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/AbstractRpcLwM2MIntegrationTest.java @@ -142,6 +142,7 @@ public abstract class AbstractRpcLwM2MIntegrationTest extends AbstractLwM2MInteg " ],\n" + " \"attributeLwm2m\": {}\n" + " },\n" + + " \"bootstrapServerUpdateEnable\": true,\n" + " \"bootstrap\": [\n" + " {\n" + " \"host\": \"0.0.0.0\",\n" + From 089ede676d7822e22912439630fb2abc26cab91a Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Mon, 29 Nov 2021 11:18:22 +0200 Subject: [PATCH 161/432] lwm2m - from 3.3.2 to 3.3.3 add to profile bootstrapServerUpdateEnable": true --- .../3.3.2/schema_update_lwm2m_bootstrap.sql | 99 ++++++++++--------- 1 file changed, 55 insertions(+), 44 deletions(-) diff --git a/application/src/main/data/upgrade/3.3.2/schema_update_lwm2m_bootstrap.sql b/application/src/main/data/upgrade/3.3.2/schema_update_lwm2m_bootstrap.sql index f21d895eb9..a182bc8117 100644 --- a/application/src/main/data/upgrade/3.3.2/schema_update_lwm2m_bootstrap.sql +++ b/application/src/main/data/upgrade/3.3.2/schema_update_lwm2m_bootstrap.sql @@ -20,15 +20,15 @@ $$ BEGIN -UPDATE device_profile -SET profile_data = jsonb_set( - profile_data, - '{transportConfiguration, bootstrap}', - get_bootstrap( - profile_data::jsonb #> '{transportConfiguration,bootstrap}', - subquery.publickey_bs, - subquery.publickey_lw), - true) + UPDATE device_profile + SET profile_data = jsonb_set( + profile_data, + '{transportConfiguration}', + get_bootstrap( + profile_data::jsonb #> '{transportConfiguration}', + subquery.publickey_bs, + subquery.publickey_lw), + true) FROM ( SELECT id, encode( @@ -40,47 +40,58 @@ SET profile_data = jsonb_set( FROM device_profile WHERE transport_type = 'LWM2M' ) AS subquery -WHERE device_profile.id = subquery.id - AND subquery.publickey_bs IS NOT NULL - AND subquery.publickey_lw IS NOT NULL; + WHERE device_profile.id = subquery.id + AND subquery.publickey_bs IS NOT NULL + AND subquery.publickey_lw IS NOT NULL; END; $$; -CREATE OR REPLACE FUNCTION get_bootstrap(bootstrap_in jsonb, publickey_bs text, publickey_lw text) RETURNS jsonb AS +CREATE OR REPLACE FUNCTION get_bootstrap(transport_configuration_in jsonb, publickey_bs text, + publickey_lw text) RETURNS jsonb AS $$ -BEGIN -RETURN json_build_array( - json_build_object('shortServerId', bootstrap_in::json #> '{bootstrapServer}' -> 'serverId', - 'securityMode', bootstrap_in::json #> '{bootstrapServer}' ->> 'securityMode', - 'binding', bootstrap_in::json #> '{servers}' ->> 'binding', - 'lifetime', bootstrap_in::json #> '{servers}' -> 'lifetime', - 'notifIfDisabled', bootstrap_in::json #> '{servers}' -> 'notifIfDisabled', - 'defaultMinPeriod', bootstrap_in::json #> '{servers}' -> 'defaultMinPeriod', - 'host', bootstrap_in::json #> '{bootstrapServer}' ->> 'host', - 'port', bootstrap_in::json #> '{bootstrapServer}' -> 'port', - 'serverPublicKey', publickey_bs, - 'bootstrapServerIs', true, - 'clientHoldOffTime', bootstrap_in::json #> '{bootstrapServer}' -> 'clientHoldOffTime', - 'bootstrapServerAccountTimeout', - bootstrap_in::json #> '{bootstrapServer}' -> 'bootstrapServerAccountTimeout' - ), - json_build_object('shortServerId', bootstrap_in::json #> '{lwm2mServer}' -> 'serverId', - 'securityMode', bootstrap_in::json #> '{lwm2mServer}' ->> 'securityMode', - 'binding', bootstrap_in::json #> '{servers}' ->> 'binding', - 'lifetime', bootstrap_in::json #> '{servers}' -> 'lifetime', - 'notifIfDisabled', bootstrap_in::json #> '{servers}' -> 'notifIfDisabled', - 'defaultMinPeriod', bootstrap_in::json #> '{servers}' -> 'defaultMinPeriod', - 'host', bootstrap_in::json #> '{lwm2mServer}' ->> 'host', - 'port', bootstrap_in::json #> '{lwm2mServer}' -> 'port', - 'serverPublicKey', publickey_lw, - 'bootstrapServerIs', false, - 'clientHoldOffTime', bootstrap_in::json #> '{lwm2mServer}' -> 'clientHoldOffTime', - 'bootstrapServerAccountTimeout', - bootstrap_in::json #> '{lwm2mServer}' -> 'bootstrapServerAccountTimeout' - ) - ); +DECLARE + bootstrap_new jsonb; + bootstrap_in jsonb; + +BEGIN + bootstrap_in := transport_configuration_in::jsonb #> '{bootstrap}'; + bootstrap_new := json_build_array( + json_build_object('shortServerId', bootstrap_in::json #> '{bootstrapServer}' -> 'serverId', + 'securityMode', bootstrap_in::json #> '{bootstrapServer}' ->> 'securityMode', + 'binding', bootstrap_in::json #> '{servers}' ->> 'binding', + 'lifetime', bootstrap_in::json #> '{servers}' -> 'lifetime', + 'notifIfDisabled', bootstrap_in::json #> '{servers}' -> 'notifIfDisabled', + 'defaultMinPeriod', bootstrap_in::json #> '{servers}' -> 'defaultMinPeriod', + 'host', bootstrap_in::json #> '{bootstrapServer}' ->> 'host', + 'port', bootstrap_in::json #> '{bootstrapServer}' -> 'port', + 'serverPublicKey', publickey_bs, + 'bootstrapServerIs', true, + 'clientHoldOffTime', bootstrap_in::json #> '{bootstrapServer}' -> 'clientHoldOffTime', + 'bootstrapServerAccountTimeout', + bootstrap_in::json #> '{bootstrapServer}' -> 'bootstrapServerAccountTimeout' + ), + json_build_object('shortServerId', bootstrap_in::json #> '{lwm2mServer}' -> 'serverId', + 'securityMode', bootstrap_in::json #> '{lwm2mServer}' ->> 'securityMode', + 'binding', bootstrap_in::json #> '{servers}' ->> 'binding', + 'lifetime', bootstrap_in::json #> '{servers}' -> 'lifetime', + 'notifIfDisabled', bootstrap_in::json #> '{servers}' -> 'notifIfDisabled', + 'defaultMinPeriod', bootstrap_in::json #> '{servers}' -> 'defaultMinPeriod', + 'host', bootstrap_in::json #> '{lwm2mServer}' ->> 'host', + 'port', bootstrap_in::json #> '{lwm2mServer}' -> 'port', + 'serverPublicKey', publickey_lw, + 'bootstrapServerIs', false, + 'clientHoldOffTime', bootstrap_in::json #> '{lwm2mServer}' -> 'clientHoldOffTime', + 'bootstrapServerAccountTimeout', + bootstrap_in::json #> '{lwm2mServer}' -> 'bootstrapServerAccountTimeout' + ) + ); + RETURN jsonb_set( + transport_configuration_in, + '{bootstrap}', + bootstrap_new, + true) || '{"bootstrapServerUpdateEnable": true}'; END ; $$ LANGUAGE plpgsql; From bdb7d0905d36927dfcf77a7ecb1b7192bc9f5cb2 Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Mon, 29 Nov 2021 11:42:41 +0200 Subject: [PATCH 162/432] UI: Fixed incorrect URL for default marker icon in maps widget --- .../app/modules/home/components/widget/lib/maps/leaflet-map.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts index 5db9db2e9e..db62775c40 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts @@ -91,6 +91,7 @@ export default abstract class LeafletMap { options: UnitedMapSettings) { this.options = options; this.editPolygons = options.showPolygon && options.editablePolygon; + L.Icon.Default.imagePath = '/'; } public initSettings(options: MapSettings) { From 4f342b596155496012dd6db39e399ae4b6885f45 Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Mon, 29 Nov 2021 12:00:34 +0200 Subject: [PATCH 163/432] UI: Fixed widgets maps backward compatibility for save location --- .../modules/home/components/widget/lib/maps/map-widget2.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-widget2.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-widget2.ts index 21c576eeb1..a2385b2877 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-widget2.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-widget2.ts @@ -70,9 +70,9 @@ export class MapWidgetController implements MapWidgetInterface { parseWithTranslation.setTranslate(this.translate); this.map = new MapClass(this.ctx, $element, this.settings); (this.ctx as any).mapInstance = this.map; - this.map.saveMarkerLocation = this.setMarkerLocation; - this.map.savePolygonLocation = this.savePolygonLocation; - this.map.saveLocation = this.saveLocation; + this.map.saveMarkerLocation = this.setMarkerLocation.bind(this); + this.map.savePolygonLocation = this.savePolygonLocation.bind(this); + this.map.saveLocation = this.saveLocation.bind(this); this.pageLink = { page: 0, pageSize: this.settings.mapPageSize, From 74340e56d7250f0bf3cdb83a7620373f563d345c Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Mon, 29 Nov 2021 12:08:43 +0200 Subject: [PATCH 164/432] lwm2m - add info from Enum --- .../lwm2m/server/ota/DefaultLwM2MOtaUpdateService.java | 6 ++++-- .../lwm2m/server/ota/firmware/FirmwareUpdateState.java | 8 ++++++-- .../lwm2m/server/ota/software/SoftwareUpdateResult.java | 8 +++++--- .../lwm2m/server/ota/software/SoftwareUpdateState.java | 8 ++++++-- .../server/transport/lwm2m/utils/LwM2MTransportUtil.java | 6 +++--- 5 files changed, 24 insertions(+), 12 deletions(-) diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/DefaultLwM2MOtaUpdateService.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/DefaultLwM2MOtaUpdateService.java index 66903d8812..5fda8f87a9 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/DefaultLwM2MOtaUpdateService.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/DefaultLwM2MOtaUpdateService.java @@ -74,6 +74,8 @@ import static org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus.UPDA import static org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus.UPDATING; import static org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus.VERIFIED; import static org.thingsboard.server.common.data.ota.OtaPackageUtil.getAttributeKey; +import static org.thingsboard.server.transport.lwm2m.server.ota.firmware.FirmwareUpdateResult.UPDATE_SUCCESSFULLY; +import static org.thingsboard.server.transport.lwm2m.server.ota.software.SoftwareUpdateResult.NOT_ENOUGH_STORAGE; import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.LOG_LWM2M_TELEMETRY; import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.convertObjectIdToVersionedId; @@ -399,7 +401,7 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl log.debug("[{}] Starting update to [{}{}] using binary", client.getEndpoint(), fwInfo.getTargetName(), fwInfo.getTargetVersion()); startUpdateUsingBinary(client, fwInfo); } - } else if (fwInfo.getResult() != null && fwInfo.getResult().getCode() > 1) { + } else if (fwInfo.getResult() != null && fwInfo.getResult().getCode() > UPDATE_SUCCESSFULLY.getCode()) { log.trace("[{}] Previous update failed. [{}]", client.getEndpoint(), fwInfo); logService.log(client, "Previous update firmware failed. Result: " + fwInfo.getResult().name()); } @@ -427,7 +429,7 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl startUpdateUsingBinary(client, swInfo); } } - } else if (swInfo.getResult() != null && swInfo.getResult().code >= 50) { + } else if (swInfo.getResult() != null && swInfo.getResult().getCode() >= NOT_ENOUGH_STORAGE.getCode()) { log.trace("[{}] Previous update failed. [{}]", client.getEndpoint(), swInfo); logService.log(client, "Previous update software failed. Result: " + swInfo.getResult().name()); } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/firmware/FirmwareUpdateState.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/firmware/FirmwareUpdateState.java index ddd04fbfd0..9d3c0b06f0 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/firmware/FirmwareUpdateState.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/firmware/FirmwareUpdateState.java @@ -15,6 +15,8 @@ */ package org.thingsboard.server.transport.lwm2m.server.ota.firmware; +import lombok.Getter; + /** * /** State R * 0: Idle (before downloading or after successful updating) @@ -28,8 +30,10 @@ public enum FirmwareUpdateState { DOWNLOADED(2, "Downloaded"), UPDATING(3, "Updating"); - public int code; - public String type; + @Getter + private int code; + @Getter + private String type; FirmwareUpdateState(int code, String type) { this.code = code; diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/software/SoftwareUpdateResult.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/software/SoftwareUpdateResult.java index 7bf5473a1b..6ceb263db5 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/software/SoftwareUpdateResult.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/software/SoftwareUpdateResult.java @@ -56,10 +56,12 @@ public enum SoftwareUpdateResult { INSTALL_FAILURE(58, "Software installation failure", true), UN_INSTALL_FAILURE(59, "Uninstallation Failure during forUpdate(arg=0)", true); - public int code; - public String type; @Getter - public boolean isAgain; + private int code; + @Getter + private String type; + @Getter + private boolean isAgain; SoftwareUpdateResult(int code, String type, boolean isAgain) { this.code = code; diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/software/SoftwareUpdateState.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/software/SoftwareUpdateState.java index 394d2e501a..c2e954f556 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/software/SoftwareUpdateState.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/software/SoftwareUpdateState.java @@ -15,6 +15,8 @@ */ package org.thingsboard.server.transport.lwm2m.server.ota.software; +import lombok.Getter; + /** * SW Update State R * 0: INITIAL Before downloading. (see 5.1.2.1) @@ -33,8 +35,10 @@ public enum SoftwareUpdateState { DELIVERED(3, "Delivered"), INSTALLED(4, "Installed"); - public int code; - public String type; + @Getter + private int code; + @Getter + private String type; SoftwareUpdateState(int code, String type) { this.code = code; diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2MTransportUtil.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2MTransportUtil.java index 3c7a8e523e..ad4189dc90 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2MTransportUtil.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2MTransportUtil.java @@ -150,7 +150,7 @@ public class LwM2MTransportUtil { if (path != null) { if (FW_STATE_ID.equals(path)) { lwM2mOtaConvert.setCurrentType(STRING); - lwM2mOtaConvert.setValue(FirmwareUpdateState.fromStateFwByCode(((Long) value).intValue()).type); + lwM2mOtaConvert.setValue(FirmwareUpdateState.fromStateFwByCode(((Long) value).intValue()).getType()); return lwM2mOtaConvert; } else if (FW_RESULT_ID.equals(path)) { lwM2mOtaConvert.setCurrentType(STRING); @@ -158,11 +158,11 @@ public class LwM2MTransportUtil { return lwM2mOtaConvert; } else if (SW_STATE_ID.equals(path)) { lwM2mOtaConvert.setCurrentType(STRING); - lwM2mOtaConvert.setValue(SoftwareUpdateState.fromUpdateStateSwByCode(((Long) value).intValue()).type); + lwM2mOtaConvert.setValue(SoftwareUpdateState.fromUpdateStateSwByCode(((Long) value).intValue()).getType()); return lwM2mOtaConvert; } else if (SW_RESULT_ID.equals(path)) { lwM2mOtaConvert.setCurrentType(STRING); - lwM2mOtaConvert.setValue(SoftwareUpdateResult.fromUpdateResultSwByCode(((Long) value).intValue()).type); + lwM2mOtaConvert.setValue(SoftwareUpdateResult.fromUpdateResultSwByCode(((Long) value).intValue()).getType()); return lwM2mOtaConvert; } } From 1298f6b13047627e9199e2812ef5b7221fba1910 Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Mon, 29 Nov 2021 16:51:43 +0200 Subject: [PATCH 165/432] Fix delete attributes cluster notification --- .../DefaultSubscriptionManagerService.java | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/subscription/DefaultSubscriptionManagerService.java b/application/src/main/java/org/thingsboard/server/service/subscription/DefaultSubscriptionManagerService.java index 15cf6f1a17..018d80f013 100644 --- a/application/src/main/java/org/thingsboard/server/service/subscription/DefaultSubscriptionManagerService.java +++ b/application/src/main/java/org/thingsboard/server/service/subscription/DefaultSubscriptionManagerService.java @@ -222,7 +222,7 @@ public class DefaultSubscriptionManagerService extends TbApplicationEventListene } } return subscriptionUpdate; - }); + }, true); if (entityId.getEntityType() == EntityType.DEVICE) { updateDeviceInactivityTimeout(tenantId, entityId, ts); } @@ -256,7 +256,7 @@ public class DefaultSubscriptionManagerService extends TbApplicationEventListene } } return subscriptionUpdate; - }); + }, true); if (entityId.getEntityType() == EntityType.DEVICE) { if (TbAttributeSubscriptionScope.SERVER_SCOPE.name().equalsIgnoreCase(scope)) { updateDeviceInactivityTimeout(tenantId, entityId, attributes); @@ -333,14 +333,15 @@ public class DefaultSubscriptionManagerService extends TbApplicationEventListene } } return subscriptionUpdate; - }); + }, false); callback.onSuccess(); } private void onLocalTelemetrySubUpdate(EntityId entityId, Function castFunction, Predicate filterFunction, - Function> processFunction) { + Function> processFunction, + boolean ignoreEmptyUpdates) { Set entitySubscriptions = subscriptionsByEntityId.get(entityId); if (entitySubscriptions != null) { entitySubscriptions.stream().map(castFunction).filter(Objects::nonNull).filter(filterFunction).forEach(s -> { @@ -351,7 +352,7 @@ public class DefaultSubscriptionManagerService extends TbApplicationEventListene localSubscriptionService.onSubscriptionUpdate(s.getSessionId(), update, TbCallback.EMPTY); } else { TopicPartitionInfo tpi = partitionService.getNotificationsTopic(ServiceType.TB_CORE, s.getServiceId()); - toCoreNotificationsProducer.send(tpi, toProto(s, subscriptionUpdate), null); + toCoreNotificationsProducer.send(tpi, toProto(s, subscriptionUpdate, ignoreEmptyUpdates), null); } } }); @@ -467,6 +468,10 @@ public class DefaultSubscriptionManagerService extends TbApplicationEventListene } private TbProtoQueueMsg toProto(TbSubscription subscription, List updates) { + return toProto(subscription, updates, true); + } + + private TbProtoQueueMsg toProto(TbSubscription subscription, List updates, boolean ignoreEmptyUpdates) { TbSubscriptionUpdateProto.Builder builder = TbSubscriptionUpdateProto.newBuilder(); builder.setSessionId(subscription.getSessionId()); @@ -494,7 +499,7 @@ public class DefaultSubscriptionManagerService extends TbApplicationEventListene dataBuilder.addValue(strVal); } } - if (hasData) { + if (!ignoreEmptyUpdates || hasData) { builder.addData(dataBuilder.build()); } }); From 721906b9214128966c318fa2fc14536c18deef9c Mon Sep 17 00:00:00 2001 From: ArtemDzhereleiko Date: Mon, 29 Nov 2021 17:46:38 +0200 Subject: [PATCH 166/432] UI: Add error message for widget --- .../src/app/core/api/widget-subscription.ts | 33 ++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/ui-ngx/src/app/core/api/widget-subscription.ts b/ui-ngx/src/app/core/api/widget-subscription.ts index c548b0fbab..1634bb7b87 100644 --- a/ui-ngx/src/app/core/api/widget-subscription.ts +++ b/ui-ngx/src/app/core/api/widget-subscription.ts @@ -787,7 +787,38 @@ export class WidgetSubscription implements IWidgetSubscription { } else if (!this.targetDeviceId) { return throwError(new Error('Target device is not set!')); } - return this.ctx.deviceService.getPersistedRpcRequests(this.targetDeviceId, pageLink, keyFilter); + const rpcSubject: Subject = new Subject(); + + this.ctx.deviceService.getPersistedRpcRequests(this.targetDeviceId, pageLink, keyFilter).subscribe( + (responseBody) => { + rpcSubject.next(responseBody); + rpcSubject.complete(); + }, + (rejection: HttpErrorResponse) => { + const index = this.executingSubjects.indexOf(rpcSubject); + if (index >= 0) { + this.executingSubjects.splice( index, 1 ); + } + this.executingRpcRequest = this.executingSubjects.length > 0; + this.callbacks.rpcStateChanged(this); + if (!this.executingRpcRequest || rejection.status === 504) { + this.rpcRejection = rejection; + if (rejection.status === 504) { + this.rpcErrorText = 'Request Timeout.'; + } else { + this.rpcErrorText = 'Error : ' + rejection.status + ' - ' + rejection.statusText; + const error = this.extractRejectionErrorText(rejection); + if (error) { + this.rpcErrorText += '
'; + this.rpcErrorText += error; + } + } + this.callbacks.onRpcFailed(this); + } + rpcSubject.error(rejection); + } + ); + return rpcSubject.asObservable(); } private extractRejectionErrorText(rejection: HttpErrorResponse) { From bfa7b519ce86a70eda8f58c85a036db3a3ccf53b Mon Sep 17 00:00:00 2001 From: ArtemDzhereleiko Date: Mon, 29 Nov 2021 18:18:10 +0200 Subject: [PATCH 167/432] UI: Change translation rsa-key to certificate-pem-format and delete in other languages --- .../home/components/device/device-credentials.component.html | 4 ++-- ui-ngx/src/assets/locale/locale.constant-cs_CZ.json | 2 -- ui-ngx/src/assets/locale/locale.constant-de_DE.json | 2 -- ui-ngx/src/assets/locale/locale.constant-el_GR.json | 2 -- ui-ngx/src/assets/locale/locale.constant-en_US.json | 4 ++-- ui-ngx/src/assets/locale/locale.constant-es_ES.json | 2 -- ui-ngx/src/assets/locale/locale.constant-fa_IR.json | 2 -- ui-ngx/src/assets/locale/locale.constant-fr_FR.json | 2 -- ui-ngx/src/assets/locale/locale.constant-it_IT.json | 2 -- ui-ngx/src/assets/locale/locale.constant-ja_JA.json | 2 -- ui-ngx/src/assets/locale/locale.constant-ka_GE.json | 2 -- ui-ngx/src/assets/locale/locale.constant-ko_KR.json | 2 -- ui-ngx/src/assets/locale/locale.constant-lv_LV.json | 2 -- ui-ngx/src/assets/locale/locale.constant-pt_BR.json | 2 -- ui-ngx/src/assets/locale/locale.constant-ro_RO.json | 2 -- ui-ngx/src/assets/locale/locale.constant-ru_RU.json | 2 -- ui-ngx/src/assets/locale/locale.constant-sl_SI.json | 2 -- ui-ngx/src/assets/locale/locale.constant-tr_TR.json | 2 -- ui-ngx/src/assets/locale/locale.constant-uk_UA.json | 2 -- ui-ngx/src/assets/locale/locale.constant-zh_CN.json | 2 -- ui-ngx/src/assets/locale/locale.constant-zh_TW.json | 2 -- 21 files changed, 4 insertions(+), 42 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/device/device-credentials.component.html b/ui-ngx/src/app/modules/home/components/device/device-credentials.component.html index d5a846189d..c95f489073 100644 --- a/ui-ngx/src/app/modules/home/components/device/device-credentials.component.html +++ b/ui-ngx/src/app/modules/home/components/device/device-credentials.component.html @@ -39,10 +39,10 @@ - device.rsa-key + device.certificate-pem-format - {{ 'device.rsa-key-required' | translate }} + {{ 'device.certificate-pem-format-required' | translate }} diff --git a/ui-ngx/src/assets/locale/locale.constant-cs_CZ.json b/ui-ngx/src/assets/locale/locale.constant-cs_CZ.json index b5a23c0150..e8742cc721 100644 --- a/ui-ngx/src/assets/locale/locale.constant-cs_CZ.json +++ b/ui-ngx/src/assets/locale/locale.constant-cs_CZ.json @@ -954,8 +954,6 @@ "access-token": "Přístupový token", "access-token-required": "Přístupový token je povinný.", "access-token-invalid": "Délka přístupového tokenu musí být od 1 do 32 znaků.", - "rsa-key": "RSA veřejný klíč", - "rsa-key-required": "RSA veřejný klíč je povinný.", "lwm2m-security-config": { "identity": "Identita klienta", "identity-required": "Identita klienta je povinná.", diff --git a/ui-ngx/src/assets/locale/locale.constant-de_DE.json b/ui-ngx/src/assets/locale/locale.constant-de_DE.json index 00cd06c893..f3f96a3a53 100644 --- a/ui-ngx/src/assets/locale/locale.constant-de_DE.json +++ b/ui-ngx/src/assets/locale/locale.constant-de_DE.json @@ -699,8 +699,6 @@ "access-token": "Zugangs-Token", "access-token-required": "Zugangs-Token ist erforderlich.", "access-token-invalid": "Die Länge des Zugangs-Tokens muss zwischen 1 und 32 Zeichen betragen.", - "rsa-key": "RSA öffentlicher Schlüssel", - "rsa-key-required": "RSA öffentlicher Schlüssel ist erforderlich.", "secret": "Geheimnis", "secret-required": "Geheimnis ist erforderlich.", "device-type": "Gerätetyp", diff --git a/ui-ngx/src/assets/locale/locale.constant-el_GR.json b/ui-ngx/src/assets/locale/locale.constant-el_GR.json index 92988533a3..6bd8168418 100644 --- a/ui-ngx/src/assets/locale/locale.constant-el_GR.json +++ b/ui-ngx/src/assets/locale/locale.constant-el_GR.json @@ -799,8 +799,6 @@ "access-token": "Διακριτικό πρόσβασης", "access-token-required": "Απαιτείται διακριτικό πρόσβασης.", "access-token-invalid": "Access token length must be from 1 to 32 characters.", - "rsa-key": "RSA public key", - "rsa-key-required": "Απαιτείται RSA public key.", "secret": "Secret", "secret-required": "Απαιτείται secret.", "device-type": "Τύπος συσκευής", diff --git a/ui-ngx/src/assets/locale/locale.constant-en_US.json b/ui-ngx/src/assets/locale/locale.constant-en_US.json index bd14f73e27..2ea80a50dd 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -980,8 +980,8 @@ "access-token": "Access token", "access-token-required": "Access token is required.", "access-token-invalid": "Access token length must be from 1 to 32 characters.", - "rsa-key": "RSA public key", - "rsa-key-required": "RSA public key is required.", + "certificate-pem-format": "Certificate in PEM format", + "certificate-pem-format-required": "Certificate is required.", "lwm2m-security-config": { "identity": "Client Identity", "identity-required": "Client Identity is required.", diff --git a/ui-ngx/src/assets/locale/locale.constant-es_ES.json b/ui-ngx/src/assets/locale/locale.constant-es_ES.json index a782298bdc..963334cc88 100644 --- a/ui-ngx/src/assets/locale/locale.constant-es_ES.json +++ b/ui-ngx/src/assets/locale/locale.constant-es_ES.json @@ -894,8 +894,6 @@ "access-token": "Tóken de acceso", "access-token-required": "Access token requerido.", "access-token-invalid": "Access token debe tener entre 1 a 32 caracteres.", - "rsa-key": "Clave pública RSA", - "rsa-key-required": "Clave pública RSA requerida.", "client-id": "ID Cliente", "client-id-pattern": "Contiene carácter inválido.", "user-name": "Nombre Usuario", diff --git a/ui-ngx/src/assets/locale/locale.constant-fa_IR.json b/ui-ngx/src/assets/locale/locale.constant-fa_IR.json index 8b74ce6f79..b0eef3fa2c 100644 --- a/ui-ngx/src/assets/locale/locale.constant-fa_IR.json +++ b/ui-ngx/src/assets/locale/locale.constant-fa_IR.json @@ -641,8 +641,6 @@ "access-token": "شناسه دسترسي", "access-token-required": ".شناسه دسترسي مورد نياز است", "access-token-invalid": ".طول شناسه دسترسي بايد از 1 تا 32 حرف باشد", - "rsa-key": "RSA کليد عمومي", - "rsa-key-required": ".مورد نياز است RSA کليد عمومي", "secret": "محرمانه", "secret-required": ".شناسه محرمانه مورد نياز است", "device-type": "نوع دستگاه", diff --git a/ui-ngx/src/assets/locale/locale.constant-fr_FR.json b/ui-ngx/src/assets/locale/locale.constant-fr_FR.json index b7f6dfebfb..02aef41b95 100644 --- a/ui-ngx/src/assets/locale/locale.constant-fr_FR.json +++ b/ui-ngx/src/assets/locale/locale.constant-fr_FR.json @@ -714,8 +714,6 @@ "no-keys-found": "Aucune clé trouvée", "public": "Public", "remove-alias": "Supprimer l'alias du dispositif", - "rsa-key": "Clé publique RSA", - "rsa-key-required": "La clé publique RSA est requise.", "secret": "Secret", "secret-required": "Code secret est requis.", "select-device": "Selectionner un dispositif", diff --git a/ui-ngx/src/assets/locale/locale.constant-it_IT.json b/ui-ngx/src/assets/locale/locale.constant-it_IT.json index 2e5ace98a7..8d86e38132 100644 --- a/ui-ngx/src/assets/locale/locale.constant-it_IT.json +++ b/ui-ngx/src/assets/locale/locale.constant-it_IT.json @@ -666,8 +666,6 @@ "access-token": "Token di accesso", "access-token-required": "Token di accesso obbligatorio.", "access-token-invalid": "Il token di accesso deve avere una lunghezza compresa tra 1 e 32 caratteri.", - "rsa-key": "Chiave pubblica RSA", - "rsa-key-required": "Chiave pubblica RSA obbligatoria.", "secret": "Secret", "secret-required": "Secret obbligatorio.", "device-type": "Tipo dispositivo", diff --git a/ui-ngx/src/assets/locale/locale.constant-ja_JA.json b/ui-ngx/src/assets/locale/locale.constant-ja_JA.json index 4b9da9e41f..6420f4fce5 100644 --- a/ui-ngx/src/assets/locale/locale.constant-ja_JA.json +++ b/ui-ngx/src/assets/locale/locale.constant-ja_JA.json @@ -624,8 +624,6 @@ "access-token": "アクセストークン", "access-token-required": "アクセストークンが必要です。", "access-token-invalid": "アクセストークンの長さは、1〜32文字でなければなりません。", - "rsa-key": "RSA公開鍵", - "rsa-key-required": "RSA公開鍵が必要です。", "secret": "秘密", "secret-required": "秘密が必要です。", "device-type": "デバイスタイプ", diff --git a/ui-ngx/src/assets/locale/locale.constant-ka_GE.json b/ui-ngx/src/assets/locale/locale.constant-ka_GE.json index 94da40c3c1..fe1d1ff793 100644 --- a/ui-ngx/src/assets/locale/locale.constant-ka_GE.json +++ b/ui-ngx/src/assets/locale/locale.constant-ka_GE.json @@ -684,8 +684,6 @@ "access-token": "ტოკენი", "access-token-required": "ტოკენი სავალდებულოა", "access-token-invalid": "ტოკენის სიგრძე უნდა იყოს 1 დან 32 სიმბოლომდე", - "rsa-key": "ღია გასაღები RSA", - "rsa-key-required": "ღია გასაღები RSA აუცილებელია", "secret": "საიდუმლო", "secret-required": "საიდუმლო აუცილებელია", "device-type": "მოწყობილობის ტიპი", diff --git a/ui-ngx/src/assets/locale/locale.constant-ko_KR.json b/ui-ngx/src/assets/locale/locale.constant-ko_KR.json index 35a291931d..de3ade448a 100644 --- a/ui-ngx/src/assets/locale/locale.constant-ko_KR.json +++ b/ui-ngx/src/assets/locale/locale.constant-ko_KR.json @@ -870,8 +870,6 @@ "access-token": "억세스 토큰", "access-token-required": "액세스 토큰을 입력하세요.", "access-token-invalid": "액세스 토큰 길이는 1 - 32 자 여야합니다.", - "rsa-key": "RSA public key", - "rsa-key-required": "RSA public key 를 입력하세요.", "client-id": "클라이언트 ID", "client-id-pattern": "잘못된 문자가 포함되어 있습니다.", "user-name": "사용자 이름", diff --git a/ui-ngx/src/assets/locale/locale.constant-lv_LV.json b/ui-ngx/src/assets/locale/locale.constant-lv_LV.json index 3563aef32e..d963a04243 100644 --- a/ui-ngx/src/assets/locale/locale.constant-lv_LV.json +++ b/ui-ngx/src/assets/locale/locale.constant-lv_LV.json @@ -642,8 +642,6 @@ "access-token": "Piekļuves tokens", "access-token-required": "Piekļuves tokens ir nepieciešams.", "access-token-invalid": "Piekļuves tokena garumam ir jābūt no 1 līdz 32 rakstzīmēm.", - "rsa-key": "RSA publiskā atslēga", - "rsa-key-required": "RSA publiskā atslēga ir nepieciešama.", "secret": "Noslēpums", "secret-required": "Noslēpums ir nepieciešams.", "device-type": "Iekārtas tips", diff --git a/ui-ngx/src/assets/locale/locale.constant-pt_BR.json b/ui-ngx/src/assets/locale/locale.constant-pt_BR.json index 7c8e1e7449..1c84ed3c16 100644 --- a/ui-ngx/src/assets/locale/locale.constant-pt_BR.json +++ b/ui-ngx/src/assets/locale/locale.constant-pt_BR.json @@ -716,8 +716,6 @@ "access-token": "Token de acesso", "access-token-required": "O token de acesso é obrigatório.", "access-token-invalid": "O token de acesso deve ter de 1 a 32 caracteres.", - "rsa-key": "Chave pública RSA", - "rsa-key-required": "A chave pública RSA é obrigatória.", "secret": "Segredo", "secret-required": "O segredo é obrigatório.", "device-type": "Tipo de dispositivo", diff --git a/ui-ngx/src/assets/locale/locale.constant-ro_RO.json b/ui-ngx/src/assets/locale/locale.constant-ro_RO.json index 9e86bd1a84..fc00f9bd50 100644 --- a/ui-ngx/src/assets/locale/locale.constant-ro_RO.json +++ b/ui-ngx/src/assets/locale/locale.constant-ro_RO.json @@ -675,8 +675,6 @@ "access-token": "Token Acces", "access-token-required": "Tokenul de acces este necesar", "access-token-invalid": "Dimensiunea tokenului de acces trebuie să fie de 1-32 caractere", - "rsa-key": "Cheie RSA publică", - "rsa-key-required": "Cheia RSA publică key este necesară", "secret": "Cod Secret", "secret-required": "Codul secret este necesar", "device-type": "Tip Dispozitiv", diff --git a/ui-ngx/src/assets/locale/locale.constant-ru_RU.json b/ui-ngx/src/assets/locale/locale.constant-ru_RU.json index 66d99281bb..d266ae78a0 100644 --- a/ui-ngx/src/assets/locale/locale.constant-ru_RU.json +++ b/ui-ngx/src/assets/locale/locale.constant-ru_RU.json @@ -678,8 +678,6 @@ "access-token": "Токен", "access-token-required": "Токен обязателен.", "access-token-invalid": "Длина токена должна быть от 1 до 32 символов.", - "rsa-key": "Открытый ключ RSA", - "rsa-key-required": "Открытый ключ RSA обязателен.", "secret": "Секрет", "secret-required": "Секрет обязателен.", "device-type": "Тип устройства", diff --git a/ui-ngx/src/assets/locale/locale.constant-sl_SI.json b/ui-ngx/src/assets/locale/locale.constant-sl_SI.json index 3e3b252bf6..1b7275dc0e 100644 --- a/ui-ngx/src/assets/locale/locale.constant-sl_SI.json +++ b/ui-ngx/src/assets/locale/locale.constant-sl_SI.json @@ -870,8 +870,6 @@ "access-token": "Dostopni žeton", "access-token-required": "Zahtevan je žeton za dostop.", "access-token-invalid": "Dolžina žetona za dostop mora biti od 1 do 32 znakov.", - "rsa-key": "Javni ključ RSA", - "rsa-key-required": "Potreben je javni ključ RSA.", "client-id": "Client ID", "client-id-pattern": "Contains invalid character.", "user-name": "User Name", diff --git a/ui-ngx/src/assets/locale/locale.constant-tr_TR.json b/ui-ngx/src/assets/locale/locale.constant-tr_TR.json index 087060361b..4c84bdca24 100644 --- a/ui-ngx/src/assets/locale/locale.constant-tr_TR.json +++ b/ui-ngx/src/assets/locale/locale.constant-tr_TR.json @@ -957,8 +957,6 @@ "access-token": "Erişim şifresi", "access-token-required": "Erişim şifresi gerekli.", "access-token-invalid": "Erişim şifresi uzunluğu 1 ile 32 karakter arasında olmalıdır.", - "rsa-key": "RSA açık anahtarı", - "rsa-key-required": "RSA açık anahtarı gerekli.", "lwm2m-security-config": { "identity": "İstemci Kimliği", "identity-required": "İstemci Kimliği gerekli.", diff --git a/ui-ngx/src/assets/locale/locale.constant-uk_UA.json b/ui-ngx/src/assets/locale/locale.constant-uk_UA.json index 43691918dd..7286016a17 100644 --- a/ui-ngx/src/assets/locale/locale.constant-uk_UA.json +++ b/ui-ngx/src/assets/locale/locale.constant-uk_UA.json @@ -795,8 +795,6 @@ "access-token": "Маркер доступу", "access-token-required": "Необхідно вказати маркер доступу.", "access-token-invalid": "Маркер доступу має бути від 1 до 32 символів.", - "rsa-key": "Публічний ключ RSA", - "rsa-key-required": "Необхідно вказати публічний ключ RSA.", "secret": "Секрет", "secret-required": "Необхідно вказати секрет.", "device-type": "Тип пристрою", diff --git a/ui-ngx/src/assets/locale/locale.constant-zh_CN.json b/ui-ngx/src/assets/locale/locale.constant-zh_CN.json index 270fd6ad4e..a5b3ba011b 100644 --- a/ui-ngx/src/assets/locale/locale.constant-zh_CN.json +++ b/ui-ngx/src/assets/locale/locale.constant-zh_CN.json @@ -1081,8 +1081,6 @@ "password": "密码", "public": "公开", "remove-alias": "删除设备别名", - "rsa-key": "RSA公钥", - "rsa-key-required": "RSA公钥必填", "search": "查找设备", "secret": "密钥", "secret-required": "密钥必填", diff --git a/ui-ngx/src/assets/locale/locale.constant-zh_TW.json b/ui-ngx/src/assets/locale/locale.constant-zh_TW.json index 59bceb7b26..6ddaedc120 100644 --- a/ui-ngx/src/assets/locale/locale.constant-zh_TW.json +++ b/ui-ngx/src/assets/locale/locale.constant-zh_TW.json @@ -625,8 +625,6 @@ "access-token": "存取令牌", "access-token-required": "需要存取令牌", "access-token-invalid": "存取令牌長度必須為1到32個字符。", - "rsa-key": "RSA公鑰", - "rsa-key-required": "需要RSA公鑰", "secret": "密鑰", "secret-required": "密鑰必填", "device-type": "設備類型", From 045fbf5b5e4d171baeccd47597b37e8b3155325d Mon Sep 17 00:00:00 2001 From: desoliture Date: Mon, 29 Nov 2021 19:01:22 +0200 Subject: [PATCH 168/432] add rpcStatus:deleted, add throwing bad_request when getting the rpc entity with status:deleted --- .../org/thingsboard/server/controller/RpcV2Controller.java | 6 ++++++ .../org/thingsboard/server/common/data/rpc/RpcStatus.java | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/RpcV2Controller.java b/application/src/main/java/org/thingsboard/server/controller/RpcV2Controller.java index 389a767cdf..cd3195c9f1 100644 --- a/application/src/main/java/org/thingsboard/server/controller/RpcV2Controller.java +++ b/application/src/main/java/org/thingsboard/server/controller/RpcV2Controller.java @@ -32,6 +32,7 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.context.request.async.DeferredResult; +import org.springframework.web.server.ResponseStatusException; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.id.DeviceId; @@ -187,10 +188,15 @@ public class RpcV2Controller extends AbstractRpcController { @RequestParam(required = false) String sortOrder) throws ThingsboardException { checkParameter("DeviceId", strDeviceId); try { + if (rpcStatus.equals(RpcStatus.DELETED)) { + throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "RpcStatus: DELETED"); + } + TenantId tenantId = getCurrentUser().getTenantId(); PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder); DeviceId deviceId = new DeviceId(UUID.fromString(strDeviceId)); final DeferredResult response = new DeferredResult<>(); + accessValidator.validate(getCurrentUser(), Operation.RPC_CALL, deviceId, new HttpValidationCallback(response, new FutureCallback<>() { @Override public void onSuccess(@Nullable DeferredResult result) { diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/rpc/RpcStatus.java b/common/data/src/main/java/org/thingsboard/server/common/data/rpc/RpcStatus.java index 43592fde0c..5ebf33d551 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/rpc/RpcStatus.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/rpc/RpcStatus.java @@ -16,5 +16,5 @@ package org.thingsboard.server.common.data.rpc; public enum RpcStatus { - QUEUED, SENT, DELIVERED, SUCCESSFUL, TIMEOUT, EXPIRED, FAILED + QUEUED, SENT, DELIVERED, SUCCESSFUL, TIMEOUT, EXPIRED, FAILED, DELETED } From b04949c62cff2ae1960bb35657fd8fa6368addda Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Mon, 29 Nov 2021 19:20:08 +0200 Subject: [PATCH 169/432] Null values support for subscription update values proto --- .../subscription/DefaultSubscriptionManagerService.java | 6 ++++-- .../server/service/subscription/TbSubscriptionUtils.java | 8 +++++--- common/cluster-api/src/main/proto/queue.proto | 9 +++++++-- 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/subscription/DefaultSubscriptionManagerService.java b/application/src/main/java/org/thingsboard/server/service/subscription/DefaultSubscriptionManagerService.java index 018d80f013..6e5ca1669f 100644 --- a/application/src/main/java/org/thingsboard/server/service/subscription/DefaultSubscriptionManagerService.java +++ b/application/src/main/java/org/thingsboard/server/service/subscription/DefaultSubscriptionManagerService.java @@ -492,12 +492,14 @@ public class DefaultSubscriptionManagerService extends TbApplicationEventListene boolean hasData = false; for (Object v : value) { Object[] array = (Object[]) v; - dataBuilder.addTs((long) array[0]); + TbSubscriptionUpdateTsValue.Builder tsValueBuilder = TbSubscriptionUpdateTsValue.newBuilder(); + tsValueBuilder.setTs((long) array[0]); String strVal = (String) array[1]; if (strVal != null) { hasData = true; - dataBuilder.addValue(strVal); + tsValueBuilder.setValue(strVal); } + dataBuilder.addTsValue(tsValueBuilder.build()); } if (!ignoreEmptyUpdates || hasData) { builder.addData(dataBuilder.build()); diff --git a/application/src/main/java/org/thingsboard/server/service/subscription/TbSubscriptionUtils.java b/application/src/main/java/org/thingsboard/server/service/subscription/TbSubscriptionUtils.java index 978d7aaac3..25b67d3a06 100644 --- a/application/src/main/java/org/thingsboard/server/service/subscription/TbSubscriptionUtils.java +++ b/application/src/main/java/org/thingsboard/server/service/subscription/TbSubscriptionUtils.java @@ -42,6 +42,7 @@ import org.thingsboard.server.gen.transport.TransportProtos.TbSubscriptionCloseP import org.thingsboard.server.gen.transport.TransportProtos.TbSubscriptionKetStateProto; import org.thingsboard.server.gen.transport.TransportProtos.TbSubscriptionProto; import org.thingsboard.server.gen.transport.TransportProtos.TbSubscriptionUpdateProto; +import org.thingsboard.server.gen.transport.TransportProtos.TbSubscriptionUpdateTsValue; import org.thingsboard.server.gen.transport.TransportProtos.TbTimeSeriesSubscriptionProto; import org.thingsboard.server.gen.transport.TransportProtos.TbTimeSeriesUpdateProto; import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg; @@ -171,10 +172,11 @@ public class TbSubscriptionUtils { Map> data = new TreeMap<>(); proto.getDataList().forEach(v -> { List values = data.computeIfAbsent(v.getKey(), k -> new ArrayList<>()); - for (int i = 0; i < v.getTsCount(); i++) { + for (int i = 0; i < v.getTsValueCount(); i++) { Object[] value = new Object[2]; - value[0] = v.getTs(i); - value[1] = v.getValue(i); + TbSubscriptionUpdateTsValue tsValue = v.getTsValue(i); + value[0] = tsValue.getTs(); + value[1] = tsValue.hasValue() ? tsValue.getValue() : null; values.add(value); } }); diff --git a/common/cluster-api/src/main/proto/queue.proto b/common/cluster-api/src/main/proto/queue.proto index 5b220974ef..dca92c1c7a 100644 --- a/common/cluster-api/src/main/proto/queue.proto +++ b/common/cluster-api/src/main/proto/queue.proto @@ -14,6 +14,7 @@ * limitations under the License. */ syntax = "proto3"; + package transport; option java_package = "org.thingsboard.server.gen.transport"; @@ -581,8 +582,12 @@ message TbSubscriptionKetStateProto { message TbSubscriptionUpdateValueListProto { string key = 1; - repeated int64 ts = 2; - repeated string value = 3; + repeated TbSubscriptionUpdateTsValue tsValue = 2; +} + +message TbSubscriptionUpdateTsValue { + int64 ts = 1; + optional string value = 2; } /** From 4ac52b10d8d041611d62ee38fb69c4e45b4f5350 Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Mon, 29 Nov 2021 19:43:26 +0200 Subject: [PATCH 170/432] fixed sessions updating on lwm2m transport start --- .../lwm2m/server/DefaultLwM2mTransportService.java | 7 ++----- .../lwm2m/server/client/LwM2mClientContextImpl.java | 7 +++++-- .../lwm2m/server/rpc/DefaultLwM2MRpcRequestHandler.java | 6 ++++++ 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2mTransportService.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2mTransportService.java index 15aeac095c..147e20c02b 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2mTransportService.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2mTransportService.java @@ -17,7 +17,6 @@ package org.thingsboard.server.transport.lwm2m.server; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.eclipse.californium.elements.util.SslContextUtil; import org.eclipse.californium.scandium.config.DtlsConnectorConfig; import org.eclipse.californium.scandium.dtls.cipher.CipherSuite; import org.eclipse.leshan.core.node.codec.DefaultLwM2mNodeDecoder; @@ -29,6 +28,7 @@ import org.springframework.stereotype.Component; import org.thingsboard.server.cache.ota.OtaPackageDataCache; import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.transport.config.ssl.SslCredentials; +import org.thingsboard.server.queue.util.AfterStartUp; import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; import org.thingsboard.server.transport.lwm2m.secure.TbLwM2MAuthorizer; @@ -37,10 +37,7 @@ import org.thingsboard.server.transport.lwm2m.server.store.TbSecurityStore; import org.thingsboard.server.transport.lwm2m.server.uplink.DefaultLwM2MUplinkMsgHandler; import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl; -import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; -import java.security.PrivateKey; -import java.security.PublicKey; import java.security.cert.X509Certificate; import static org.eclipse.californium.scandium.dtls.cipher.CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256; @@ -71,7 +68,7 @@ public class DefaultLwM2mTransportService implements LwM2MTransportService { private LeshanServer server; - @PostConstruct + @AfterStartUp public void init() { this.server = getLhServer(); /* diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java index da304821da..823f16a99a 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java @@ -22,7 +22,10 @@ import org.eclipse.leshan.core.model.ResourceModel; import org.eclipse.leshan.core.node.LwM2mPath; import org.eclipse.leshan.server.registration.Registration; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.context.event.ApplicationReadyEvent; import org.springframework.context.annotation.Lazy; +import org.springframework.context.event.EventListener; +import org.springframework.core.annotation.Order; import org.springframework.stereotype.Service; import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.device.data.PowerMode; @@ -33,7 +36,6 @@ import org.thingsboard.server.common.transport.TransportDeviceProfileCache; import org.thingsboard.server.common.transport.TransportServiceCallback; import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse; import org.thingsboard.server.gen.transport.TransportProtos; -import org.thingsboard.server.queue.util.AfterStartUp; import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; import org.thingsboard.server.transport.lwm2m.config.LwM2mVersion; @@ -88,7 +90,8 @@ public class LwM2mClientContextImpl implements LwM2mClientContext { private final Map lwM2mClientsByRegistrationId = new ConcurrentHashMap<>(); private final Map profiles = new ConcurrentHashMap<>(); - @AfterStartUp + @EventListener(ApplicationReadyEvent.class) + @Order(Integer.MAX_VALUE - 1) public void init() { String nodeId = context.getNodeId(); Set fetchedClients = clientStore.getAll(); diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/DefaultLwM2MRpcRequestHandler.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/DefaultLwM2MRpcRequestHandler.java index 161ca3d2f1..a728a0b6e0 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/DefaultLwM2MRpcRequestHandler.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/DefaultLwM2MRpcRequestHandler.java @@ -87,6 +87,12 @@ public class DefaultLwM2MRpcRequestHandler implements LwM2MRpcRequestHandler { return; } LwM2mClient client = clientContext.getClientBySessionInfo(sessionInfo); + + if (client == null) { + log.warn("Missing client for session: [{}]", sessionInfo); + return; + } + if (client.getRegistration() == null) { this.sendErrorRpcResponse(sessionInfo, rpcRequest.getRequestId(), ResponseCode.INTERNAL_SERVER_ERROR, "Registration is empty"); return; From 8232244b6e5436d724c38b7eecd7969b172f47df Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Tue, 30 Nov 2021 09:40:11 +0200 Subject: [PATCH 171/432] Update node and yarn versions --- ui-ngx/pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ui-ngx/pom.xml b/ui-ngx/pom.xml index d071908001..328a63f949 100644 --- a/ui-ngx/pom.xml +++ b/ui-ngx/pom.xml @@ -56,8 +56,8 @@ install-node-and-yarn - v12.16.1 - v1.22.4 + v16.13.0 + v1.22.17 From 6578c5eaeb704943f1b7ca5a35840c28837f6640 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Tue, 30 Nov 2021 09:41:46 +0200 Subject: [PATCH 172/432] Update webpack --- ui-ngx/package.json | 2 +- ui-ngx/yarn.lock | 343 +++++++++++++++++++++++++++++++++++++++----- 2 files changed, 310 insertions(+), 35 deletions(-) diff --git a/ui-ngx/package.json b/ui-ngx/package.json index 653711a8c1..672af523b0 100644 --- a/ui-ngx/package.json +++ b/ui-ngx/package.json @@ -143,7 +143,7 @@ "ts-node": "^9.0.0", "tslint": "~6.1.3", "typescript": "~4.0.3", - "webpack": "^4.46.0" + "webpack": "^5.64.4" }, "resolutions": { "lodash": "~4.17.21" diff --git a/ui-ngx/yarn.lock b/ui-ngx/yarn.lock index 36eb458108..c749b240a5 100644 --- a/ui-ngx/yarn.lock +++ b/ui-ngx/yarn.lock @@ -1881,6 +1881,27 @@ resolved "https://registry.yarnpkg.com/@types/cors/-/cors-2.8.10.tgz#61cc8469849e5bcdd0c7044122265c39cec10cf4" integrity sha512-C7srjHiVG3Ey1nR6d511dtDkCEjxuN9W1HWAEjGq8kpcwmNM6JJkpC0xvabM7BXTG2wDq8Eu33iH9aQKa7IvLQ== +"@types/eslint-scope@^3.7.0": + version "3.7.1" + resolved "https://registry.yarnpkg.com/@types/eslint-scope/-/eslint-scope-3.7.1.tgz#8dc390a7b4f9dd9f1284629efce982e41612116e" + integrity sha512-SCFeogqiptms4Fg29WpOTk5nHIzfpKCemSN63ksBQYKTcXoJEmJagV+DhVmbapZzY4/5YaOV1nZwrsU79fFm1g== + dependencies: + "@types/eslint" "*" + "@types/estree" "*" + +"@types/eslint@*": + version "8.2.0" + resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-8.2.0.tgz#afd0519223c29c347087542cbaee2fedc0873b16" + integrity sha512-74hbvsnc+7TEDa1z5YLSe4/q8hGYB3USNvCuzHUJrjPV6hXaq8IXcngCrHkuvFt0+8rFz7xYXrHgNayIX0UZvQ== + dependencies: + "@types/estree" "*" + "@types/json-schema" "*" + +"@types/estree@*", "@types/estree@^0.0.50": + version "0.0.50" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.50.tgz#1e0caa9364d3fccd2931c3ed96fdbeaa5d4cca83" + integrity sha512-C6N5s2ZFtuZRj54k2/zyRhNDjJwwcViAM3Nbm8zjBpbqAdZ00mr0CFxvSKeO8Y/e03WVFLpQMdHYVfUd6SB+Hw== + "@types/flot@^0.0.31": version "0.0.31" resolved "https://registry.yarnpkg.com/@types/flot/-/flot-0.0.31.tgz#0daca37c6c855b69a0a7e2e37dd0f84b3db8c8c1" @@ -1947,6 +1968,11 @@ resolved "https://registry.yarnpkg.com/@types/js-beautify/-/js-beautify-1.13.1.tgz#d4739266c5dcad561226cd1ec5407fa0542d863d" integrity sha512-F3YCoZS//n74Wu+hxoVrxX1H8qaWo+WAgQ+ObmFH4ZFwI0fIwiJTW7pvkCRShw8ST7+ej7sB68K+ZHAZgK4S4Q== +"@types/json-schema@*", "@types/json-schema@^7.0.8": + version "7.0.9" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.9.tgz#97edc9037ea0c38585320b28964dde3b39e4660d" + integrity sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ== + "@types/json-schema@^7.0.5": version "7.0.6" resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.6.tgz#f4c7ec43e81b319a9815115031709f26987891f0" @@ -2138,6 +2164,14 @@ "@types/source-list-map" "*" source-map "^0.6.1" +"@webassemblyjs/ast@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.11.1.tgz#2bfd767eae1a6996f432ff7e8d7fc75679c0b6a7" + integrity sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw== + dependencies: + "@webassemblyjs/helper-numbers" "1.11.1" + "@webassemblyjs/helper-wasm-bytecode" "1.11.1" + "@webassemblyjs/ast@1.9.0": version "1.9.0" resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.9.0.tgz#bd850604b4042459a5a41cd7d338cbed695ed964" @@ -2147,16 +2181,31 @@ "@webassemblyjs/helper-wasm-bytecode" "1.9.0" "@webassemblyjs/wast-parser" "1.9.0" +"@webassemblyjs/floating-point-hex-parser@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz#f6c61a705f0fd7a6aecaa4e8198f23d9dc179e4f" + integrity sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ== + "@webassemblyjs/floating-point-hex-parser@1.9.0": version "1.9.0" resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.9.0.tgz#3c3d3b271bddfc84deb00f71344438311d52ffb4" integrity sha512-TG5qcFsS8QB4g4MhrxK5TqfdNe7Ey/7YL/xN+36rRjl/BlGE/NcBvJcqsRgCP6Z92mRE+7N50pRIi8SmKUbcQA== +"@webassemblyjs/helper-api-error@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz#1a63192d8788e5c012800ba6a7a46c705288fd16" + integrity sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg== + "@webassemblyjs/helper-api-error@1.9.0": version "1.9.0" resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.9.0.tgz#203f676e333b96c9da2eeab3ccef33c45928b6a2" integrity sha512-NcMLjoFMXpsASZFxJ5h2HZRcEhDkvnNFOAKneP5RbKRzaWJN36NC4jqQHKwStIhGXu5mUWlUUk7ygdtrO8lbmw== +"@webassemblyjs/helper-buffer@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz#832a900eb444884cde9a7cad467f81500f5e5ab5" + integrity sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA== + "@webassemblyjs/helper-buffer@1.9.0": version "1.9.0" resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.9.0.tgz#a1442d269c5feb23fcbc9ef759dac3547f29de00" @@ -2181,11 +2230,35 @@ dependencies: "@webassemblyjs/ast" "1.9.0" +"@webassemblyjs/helper-numbers@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz#64d81da219fbbba1e3bd1bfc74f6e8c4e10a62ae" + integrity sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ== + dependencies: + "@webassemblyjs/floating-point-hex-parser" "1.11.1" + "@webassemblyjs/helper-api-error" "1.11.1" + "@xtuc/long" "4.2.2" + +"@webassemblyjs/helper-wasm-bytecode@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz#f328241e41e7b199d0b20c18e88429c4433295e1" + integrity sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q== + "@webassemblyjs/helper-wasm-bytecode@1.9.0": version "1.9.0" resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.9.0.tgz#4fed8beac9b8c14f8c58b70d124d549dd1fe5790" integrity sha512-R7FStIzyNcd7xKxCZH5lE0Bqy+hGTwS3LJjuv1ZVxd9O7eHCedSdrId/hMOd20I+v8wDXEn+bjfKDLzTepoaUw== +"@webassemblyjs/helper-wasm-section@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz#21ee065a7b635f319e738f0dd73bfbda281c097a" + integrity sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg== + dependencies: + "@webassemblyjs/ast" "1.11.1" + "@webassemblyjs/helper-buffer" "1.11.1" + "@webassemblyjs/helper-wasm-bytecode" "1.11.1" + "@webassemblyjs/wasm-gen" "1.11.1" + "@webassemblyjs/helper-wasm-section@1.9.0": version "1.9.0" resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.9.0.tgz#5a4138d5a6292ba18b04c5ae49717e4167965346" @@ -2196,6 +2269,13 @@ "@webassemblyjs/helper-wasm-bytecode" "1.9.0" "@webassemblyjs/wasm-gen" "1.9.0" +"@webassemblyjs/ieee754@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz#963929e9bbd05709e7e12243a099180812992614" + integrity sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ== + dependencies: + "@xtuc/ieee754" "^1.2.0" + "@webassemblyjs/ieee754@1.9.0": version "1.9.0" resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.9.0.tgz#15c7a0fbaae83fb26143bbacf6d6df1702ad39e4" @@ -2203,6 +2283,13 @@ dependencies: "@xtuc/ieee754" "^1.2.0" +"@webassemblyjs/leb128@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.11.1.tgz#ce814b45574e93d76bae1fb2644ab9cdd9527aa5" + integrity sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw== + dependencies: + "@xtuc/long" "4.2.2" + "@webassemblyjs/leb128@1.9.0": version "1.9.0" resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.9.0.tgz#f19ca0b76a6dc55623a09cffa769e838fa1e1c95" @@ -2210,11 +2297,30 @@ dependencies: "@xtuc/long" "4.2.2" +"@webassemblyjs/utf8@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.11.1.tgz#d1f8b764369e7c6e6bae350e854dec9a59f0a3ff" + integrity sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ== + "@webassemblyjs/utf8@1.9.0": version "1.9.0" resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.9.0.tgz#04d33b636f78e6a6813227e82402f7637b6229ab" integrity sha512-GZbQlWtopBTP0u7cHrEx+73yZKrQoBMpwkGEIqlacljhXCkVM1kMQge/Mf+csMJAjEdSwhOyLAS0AoR3AG5P8w== +"@webassemblyjs/wasm-edit@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz#ad206ebf4bf95a058ce9880a8c092c5dec8193d6" + integrity sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA== + dependencies: + "@webassemblyjs/ast" "1.11.1" + "@webassemblyjs/helper-buffer" "1.11.1" + "@webassemblyjs/helper-wasm-bytecode" "1.11.1" + "@webassemblyjs/helper-wasm-section" "1.11.1" + "@webassemblyjs/wasm-gen" "1.11.1" + "@webassemblyjs/wasm-opt" "1.11.1" + "@webassemblyjs/wasm-parser" "1.11.1" + "@webassemblyjs/wast-printer" "1.11.1" + "@webassemblyjs/wasm-edit@1.9.0": version "1.9.0" resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.9.0.tgz#3fe6d79d3f0f922183aa86002c42dd256cfee9cf" @@ -2229,6 +2335,17 @@ "@webassemblyjs/wasm-parser" "1.9.0" "@webassemblyjs/wast-printer" "1.9.0" +"@webassemblyjs/wasm-gen@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz#86c5ea304849759b7d88c47a32f4f039ae3c8f76" + integrity sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA== + dependencies: + "@webassemblyjs/ast" "1.11.1" + "@webassemblyjs/helper-wasm-bytecode" "1.11.1" + "@webassemblyjs/ieee754" "1.11.1" + "@webassemblyjs/leb128" "1.11.1" + "@webassemblyjs/utf8" "1.11.1" + "@webassemblyjs/wasm-gen@1.9.0": version "1.9.0" resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.9.0.tgz#50bc70ec68ded8e2763b01a1418bf43491a7a49c" @@ -2240,6 +2357,16 @@ "@webassemblyjs/leb128" "1.9.0" "@webassemblyjs/utf8" "1.9.0" +"@webassemblyjs/wasm-opt@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz#657b4c2202f4cf3b345f8a4c6461c8c2418985f2" + integrity sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw== + dependencies: + "@webassemblyjs/ast" "1.11.1" + "@webassemblyjs/helper-buffer" "1.11.1" + "@webassemblyjs/wasm-gen" "1.11.1" + "@webassemblyjs/wasm-parser" "1.11.1" + "@webassemblyjs/wasm-opt@1.9.0": version "1.9.0" resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.9.0.tgz#2211181e5b31326443cc8112eb9f0b9028721a61" @@ -2250,6 +2377,18 @@ "@webassemblyjs/wasm-gen" "1.9.0" "@webassemblyjs/wasm-parser" "1.9.0" +"@webassemblyjs/wasm-parser@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz#86ca734534f417e9bd3c67c7a1c75d8be41fb199" + integrity sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA== + dependencies: + "@webassemblyjs/ast" "1.11.1" + "@webassemblyjs/helper-api-error" "1.11.1" + "@webassemblyjs/helper-wasm-bytecode" "1.11.1" + "@webassemblyjs/ieee754" "1.11.1" + "@webassemblyjs/leb128" "1.11.1" + "@webassemblyjs/utf8" "1.11.1" + "@webassemblyjs/wasm-parser@1.9.0": version "1.9.0" resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.9.0.tgz#9d48e44826df4a6598294aa6c87469d642fff65e" @@ -2274,6 +2413,14 @@ "@webassemblyjs/helper-fsm" "1.9.0" "@xtuc/long" "4.2.2" +"@webassemblyjs/wast-printer@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz#d0c73beda8eec5426f10ae8ef55cee5e7084c2f0" + integrity sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg== + dependencies: + "@webassemblyjs/ast" "1.11.1" + "@xtuc/long" "4.2.2" + "@webassemblyjs/wast-printer@1.9.0": version "1.9.0" resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.9.0.tgz#4935d54c85fef637b00ce9f52377451d00d47899" @@ -2321,11 +2468,21 @@ ace-builds@^1.4.12, ace-builds@^1.4.6: resolved "https://registry.yarnpkg.com/ace-builds/-/ace-builds-1.4.12.tgz#888efa386e36f4345f40b5233fcc4fe4c588fae7" integrity sha512-G+chJctFPiiLGvs3+/Mly3apXTcfgE45dT5yp12BcWZ1kUs+gm0qd3/fv4gsz6fVag4mM0moHVpjHDIgph6Psg== +acorn-import-assertions@^1.7.6: + version "1.8.0" + resolved "https://registry.yarnpkg.com/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz#ba2b5939ce62c238db6d93d81c9b111b29b855e9" + integrity sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw== + acorn@^6.4.1: version "6.4.2" resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.4.2.tgz#35866fd710528e92de10cf06016498e47e39e1e6" integrity sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ== +acorn@^8.4.1: + version "8.6.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.6.0.tgz#e3692ba0eb1a0c83eaa4f37f5fa7368dd7142895" + integrity sha512-U1riIR+lBSNi3IbxtaHOIKdH8sLFv3NYfNv8sg7ZsNhcfl4HF2++BfqqrNAxoCLQW1iiylOj76ecnaUxz+z9yw== + add-dom-event-listener@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/add-dom-event-listener/-/add-dom-event-listener-1.1.0.tgz#6a92db3a0dd0abc254e095c0f1dc14acbbaae310" @@ -4417,14 +4574,13 @@ enhanced-resolve@^4.3.0: memory-fs "^0.5.0" tapable "^1.0.0" -enhanced-resolve@^4.5.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-4.5.0.tgz#2f3cfd84dbe3b487f18f2db2ef1e064a571ca5ec" - integrity sha512-Nv9m36S/vxpsI+Hc4/ZGRs0n9mXqSWGGq49zxb/cJfPAQMbUtttJAlNPS4AQzaBdw/pKskw5bMbekT/Y7W/Wlg== +enhanced-resolve@^5.8.3: + version "5.8.3" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.8.3.tgz#6d552d465cce0423f5b3d718511ea53826a7b2f0" + integrity sha512-EGAbGvH7j7Xt2nc0E7D99La1OiEs8LnyimkRgwExpUMScN6O+3x9tIWs7PLQZVNx4YD+00skHXPXi1yQHpAmZA== dependencies: - graceful-fs "^4.1.2" - memory-fs "^0.5.0" - tapable "^1.0.0" + graceful-fs "^4.2.4" + tapable "^2.2.0" ent@~2.2.0: version "2.2.0" @@ -4500,6 +4656,11 @@ es-abstract@^1.18.0-next.0, es-abstract@^1.18.0-next.1: string.prototype.trimend "^1.0.1" string.prototype.trimstart "^1.0.1" +es-module-lexer@^0.9.0: + version "0.9.3" + resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-0.9.3.tgz#6f13db00cc38417137daf74366f535c8eb438f19" + integrity sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ== + es-to-primitive@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" @@ -4541,6 +4702,14 @@ escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= +eslint-scope@5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" + integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== + dependencies: + esrecurse "^4.3.0" + estraverse "^4.1.1" + eslint-scope@^4.0.3: version "4.0.3" resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-4.0.3.tgz#ca03833310f6889a3264781aa82e63eb9cfe7848" @@ -4554,7 +4723,7 @@ esprima@^4.0.0: resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== -esrecurse@^4.1.0: +esrecurse@^4.1.0, esrecurse@^4.3.0: version "4.3.0" resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== @@ -4596,6 +4765,11 @@ events@^3.0.0: resolved "https://registry.yarnpkg.com/events/-/events-3.2.0.tgz#93b87c18f8efcd4202a461aec4dfc0556b639379" integrity sha512-/46HWwbfCX2xTawVfkKLGxMifJYQBWMwY1mjywRtb4c9x8l5NP3KoJtnIOiL1hfdRkIuYhETxQlo62IF8tcnlg== +events@^3.2.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" + integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== + eventsource@^1.0.7: version "1.0.7" resolved "https://registry.yarnpkg.com/eventsource/-/eventsource-1.0.7.tgz#8fbc72c93fcd34088090bc0a4e64f4b5cee6d8d0" @@ -5100,6 +5274,11 @@ glob-parent@^5.1.0, glob-parent@^5.1.1, glob-parent@~5.1.0: dependencies: is-glob "^4.0.1" +glob-to-regexp@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e" + integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw== + glob@7.1.6, glob@^7.0.3, glob@^7.0.6, glob@^7.1.1, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6: version "7.1.6" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" @@ -6071,6 +6250,15 @@ jest-worker@26.6.2, jest-worker@^26.5.0: merge-stream "^2.0.0" supports-color "^7.0.0" +jest-worker@^27.0.6: + version "27.4.0" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.4.0.tgz#fa10dddc611cbb47a4153543dd16a0c7e7fd745c" + integrity sha512-4WuKcUxtzxBoKOUFbt1MtTY9fJwPVD4aN/4Cgxee7OLetPZn5as2bjfZz98XSf2Zq1JFfhqPZpS+43BmWXKgCA== + dependencies: + "@types/node" "*" + merge-stream "^2.0.0" + supports-color "^8.0.0" + jquery.terminal@^2.24.0: version "2.24.0" resolved "https://registry.yarnpkg.com/jquery.terminal/-/jquery.terminal-2.24.0.tgz#779a92b4478ac7542e7adaf5e17f4d4d92fd622c" @@ -6510,6 +6698,11 @@ loader-runner@^2.4.0: resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-2.4.0.tgz#ed47066bfe534d7e84c4c7b9998c2a75607d9357" integrity sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw== +loader-runner@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-4.2.0.tgz#d7022380d66d14c5fb1d496b89864ebcfd478384" + integrity sha512-92+huvxMvYlMzMt0iIOukcwYBFpkYJdpl2xsZ7LrlayO7E8SOv+JJUEK17B/dJIHAOLMfh2dZZ/Y18WgmGtYNw== + loader-utils@2.0.0, loader-utils@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-2.0.0.tgz#e4cace5b816d425a166b5f097e10cd12b36064b0" @@ -6818,6 +7011,11 @@ mime-db@1.44.0: resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.44.0.tgz#fa11c5eb0aca1334b4233cb4d52f10c5a6272f92" integrity sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg== +mime-db@1.51.0: + version "1.51.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.51.0.tgz#d9ff62451859b18342d960850dc3cfb77e63fb0c" + integrity sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g== + "mime-db@>= 1.43.0 < 2": version "1.45.0" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.45.0.tgz#cceeda21ccd7c3a745eba2decd55d4b73e7879ea" @@ -6830,6 +7028,13 @@ mime-types@^2.1.12, mime-types@~2.1.17, mime-types@~2.1.19, mime-types@~2.1.24: dependencies: mime-db "1.44.0" +mime-types@^2.1.27: + version "2.1.34" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.34.tgz#5a712f9ec1503511a945803640fafe09d3793c24" + integrity sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A== + dependencies: + mime-db "1.51.0" + mime@1.6.0, mime@^1.4.1: version "1.6.0" resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" @@ -9079,6 +9284,15 @@ schema-utils@^3.0.0: ajv "^6.12.5" ajv-keywords "^3.5.2" +schema-utils@^3.1.0, schema-utils@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-3.1.1.tgz#bc74c4b6b6995c1d88f76a8b77bea7219e0c8281" + integrity sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw== + dependencies: + "@types/json-schema" "^7.0.8" + ajv "^6.12.5" + ajv-keywords "^3.5.2" + screenfull@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/screenfull/-/screenfull-5.1.0.tgz#85c13c70f4ead4c1b8a935c70010dfdcd2c0e5c8" @@ -9192,6 +9406,13 @@ serialize-javascript@^5.0.1: dependencies: randombytes "^2.1.0" +serialize-javascript@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.0.tgz#efae5d88f45d7924141da8b5c3a7a7e663fefeb8" + integrity sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag== + dependencies: + randombytes "^2.1.0" + serve-index@^1.9.1: version "1.9.1" resolved "https://registry.yarnpkg.com/serve-index/-/serve-index-1.9.1.tgz#d3768d69b1e7d82e5ce050fff5b453bea12a9239" @@ -9460,6 +9681,14 @@ source-map-support@~0.4.0: dependencies: source-map "^0.5.6" +source-map-support@~0.5.20: + version "0.5.21" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" + integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + source-map-url@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" @@ -9800,6 +10029,13 @@ supports-color@^7.0.0, supports-color@^7.1.0: dependencies: has-flag "^4.0.0" +supports-color@^8.0.0: + version "8.1.1" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" + integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== + dependencies: + has-flag "^4.0.0" + svgo@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/svgo/-/svgo-2.3.0.tgz#6b3af81d0cbd1e19c83f5f63cec2cb98c70b5373" @@ -9833,6 +10069,11 @@ tapable@^1.0.0, tapable@^1.1.3: resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.1.3.tgz#a1fccc06b58db61fd7a45da2da44f5f3a3e67ba2" integrity sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA== +tapable@^2.1.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0" + integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ== + tapable@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.0.tgz#5c373d281d9c672848213d0e037d1c4165ab426b" @@ -9892,6 +10133,17 @@ terser-webpack-plugin@^1.4.3: webpack-sources "^1.4.0" worker-farm "^1.7.0" +terser-webpack-plugin@^5.1.3: + version "5.2.5" + resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.2.5.tgz#ce65b9880a0c36872555c4874f45bbdb02ee32c9" + integrity sha512-3luOVHku5l0QBeYS8r4CdHYWEGMmIj3H1U64jgkdZzECcSOJAyJ9TjuqcQZvw1Y+4AOBN9SeYJPJmFn2cM4/2g== + dependencies: + jest-worker "^27.0.6" + schema-utils "^3.1.1" + serialize-javascript "^6.0.0" + source-map "^0.6.1" + terser "^5.7.2" + terser@5.5.1: version "5.5.1" resolved "https://registry.yarnpkg.com/terser/-/terser-5.5.1.tgz#540caa25139d6f496fdea056e414284886fb2289" @@ -9919,6 +10171,15 @@ terser@^5.3.4: source-map "~0.7.2" source-map-support "~0.5.19" +terser@^5.7.2: + version "5.10.0" + resolved "https://registry.yarnpkg.com/terser/-/terser-5.10.0.tgz#b86390809c0389105eb0a0b62397563096ddafcc" + integrity sha512-AMmF99DMfEDiRJfxfY5jj5wNH/bYO09cniSqhfoyxc8sFoYIgkJy86G04UoZU5VjlpnplVu0K6Tx6E9b5+DlHA== + dependencies: + commander "^2.20.0" + source-map "~0.7.2" + source-map-support "~0.5.20" + text-table@0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" @@ -10412,6 +10673,14 @@ watchpack@^1.7.4: chokidar "^3.4.1" watchpack-chokidar2 "^2.0.0" +watchpack@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.3.0.tgz#a41bca3da6afaff31e92a433f4c856a0c25ea0c4" + integrity sha512-MnN0Q1OsvB/GGHETrFeZPQaOelWh/7O+EiFlj8sM9GPjtQkis7k01aAxrg/18kTfoIVcLL+haEVFlXDaSRwKRw== + dependencies: + glob-to-regexp "^0.4.1" + graceful-fs "^4.1.2" + wbuf@^1.1.0, wbuf@^1.7.3: version "1.7.3" resolved "https://registry.yarnpkg.com/wbuf/-/wbuf-1.7.3.tgz#c1d8d149316d3ea852848895cb6a0bfe887b87df" @@ -10533,6 +10802,11 @@ webpack-sources@^1.1.0, webpack-sources@^1.2.0, webpack-sources@^1.3.0, webpack- source-list-map "^2.0.0" source-map "~0.6.1" +webpack-sources@^3.2.2: + version "3.2.2" + resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.2.tgz#d88e3741833efec57c4c789b6010db9977545260" + integrity sha512-cp5qdmHnu5T8wRg2G3vZZHoJPN14aqQ89SyQ11NpGH5zEMDCclt49rzo+MaRazk7/UeILhAI+/sEtcM+7Fr0nw== + webpack-subresource-integrity@1.5.2: version "1.5.2" resolved "https://registry.yarnpkg.com/webpack-subresource-integrity/-/webpack-subresource-integrity-1.5.2.tgz#e40b6578d3072e2d24104975249c52c66e9a743e" @@ -10569,34 +10843,35 @@ webpack@4.44.2: watchpack "^1.7.4" webpack-sources "^1.4.1" -webpack@^4.46.0: - version "4.46.0" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.46.0.tgz#bf9b4404ea20a073605e0a011d188d77cb6ad542" - integrity sha512-6jJuJjg8znb/xRItk7bkT0+Q7AHCYjjFnvKIWQPkNIOyRqoCGvkOs0ipeQzrqz4l5FtN5ZI/ukEHroeX/o1/5Q== - dependencies: - "@webassemblyjs/ast" "1.9.0" - "@webassemblyjs/helper-module-context" "1.9.0" - "@webassemblyjs/wasm-edit" "1.9.0" - "@webassemblyjs/wasm-parser" "1.9.0" - acorn "^6.4.1" - ajv "^6.10.2" - ajv-keywords "^3.4.1" +webpack@^5.64.4: + version "5.64.4" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.64.4.tgz#e1454b6a13009f57cc2c78e08416cd674622937b" + integrity sha512-LWhqfKjCLoYJLKJY8wk2C3h77i8VyHowG3qYNZiIqD6D0ZS40439S/KVuc/PY48jp2yQmy0mhMknq8cys4jFMw== + dependencies: + "@types/eslint-scope" "^3.7.0" + "@types/estree" "^0.0.50" + "@webassemblyjs/ast" "1.11.1" + "@webassemblyjs/wasm-edit" "1.11.1" + "@webassemblyjs/wasm-parser" "1.11.1" + acorn "^8.4.1" + acorn-import-assertions "^1.7.6" + browserslist "^4.14.5" chrome-trace-event "^1.0.2" - enhanced-resolve "^4.5.0" - eslint-scope "^4.0.3" + enhanced-resolve "^5.8.3" + es-module-lexer "^0.9.0" + eslint-scope "5.1.1" + events "^3.2.0" + glob-to-regexp "^0.4.1" + graceful-fs "^4.2.4" json-parse-better-errors "^1.0.2" - loader-runner "^2.4.0" - loader-utils "^1.2.3" - memory-fs "^0.4.1" - micromatch "^3.1.10" - mkdirp "^0.5.3" - neo-async "^2.6.1" - node-libs-browser "^2.2.1" - schema-utils "^1.0.0" - tapable "^1.1.3" - terser-webpack-plugin "^1.4.3" - watchpack "^1.7.4" - webpack-sources "^1.4.1" + loader-runner "^4.2.0" + mime-types "^2.1.27" + neo-async "^2.6.2" + schema-utils "^3.1.0" + tapable "^2.1.1" + terser-webpack-plugin "^5.1.3" + watchpack "^2.3.0" + webpack-sources "^3.2.2" websocket-driver@>=0.5.1, websocket-driver@^0.7.4: version "0.7.4" From ad8ffd6734612f204eeb6196e72d37bf73bd2491 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Tue, 30 Nov 2021 09:44:19 +0200 Subject: [PATCH 173/432] Update webpack and ngrx --- ui-ngx/package.json | 8 ++++---- ui-ngx/yarn.lock | 31 ++++++++++++++++++------------- 2 files changed, 22 insertions(+), 17 deletions(-) diff --git a/ui-ngx/package.json b/ui-ngx/package.json index 672af523b0..ba60fac028 100644 --- a/ui-ngx/package.json +++ b/ui-ngx/package.json @@ -34,9 +34,9 @@ "@material-ui/core": "^4.11.4", "@material-ui/icons": "^4.11.2", "@material-ui/pickers": "^3.3.10", - "@ngrx/effects": "^10.1.2", - "@ngrx/store": "^10.1.2", - "@ngrx/store-devtools": "^10.1.2", + "@ngrx/effects": "^12.5.1", + "@ngrx/store": "^12.5.1", + "@ngrx/store-devtools": "^12.5.1", "@ngx-translate/core": "^13.0.0", "@ngx-translate/http-loader": "^6.0.0", "ace-builds": "^1.4.12", @@ -105,7 +105,7 @@ "@angular/cli": "^11.2.13", "@angular/compiler-cli": "^11.2.14", "@angular/language-service": "^11.2.14", - "@ngtools/webpack": "~11.2.13", + "@ngtools/webpack": "~12.2.13", "@types/canvas-gauges": "^2.1.2", "@types/flot": "^0.0.31", "@types/jasmine": "~3.7.4", diff --git a/ui-ngx/yarn.lock b/ui-ngx/yarn.lock index c749b240a5..5e88917fd1 100644 --- a/ui-ngx/yarn.lock +++ b/ui-ngx/yarn.lock @@ -1545,28 +1545,28 @@ prop-types "^15.7.2" react-is "^16.8.0 || ^17.0.0" -"@ngrx/effects@^10.1.2": - version "10.1.2" - resolved "https://registry.yarnpkg.com/@ngrx/effects/-/effects-10.1.2.tgz#f1c9daa2e3e13aeb6af272cb52f6dff73d364d68" - integrity sha512-6pX6FEzLlqdbtFVMbCvscsaL6QC/L95e72JKj76Xz+8V77UTlpVsxWyMo7YU9pM4EXNpBGmOpMs2xKjfBfK05Q== +"@ngrx/effects@^12.5.1": + version "12.5.1" + resolved "https://registry.yarnpkg.com/@ngrx/effects/-/effects-12.5.1.tgz#acd0ff86d8db514e47337508dde83cc98f7a3416" + integrity sha512-fVNGIIntYLRWW1XWe0os2XOv03L22S4WTkX0OPZ9O6ztwuaNq0yzxWN7UeAC6H385F+g0k76KwRV78zHyP0bfQ== dependencies: tslib "^2.0.0" -"@ngrx/store-devtools@^10.1.2": - version "10.1.2" - resolved "https://registry.yarnpkg.com/@ngrx/store-devtools/-/store-devtools-10.1.2.tgz#1dba8c84df4b56a2b15d6abc01c3c378d1518830" - integrity sha512-HE681GuZ+lRgSXpgt7y7LKzsfu/+Tgy9yPZpaitvkhg+eCIjnN5Uvs1rWqETHYWnsKliW25yoqFUAVw+xb7hug== +"@ngrx/store-devtools@^12.5.1": + version "12.5.1" + resolved "https://registry.yarnpkg.com/@ngrx/store-devtools/-/store-devtools-12.5.1.tgz#75f8ef9a4bf4a40d5343ff437651f0f3092914b5" + integrity sha512-SXMxVO3KzQUfB9G20gdNT5t/RcbtbaUySXLuH+b69z/eb34wH9AOYifdSdcEi8oqPjDrWYBq6a8Uh+yDHf9IfA== dependencies: tslib "^2.0.0" -"@ngrx/store@^10.1.2": - version "10.1.2" - resolved "https://registry.yarnpkg.com/@ngrx/store/-/store-10.1.2.tgz#a41aee81ea7b7e4a9f927be560e6024830211efb" - integrity sha512-FUjN786ch4Qt9WgJ78ef7Yquq3mPCekgcWgZrs4ycZw1f+KdfTHLTk1bGDtO8A8CzOya5yTT7KhxbdVjbOS5ng== +"@ngrx/store@^12.5.1": + version "12.5.1" + resolved "https://registry.yarnpkg.com/@ngrx/store/-/store-12.5.1.tgz#a7c21d7df1d017d2cb7e77804b210cc14bcf8786" + integrity sha512-NLVkHLVeZc7IboXSDZlFoq1QrupmwYTYKRHS6se7ZasAv/lrIjHWsVVdICKSVRBsHZYu3+dmCXmu+YgulP7iHw== dependencies: tslib "^2.0.0" -"@ngtools/webpack@11.2.13", "@ngtools/webpack@~11.2.13": +"@ngtools/webpack@11.2.13": version "11.2.13" resolved "https://registry.yarnpkg.com/@ngtools/webpack/-/webpack-11.2.13.tgz#dbd77deb37ab57fd98678bd637fe87693fd71f4f" integrity sha512-Wbv1zjLaS1zXcJ1wryYc6vhKWq8r/+ZrdN5SlRIf3xf7fwuTymbvL41SndUibssXir6s4vePYqZL241nkThx9g== @@ -1575,6 +1575,11 @@ enhanced-resolve "5.7.0" webpack-sources "2.2.0" +"@ngtools/webpack@~12.2.13": + version "12.2.13" + resolved "https://registry.yarnpkg.com/@ngtools/webpack/-/webpack-12.2.13.tgz#44d711edfa39d175a2d655aa5c6f9968dfedcc35" + integrity sha512-krAwMyRqOaC1S0+IxAFid9F6A6ABip2DJ0tgCx26X+1Vw/d1GKtV9ZqDJFizMf5k1ywl9aBlhOazWpq5d6i+gw== + "@ngx-translate/core@^13.0.0": version "13.0.0" resolved "https://registry.yarnpkg.com/@ngx-translate/core/-/core-13.0.0.tgz#60547cb8a0845a2a0abfde6b0bf5ec6516a63fd6" From 0dfc060fdfb4498ecc7017556a4b741a88b2fe67 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Tue, 30 Nov 2021 09:46:42 +0200 Subject: [PATCH 174/432] Update deps versions --- ui-ngx/package.json | 2 +- ui-ngx/yarn.lock | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/ui-ngx/package.json b/ui-ngx/package.json index ba60fac028..08ef9ad473 100644 --- a/ui-ngx/package.json +++ b/ui-ngx/package.json @@ -41,7 +41,7 @@ "@ngx-translate/http-loader": "^6.0.0", "ace-builds": "^1.4.12", "angular-gridster2": "~11.2.0", - "angular2-hotkeys": "^2.2.0", + "angular2-hotkeys": "^2.4.0", "canvas-gauges": "^2.1.7", "compass-sass-mixins": "^0.12.7", "core-js": "^3.18.3", diff --git a/ui-ngx/yarn.lock b/ui-ngx/yarn.lock index 5e88917fd1..cd28f3ef00 100644 --- a/ui-ngx/yarn.lock +++ b/ui-ngx/yarn.lock @@ -2581,13 +2581,14 @@ angular-gridster2@~11.2.0: dependencies: tslib "^2.0.0" -angular2-hotkeys@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/angular2-hotkeys/-/angular2-hotkeys-2.2.0.tgz#7b52ba99c42c56656360953ab79d776f583d1ab8" - integrity sha512-2O2wtPyscQU/PtyPc+TefSHAql0VI51rrKyIt87YAvBaGUZEj5PZG2QtC7kYI3sFhXYlvrNefUxXoehFjEVQAQ== +angular2-hotkeys@^2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/angular2-hotkeys/-/angular2-hotkeys-2.4.0.tgz#b814ccc43bb55eddff103d2ccf42afd832e3ff9d" + integrity sha512-m1UHmPBCKNUoGDPbyfLxUcUXd7vn1welfpfCLv7hEM2HIYfEtFo158xx7l4mAufEeE5179uFJggSQcVwJennfg== dependencies: "@types/mousetrap" "^1.6.0" mousetrap "^1.6.0" + tslib "^2.0.0" ansi-colors@4.1.1: version "4.1.1" From d8879de327e55258792c6a565e5046c33716b621 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Tue, 30 Nov 2021 09:50:11 +0200 Subject: [PATCH 175/432] Angular core and cli 12 --- ui-ngx/package.json | 30 +- ui-ngx/src/environments/environment.ts | 2 +- ui-ngx/src/polyfills.ts | 2 +- ui-ngx/src/test.ts | 2 +- ui-ngx/yarn.lock | 2861 +++++++++++++++++++++--- 5 files changed, 2590 insertions(+), 307 deletions(-) diff --git a/ui-ngx/package.json b/ui-ngx/package.json index 08ef9ad473..06ec15ace2 100644 --- a/ui-ngx/package.json +++ b/ui-ngx/package.json @@ -5,7 +5,7 @@ "ng": "ng", "start": "node --max_old_space_size=8048 ./node_modules/@angular/cli/bin/ng serve --host 0.0.0.0 --open", "build": "ng build", - "build:prod": "ng build --prod --vendor-chunk", + "build:prod": "ng build --configuration production --vendor-chunk", "test": "ng test", "lint": "ng lint", "e2e": "ng e2e", @@ -13,17 +13,17 @@ }, "private": true, "dependencies": { - "@angular/animations": "^11.2.14", + "@angular/animations": "^12.2.13", "@angular/cdk": "^11.2.13", - "@angular/common": "^11.2.14", - "@angular/compiler": "^11.2.14", - "@angular/core": "^11.2.14", + "@angular/common": "^12.2.13", + "@angular/compiler": "^12.2.13", + "@angular/core": "^12.2.13", "@angular/flex-layout": "^11.0.0-beta.33", - "@angular/forms": "^11.2.14", + "@angular/forms": "^12.2.13", "@angular/material": "^11.2.13", - "@angular/platform-browser": "^11.2.14", - "@angular/platform-browser-dynamic": "^11.2.14", - "@angular/router": "^11.2.14", + "@angular/platform-browser": "^12.2.13", + "@angular/platform-browser-dynamic": "^12.2.13", + "@angular/router": "^12.2.13", "@auth0/angular-jwt": "^5.0.2", "@date-io/date-fns": "^2.10.11", "@flowjs/flow.js": "^2.14.1", @@ -101,10 +101,10 @@ }, "devDependencies": { "@angular-builders/custom-webpack": "~11.1.1", - "@angular-devkit/build-angular": "^0.1102.13", - "@angular/cli": "^11.2.13", - "@angular/compiler-cli": "^11.2.14", - "@angular/language-service": "^11.2.14", + "@angular-devkit/build-angular": "^12.2.13", + "@angular/cli": "^12.2.13", + "@angular/compiler-cli": "^12.2.13", + "@angular/language-service": "^12.2.13", "@ngtools/webpack": "~12.2.13", "@types/canvas-gauges": "^2.1.2", "@types/flot": "^0.0.31", @@ -142,10 +142,10 @@ "protractor": "~7.0.0", "ts-node": "^9.0.0", "tslint": "~6.1.3", - "typescript": "~4.0.3", + "typescript": "~4.3.5", "webpack": "^5.64.4" }, "resolutions": { "lodash": "~4.17.21" } -} +} \ No newline at end of file diff --git a/ui-ngx/src/environments/environment.ts b/ui-ngx/src/environments/environment.ts index fd558aa87b..35f971c1d2 100644 --- a/ui-ngx/src/environments/environment.ts +++ b/ui-ngx/src/environments/environment.ts @@ -35,4 +35,4 @@ export const environment = { * This import should be commented out in production mode because it will have a negative impact * on performance if an error is thrown. */ -// import 'zone.js/dist/zone-error'; // Included with Angular CLI. +// import 'zone.js/plugins/zone-error'; // Included with Angular CLI. diff --git a/ui-ngx/src/polyfills.ts b/ui-ngx/src/polyfills.ts index 9da0bd3053..7c910914db 100644 --- a/ui-ngx/src/polyfills.ts +++ b/ui-ngx/src/polyfills.ts @@ -73,7 +73,7 @@ */ import './zone-flags'; -import 'zone.js/dist/zone'; // Included with Angular CLI. +import 'zone.js'; // Included with Angular CLI. import 'core-js/es/array'; /*************************************************************************************************** diff --git a/ui-ngx/src/test.ts b/ui-ngx/src/test.ts index 2fad0ab73c..567a569ad0 100644 --- a/ui-ngx/src/test.ts +++ b/ui-ngx/src/test.ts @@ -16,7 +16,7 @@ // This file is required by karma.conf.js and loads recursively all the .spec and framework files -import 'zone.js/dist/zone-testing'; +import 'zone.js/testing'; import { getTestBed } from '@angular/core/testing'; import { BrowserDynamicTestingModule, diff --git a/ui-ngx/yarn.lock b/ui-ngx/yarn.lock index cd28f3ef00..b1b280a8bc 100644 --- a/ui-ngx/yarn.lock +++ b/ui-ngx/yarn.lock @@ -2,6 +2,14 @@ # yarn lockfile v1 +"@ampproject/remapping@1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-1.0.1.tgz#1398e73e567c2a7992df6554c15bb94a89b68ba2" + integrity sha512-Ta9bMA3EtUHDaZJXqUoT5cn/EecwOp+SXpKJqxDbDuMbLvEMu6YTyDDuvTWeStODfdmXyfMo7LymQyPkN3BicA== + dependencies: + "@jridgewell/resolve-uri" "1.0.0" + sourcemap-codec "1.4.8" + "@angular-builders/custom-webpack@~11.1.1": version "11.1.1" resolved "https://registry.yarnpkg.com/@angular-builders/custom-webpack/-/custom-webpack-11.1.1.tgz#5ef535f5c51cb2f5a27f53fcfab54176cd1d14d4" @@ -23,7 +31,15 @@ "@angular-devkit/core" "11.2.13" rxjs "6.6.3" -"@angular-devkit/build-angular@>=0.1100.0 < 0.1200.0", "@angular-devkit/build-angular@^0.1102.13": +"@angular-devkit/architect@0.1202.13": + version "0.1202.13" + resolved "https://registry.yarnpkg.com/@angular-devkit/architect/-/architect-0.1202.13.tgz#b9b883d62f628a6b31ce071da91e268f61da00ef" + integrity sha512-LXgiidXwBgyWPqqWK4xR1/kCPQTMTzG5w+s7+LvENUZwbcdl6CKrOMjfgjo6WPr6yeq+WWQvPCD4pZ6nXRTm7A== + dependencies: + "@angular-devkit/core" "12.2.13" + rxjs "6.6.7" + +"@angular-devkit/build-angular@>=0.1100.0 < 0.1200.0": version "0.1102.13" resolved "https://registry.yarnpkg.com/@angular-devkit/build-angular/-/build-angular-0.1102.13.tgz#3d7bac8d471c6f2b7067236151cc5018b2ad1a51" integrity sha512-1ezVautOtfl16pOT3p7Z9IPd7vSyy6lZ+HZWqMK1AmUjNhsEA2WeuC/XznGatC3K+9IcfV+eSm6cP0iuLyETzw== @@ -102,6 +118,83 @@ webpack-subresource-integrity "1.5.2" worker-plugin "5.0.0" +"@angular-devkit/build-angular@^12.2.13": + version "12.2.13" + resolved "https://registry.yarnpkg.com/@angular-devkit/build-angular/-/build-angular-12.2.13.tgz#f5564d3ec9db132956473bb904bb3590482f5b36" + integrity sha512-iJ1P/RZ1hk2n/HtEqB5ohXvHa+Hf0BXShYskSGrn6/klcTb0eJTCREsFxHk7mNEmRIGPWkjbLAslqpPgwiagXg== + dependencies: + "@ampproject/remapping" "1.0.1" + "@angular-devkit/architect" "0.1202.13" + "@angular-devkit/build-optimizer" "0.1202.13" + "@angular-devkit/build-webpack" "0.1202.13" + "@angular-devkit/core" "12.2.13" + "@babel/core" "7.14.8" + "@babel/generator" "7.14.8" + "@babel/helper-annotate-as-pure" "7.14.5" + "@babel/plugin-proposal-async-generator-functions" "7.14.7" + "@babel/plugin-transform-async-to-generator" "7.14.5" + "@babel/plugin-transform-runtime" "7.14.5" + "@babel/preset-env" "7.14.8" + "@babel/runtime" "7.14.8" + "@babel/template" "7.14.5" + "@discoveryjs/json-ext" "0.5.3" + "@jsdevtools/coverage-istanbul-loader" "3.0.5" + "@ngtools/webpack" "12.2.13" + ansi-colors "4.1.1" + babel-loader "8.2.2" + browserslist "^4.9.1" + cacache "15.2.0" + caniuse-lite "^1.0.30001032" + circular-dependency-plugin "5.2.2" + copy-webpack-plugin "9.0.1" + core-js "3.16.0" + critters "0.0.12" + css-loader "6.2.0" + css-minimizer-webpack-plugin "3.0.2" + esbuild-wasm "0.13.8" + find-cache-dir "3.3.1" + glob "7.1.7" + https-proxy-agent "5.0.0" + inquirer "8.1.2" + karma-source-map-support "1.4.0" + less "4.1.1" + less-loader "10.0.1" + license-webpack-plugin "2.3.20" + loader-utils "2.0.0" + mini-css-extract-plugin "2.4.2" + minimatch "3.0.4" + open "8.2.1" + ora "5.4.1" + parse5-html-rewriting-stream "6.0.1" + piscina "3.1.0" + postcss "8.3.6" + postcss-import "14.0.2" + postcss-loader "6.1.1" + postcss-preset-env "6.7.0" + regenerator-runtime "0.13.9" + resolve-url-loader "4.0.0" + rxjs "6.6.7" + sass "1.36.0" + sass-loader "12.1.0" + semver "7.3.5" + source-map-loader "3.0.0" + source-map-support "0.5.19" + style-loader "3.2.1" + stylus "0.54.8" + stylus-loader "6.1.0" + terser "5.7.1" + terser-webpack-plugin "5.1.4" + text-table "0.2.0" + tree-kill "1.2.2" + tslib "2.3.0" + webpack "5.50.0" + webpack-dev-middleware "5.0.0" + webpack-dev-server "3.11.2" + webpack-merge "5.8.0" + webpack-subresource-integrity "1.5.2" + optionalDependencies: + esbuild "0.13.8" + "@angular-devkit/build-optimizer@0.1102.13": version "0.1102.13" resolved "https://registry.yarnpkg.com/@angular-devkit/build-optimizer/-/build-optimizer-0.1102.13.tgz#5c60fa88db41f22f296f1ee628f4c6abe90dac95" @@ -113,6 +206,15 @@ typescript "4.1.5" webpack-sources "2.2.0" +"@angular-devkit/build-optimizer@0.1202.13": + version "0.1202.13" + resolved "https://registry.yarnpkg.com/@angular-devkit/build-optimizer/-/build-optimizer-0.1202.13.tgz#7f0b13368cc2a08b1f4789ab1296a1609f5049ea" + integrity sha512-XX6rX5+mAl+MiIJDvi5N5mBLWOoskhMJ5r/G1PEqv0CMMJSSw60zUTndjxfq/nrX0PtsV3j/aqHN4Sj0w/gumg== + dependencies: + source-map "0.7.3" + tslib "2.3.0" + typescript "4.3.5" + "@angular-devkit/build-webpack@0.1102.13": version "0.1102.13" resolved "https://registry.yarnpkg.com/@angular-devkit/build-webpack/-/build-webpack-0.1102.13.tgz#d7d552500713278cc3ed28c3cc669f31b4f285a6" @@ -122,6 +224,14 @@ "@angular-devkit/core" "11.2.13" rxjs "6.6.3" +"@angular-devkit/build-webpack@0.1202.13": + version "0.1202.13" + resolved "https://registry.yarnpkg.com/@angular-devkit/build-webpack/-/build-webpack-0.1202.13.tgz#875f9f9677bb10056b52230965dc2f00bd3089dd" + integrity sha512-KafzGyHuU2gBKaSICfMTFP2niTYZ/46DKU94TQ0lCILdJZsj0NE5M/288LSCbYgu2c7srJKz+Rvb+JcYGxIZ1g== + dependencies: + "@angular-devkit/architect" "0.1202.13" + rxjs "6.6.7" + "@angular-devkit/core@11.2.13", "@angular-devkit/core@^11.0.0": version "11.2.13" resolved "https://registry.yarnpkg.com/@angular-devkit/core/-/core-11.2.13.tgz#7829862132555a52009d0af9671b06ffdf9200f1" @@ -133,21 +243,33 @@ rxjs "6.6.3" source-map "0.7.3" -"@angular-devkit/schematics@11.2.13": - version "11.2.13" - resolved "https://registry.yarnpkg.com/@angular-devkit/schematics/-/schematics-11.2.13.tgz#ce3b55e7f38ca9c40cb9c9c8d0096bd8e1490bb1" - integrity sha512-HMQWs9tsvmsS/QoL+ayxCYqjpP2Qc1x30EJrDU8zPDsaRCe06Uj7VYedBKlHpDGxh0D2F2oRSG1YkXGHr3H/TQ== +"@angular-devkit/core@12.2.13": + version "12.2.13" + resolved "https://registry.yarnpkg.com/@angular-devkit/core/-/core-12.2.13.tgz#db3929d1bfce71010b37fb7c4e6c33ef80a4f35f" + integrity sha512-9csMF0p+lTvlWnutxxTZ/+pDRMIbXk/TV4MGLbcqUPPfeG3dCRwErns73xLuMTwp9qO/KCLkFqNaM6cGOoqsDA== dependencies: - "@angular-devkit/core" "11.2.13" - ora "5.3.0" - rxjs "6.6.3" + ajv "8.6.2" + ajv-formats "2.1.0" + fast-json-stable-stringify "2.1.0" + magic-string "0.25.7" + rxjs "6.6.7" + source-map "0.7.3" -"@angular/animations@^11.2.14": - version "11.2.14" - resolved "https://registry.yarnpkg.com/@angular/animations/-/animations-11.2.14.tgz#cf119ea779bf11bd3759f1355c85e4e8e9e7bb03" - integrity sha512-Heq/nNrCmb3jbkusu+BQszOecfFI/31Oxxj+CDQkqqYpBcswk6bOJLoEE472o+vmgxaXbgeflU9qbIiCQhpMFA== +"@angular-devkit/schematics@12.2.13": + version "12.2.13" + resolved "https://registry.yarnpkg.com/@angular-devkit/schematics/-/schematics-12.2.13.tgz#6464d86fa3ccd0efb5ead46c793cef9ec45c7758" + integrity sha512-LQTv72R5Ma1uowMEeii2wIoDWI4bYQyZvunqPy9jRveBTjli2yVwwcOziGCVyttwlYs46bSdxThgeEvVIako2w== dependencies: - tslib "^2.0.0" + "@angular-devkit/core" "12.2.13" + ora "5.4.1" + rxjs "6.6.7" + +"@angular/animations@^12.2.13": + version "12.2.13" + resolved "https://registry.yarnpkg.com/@angular/animations/-/animations-12.2.13.tgz#909b79c56a85bb31c0605ed419850340b5580be9" + integrity sha512-qpdmvu+nxsKnimJ3Hc1joNuzK7xXYyE+VtNMk4K77Ao/9+5C/juGMce85DhqZCcu1xraZ3YYIrzYmL/GgdUK4g== + dependencies: + tslib "^2.2.0" "@angular/cdk@^11.2.13": version "11.2.13" @@ -158,85 +280,81 @@ optionalDependencies: parse5 "^5.0.0" -"@angular/cli@^11.2.13": - version "11.2.13" - resolved "https://registry.yarnpkg.com/@angular/cli/-/cli-11.2.13.tgz#10534aa2d16e438cf4bb0e912ab28a1eb67dafe1" - integrity sha512-ma5+Iu24XacSY5WrcZ5WJQMv7/RPhWxtbkpr11hndlgUmjmM6dYNGHJOFRXcU7bP7kbOVdd7cZ++2vMGlh0kcg== +"@angular/cli@^12.2.13": + version "12.2.13" + resolved "https://registry.yarnpkg.com/@angular/cli/-/cli-12.2.13.tgz#ca586c14a6f83bb4390875be0a0fa709b9a2ae29" + integrity sha512-Yz6MuwdxxP6U2i8iRuCSNZeJxlLDPshT/joymCsFdjwSMGEH9Kk9DdvAfFYfzdHGdHbGrDdASJ4G+uALyNSLxw== dependencies: - "@angular-devkit/architect" "0.1102.13" - "@angular-devkit/core" "11.2.13" - "@angular-devkit/schematics" "11.2.13" - "@schematics/angular" "11.2.13" - "@schematics/update" "0.1102.13" + "@angular-devkit/architect" "0.1202.13" + "@angular-devkit/core" "12.2.13" + "@angular-devkit/schematics" "12.2.13" + "@schematics/angular" "12.2.13" "@yarnpkg/lockfile" "1.1.0" ansi-colors "4.1.1" - debug "4.3.1" + debug "4.3.2" ini "2.0.0" - inquirer "7.3.3" + inquirer "8.1.2" jsonc-parser "3.0.0" - npm-package-arg "8.1.0" - npm-pick-manifest "6.1.0" - open "7.4.0" - ora "5.3.0" - pacote "11.2.4" - resolve "1.19.0" - rimraf "3.0.2" - semver "7.3.4" - symbol-observable "3.0.0" - universal-analytics "0.4.23" + npm-package-arg "8.1.5" + npm-pick-manifest "6.1.1" + open "8.2.1" + ora "5.4.1" + pacote "11.3.5" + resolve "1.20.0" + semver "7.3.5" + symbol-observable "4.0.0" uuid "8.3.2" -"@angular/common@^11.2.14": - version "11.2.14" - resolved "https://registry.yarnpkg.com/@angular/common/-/common-11.2.14.tgz#52887277b0ae0438e584f9ae97b417ee51a694b5" - integrity sha512-ZSLV/3j7eCTyLf/8g4yBFLWySjiLz3vLJAGWscYoUpnJWMnug1VRu6zoF/COxCbtORgE+Wz6K0uhfS6MziBGVw== +"@angular/common@^12.2.13": + version "12.2.13" + resolved "https://registry.yarnpkg.com/@angular/common/-/common-12.2.13.tgz#fe52ffae8668c1dec41b26cdc3a749101399e1fe" + integrity sha512-I1t/jl9ojCwTJKT7PKHnk23D+vMHTHS/9qZ2nndCjzGusMK8029nn8l3tHAkwefvxZWSaLAk1MgsVcP+rHQNsQ== dependencies: - tslib "^2.0.0" + tslib "^2.2.0" -"@angular/compiler-cli@^11.2.14": - version "11.2.14" - resolved "https://registry.yarnpkg.com/@angular/compiler-cli/-/compiler-cli-11.2.14.tgz#fdd22aeec25aa2477595bed631d19e977254ecc5" - integrity sha512-A7ltnCp03/EVqK/Q3tVUDsokgz5GHW3dSPGl0Csk7Ys5uBB9ibHTmVt4eiXA4jt0+6Bk+mKxwe5BEDqLvwYFAg== +"@angular/compiler-cli@^12.2.13": + version "12.2.13" + resolved "https://registry.yarnpkg.com/@angular/compiler-cli/-/compiler-cli-12.2.13.tgz#3ce463263e80a861e14af2ed3ba81598060e3ce0" + integrity sha512-qmnmihl3SCRooj/mCsNIZLtnQ6qbx1/L6aMIEQosPvQhMeGMt8GCYvQPE8IZ+sahv7fih95HCWNa9TeLpOylug== dependencies: "@babel/core" "^7.8.6" "@babel/types" "^7.8.6" canonical-path "1.0.0" chokidar "^3.0.0" convert-source-map "^1.5.1" - dependency-graph "^0.7.2" - fs-extra "4.0.2" + dependency-graph "^0.11.0" magic-string "^0.25.0" minimist "^1.2.0" reflect-metadata "^0.1.2" - semver "^6.3.0" + semver "^7.0.0" source-map "^0.6.1" sourcemap-codec "^1.4.8" - tslib "^2.0.0" - yargs "^16.2.0" + tslib "^2.2.0" + yargs "^17.0.0" "@angular/compiler@9.0.0": version "9.0.0" resolved "https://registry.yarnpkg.com/@angular/compiler/-/compiler-9.0.0.tgz#87e0bef4c369b6cadae07e3a4295778fc93799d5" integrity sha512-ctjwuntPfZZT2mNj2NDIVu51t9cvbhl/16epc5xEwyzyDt76pX9UgwvY+MbXrf/C/FWwdtmNtfP698BKI+9leQ== -"@angular/compiler@^11.2.14": - version "11.2.14" - resolved "https://registry.yarnpkg.com/@angular/compiler/-/compiler-11.2.14.tgz#9d3ea26b4d2d858aab935f69af9e201f53453a0f" - integrity sha512-XBOK3HgA+/y6Cz7kOX4zcJYmgJ264XnfcbXUMU2cD7Ac+mbNhLPKohWrEiSWalfcjnpf5gRfufQrQP7lpAGu0A== +"@angular/compiler@^12.2.13": + version "12.2.13" + resolved "https://registry.yarnpkg.com/@angular/compiler/-/compiler-12.2.13.tgz#7eef6fdb81b9de6fd0e2cdda2ad8a084c1d9535b" + integrity sha512-L0saTTJJtxldjhaGIL6b1BCfodPOEz4Wrev3pEUK5UcODooj5HLiE/aO6jiNb8M4XTbdqByKyqvZyWzGHeexVQ== dependencies: - tslib "^2.0.0" + tslib "^2.2.0" "@angular/core@9.0.0": version "9.0.0" resolved "https://registry.yarnpkg.com/@angular/core/-/core-9.0.0.tgz#227dc53e1ac81824f998c6e76000b7efc522641e" integrity sha512-6Pxgsrf0qF9iFFqmIcWmjJGkkCaCm6V5QNnxMy2KloO3SDq6QuMVRbN9RtC8Urmo25LP+eZ6ZgYqFYpdD8Hd9w== -"@angular/core@^11.2.14": - version "11.2.14" - resolved "https://registry.yarnpkg.com/@angular/core/-/core-11.2.14.tgz#3ebe298c79d5413dc670d56b7f503bd4d788d4a8" - integrity sha512-vpR4XqBGitk1Faph37CSpemwIYTmJ3pdIVNoHKP6jLonpWu+0azkchf0f7oD8/2ivj2F81opcIw0tcsy/D/5Vg== +"@angular/core@^12.2.13": + version "12.2.13" + resolved "https://registry.yarnpkg.com/@angular/core/-/core-12.2.13.tgz#fc40acbdcee5c5878bd249ddc0d643be724076c3" + integrity sha512-tZ5nAnmOi418JDaJIFiiP9z2JrluMJZvUvXO4QDUs52BXaL2yuP7MJ2LczWOVJXrBLZXeZGfjDjZmaFPA24grg== dependencies: - tslib "^2.0.0" + tslib "^2.2.0" "@angular/flex-layout@^11.0.0-beta.33": version "11.0.0-beta.33" @@ -245,17 +363,17 @@ dependencies: tslib "^2.0.0" -"@angular/forms@^11.2.14": - version "11.2.14" - resolved "https://registry.yarnpkg.com/@angular/forms/-/forms-11.2.14.tgz#dc858408f7647f4fd033996a03aa74df18a02079" - integrity sha512-4LWqY6KEIk1AZQFnk+4PJSOCamlD4tumuVN06gO4D0dZo9Cx+GcvW6pM6N0CPubRvPs3sScCnu20WT11HNWC1w== +"@angular/forms@^12.2.13": + version "12.2.13" + resolved "https://registry.yarnpkg.com/@angular/forms/-/forms-12.2.13.tgz#4de90e88991c274b5d5e3ab0300267e161ba78f2" + integrity sha512-wa7I5R8sck2q+VWNL262GJTVxtpEHMys8Bt6oE+lyHB5zlZAgOXwAb8GE4XVwuc+BZU1Gvrocn21P/8KvDY1uw== dependencies: - tslib "^2.0.0" + tslib "^2.2.0" -"@angular/language-service@^11.2.14": - version "11.2.14" - resolved "https://registry.yarnpkg.com/@angular/language-service/-/language-service-11.2.14.tgz#452369cdffe76ac6d07836596fb47f9e69a6d119" - integrity sha512-3+0F0X4r1WeNOV6VmaMzYnJENPVmLX2/MX3/lugwZPNYKVXl/oGyh/4PB8ktntIj0tnxQuErzqRSeucNStNGRw== +"@angular/language-service@^12.2.13": + version "12.2.13" + resolved "https://registry.yarnpkg.com/@angular/language-service/-/language-service-12.2.13.tgz#326045a328f8a962287037d7a85be8120074421c" + integrity sha512-jb9s3IJuWNKTRcM90NOwvMfiy85nnKfTxxLVn8/QFMO6+Ps/hsVZNp+W/TmAEDvCkon+9q0O4hwa4MY1m/Dlkw== "@angular/material@^11.2.13": version "11.2.13" @@ -264,32 +382,37 @@ dependencies: tslib "^2.0.0" -"@angular/platform-browser-dynamic@^11.2.14": - version "11.2.14" - resolved "https://registry.yarnpkg.com/@angular/platform-browser-dynamic/-/platform-browser-dynamic-11.2.14.tgz#3c7fff1a1daacba5390acf033d28c377ec281166" - integrity sha512-TWTPdFs6iBBcp+/YMsgCRQwdHpWGq8KjeJDJ2tfatGgBD3Gqt2YaHOMST1zPW6RkrmupytTejuVqXzeaKWFxuw== +"@angular/platform-browser-dynamic@^12.2.13": + version "12.2.13" + resolved "https://registry.yarnpkg.com/@angular/platform-browser-dynamic/-/platform-browser-dynamic-12.2.13.tgz#9ee6309f511da419d5d80a1a8279adc806e92f04" + integrity sha512-a7y7R3vOXhMAk9uQWK5/23DefahuF0UYJSFM/wKeVo5zR+qOCVCTfafkJMcWbuZWTrSDbVafJ1xbcWnu3+TkCg== dependencies: - tslib "^2.0.0" + tslib "^2.2.0" -"@angular/platform-browser@^11.2.14": - version "11.2.14" - resolved "https://registry.yarnpkg.com/@angular/platform-browser/-/platform-browser-11.2.14.tgz#e52ad7a54a42a865033a17e57e213013919f1b1d" - integrity sha512-fb7b7ss/gRoP8wLAN17W62leMgjynuyjEPU2eUoAAazsG9f2cgM+z3rK29GYncDVyYQxZUZYnjSqvL6GSXx86A== +"@angular/platform-browser@^12.2.13": + version "12.2.13" + resolved "https://registry.yarnpkg.com/@angular/platform-browser/-/platform-browser-12.2.13.tgz#769fb148b2128663d6b405d2a41023f2cdaa1c95" + integrity sha512-Ua8m2GtG2msqz/Mr/MK7s8RXud554x8cup2THVAwetyTaY5th/1LOZX0hhDIhfsxBCLHnC53LRhMbSsI0cikOg== dependencies: - tslib "^2.0.0" + tslib "^2.2.0" -"@angular/router@^11.2.14": - version "11.2.14" - resolved "https://registry.yarnpkg.com/@angular/router/-/router-11.2.14.tgz#4a8eb6d010a1a45c8e7f0c3b5b705959bdb69294" - integrity sha512-3aYBmj+zrEL9yf/ntIQxHIYaWShZOBKP3U07X2mX+TPMpGlvHDnR7L6bWhQVZwewzMMz7YVR16ldg50IFuAlfA== +"@angular/router@^12.2.13": + version "12.2.13" + resolved "https://registry.yarnpkg.com/@angular/router/-/router-12.2.13.tgz#e5b939a9675f9d4834fee3e75eb8d040ef63b3b5" + integrity sha512-HZL/Pzp6I7fQiMLrzfEzhnqhgNcGcFjBgMMOoLp5IA1IV26rp1NU6zYJzPrXtopBx7XLl8BECehAwFqrJsu/PQ== dependencies: - tslib "^2.0.0" + tslib "^2.2.0" "@ant-design/css-animation@^1.7.2": version "1.7.3" resolved "https://registry.yarnpkg.com/@ant-design/css-animation/-/css-animation-1.7.3.tgz#60a1c970014e86b28f940510d69e503e428f1136" integrity sha512-LrX0OGZtW+W6iLnTAqnTaoIsRelYeuLZWsrmBJFUXDALQphPsN8cE5DCsmoSlL0QYb94BQxINiuS70Ar/8BNgA== +"@assemblyscript/loader@^0.10.1": + version "0.10.1" + resolved "https://registry.yarnpkg.com/@assemblyscript/loader/-/loader-0.10.1.tgz#70e45678f06c72fa2e350e8553ec4a4d72b92e06" + integrity sha512-H71nDOOL8Y7kWRLqf6Sums+01Q5msqBW2KhDUTemh1tvY04eSkSXrK0uj/4mmY0Xr16/3zyZmsrxN7CKuRbNRg== + "@auth0/angular-jwt@^5.0.2": version "5.0.2" resolved "https://registry.yarnpkg.com/@auth0/angular-jwt/-/angular-jwt-5.0.2.tgz#0a23f240e8c6ed37c5c7a354ad79a755a217936e" @@ -311,11 +434,23 @@ dependencies: "@babel/highlight" "^7.12.13" +"@babel/code-frame@^7.14.5", "@babel/code-frame@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.16.0.tgz#0dfc80309beec8411e65e706461c408b0bb9b431" + integrity sha512-IF4EOMEV+bfYwOmNxGzSnjR2EmQod7f1UXOpZM3l4i4o4QNwzjtJAu/HxdjHq0aYBvdqMuQEY1eg0nqW9ZPORA== + dependencies: + "@babel/highlight" "^7.16.0" + "@babel/compat-data@^7.12.7", "@babel/compat-data@^7.13.15", "@babel/compat-data@^7.14.0": version "7.14.0" resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.14.0.tgz#a901128bce2ad02565df95e6ecbf195cf9465919" integrity sha512-vu9V3uMM/1o5Hl5OekMUowo3FqXLJSw+s+66nt0fSWVWTtmosdzn45JHOB3cPtZoe6CTBDzvSw0RdOY85Q37+Q== +"@babel/compat-data@^7.13.11", "@babel/compat-data@^7.14.7", "@babel/compat-data@^7.16.0": + version "7.16.4" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.16.4.tgz#081d6bbc336ec5c2435c6346b2ae1fb98b5ac68e" + integrity sha512-1o/jo7D+kC9ZjHX5v+EHrdjl3PhxMrLSOTGsOdHJ+KL8HCaEK6ehrVL2RS6oHDZp+L7xLirLrPmQtEng769J/Q== + "@babel/core@7.12.10": version "7.12.10" resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.12.10.tgz#b79a2e1b9f70ed3d84bbfb6d8c4ef825f606bccd" @@ -337,6 +472,27 @@ semver "^5.4.1" source-map "^0.5.0" +"@babel/core@7.14.8": + version "7.14.8" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.14.8.tgz#20cdf7c84b5d86d83fac8710a8bc605a7ba3f010" + integrity sha512-/AtaeEhT6ErpDhInbXmjHcUQXH0L0TEgscfcxk1qbOvLuKCa5aZT0SOOtDKFY96/CLROwbLSKyFor6idgNaU4Q== + dependencies: + "@babel/code-frame" "^7.14.5" + "@babel/generator" "^7.14.8" + "@babel/helper-compilation-targets" "^7.14.5" + "@babel/helper-module-transforms" "^7.14.8" + "@babel/helpers" "^7.14.8" + "@babel/parser" "^7.14.8" + "@babel/template" "^7.14.5" + "@babel/traverse" "^7.14.8" + "@babel/types" "^7.14.8" + convert-source-map "^1.7.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.1.2" + semver "^6.3.0" + source-map "^0.5.0" + "@babel/core@^7.7.5": version "7.11.6" resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.11.6.tgz#3a9455dc7387ff1bac45770650bc13ba04a15651" @@ -389,6 +545,15 @@ jsesc "^2.5.1" source-map "^0.5.0" +"@babel/generator@7.14.8": + version "7.14.8" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.14.8.tgz#bf86fd6af96cf3b74395a8ca409515f89423e070" + integrity sha512-cYDUpvIzhBVnMzRoY1fkSEhK/HmwEVwlyULYgn/tMQYd6Obag3ylCjONle3gdErfXBW61SVTlR9QR7uWlgeIkg== + dependencies: + "@babel/types" "^7.14.8" + jsesc "^2.5.1" + source-map "^0.5.0" + "@babel/generator@^7.11.5", "@babel/generator@^7.11.6": version "7.11.6" resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.11.6.tgz#b868900f81b163b4d464ea24545c61cbac4dc620" @@ -407,6 +572,22 @@ jsesc "^2.5.1" source-map "^0.5.0" +"@babel/generator@^7.14.8", "@babel/generator@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.16.0.tgz#d40f3d1d5075e62d3500bccb67f3daa8a95265b2" + integrity sha512-RR8hUCfRQn9j9RPKEVXo9LiwoxLPYn6hNZlvUOR8tSnaxlD0p0+la00ZP9/SnRt6HchKr+X0fO2r8vrETiJGew== + dependencies: + "@babel/types" "^7.16.0" + jsesc "^2.5.1" + source-map "^0.5.0" + +"@babel/helper-annotate-as-pure@7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.14.5.tgz#7bf478ec3b71726d56a8ca5775b046fc29879e61" + integrity sha512-EivH9EgBIb+G8ij1B2jAwSH36WnGvkQSEC6CkX/6v6ZFlw5fVOHvsgGF4uiEHO2GzMvunZb6tDLQEQSdrdocrA== + dependencies: + "@babel/types" "^7.14.5" + "@babel/helper-annotate-as-pure@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.10.4.tgz#5bf0d495a3f757ac3bda48b5bf3b3ba309c72ba3" @@ -421,6 +602,13 @@ dependencies: "@babel/types" "^7.12.13" +"@babel/helper-annotate-as-pure@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.16.0.tgz#9a1f0ebcda53d9a2d00108c4ceace6a5d5f1f08d" + integrity sha512-ItmYF9vR4zA8cByDocY05o0LGUkp1zhbTQOH1NFyl5xXEqlTJQCEJjieriw+aFpxo16swMxUnUiKS7a/r4vtHg== + dependencies: + "@babel/types" "^7.16.0" + "@babel/helper-builder-binary-assignment-operator-visitor@^7.12.13": version "7.12.13" resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.12.13.tgz#6bc20361c88b0a74d05137a65cac8d3cbf6f61fc" @@ -429,6 +617,14 @@ "@babel/helper-explode-assignable-expression" "^7.12.13" "@babel/types" "^7.12.13" +"@babel/helper-builder-binary-assignment-operator-visitor@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.16.0.tgz#f1a686b92da794020c26582eb852e9accd0d7882" + integrity sha512-9KuleLT0e77wFUku6TUkqZzCEymBdtuQQ27MhEKzf9UOOJu3cYj98kyaDAzxpC7lV6DGiZFuC8XqDsq8/Kl6aQ== + dependencies: + "@babel/helper-explode-assignable-expression" "^7.16.0" + "@babel/types" "^7.16.0" + "@babel/helper-compilation-targets@^7.12.5", "@babel/helper-compilation-targets@^7.13.16": version "7.13.16" resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.13.16.tgz#6e91dccf15e3f43e5556dffe32d860109887563c" @@ -439,6 +635,16 @@ browserslist "^4.14.5" semver "^6.3.0" +"@babel/helper-compilation-targets@^7.13.0", "@babel/helper-compilation-targets@^7.14.5", "@babel/helper-compilation-targets@^7.16.0": + version "7.16.3" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.16.3.tgz#5b480cd13f68363df6ec4dc8ac8e2da11363cbf0" + integrity sha512-vKsoSQAyBmxS35JUOOt+07cLc6Nk/2ljLIHwmq2/NM6hdioUaqEXq/S+nXvbvXbZkNDlWOymPanJGOc4CBjSJA== + dependencies: + "@babel/compat-data" "^7.16.0" + "@babel/helper-validator-option" "^7.14.5" + browserslist "^4.17.5" + semver "^6.3.0" + "@babel/helper-create-class-features-plugin@^7.13.0": version "7.14.3" resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.14.3.tgz#832111bcf4f57ca57a4c5b1a000fc125abc6554a" @@ -451,6 +657,18 @@ "@babel/helper-replace-supers" "^7.14.3" "@babel/helper-split-export-declaration" "^7.12.13" +"@babel/helper-create-class-features-plugin@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.16.0.tgz#090d4d166b342a03a9fec37ef4fd5aeb9c7c6a4b" + integrity sha512-XLwWvqEaq19zFlF5PTgOod4bUA+XbkR4WLQBct1bkzmxJGB0ZEJaoKF4c8cgH9oBtCDuYJ8BP5NB9uFiEgO5QA== + dependencies: + "@babel/helper-annotate-as-pure" "^7.16.0" + "@babel/helper-function-name" "^7.16.0" + "@babel/helper-member-expression-to-functions" "^7.16.0" + "@babel/helper-optimise-call-expression" "^7.16.0" + "@babel/helper-replace-supers" "^7.16.0" + "@babel/helper-split-export-declaration" "^7.16.0" + "@babel/helper-create-regexp-features-plugin@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.10.4.tgz#fdd60d88524659a0b6959c0579925e425714f3b8" @@ -468,6 +686,28 @@ "@babel/helper-annotate-as-pure" "^7.12.13" regexpu-core "^4.7.1" +"@babel/helper-create-regexp-features-plugin@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.16.0.tgz#06b2348ce37fccc4f5e18dcd8d75053f2a7c44ff" + integrity sha512-3DyG0zAFAZKcOp7aVr33ddwkxJ0Z0Jr5V99y3I690eYLpukJsJvAbzTy1ewoCqsML8SbIrjH14Jc/nSQ4TvNPA== + dependencies: + "@babel/helper-annotate-as-pure" "^7.16.0" + regexpu-core "^4.7.1" + +"@babel/helper-define-polyfill-provider@^0.2.2", "@babel/helper-define-polyfill-provider@^0.2.4": + version "0.2.4" + resolved "https://registry.yarnpkg.com/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.2.4.tgz#8867aed79d3ea6cade40f801efb7ac5c66916b10" + integrity sha512-OrpPZ97s+aPi6h2n1OXzdhVis1SGSsMU2aMHgLcOKfsp4/v1NWpx3CWT3lBj5eeBq9cDkPkh+YCfdF7O12uNDQ== + dependencies: + "@babel/helper-compilation-targets" "^7.13.0" + "@babel/helper-module-imports" "^7.12.13" + "@babel/helper-plugin-utils" "^7.13.0" + "@babel/traverse" "^7.13.0" + debug "^4.1.1" + lodash.debounce "^4.0.8" + resolve "^1.14.2" + semver "^6.1.2" + "@babel/helper-explode-assignable-expression@^7.12.13": version "7.13.0" resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.13.0.tgz#17b5c59ff473d9f956f40ef570cf3a76ca12657f" @@ -475,6 +715,13 @@ dependencies: "@babel/types" "^7.13.0" +"@babel/helper-explode-assignable-expression@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.16.0.tgz#753017337a15f46f9c09f674cff10cee9b9d7778" + integrity sha512-Hk2SLxC9ZbcOhLpg/yMznzJ11W++lg5GMbxt1ev6TXUiJB0N42KPC+7w8a+eWGuqDnUYuwStJoZHM7RgmIOaGQ== + dependencies: + "@babel/types" "^7.16.0" + "@babel/helper-function-name@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.10.4.tgz#d2d3b20c59ad8c47112fa7d2a94bc09d5ef82f1a" @@ -493,6 +740,15 @@ "@babel/template" "^7.12.13" "@babel/types" "^7.14.2" +"@babel/helper-function-name@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.16.0.tgz#b7dd0797d00bbfee4f07e9c4ea5b0e30c8bb1481" + integrity sha512-BZh4mEk1xi2h4HFjWUXRQX5AEx4rvaZxHgax9gcjdLWdkjsY7MKt5p0otjsg5noXw+pB+clMCjw+aEVYADMjog== + dependencies: + "@babel/helper-get-function-arity" "^7.16.0" + "@babel/template" "^7.16.0" + "@babel/types" "^7.16.0" + "@babel/helper-get-function-arity@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.10.4.tgz#98c1cbea0e2332f33f9a4661b8ce1505b2c19ba2" @@ -507,6 +763,13 @@ dependencies: "@babel/types" "^7.12.13" +"@babel/helper-get-function-arity@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.0.tgz#0088c7486b29a9cb5d948b1a1de46db66e089cfa" + integrity sha512-ASCquNcywC1NkYh/z7Cgp3w31YW8aojjYIlNg4VeJiHkqyP4AzIvr4qx7pYDb4/s8YcsZWqqOSxgkvjUz1kpDQ== + dependencies: + "@babel/types" "^7.16.0" + "@babel/helper-hoist-variables@^7.13.0": version "7.13.16" resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.13.16.tgz#1b1651249e94b51f8f0d33439843e33e39775b30" @@ -515,6 +778,13 @@ "@babel/traverse" "^7.13.15" "@babel/types" "^7.13.16" +"@babel/helper-hoist-variables@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.0.tgz#4c9023c2f1def7e28ff46fc1dbcd36a39beaa81a" + integrity sha512-1AZlpazjUR0EQZQv3sgRNfM9mEVWPK3M6vlalczA+EECcPz3XPh6VplbErL5UoMpChhSck5wAJHthlj1bYpcmg== + dependencies: + "@babel/types" "^7.16.0" + "@babel/helper-member-expression-to-functions@^7.10.4": version "7.11.0" resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.11.0.tgz#ae69c83d84ee82f4b42f96e2a09410935a8f26df" @@ -529,6 +799,13 @@ dependencies: "@babel/types" "^7.13.12" +"@babel/helper-member-expression-to-functions@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.16.0.tgz#29287040efd197c77636ef75188e81da8bccd5a4" + integrity sha512-bsjlBFPuWT6IWhl28EdrQ+gTvSvj5tqVP5Xeftp07SEuz5pLnsXZuDkDD3Rfcxy0IsHmbZ+7B2/9SHzxO0T+sQ== + dependencies: + "@babel/types" "^7.16.0" + "@babel/helper-module-imports@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.10.4.tgz#4c5c54be04bd31670a7382797d75b9fa2e5b5620" @@ -543,6 +820,13 @@ dependencies: "@babel/types" "^7.13.12" +"@babel/helper-module-imports@^7.14.5", "@babel/helper-module-imports@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.16.0.tgz#90538e60b672ecf1b448f5f4f5433d37e79a3ec3" + integrity sha512-kkH7sWzKPq0xt3H1n+ghb4xEMP8k0U7XV3kkB+ZGy69kDk2ySFW1qPi06sjKzFY3t1j6XbJSqr4mF9L7CYVyhg== + dependencies: + "@babel/types" "^7.16.0" + "@babel/helper-module-transforms@^7.11.0": version "7.11.0" resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.11.0.tgz#b16f250229e47211abdd84b34b64737c2ab2d359" @@ -570,6 +854,20 @@ "@babel/traverse" "^7.14.2" "@babel/types" "^7.14.2" +"@babel/helper-module-transforms@^7.14.8", "@babel/helper-module-transforms@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.16.0.tgz#1c82a8dd4cb34577502ebd2909699b194c3e9bb5" + integrity sha512-My4cr9ATcaBbmaEa8M0dZNA74cfI6gitvUAskgDtAFmAqyFKDSHQo5YstxPbN+lzHl2D9l/YOEFqb2mtUh4gfA== + dependencies: + "@babel/helper-module-imports" "^7.16.0" + "@babel/helper-replace-supers" "^7.16.0" + "@babel/helper-simple-access" "^7.16.0" + "@babel/helper-split-export-declaration" "^7.16.0" + "@babel/helper-validator-identifier" "^7.15.7" + "@babel/template" "^7.16.0" + "@babel/traverse" "^7.16.0" + "@babel/types" "^7.16.0" + "@babel/helper-optimise-call-expression@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.10.4.tgz#50dc96413d594f995a77905905b05893cd779673" @@ -584,6 +882,13 @@ dependencies: "@babel/types" "^7.12.13" +"@babel/helper-optimise-call-expression@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.16.0.tgz#cecdb145d70c54096b1564f8e9f10cd7d193b338" + integrity sha512-SuI467Gi2V8fkofm2JPnZzB/SUuXoJA5zXe/xzyPP2M04686RzFKFHPK6HDVN6JvWBIEW8tt9hPR7fXdn2Lgpw== + dependencies: + "@babel/types" "^7.16.0" + "@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz#2f75a831269d4f677de49986dff59927533cf375" @@ -594,6 +899,11 @@ resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz#806526ce125aed03373bc416a828321e3a6a33af" integrity sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ== +"@babel/helper-plugin-utils@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.14.5.tgz#5ac822ce97eec46741ab70a517971e443a70c5a9" + integrity sha512-/37qQCE3K0vvZKwoK4XU/irIJQdIfCJuhU5eKnNxpFDsOkgFaUAwbv+RYw6eYgsC0E4hS7r5KqGULUogqui0fQ== + "@babel/helper-regex@^7.10.4": version "7.10.5" resolved "https://registry.yarnpkg.com/@babel/helper-regex/-/helper-regex-7.10.5.tgz#32dfbb79899073c415557053a19bd055aae50ae0" @@ -610,6 +920,15 @@ "@babel/helper-wrap-function" "^7.13.0" "@babel/types" "^7.13.0" +"@babel/helper-remap-async-to-generator@^7.14.5", "@babel/helper-remap-async-to-generator@^7.16.0", "@babel/helper-remap-async-to-generator@^7.16.4": + version "7.16.4" + resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.16.4.tgz#5d7902f61349ff6b963e07f06a389ce139fbfe6e" + integrity sha512-vGERmmhR+s7eH5Y/cp8PCVzj4XEjerq8jooMfxFdA5xVtAk9Sh4AQsrWgiErUEBjtGrBtOFKDUcWQFW4/dFwMA== + dependencies: + "@babel/helper-annotate-as-pure" "^7.16.0" + "@babel/helper-wrap-function" "^7.16.0" + "@babel/types" "^7.16.0" + "@babel/helper-replace-supers@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.10.4.tgz#d585cd9388ea06e6031e4cd44b6713cbead9e6cf" @@ -630,6 +949,16 @@ "@babel/traverse" "^7.14.2" "@babel/types" "^7.14.2" +"@babel/helper-replace-supers@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.16.0.tgz#73055e8d3cf9bcba8ddb55cad93fedc860f68f17" + integrity sha512-TQxuQfSCdoha7cpRNJvfaYxxxzmbxXw/+6cS7V02eeDYyhxderSoMVALvwupA54/pZcOTtVeJ0xccp1nGWladA== + dependencies: + "@babel/helper-member-expression-to-functions" "^7.16.0" + "@babel/helper-optimise-call-expression" "^7.16.0" + "@babel/traverse" "^7.16.0" + "@babel/types" "^7.16.0" + "@babel/helper-simple-access@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.10.4.tgz#0f5ccda2945277a2a7a2d3a821e15395edcf3461" @@ -645,6 +974,13 @@ dependencies: "@babel/types" "^7.13.12" +"@babel/helper-simple-access@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.16.0.tgz#21d6a27620e383e37534cf6c10bba019a6f90517" + integrity sha512-o1rjBT/gppAqKsYfUdfHq5Rk03lMQrkPHG1OWzHWpLgVXRH4HnMM9Et9CVdIqwkCQlobnGHEJMsgWP/jE1zUiw== + dependencies: + "@babel/types" "^7.16.0" + "@babel/helper-skip-transparent-expression-wrappers@^7.12.1": version "7.12.1" resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.12.1.tgz#462dc63a7e435ade8468385c63d2b84cce4b3cbf" @@ -652,6 +988,13 @@ dependencies: "@babel/types" "^7.12.1" +"@babel/helper-skip-transparent-expression-wrappers@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.16.0.tgz#0ee3388070147c3ae051e487eca3ebb0e2e8bb09" + integrity sha512-+il1gTy0oHwUsBQZyJvukbB4vPMdcYBrFHa0Uc4AizLxbq6BOYC51Rv4tWocX9BLBDLZ4kc6qUFpQ6HRgL+3zw== + dependencies: + "@babel/types" "^7.16.0" + "@babel/helper-split-export-declaration@^7.11.0": version "7.11.0" resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.11.0.tgz#f8a491244acf6a676158ac42072911ba83ad099f" @@ -666,6 +1009,13 @@ dependencies: "@babel/types" "^7.12.13" +"@babel/helper-split-export-declaration@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.0.tgz#29672f43663e936df370aaeb22beddb3baec7438" + integrity sha512-0YMMRpuDFNGTHNRiiqJX19GjNXA4H0E8jZ2ibccfSxaCogbm3am5WN/2nQNj0YnQwGWM1J06GOcQ2qnh3+0paw== + dependencies: + "@babel/types" "^7.16.0" + "@babel/helper-validator-identifier@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz#a78c7a7251e01f616512d31b10adcf52ada5e0d2" @@ -676,11 +1026,21 @@ resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.0.tgz#d26cad8a47c65286b15df1547319a5d0bcf27288" integrity sha512-V3ts7zMSu5lfiwWDVWzRDGIN+lnCEUdaXgtVHJgLb1rGaA6jMrtB9EmE7L18foXJIE8Un/A/h6NJfGQp/e1J4A== +"@babel/helper-validator-identifier@^7.15.7": + version "7.15.7" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz#220df993bfe904a4a6b02ab4f3385a5ebf6e2389" + integrity sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w== + "@babel/helper-validator-option@^7.12.11", "@babel/helper-validator-option@^7.12.17": version "7.12.17" resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.12.17.tgz#d1fbf012e1a79b7eebbfdc6d270baaf8d9eb9831" integrity sha512-TopkMDmLzq8ngChwRlyjR6raKD6gMSae4JdYDB8bByKreQgG0RBTuKe9LRxW3wFtUnjxOPRKBDwEH6Mg5KeDfw== +"@babel/helper-validator-option@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.14.5.tgz#6e72a1fff18d5dfcb878e1e62f1a021c4b72d5a3" + integrity sha512-OX8D5eeX4XwcroVW45NMvoYaIuFI+GQpA2a8Gi+X/U/cDUIRsV37qQfF905F0htTRCREQIB4KqPeaveRJUl3Ow== + "@babel/helper-wrap-function@^7.13.0": version "7.13.0" resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.13.0.tgz#bdb5c66fda8526ec235ab894ad53a1235c79fcc4" @@ -691,6 +1051,16 @@ "@babel/traverse" "^7.13.0" "@babel/types" "^7.13.0" +"@babel/helper-wrap-function@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.16.0.tgz#b3cf318afce774dfe75b86767cd6d68f3482e57c" + integrity sha512-VVMGzYY3vkWgCJML+qVLvGIam902mJW0FvT7Avj1zEe0Gn7D93aWdLblYARTxEw+6DhZmtzhBM2zv0ekE5zg1g== + dependencies: + "@babel/helper-function-name" "^7.16.0" + "@babel/template" "^7.16.0" + "@babel/traverse" "^7.16.0" + "@babel/types" "^7.16.0" + "@babel/helpers@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.10.4.tgz#2abeb0d721aff7c0a97376b9e1f6f65d7a475044" @@ -709,6 +1079,15 @@ "@babel/traverse" "^7.14.0" "@babel/types" "^7.14.0" +"@babel/helpers@^7.14.8": + version "7.16.3" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.16.3.tgz#27fc64f40b996e7074dc73128c3e5c3e7f55c43c" + integrity sha512-Xn8IhDlBPhvYTvgewPKawhADichOsbkZuzN7qz2BusOM0brChsyXMDJvldWaYMMUNiCQdQzNEioXTp3sC8Nt8w== + dependencies: + "@babel/template" "^7.16.0" + "@babel/traverse" "^7.16.3" + "@babel/types" "^7.16.0" + "@babel/highlight@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.10.4.tgz#7d1bdfd65753538fabe6c38596cdb76d9ac60143" @@ -727,6 +1106,15 @@ chalk "^2.0.0" js-tokens "^4.0.0" +"@babel/highlight@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.16.0.tgz#6ceb32b2ca4b8f5f361fb7fd821e3fddf4a1725a" + integrity sha512-t8MH41kUQylBtu2+4IQA3atqevA2lRgqA2wyVB/YiWmsDSuylZZuXOUy9ric30hfzauEFfdsuk/eXTRrGrfd0g== + dependencies: + "@babel/helper-validator-identifier" "^7.15.7" + chalk "^2.0.0" + js-tokens "^4.0.0" + "@babel/parser@^7.10.4", "@babel/parser@^7.11.5": version "7.11.5" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.11.5.tgz#c7ff6303df71080ec7a4f5b8c003c58f1cf51037" @@ -737,6 +1125,29 @@ resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.14.3.tgz#9b530eecb071fd0c93519df25c5ff9f14759f298" integrity sha512-7MpZDIfI7sUC5zWo2+foJ50CSI5lcqDehZ0lVgIhSi4bFEk94fLAKlF3Q0nzSQQ+ca0lm+O6G9ztKVBeu8PMRQ== +"@babel/parser@^7.14.5", "@babel/parser@^7.14.8", "@babel/parser@^7.16.0", "@babel/parser@^7.16.3": + version "7.16.4" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.16.4.tgz#d5f92f57cf2c74ffe9b37981c0e72fee7311372e" + integrity sha512-6V0qdPUaiVHH3RtZeLIsc+6pDhbYzHR8ogA8w+f+Wc77DuXto19g2QUwveINoS34Uw+W8/hQDGJCx+i4n7xcng== + +"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.14.5": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.16.0.tgz#358972eaab006f5eb0826183b0c93cbcaf13e1e2" + integrity sha512-4tcFwwicpWTrpl9qjf7UsoosaArgImF85AxqCRZlgc3IQDvkUHjJpruXAL58Wmj+T6fypWTC/BakfEkwIL/pwA== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-skip-transparent-expression-wrappers" "^7.16.0" + "@babel/plugin-proposal-optional-chaining" "^7.16.0" + +"@babel/plugin-proposal-async-generator-functions@7.14.7": + version "7.14.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.14.7.tgz#784a48c3d8ed073f65adcf30b57bcbf6c8119ace" + integrity sha512-RK8Wj7lXLY3bqei69/cc25gwS5puEc3dknoFPFbqfy3XxYQBQFvu4ioWpafMBAB+L9NyptQK4nMOa5Xz16og8Q== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-remap-async-to-generator" "^7.14.5" + "@babel/plugin-syntax-async-generators" "^7.8.4" + "@babel/plugin-proposal-async-generator-functions@^7.12.1": version "7.14.2" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.14.2.tgz#3a2085abbf5d5f962d480dbc81347385ed62eb1e" @@ -746,6 +1157,15 @@ "@babel/helper-remap-async-to-generator" "^7.13.0" "@babel/plugin-syntax-async-generators" "^7.8.4" +"@babel/plugin-proposal-async-generator-functions@^7.14.7": + version "7.16.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.16.4.tgz#e606eb6015fec6fa5978c940f315eae4e300b081" + integrity sha512-/CUekqaAaZCQHleSK/9HajvcD/zdnJiKRiuUFq8ITE+0HsPzquf53cpFiqAwl/UfmJbR6n5uGPQSPdrmKOvHHg== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-remap-async-to-generator" "^7.16.4" + "@babel/plugin-syntax-async-generators" "^7.8.4" + "@babel/plugin-proposal-class-properties@^7.12.1": version "7.13.0" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.13.0.tgz#146376000b94efd001e57a40a88a525afaab9f37" @@ -754,6 +1174,23 @@ "@babel/helper-create-class-features-plugin" "^7.13.0" "@babel/helper-plugin-utils" "^7.13.0" +"@babel/plugin-proposal-class-properties@^7.14.5": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.16.0.tgz#c029618267ddebc7280fa286e0f8ca2a278a2d1a" + integrity sha512-mCF3HcuZSY9Fcx56Lbn+CGdT44ioBMMvjNVldpKtj8tpniETdLjnxdHI1+sDWXIM1nNt+EanJOZ3IG9lzVjs7A== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.16.0" + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-proposal-class-static-block@^7.14.5": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.16.0.tgz#5296942c564d8144c83eea347d0aa8a0b89170e7" + integrity sha512-mAy3sdcY9sKAkf3lQbDiv3olOfiLqI51c9DR9b19uMoR2Z6r5pmGl7dfNFqEvqOyqbf1ta4lknK4gc5PJn3mfA== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.16.0" + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-syntax-class-static-block" "^7.14.5" + "@babel/plugin-proposal-dynamic-import@^7.12.1": version "7.14.2" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.14.2.tgz#01ebabd7c381cff231fa43e302939a9de5be9d9f" @@ -762,6 +1199,14 @@ "@babel/helper-plugin-utils" "^7.13.0" "@babel/plugin-syntax-dynamic-import" "^7.8.3" +"@babel/plugin-proposal-dynamic-import@^7.14.5": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.16.0.tgz#783eca61d50526202f9b296095453977e88659f1" + integrity sha512-QGSA6ExWk95jFQgwz5GQ2Dr95cf7eI7TKutIXXTb7B1gCLTCz5hTjFTQGfLFBBiC5WSNi7udNwWsqbbMh1c4yQ== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-syntax-dynamic-import" "^7.8.3" + "@babel/plugin-proposal-export-namespace-from@^7.12.1": version "7.14.2" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.14.2.tgz#62542f94aa9ce8f6dba79eec698af22112253791" @@ -770,6 +1215,14 @@ "@babel/helper-plugin-utils" "^7.13.0" "@babel/plugin-syntax-export-namespace-from" "^7.8.3" +"@babel/plugin-proposal-export-namespace-from@^7.14.5": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.16.0.tgz#9c01dee40b9d6b847b656aaf4a3976a71740f222" + integrity sha512-CjI4nxM/D+5wCnhD11MHB1AwRSAYeDT+h8gCdcVJZ/OK7+wRzFsf7PFPWVpVpNRkHMmMkQWAHpTq+15IXQ1diA== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-syntax-export-namespace-from" "^7.8.3" + "@babel/plugin-proposal-json-strings@^7.12.1": version "7.14.2" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.14.2.tgz#830b4e2426a782e8b2878fbfe2cba85b70cbf98c" @@ -778,6 +1231,14 @@ "@babel/helper-plugin-utils" "^7.13.0" "@babel/plugin-syntax-json-strings" "^7.8.3" +"@babel/plugin-proposal-json-strings@^7.14.5": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.16.0.tgz#cae35a95ed1d2a7fa29c4dc41540b84a72e9ab25" + integrity sha512-kouIPuiv8mSi5JkEhzApg5Gn6hFyKPnlkO0a9YSzqRurH8wYzSlf6RJdzluAsbqecdW5pBvDJDfyDIUR/vLxvg== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-syntax-json-strings" "^7.8.3" + "@babel/plugin-proposal-logical-assignment-operators@^7.12.1": version "7.14.2" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.14.2.tgz#222348c080a1678e0e74ea63fe76f275882d1fd7" @@ -786,6 +1247,14 @@ "@babel/helper-plugin-utils" "^7.13.0" "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" +"@babel/plugin-proposal-logical-assignment-operators@^7.14.5": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.16.0.tgz#a711b8ceb3ffddd3ef88d3a49e86dbd3cc7db3fd" + integrity sha512-pbW0fE30sVTYXXm9lpVQQ/Vc+iTeQKiXlaNRZPPN2A2VdlWyAtsUrsQ3xydSlDW00TFMK7a8m3cDTkBF5WnV3Q== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" + "@babel/plugin-proposal-nullish-coalescing-operator@^7.12.1": version "7.14.2" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.14.2.tgz#425b11dc62fc26939a2ab42cbba680bdf5734546" @@ -794,6 +1263,14 @@ "@babel/helper-plugin-utils" "^7.13.0" "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" +"@babel/plugin-proposal-nullish-coalescing-operator@^7.14.5": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.16.0.tgz#44e1cce08fe2427482cf446a91bb451528ed0596" + integrity sha512-3bnHA8CAFm7cG93v8loghDYyQ8r97Qydf63BeYiGgYbjKKB/XP53W15wfRC7dvKfoiJ34f6Rbyyx2btExc8XsQ== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" + "@babel/plugin-proposal-numeric-separator@^7.12.7": version "7.14.2" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.14.2.tgz#82b4cc06571143faf50626104b335dd71baa4f9e" @@ -802,6 +1279,14 @@ "@babel/helper-plugin-utils" "^7.13.0" "@babel/plugin-syntax-numeric-separator" "^7.10.4" +"@babel/plugin-proposal-numeric-separator@^7.14.5": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.16.0.tgz#5d418e4fbbf8b9b7d03125d3a52730433a373734" + integrity sha512-FAhE2I6mjispy+vwwd6xWPyEx3NYFS13pikDBWUAFGZvq6POGs5eNchw8+1CYoEgBl9n11I3NkzD7ghn25PQ9Q== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-syntax-numeric-separator" "^7.10.4" + "@babel/plugin-proposal-object-rest-spread@^7.12.1": version "7.14.2" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.14.2.tgz#e17d418f81cc103fedd4ce037e181c8056225abc" @@ -813,6 +1298,17 @@ "@babel/plugin-syntax-object-rest-spread" "^7.8.3" "@babel/plugin-transform-parameters" "^7.14.2" +"@babel/plugin-proposal-object-rest-spread@^7.14.7": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.16.0.tgz#5fb32f6d924d6e6712810362a60e12a2609872e6" + integrity sha512-LU/+jp89efe5HuWJLmMmFG0+xbz+I2rSI7iLc1AlaeSMDMOGzWlc5yJrMN1d04osXN4sSfpo4O+azkBNBes0jg== + dependencies: + "@babel/compat-data" "^7.16.0" + "@babel/helper-compilation-targets" "^7.16.0" + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-syntax-object-rest-spread" "^7.8.3" + "@babel/plugin-transform-parameters" "^7.16.0" + "@babel/plugin-proposal-optional-catch-binding@^7.12.1": version "7.14.2" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.14.2.tgz#150d4e58e525b16a9a1431bd5326c4eed870d717" @@ -821,6 +1317,14 @@ "@babel/helper-plugin-utils" "^7.13.0" "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" +"@babel/plugin-proposal-optional-catch-binding@^7.14.5": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.16.0.tgz#5910085811ab4c28b00d6ebffa4ab0274d1e5f16" + integrity sha512-kicDo0A/5J0nrsCPbn89mTG3Bm4XgYi0CZtvex9Oyw7gGZE3HXGD0zpQNH+mo+tEfbo8wbmMvJftOwpmPy7aVw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" + "@babel/plugin-proposal-optional-chaining@^7.12.7": version "7.14.2" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.14.2.tgz#df8171a8b9c43ebf4c1dabe6311b432d83e1b34e" @@ -830,6 +1334,15 @@ "@babel/helper-skip-transparent-expression-wrappers" "^7.12.1" "@babel/plugin-syntax-optional-chaining" "^7.8.3" +"@babel/plugin-proposal-optional-chaining@^7.14.5", "@babel/plugin-proposal-optional-chaining@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.16.0.tgz#56dbc3970825683608e9efb55ea82c2a2d6c8dc0" + integrity sha512-Y4rFpkZODfHrVo70Uaj6cC1JJOt3Pp0MdWSwIKtb8z1/lsjl9AmnB7ErRFV+QNGIfcY1Eruc2UMx5KaRnXjMyg== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-skip-transparent-expression-wrappers" "^7.16.0" + "@babel/plugin-syntax-optional-chaining" "^7.8.3" + "@babel/plugin-proposal-private-methods@^7.12.1": version "7.13.0" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.13.0.tgz#04bd4c6d40f6e6bbfa2f57e2d8094bad900ef787" @@ -838,6 +1351,24 @@ "@babel/helper-create-class-features-plugin" "^7.13.0" "@babel/helper-plugin-utils" "^7.13.0" +"@babel/plugin-proposal-private-methods@^7.14.5": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.16.0.tgz#b4dafb9c717e4301c5776b30d080d6383c89aff6" + integrity sha512-IvHmcTHDFztQGnn6aWq4t12QaBXTKr1whF/dgp9kz84X6GUcwq9utj7z2wFCUfeOup/QKnOlt2k0zxkGFx9ubg== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.16.0" + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-proposal-private-property-in-object@^7.14.5": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.16.0.tgz#69e935b2c5c79d2488112d886f0c4e2790fee76f" + integrity sha512-3jQUr/HBbMVZmi72LpjQwlZ55i1queL8KcDTQEkAHihttJnAPrcvG9ZNXIfsd2ugpizZo595egYV6xy+pv4Ofw== + dependencies: + "@babel/helper-annotate-as-pure" "^7.16.0" + "@babel/helper-create-class-features-plugin" "^7.16.0" + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-syntax-private-property-in-object" "^7.14.5" + "@babel/plugin-proposal-unicode-property-regex@^7.12.1": version "7.12.13" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.12.13.tgz#bebde51339be829c17aaaaced18641deb62b39ba" @@ -846,6 +1377,14 @@ "@babel/helper-create-regexp-features-plugin" "^7.12.13" "@babel/helper-plugin-utils" "^7.12.13" +"@babel/plugin-proposal-unicode-property-regex@^7.14.5": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.16.0.tgz#890482dfc5ea378e42e19a71e709728cabf18612" + integrity sha512-ti7IdM54NXv29cA4+bNNKEMS4jLMCbJgl+Drv+FgYy0erJLAxNAIXcNjNjrRZEcWq0xJHsNVwQezskMFpF8N9g== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.16.0" + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-proposal-unicode-property-regex@^7.4.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.10.4.tgz#4483cda53041ce3413b7fe2f00022665ddfaa75d" @@ -861,13 +1400,20 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-class-properties@^7.12.1": +"@babel/plugin-syntax-class-properties@^7.12.1", "@babel/plugin-syntax-class-properties@^7.12.13": version "7.12.13" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz#b5c987274c4a3a82b89714796931a6b53544ae10" integrity sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA== dependencies: "@babel/helper-plugin-utils" "^7.12.13" +"@babel/plugin-syntax-class-static-block@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz#195df89b146b4b78b3bf897fd7a257c84659d406" + integrity sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-syntax-dynamic-import@^7.8.0", "@babel/plugin-syntax-dynamic-import@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz#62bf98b2da3cd21d626154fc96ee5b3cb68eacb3" @@ -931,6 +1477,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.0" +"@babel/plugin-syntax-private-property-in-object@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz#0dc6671ec0ea22b6e94a1114f857970cd39de1ad" + integrity sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-syntax-top-level-await@^7.12.1": version "7.12.13" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.12.13.tgz#c5f0fa6e249f5b739727f923540cf7a806130178" @@ -938,6 +1491,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.12.13" +"@babel/plugin-syntax-top-level-await@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz#c1cfdadc35a646240001f06138247b741c34d94c" + integrity sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-transform-arrow-functions@^7.12.1": version "7.13.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.13.0.tgz#10a59bebad52d637a027afa692e8d5ceff5e3dae" @@ -945,6 +1505,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.13.0" +"@babel/plugin-transform-arrow-functions@^7.14.5": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.16.0.tgz#951706f8b449c834ed07bd474c0924c944b95a8e" + integrity sha512-vIFb5250Rbh7roWARvCLvIJ/PtAU5Lhv7BtZ1u24COwpI9Ypjsh+bZcKk6rlIyalK+r0jOc1XQ8I4ovNxNrWrA== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-transform-async-to-generator@7.12.1": version "7.12.1" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.12.1.tgz#3849a49cc2a22e9743cbd6b52926d30337229af1" @@ -954,6 +1521,15 @@ "@babel/helper-plugin-utils" "^7.10.4" "@babel/helper-remap-async-to-generator" "^7.12.1" +"@babel/plugin-transform-async-to-generator@7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.14.5.tgz#72c789084d8f2094acb945633943ef8443d39e67" + integrity sha512-szkbzQ0mNk0rpu76fzDdqSyPu0MuvpXgC+6rz5rpMb5OIRxdmHfQxrktL8CYolL2d8luMCZTR0DpIMIdL27IjA== + dependencies: + "@babel/helper-module-imports" "^7.14.5" + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-remap-async-to-generator" "^7.14.5" + "@babel/plugin-transform-async-to-generator@^7.12.1": version "7.13.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.13.0.tgz#8e112bf6771b82bf1e974e5e26806c5c99aa516f" @@ -963,6 +1539,15 @@ "@babel/helper-plugin-utils" "^7.13.0" "@babel/helper-remap-async-to-generator" "^7.13.0" +"@babel/plugin-transform-async-to-generator@^7.14.5": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.16.0.tgz#df12637f9630ddfa0ef9d7a11bc414d629d38604" + integrity sha512-PbIr7G9kR8tdH6g8Wouir5uVjklETk91GMVSUq+VaOgiinbCkBP6Q7NN/suM/QutZkMJMvcyAriogcYAdhg8Gw== + dependencies: + "@babel/helper-module-imports" "^7.16.0" + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-remap-async-to-generator" "^7.16.0" + "@babel/plugin-transform-block-scoped-functions@^7.12.1": version "7.12.13" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.12.13.tgz#a9bf1836f2a39b4eb6cf09967739de29ea4bf4c4" @@ -970,6 +1555,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.12.13" +"@babel/plugin-transform-block-scoped-functions@^7.14.5": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.16.0.tgz#c618763233ad02847805abcac4c345ce9de7145d" + integrity sha512-V14As3haUOP4ZWrLJ3VVx5rCnrYhMSHN/jX7z6FAt5hjRkLsb0snPCmJwSOML5oxkKO4FNoNv7V5hw/y2bjuvg== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-transform-block-scoping@^7.12.11": version "7.14.2" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.14.2.tgz#761cb12ab5a88d640ad4af4aa81f820e6b5fdf5c" @@ -977,6 +1569,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.13.0" +"@babel/plugin-transform-block-scoping@^7.14.5": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.16.0.tgz#bcf433fb482fe8c3d3b4e8a66b1c4a8e77d37c16" + integrity sha512-27n3l67/R3UrXfizlvHGuTwsRIFyce3D/6a37GRxn28iyTPvNXaW4XvznexRh1zUNLPjbLL22Id0XQElV94ruw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-transform-classes@^7.12.1": version "7.14.2" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.14.2.tgz#3f1196c5709f064c252ad056207d87b7aeb2d03d" @@ -990,6 +1589,19 @@ "@babel/helper-split-export-declaration" "^7.12.13" globals "^11.1.0" +"@babel/plugin-transform-classes@^7.14.5": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.16.0.tgz#54cf5ff0b2242c6573d753cd4bfc7077a8b282f5" + integrity sha512-HUxMvy6GtAdd+GKBNYDWCIA776byUQH8zjnfjxwT1P1ARv/wFu8eBDpmXQcLS/IwRtrxIReGiplOwMeyO7nsDQ== + dependencies: + "@babel/helper-annotate-as-pure" "^7.16.0" + "@babel/helper-function-name" "^7.16.0" + "@babel/helper-optimise-call-expression" "^7.16.0" + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-replace-supers" "^7.16.0" + "@babel/helper-split-export-declaration" "^7.16.0" + globals "^11.1.0" + "@babel/plugin-transform-computed-properties@^7.12.1": version "7.13.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.13.0.tgz#845c6e8b9bb55376b1fa0b92ef0bdc8ea06644ed" @@ -997,6 +1609,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.13.0" +"@babel/plugin-transform-computed-properties@^7.14.5": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.16.0.tgz#e0c385507d21e1b0b076d66bed6d5231b85110b7" + integrity sha512-63l1dRXday6S8V3WFY5mXJwcRAnPYxvFfTlt67bwV1rTyVTM5zrp0DBBb13Kl7+ehkCVwIZPumPpFP/4u70+Tw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-transform-destructuring@^7.12.1": version "7.13.17" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.13.17.tgz#678d96576638c19d5b36b332504d3fd6e06dea27" @@ -1004,6 +1623,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.13.0" +"@babel/plugin-transform-destructuring@^7.14.7": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.16.0.tgz#ad3d7e74584ad5ea4eadb1e6642146c590dee33c" + integrity sha512-Q7tBUwjxLTsHEoqktemHBMtb3NYwyJPTJdM+wDwb0g8PZ3kQUIzNvwD5lPaqW/p54TXBc/MXZu9Jr7tbUEUM8Q== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-transform-dotall-regex@^7.12.1": version "7.12.13" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.12.13.tgz#3f1601cc29905bfcb67f53910f197aeafebb25ad" @@ -1012,6 +1638,14 @@ "@babel/helper-create-regexp-features-plugin" "^7.12.13" "@babel/helper-plugin-utils" "^7.12.13" +"@babel/plugin-transform-dotall-regex@^7.14.5": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.16.0.tgz#50bab00c1084b6162d0a58a818031cf57798e06f" + integrity sha512-FXlDZfQeLILfJlC6I1qyEwcHK5UpRCFkaoVyA1nk9A1L1Yu583YO4un2KsLBsu3IJb4CUbctZks8tD9xPQubLw== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.16.0" + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-transform-dotall-regex@^7.4.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.10.4.tgz#469c2062105c1eb6a040eaf4fac4b488078395ee" @@ -1027,6 +1661,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.12.13" +"@babel/plugin-transform-duplicate-keys@^7.14.5": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.16.0.tgz#8bc2e21813e3e89e5e5bf3b60aa5fc458575a176" + integrity sha512-LIe2kcHKAZOJDNxujvmp6z3mfN6V9lJxubU4fJIGoQCkKe3Ec2OcbdlYP+vW++4MpxwG0d1wSDOJtQW5kLnkZQ== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-transform-exponentiation-operator@^7.12.1": version "7.12.13" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.12.13.tgz#4d52390b9a273e651e4aba6aee49ef40e80cd0a1" @@ -1035,6 +1676,14 @@ "@babel/helper-builder-binary-assignment-operator-visitor" "^7.12.13" "@babel/helper-plugin-utils" "^7.12.13" +"@babel/plugin-transform-exponentiation-operator@^7.14.5": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.16.0.tgz#a180cd2881e3533cef9d3901e48dad0fbeff4be4" + integrity sha512-OwYEvzFI38hXklsrbNivzpO3fh87skzx8Pnqi4LoSYeav0xHlueSoCJrSgTPfnbyzopo5b3YVAJkFIcUpK2wsw== + dependencies: + "@babel/helper-builder-binary-assignment-operator-visitor" "^7.16.0" + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-transform-for-of@^7.12.1": version "7.13.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.13.0.tgz#c799f881a8091ac26b54867a845c3e97d2696062" @@ -1042,6 +1691,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.13.0" +"@babel/plugin-transform-for-of@^7.14.5": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.16.0.tgz#f7abaced155260e2461359bbc7c7248aca5e6bd2" + integrity sha512-5QKUw2kO+GVmKr2wMYSATCTTnHyscl6sxFRAY+rvN7h7WB0lcG0o4NoV6ZQU32OZGVsYUsfLGgPQpDFdkfjlJQ== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-transform-function-name@^7.12.1": version "7.12.13" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.12.13.tgz#bb024452f9aaed861d374c8e7a24252ce3a50051" @@ -1050,6 +1706,14 @@ "@babel/helper-function-name" "^7.12.13" "@babel/helper-plugin-utils" "^7.12.13" +"@babel/plugin-transform-function-name@^7.14.5": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.16.0.tgz#02e3699c284c6262236599f751065c5d5f1f400e" + integrity sha512-lBzMle9jcOXtSOXUpc7tvvTpENu/NuekNJVova5lCCWCV9/U1ho2HH2y0p6mBg8fPm/syEAbfaaemYGOHCY3mg== + dependencies: + "@babel/helper-function-name" "^7.16.0" + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-transform-literals@^7.12.1": version "7.12.13" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.12.13.tgz#2ca45bafe4a820197cf315794a4d26560fe4bdb9" @@ -1057,6 +1721,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.12.13" +"@babel/plugin-transform-literals@^7.14.5": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.16.0.tgz#79711e670ffceb31bd298229d50f3621f7980cac" + integrity sha512-gQDlsSF1iv9RU04clgXqRjrPyyoJMTclFt3K1cjLmTKikc0s/6vE3hlDeEVC71wLTRu72Fq7650kABrdTc2wMQ== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-transform-member-expression-literals@^7.12.1": version "7.12.13" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.12.13.tgz#5ffa66cd59b9e191314c9f1f803b938e8c081e40" @@ -1064,6 +1735,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.12.13" +"@babel/plugin-transform-member-expression-literals@^7.14.5": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.16.0.tgz#5251b4cce01eaf8314403d21aedb269d79f5e64b" + integrity sha512-WRpw5HL4Jhnxw8QARzRvwojp9MIE7Tdk3ez6vRyUk1MwgjJN0aNpRoXainLR5SgxmoXx/vsXGZ6OthP6t/RbUg== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-transform-modules-amd@^7.12.1": version "7.14.2" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.14.2.tgz#6622806fe1a7c07a1388444222ef9535f2ca17b0" @@ -1073,6 +1751,15 @@ "@babel/helper-plugin-utils" "^7.13.0" babel-plugin-dynamic-import-node "^2.3.3" +"@babel/plugin-transform-modules-amd@^7.14.5": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.16.0.tgz#09abd41e18dcf4fd479c598c1cef7bd39eb1337e" + integrity sha512-rWFhWbCJ9Wdmzln1NmSCqn7P0RAD+ogXG/bd9Kg5c7PKWkJtkiXmYsMBeXjDlzHpVTJ4I/hnjs45zX4dEv81xw== + dependencies: + "@babel/helper-module-transforms" "^7.16.0" + "@babel/helper-plugin-utils" "^7.14.5" + babel-plugin-dynamic-import-node "^2.3.3" + "@babel/plugin-transform-modules-commonjs@^7.12.1": version "7.14.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.14.0.tgz#52bc199cb581e0992edba0f0f80356467587f161" @@ -1083,6 +1770,16 @@ "@babel/helper-simple-access" "^7.13.12" babel-plugin-dynamic-import-node "^2.3.3" +"@babel/plugin-transform-modules-commonjs@^7.14.5": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.16.0.tgz#add58e638c8ddc4875bd9a9ecb5c594613f6c922" + integrity sha512-Dzi+NWqyEotgzk/sb7kgQPJQf7AJkQBWsVp1N6JWc1lBVo0vkElUnGdr1PzUBmfsCCN5OOFya3RtpeHk15oLKQ== + dependencies: + "@babel/helper-module-transforms" "^7.16.0" + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-simple-access" "^7.16.0" + babel-plugin-dynamic-import-node "^2.3.3" + "@babel/plugin-transform-modules-systemjs@^7.12.1": version "7.13.8" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.13.8.tgz#6d066ee2bff3c7b3d60bf28dec169ad993831ae3" @@ -1094,6 +1791,17 @@ "@babel/helper-validator-identifier" "^7.12.11" babel-plugin-dynamic-import-node "^2.3.3" +"@babel/plugin-transform-modules-systemjs@^7.14.5": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.16.0.tgz#a92cf240afeb605f4ca16670453024425e421ea4" + integrity sha512-yuGBaHS3lF1m/5R+6fjIke64ii5luRUg97N2wr+z1sF0V+sNSXPxXDdEEL/iYLszsN5VKxVB1IPfEqhzVpiqvg== + dependencies: + "@babel/helper-hoist-variables" "^7.16.0" + "@babel/helper-module-transforms" "^7.16.0" + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-validator-identifier" "^7.15.7" + babel-plugin-dynamic-import-node "^2.3.3" + "@babel/plugin-transform-modules-umd@^7.12.1": version "7.14.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.14.0.tgz#2f8179d1bbc9263665ce4a65f305526b2ea8ac34" @@ -1102,6 +1810,14 @@ "@babel/helper-module-transforms" "^7.14.0" "@babel/helper-plugin-utils" "^7.13.0" +"@babel/plugin-transform-modules-umd@^7.14.5": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.16.0.tgz#195f26c2ad6d6a391b70880effce18ce625e06a7" + integrity sha512-nx4f6no57himWiHhxDM5pjwhae5vLpTK2zCnDH8+wNLJy0TVER/LJRHl2bkt6w9Aad2sPD5iNNoUpY3X9sTGDg== + dependencies: + "@babel/helper-module-transforms" "^7.16.0" + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-transform-named-capturing-groups-regex@^7.12.1": version "7.12.13" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.12.13.tgz#2213725a5f5bbbe364b50c3ba5998c9599c5c9d9" @@ -1109,6 +1825,13 @@ dependencies: "@babel/helper-create-regexp-features-plugin" "^7.12.13" +"@babel/plugin-transform-named-capturing-groups-regex@^7.14.7": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.16.0.tgz#d3db61cc5d5b97986559967cd5ea83e5c32096ca" + integrity sha512-LogN88uO+7EhxWc8WZuQ8vxdSyVGxhkh8WTC3tzlT8LccMuQdA81e9SGV6zY7kY2LjDhhDOFdQVxdGwPyBCnvg== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.16.0" + "@babel/plugin-transform-new-target@^7.12.1": version "7.12.13" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.12.13.tgz#e22d8c3af24b150dd528cbd6e685e799bf1c351c" @@ -1116,6 +1839,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.12.13" +"@babel/plugin-transform-new-target@^7.14.5": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.16.0.tgz#af823ab576f752215a49937779a41ca65825ab35" + integrity sha512-fhjrDEYv2DBsGN/P6rlqakwRwIp7rBGLPbrKxwh7oVt5NNkIhZVOY2GRV+ULLsQri1bDqwDWnU3vhlmx5B2aCw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-transform-object-super@^7.12.1": version "7.12.13" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.12.13.tgz#b4416a2d63b8f7be314f3d349bd55a9c1b5171f7" @@ -1124,6 +1854,14 @@ "@babel/helper-plugin-utils" "^7.12.13" "@babel/helper-replace-supers" "^7.12.13" +"@babel/plugin-transform-object-super@^7.14.5": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.16.0.tgz#fb20d5806dc6491a06296ac14ea8e8d6fedda72b" + integrity sha512-fds+puedQHn4cPLshoHcR1DTMN0q1V9ou0mUjm8whx9pGcNvDrVVrgw+KJzzCaiTdaYhldtrUps8DWVMgrSEyg== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-replace-supers" "^7.16.0" + "@babel/plugin-transform-parameters@^7.12.1", "@babel/plugin-transform-parameters@^7.14.2": version "7.14.2" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.14.2.tgz#e4290f72e0e9e831000d066427c4667098decc31" @@ -1131,6 +1869,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.13.0" +"@babel/plugin-transform-parameters@^7.14.5", "@babel/plugin-transform-parameters@^7.16.0": + version "7.16.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.16.3.tgz#fa9e4c874ee5223f891ee6fa8d737f4766d31d15" + integrity sha512-3MaDpJrOXT1MZ/WCmkOFo7EtmVVC8H4EUZVrHvFOsmwkk4lOjQj8rzv8JKUZV4YoQKeoIgk07GO+acPU9IMu/w== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-transform-property-literals@^7.12.1": version "7.12.13" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.12.13.tgz#4e6a9e37864d8f1b3bc0e2dce7bf8857db8b1a81" @@ -1138,6 +1883,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.12.13" +"@babel/plugin-transform-property-literals@^7.14.5": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.16.0.tgz#a95c552189a96a00059f6776dc4e00e3690c78d1" + integrity sha512-XLldD4V8+pOqX2hwfWhgwXzGdnDOThxaNTgqagOcpBgIxbUvpgU2FMvo5E1RyHbk756WYgdbS0T8y0Cj9FKkWQ== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-transform-regenerator@^7.12.1": version "7.13.15" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.13.15.tgz#e5eb28945bf8b6563e7f818945f966a8d2997f39" @@ -1145,6 +1897,13 @@ dependencies: regenerator-transform "^0.14.2" +"@babel/plugin-transform-regenerator@^7.14.5": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.16.0.tgz#eaee422c84b0232d03aea7db99c97deeaf6125a4" + integrity sha512-JAvGxgKuwS2PihiSFaDrp94XOzzTUeDeOQlcKzVAyaPap7BnZXK/lvMDiubkPTdotPKOIZq9xWXWnggUMYiExg== + dependencies: + regenerator-transform "^0.14.2" + "@babel/plugin-transform-reserved-words@^7.12.1": version "7.12.13" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.12.13.tgz#7d9988d4f06e0fe697ea1d9803188aa18b472695" @@ -1152,6 +1911,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.12.13" +"@babel/plugin-transform-reserved-words@^7.14.5": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.16.0.tgz#fff4b9dcb19e12619394bda172d14f2d04c0379c" + integrity sha512-Dgs8NNCehHSvXdhEhln8u/TtJxfVwGYCgP2OOr5Z3Ar+B+zXicEOKNTyc+eca2cuEOMtjW6m9P9ijOt8QdqWkg== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-transform-runtime@7.12.10": version "7.12.10" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.12.10.tgz#af0fded4e846c4b37078e8e5d06deac6cd848562" @@ -1161,6 +1927,18 @@ "@babel/helper-plugin-utils" "^7.10.4" semver "^5.5.1" +"@babel/plugin-transform-runtime@7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.14.5.tgz#30491dad49c6059f8f8fa5ee8896a0089e987523" + integrity sha512-fPMBhh1AV8ZyneiCIA+wYYUH1arzlXR1UMcApjvchDhfKxhy2r2lReJv8uHEyihi4IFIGlr1Pdx7S5fkESDQsg== + dependencies: + "@babel/helper-module-imports" "^7.14.5" + "@babel/helper-plugin-utils" "^7.14.5" + babel-plugin-polyfill-corejs2 "^0.2.2" + babel-plugin-polyfill-corejs3 "^0.2.2" + babel-plugin-polyfill-regenerator "^0.2.2" + semver "^6.3.0" + "@babel/plugin-transform-shorthand-properties@^7.12.1": version "7.12.13" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.12.13.tgz#db755732b70c539d504c6390d9ce90fe64aff7ad" @@ -1168,6 +1946,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.12.13" +"@babel/plugin-transform-shorthand-properties@^7.14.5": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.16.0.tgz#090372e3141f7cc324ed70b3daf5379df2fa384d" + integrity sha512-iVb1mTcD8fuhSv3k99+5tlXu5N0v8/DPm2mO3WACLG6al1CGZH7v09HJyUb1TtYl/Z+KrM6pHSIJdZxP5A+xow== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-transform-spread@^7.12.1": version "7.13.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.13.0.tgz#84887710e273c1815ace7ae459f6f42a5d31d5fd" @@ -1176,6 +1961,14 @@ "@babel/helper-plugin-utils" "^7.13.0" "@babel/helper-skip-transparent-expression-wrappers" "^7.12.1" +"@babel/plugin-transform-spread@^7.14.6": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.16.0.tgz#d21ca099bbd53ab307a8621e019a7bd0f40cdcfb" + integrity sha512-Ao4MSYRaLAQczZVp9/7E7QHsCuK92yHRrmVNRe/SlEJjhzivq0BSn8mEraimL8wizHZ3fuaHxKH0iwzI13GyGg== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-skip-transparent-expression-wrappers" "^7.16.0" + "@babel/plugin-transform-sticky-regex@^7.12.7": version "7.12.13" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.12.13.tgz#760ffd936face73f860ae646fb86ee82f3d06d1f" @@ -1183,6 +1976,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.12.13" +"@babel/plugin-transform-sticky-regex@^7.14.5": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.16.0.tgz#c35ea31a02d86be485f6aa510184b677a91738fd" + integrity sha512-/ntT2NljR9foobKk4E/YyOSwcGUXtYWv5tinMK/3RkypyNBNdhHUaq6Orw5DWq9ZcNlS03BIlEALFeQgeVAo4Q== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-transform-template-literals@^7.12.1": version "7.13.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.13.0.tgz#a36049127977ad94438dee7443598d1cefdf409d" @@ -1190,6 +1990,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.13.0" +"@babel/plugin-transform-template-literals@^7.14.5": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.16.0.tgz#a8eced3a8e7b8e2d40ec4ec4548a45912630d302" + integrity sha512-Rd4Ic89hA/f7xUSJQk5PnC+4so50vBoBfxjdQAdvngwidM8jYIBVxBZ/sARxD4e0yMXRbJVDrYf7dyRtIIKT6Q== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-transform-typeof-symbol@^7.12.10": version "7.12.13" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.12.13.tgz#785dd67a1f2ea579d9c2be722de8c84cb85f5a7f" @@ -1197,6 +2004,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.12.13" +"@babel/plugin-transform-typeof-symbol@^7.14.5": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.16.0.tgz#8b19a244c6f8c9d668dca6a6f754ad6ead1128f2" + integrity sha512-++V2L8Bdf4vcaHi2raILnptTBjGEFxn5315YU+e8+EqXIucA+q349qWngCLpUYqqv233suJ6NOienIVUpS9cqg== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-transform-unicode-escapes@^7.12.1": version "7.12.13" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.12.13.tgz#840ced3b816d3b5127dd1d12dcedc5dead1a5e74" @@ -1204,6 +2018,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.12.13" +"@babel/plugin-transform-unicode-escapes@^7.14.5": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.16.0.tgz#1a354064b4c45663a32334f46fa0cf6100b5b1f3" + integrity sha512-VFi4dhgJM7Bpk8lRc5CMaRGlKZ29W9C3geZjt9beuzSUrlJxsNwX7ReLwaL6WEvsOf2EQkyIJEPtF8EXjB/g2A== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-transform-unicode-regex@^7.12.1": version "7.12.13" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.12.13.tgz#b52521685804e155b1202e83fc188d34bb70f5ac" @@ -1212,6 +2033,14 @@ "@babel/helper-create-regexp-features-plugin" "^7.12.13" "@babel/helper-plugin-utils" "^7.12.13" +"@babel/plugin-transform-unicode-regex@^7.14.5": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.16.0.tgz#293b80950177c8c85aede87cef280259fb995402" + integrity sha512-jHLK4LxhHjvCeZDWyA9c+P9XH1sOxRd1RO9xMtDVRAOND/PczPqizEtVdx4TQF/wyPaewqpT+tgQFYMnN/P94A== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.16.0" + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/preset-env@7.12.11": version "7.12.11" resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.12.11.tgz#55d5f7981487365c93dbbc84507b1c7215e857f9" @@ -1284,6 +2113,85 @@ core-js-compat "^3.8.0" semver "^5.5.0" +"@babel/preset-env@7.14.8": + version "7.14.8" + resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.14.8.tgz#254942f5ca80ccabcfbb2a9f524c74bca574005b" + integrity sha512-a9aOppDU93oArQ51H+B8M1vH+tayZbuBqzjOhntGetZVa+4tTu5jp+XTwqHGG2lxslqomPYVSjIxQkFwXzgnxg== + dependencies: + "@babel/compat-data" "^7.14.7" + "@babel/helper-compilation-targets" "^7.14.5" + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-validator-option" "^7.14.5" + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining" "^7.14.5" + "@babel/plugin-proposal-async-generator-functions" "^7.14.7" + "@babel/plugin-proposal-class-properties" "^7.14.5" + "@babel/plugin-proposal-class-static-block" "^7.14.5" + "@babel/plugin-proposal-dynamic-import" "^7.14.5" + "@babel/plugin-proposal-export-namespace-from" "^7.14.5" + "@babel/plugin-proposal-json-strings" "^7.14.5" + "@babel/plugin-proposal-logical-assignment-operators" "^7.14.5" + "@babel/plugin-proposal-nullish-coalescing-operator" "^7.14.5" + "@babel/plugin-proposal-numeric-separator" "^7.14.5" + "@babel/plugin-proposal-object-rest-spread" "^7.14.7" + "@babel/plugin-proposal-optional-catch-binding" "^7.14.5" + "@babel/plugin-proposal-optional-chaining" "^7.14.5" + "@babel/plugin-proposal-private-methods" "^7.14.5" + "@babel/plugin-proposal-private-property-in-object" "^7.14.5" + "@babel/plugin-proposal-unicode-property-regex" "^7.14.5" + "@babel/plugin-syntax-async-generators" "^7.8.4" + "@babel/plugin-syntax-class-properties" "^7.12.13" + "@babel/plugin-syntax-class-static-block" "^7.14.5" + "@babel/plugin-syntax-dynamic-import" "^7.8.3" + "@babel/plugin-syntax-export-namespace-from" "^7.8.3" + "@babel/plugin-syntax-json-strings" "^7.8.3" + "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" + "@babel/plugin-syntax-numeric-separator" "^7.10.4" + "@babel/plugin-syntax-object-rest-spread" "^7.8.3" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" + "@babel/plugin-syntax-optional-chaining" "^7.8.3" + "@babel/plugin-syntax-private-property-in-object" "^7.14.5" + "@babel/plugin-syntax-top-level-await" "^7.14.5" + "@babel/plugin-transform-arrow-functions" "^7.14.5" + "@babel/plugin-transform-async-to-generator" "^7.14.5" + "@babel/plugin-transform-block-scoped-functions" "^7.14.5" + "@babel/plugin-transform-block-scoping" "^7.14.5" + "@babel/plugin-transform-classes" "^7.14.5" + "@babel/plugin-transform-computed-properties" "^7.14.5" + "@babel/plugin-transform-destructuring" "^7.14.7" + "@babel/plugin-transform-dotall-regex" "^7.14.5" + "@babel/plugin-transform-duplicate-keys" "^7.14.5" + "@babel/plugin-transform-exponentiation-operator" "^7.14.5" + "@babel/plugin-transform-for-of" "^7.14.5" + "@babel/plugin-transform-function-name" "^7.14.5" + "@babel/plugin-transform-literals" "^7.14.5" + "@babel/plugin-transform-member-expression-literals" "^7.14.5" + "@babel/plugin-transform-modules-amd" "^7.14.5" + "@babel/plugin-transform-modules-commonjs" "^7.14.5" + "@babel/plugin-transform-modules-systemjs" "^7.14.5" + "@babel/plugin-transform-modules-umd" "^7.14.5" + "@babel/plugin-transform-named-capturing-groups-regex" "^7.14.7" + "@babel/plugin-transform-new-target" "^7.14.5" + "@babel/plugin-transform-object-super" "^7.14.5" + "@babel/plugin-transform-parameters" "^7.14.5" + "@babel/plugin-transform-property-literals" "^7.14.5" + "@babel/plugin-transform-regenerator" "^7.14.5" + "@babel/plugin-transform-reserved-words" "^7.14.5" + "@babel/plugin-transform-shorthand-properties" "^7.14.5" + "@babel/plugin-transform-spread" "^7.14.6" + "@babel/plugin-transform-sticky-regex" "^7.14.5" + "@babel/plugin-transform-template-literals" "^7.14.5" + "@babel/plugin-transform-typeof-symbol" "^7.14.5" + "@babel/plugin-transform-unicode-escapes" "^7.14.5" + "@babel/plugin-transform-unicode-regex" "^7.14.5" + "@babel/preset-modules" "^0.1.4" + "@babel/types" "^7.14.8" + babel-plugin-polyfill-corejs2 "^0.2.2" + babel-plugin-polyfill-corejs3 "^0.2.2" + babel-plugin-polyfill-regenerator "^0.2.2" + core-js-compat "^3.15.0" + semver "^6.3.0" + "@babel/preset-modules@^0.1.3": version "0.1.4" resolved "https://registry.yarnpkg.com/@babel/preset-modules/-/preset-modules-0.1.4.tgz#362f2b68c662842970fdb5e254ffc8fc1c2e415e" @@ -1295,6 +2203,17 @@ "@babel/types" "^7.4.4" esutils "^2.0.2" +"@babel/preset-modules@^0.1.4": + version "0.1.5" + resolved "https://registry.yarnpkg.com/@babel/preset-modules/-/preset-modules-0.1.5.tgz#ef939d6e7f268827e1841638dc6ff95515e115d9" + integrity sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-proposal-unicode-property-regex" "^7.4.4" + "@babel/plugin-transform-dotall-regex" "^7.4.4" + "@babel/types" "^7.4.4" + esutils "^2.0.2" + "@babel/runtime@7.12.5", "@babel/runtime@^7.12.5": version "7.12.5" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.12.5.tgz#410e7e487441e1b360c29be715d870d9b985882e" @@ -1302,6 +2221,13 @@ dependencies: regenerator-runtime "^0.13.4" +"@babel/runtime@7.14.8": + version "7.14.8" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.14.8.tgz#7119a56f421018852694290b9f9148097391b446" + integrity sha512-twj3L8Og5SaCRCErB4x4ajbvBIVV77CGeFglHpeg5WC5FF8TZzBWXtTJ4MqaD9QszLYTtr+IsaAL2rEUevb+eg== + dependencies: + regenerator-runtime "^0.13.4" + "@babel/runtime@^7.10.1", "@babel/runtime@^7.11.1", "@babel/runtime@^7.11.2", "@babel/runtime@^7.3.1", "@babel/runtime@^7.4.4", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.0", "@babel/runtime@^7.8.3", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7": version "7.11.2" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.11.2.tgz#f549c13c754cc40b87644b9fa9f09a6a95fe0736" @@ -1318,6 +2244,15 @@ "@babel/parser" "^7.12.7" "@babel/types" "^7.12.7" +"@babel/template@7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.14.5.tgz#a9bc9d8b33354ff6e55a9c60d1109200a68974f4" + integrity sha512-6Z3Po85sfxRGachLULUhOmvAaOo7xCvqGQtxINai2mEGPFm6pQ4z5QInFnUrRpfoSV60BnjyF5F3c+15fxFV1g== + dependencies: + "@babel/code-frame" "^7.14.5" + "@babel/parser" "^7.14.5" + "@babel/types" "^7.14.5" + "@babel/template@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.10.4.tgz#3251996c4200ebc71d1a8fc405fba940f36ba278" @@ -1336,6 +2271,15 @@ "@babel/parser" "^7.12.13" "@babel/types" "^7.12.13" +"@babel/template@^7.14.5", "@babel/template@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.16.0.tgz#d16a35ebf4cd74e202083356fab21dd89363ddd6" + integrity sha512-MnZdpFD/ZdYhXwiunMqqgyZyucaYsbL0IrjoGjaVhGilz+x8YB++kRfygSOIj1yOtWKPlx7NBp+9I1RQSgsd5A== + dependencies: + "@babel/code-frame" "^7.16.0" + "@babel/parser" "^7.16.0" + "@babel/types" "^7.16.0" + "@babel/traverse@^7.10.4", "@babel/traverse@^7.11.5": version "7.11.5" resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.11.5.tgz#be777b93b518eb6d76ee2e1ea1d143daa11e61c3" @@ -1365,6 +2309,21 @@ debug "^4.1.0" globals "^11.1.0" +"@babel/traverse@^7.14.8", "@babel/traverse@^7.16.0", "@babel/traverse@^7.16.3": + version "7.16.3" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.16.3.tgz#f63e8a938cc1b780f66d9ed3c54f532ca2d14787" + integrity sha512-eolumr1vVMjqevCpwVO99yN/LoGL0EyHiLO5I043aYQvwOJ9eR5UsZSClHVCzfhBduMAsSzgA/6AyqPjNayJag== + dependencies: + "@babel/code-frame" "^7.16.0" + "@babel/generator" "^7.16.0" + "@babel/helper-function-name" "^7.16.0" + "@babel/helper-hoist-variables" "^7.16.0" + "@babel/helper-split-export-declaration" "^7.16.0" + "@babel/parser" "^7.16.3" + "@babel/types" "^7.16.0" + debug "^4.1.0" + globals "^11.1.0" + "@babel/types@^7.10.4", "@babel/types@^7.11.0", "@babel/types@^7.11.5", "@babel/types@^7.4.4": version "7.11.5" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.11.5.tgz#d9de577d01252d77c6800cee039ee64faf75662d" @@ -1382,6 +2341,19 @@ "@babel/helper-validator-identifier" "^7.14.0" to-fast-properties "^2.0.0" +"@babel/types@^7.14.5", "@babel/types@^7.14.8", "@babel/types@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.16.0.tgz#db3b313804f96aadd0b776c4823e127ad67289ba" + integrity sha512-PJgg/k3SdLsGb3hhisFvtLOw5ts113klrpLuIPtCJIU+BB24fqq6lf8RWqKJEjzqXR9AEH1rIb5XTqwBHB+kQg== + dependencies: + "@babel/helper-validator-identifier" "^7.15.7" + to-fast-properties "^2.0.0" + +"@csstools/convert-colors@^1.4.0": + version "1.4.0" + resolved "https://registry.yarnpkg.com/@csstools/convert-colors/-/convert-colors-1.4.0.tgz#ad495dc41b12e75d588c6db8b9834f08fa131eb7" + integrity sha512-5a6wqoJV/xEdbRNKVo6I4hO3VjyDq//8q2f9I6PBAvMesJHFauXDorcNCsr9RzvsZnaWi5NYCcfyqP1QeFHFbw== + "@date-io/core@1.x": version "1.3.13" resolved "https://registry.yarnpkg.com/@date-io/core/-/core-1.3.13.tgz#90c71da493f20204b7a972929cc5c482d078b3fa" @@ -1404,6 +2376,11 @@ resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.2.tgz#8f03a22a04de437254e8ce8cc84ba39689288752" integrity sha512-HyYEUDeIj5rRQU2Hk5HTB2uHsbRQpF70nvMhVzi+VJR0X+xNEhjPui4/kBf3VeH/wqD28PT4sVOm8qqLjBrSZg== +"@discoveryjs/json-ext@0.5.3": + version "0.5.3" + resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.3.tgz#90420f9f9c6d3987f176a19a7d8e764271a2f55d" + integrity sha512-Fxt+AfXgjMoin2maPIYzFZnQjAXjAL0PHscM5pRTtatFqB+vZxAM9tLp2Optnuw3QOQC40jTNeGYFOMvyf7v9g== + "@emotion/hash@^0.8.0": version "0.8.0" resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.8.0.tgz#bbbff68978fefdbe68ccb533bc8cbe1d1afb5413" @@ -1422,6 +2399,11 @@ "@types/flowjs" "2.13.3" tslib "^1.9.0" +"@gar/promisify@^1.0.1": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@gar/promisify/-/promisify-1.1.2.tgz#30aa825f11d438671d585bd44e7fd564535fc210" + integrity sha512-82cpyJyKRoQoRi+14ibCeGPu0CwypgtBAdBhq1WfvagpCZNKqwXbKwXllYSMG91DhmG4jt9gN8eP6lGOtozuaw== + "@geoman-io/leaflet-geoman-free@^2.11.3": version "2.11.3" resolved "https://registry.yarnpkg.com/@geoman-io/leaflet-geoman-free/-/leaflet-geoman-free-2.11.3.tgz#480164ab76c2b2a885003e0c111284f3c3160a36" @@ -1439,6 +2421,11 @@ resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.2.tgz#26520bf09abe4a5644cd5414e37125a8954241dd" integrity sha512-tsAQNx32a8CoFhjhijUIhI4kccIAgmGhy8LZMZgGfmXcpMbPRUqn5LWmgRttILi6yeGmBJd2xsPkFMs0PzgPCw== +"@jridgewell/resolve-uri@1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-1.0.0.tgz#3fdf5798f0b49e90155896f6291df186eac06c83" + integrity sha512-9oLAnygRMi8Q5QkYEU4XWK04B+nuoXoxjRvRxgjuChkLZFBja0YPSgdZ7dZtwhncLBcQe/I/E+fLuk5qxcYVJA== + "@jsdevtools/coverage-istanbul-loader@3.0.5": version "3.0.5" resolved "https://registry.yarnpkg.com/@jsdevtools/coverage-istanbul-loader/-/coverage-istanbul-loader-3.0.5.tgz#2a4bc65d0271df8d4435982db4af35d81754ee26" @@ -1575,7 +2562,7 @@ enhanced-resolve "5.7.0" webpack-sources "2.2.0" -"@ngtools/webpack@~12.2.13": +"@ngtools/webpack@12.2.13", "@ngtools/webpack@~12.2.13": version "12.2.13" resolved "https://registry.yarnpkg.com/@ngtools/webpack/-/webpack-12.2.13.tgz#44d711edfa39d175a2d655aa5c6f9968dfedcc35" integrity sha512-krAwMyRqOaC1S0+IxAFid9F6A6ABip2DJ0tgCx26X+1Vw/d1GKtV9ZqDJFizMf5k1ywl9aBlhOazWpq5d6i+gw== @@ -1615,15 +2602,18 @@ "@nodelib/fs.scandir" "2.1.3" fastq "^1.6.0" -"@npmcli/ci-detect@^1.0.0": - version "1.3.0" - resolved "https://registry.yarnpkg.com/@npmcli/ci-detect/-/ci-detect-1.3.0.tgz#6c1d2c625fb6ef1b9dea85ad0a5afcbef85ef22a" - integrity sha512-oN3y7FAROHhrAt7Rr7PnTSwrHrZVRTS2ZbyxeQwSSYD0ifwM3YNgQqbaRmjcWoPyq77MjchusjJDspbzMmip1Q== +"@npmcli/fs@^1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@npmcli/fs/-/fs-1.0.0.tgz#589612cfad3a6ea0feafcb901d29c63fd52db09f" + integrity sha512-8ltnOpRR/oJbOp8vaGUnipOi3bqkcW+sLHFlyXIr08OGHmVJLB1Hn7QtGXbYcpVtH1gAYZTlmDXtE4YV0+AMMQ== + dependencies: + "@gar/promisify" "^1.0.1" + semver "^7.3.5" -"@npmcli/git@^2.0.1": - version "2.0.9" - resolved "https://registry.yarnpkg.com/@npmcli/git/-/git-2.0.9.tgz#915bbfe66300e67b4da5ef765a4475ffb2ca5b6b" - integrity sha512-hTMbMryvOqGLwnmMBKs5usbPsJtyEsMsgXwJbmNrsEuQQh1LAIMDU77IoOrwkCg+NgQWl+ySlarJASwM3SutCA== +"@npmcli/git@^2.1.0": + version "2.1.0" + resolved "https://registry.yarnpkg.com/@npmcli/git/-/git-2.1.0.tgz#2fbd77e147530247d37f325930d457b3ebe894f6" + integrity sha512-/hBFX/QG1b+N7PZBFs0bi+evgRZcK9nWBxQKZkGoXUT5hJSwl5c4d7y8/hm+NQZRPhQ67RzFaj5UM9YeyKoryw== dependencies: "@npmcli/promise-spawn" "^1.3.2" lru-cache "^6.0.0" @@ -1634,7 +2624,7 @@ semver "^7.3.5" which "^2.0.2" -"@npmcli/installed-package-contents@^1.0.5": +"@npmcli/installed-package-contents@^1.0.6": version "1.0.7" resolved "https://registry.yarnpkg.com/@npmcli/installed-package-contents/-/installed-package-contents-1.0.7.tgz#ab7408c6147911b970a8abe261ce512232a3f4fa" integrity sha512-9rufe0wnJusCQoLpV9ZPKIVP55itrM5BxOXs10DmdbRfgWtHy1LDyskbwRnBghuB0PrF7pNPOqREVtpz4HqzKw== @@ -1661,40 +2651,25 @@ dependencies: infer-owner "^1.0.4" -"@npmcli/run-script@^1.3.0": - version "1.8.5" - resolved "https://registry.yarnpkg.com/@npmcli/run-script/-/run-script-1.8.5.tgz#f250a0c5e1a08a792d775a315d0ff42fc3a51e1d" - integrity sha512-NQspusBCpTjNwNRFMtz2C5MxoxyzlbuJ4YEhxAKrIonTiirKDtatsZictx9RgamQIx6+QuHMNmPl0wQdoESs9A== +"@npmcli/run-script@^1.8.2": + version "1.8.6" + resolved "https://registry.yarnpkg.com/@npmcli/run-script/-/run-script-1.8.6.tgz#18314802a6660b0d4baa4c3afe7f1ad39d8c28b7" + integrity sha512-e42bVZnC6VluBZBAFEr3YrdqSspG3bgilyg4nSLBJ7TRGNCzxHa92XAHxQBLYg0BmgwO4b2mf3h/l5EkEWRn3g== dependencies: "@npmcli/node-gyp" "^1.0.2" "@npmcli/promise-spawn" "^1.3.2" - infer-owner "^1.0.4" node-gyp "^7.1.0" read-package-json-fast "^2.0.1" -"@schematics/angular@11.2.13": - version "11.2.13" - resolved "https://registry.yarnpkg.com/@schematics/angular/-/angular-11.2.13.tgz#a37e9e7a2cf0a37a8948f0afb0f29e6671ce740a" - integrity sha512-cMXWruwSkH2XEKDA8df70Ey/5okdJrRCgsnXkGuLRC+GQM7ArLPkgoVw0GXM8TfI0bWyGWT7QYbHBzsyN5ajGA== +"@schematics/angular@12.2.13": + version "12.2.13" + resolved "https://registry.yarnpkg.com/@schematics/angular/-/angular-12.2.13.tgz#5bf3e7b699a42d7fd7f7aa12bbe4534e671e7201" + integrity sha512-TrigQ9TCmAedf1J5PSSSfTC+sScYrITeAUN8a9rlkjZNvff8hHVyQaiZmhqL+egKQL828mhkqpnFUDd4QsPBIw== dependencies: - "@angular-devkit/core" "11.2.13" - "@angular-devkit/schematics" "11.2.13" + "@angular-devkit/core" "12.2.13" + "@angular-devkit/schematics" "12.2.13" jsonc-parser "3.0.0" -"@schematics/update@0.1102.13": - version "0.1102.13" - resolved "https://registry.yarnpkg.com/@schematics/update/-/update-0.1102.13.tgz#d6e5a3df5bf22900f26dc76a8351651f99a655fb" - integrity sha512-lHym4eUhbvUORwRJQJzgVFjofnc9nB2f/Ef3NNEgn3OkvsxHWtPH8NCQy/tj6sBAsyqK2T88aO2nejU9fZgMog== - dependencies: - "@angular-devkit/core" "11.2.13" - "@angular-devkit/schematics" "11.2.13" - "@yarnpkg/lockfile" "1.1.0" - ini "2.0.0" - npm-package-arg "^8.0.0" - pacote "11.2.4" - semver "7.3.4" - semver-intersect "1.4.0" - "@tootallnate/once@1": version "1.1.2" resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82" @@ -1705,6 +2680,11 @@ resolved "https://registry.yarnpkg.com/@trysound/sax/-/sax-0.1.1.tgz#3348564048e7a2d7398c935d466c0414ebb6a669" integrity sha512-Z6DoceYb/1xSg5+e+ZlPZ9v0N16ZvZ+wYMraFue4HYrE4ttONKtsvruIRf6t9TBR0YvSOfi1hUU0fJfBLCDYow== +"@trysound/sax@0.2.0": + version "0.2.0" + resolved "https://registry.yarnpkg.com/@trysound/sax/-/sax-0.2.0.tgz#cccaab758af56761eb7bf37af6f03f326dd798ad" + integrity sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA== + "@turf/bbox@*", "@turf/bbox@^6.3.0": version "6.5.0" resolved "https://registry.yarnpkg.com/@turf/bbox/-/bbox-6.5.0.tgz#bec30a744019eae420dac9ea46fb75caa44d8dc5" @@ -2508,7 +3488,7 @@ adm-zip@^0.4.9: resolved "https://registry.yarnpkg.com/adm-zip/-/adm-zip-0.4.16.tgz#cf4c508fdffab02c269cbc7f471a875f05570365" integrity sha512-TFi4HBKSGfIKsK5YCkKaaFG2m4PEDyViZmEwof3MTIgzimHLto6muaHVpbrljdIvIrFZzEq/p4nafOeLcYegrg== -agent-base@6: +agent-base@6, agent-base@^6.0.2: version "6.0.2" resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ== @@ -2544,6 +3524,13 @@ ajv-errors@^1.0.0: resolved "https://registry.yarnpkg.com/ajv-errors/-/ajv-errors-1.0.1.tgz#f35986aceb91afadec4102fbd85014950cefa64d" integrity sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ== +ajv-formats@2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/ajv-formats/-/ajv-formats-2.1.0.tgz#96eaf83e38d32108b66d82a9cb0cfa24886cdfeb" + integrity sha512-USH2jBb+C/hIpwD2iRjp0pe0k+MvzG0mlSn/FIdCgQhUb9ALPRjt2KIQdfZDS9r0ZIeUAg7gOu9KL0PFqGqr5Q== + dependencies: + ajv "^8.0.0" + ajv-keywords@^3.1.0, ajv-keywords@^3.4.1, ajv-keywords@^3.5.2: version "3.5.2" resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d" @@ -2559,6 +3546,16 @@ ajv@6.12.6, ajv@^6.12.5: json-schema-traverse "^0.4.1" uri-js "^4.2.2" +ajv@8.6.2: + version "8.6.2" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.6.2.tgz#2fb45e0e5fcbc0813326c1c3da535d1881bb0571" + integrity sha512-9807RlWAgT564wT+DjeyU5OFMPjmzxVobvDFmNAhY+5zD6A2ly3jDp6sgnfyDtlIQ+7H97oc/DGCzzfu9rjw9w== + dependencies: + fast-deep-equal "^3.1.1" + json-schema-traverse "^1.0.0" + require-from-string "^2.0.2" + uri-js "^4.2.2" + ajv@^6.1.0, ajv@^6.10.2, ajv@^6.12.3, ajv@^6.12.4: version "6.12.5" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.5.tgz#19b0e8bae8f476e5ba666300387775fb1a00a4da" @@ -2569,6 +3566,16 @@ ajv@^6.1.0, ajv@^6.10.2, ajv@^6.12.3, ajv@^6.12.4: json-schema-traverse "^0.4.1" uri-js "^4.2.2" +ajv@^8.0.0: + version "8.8.2" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.8.2.tgz#01b4fef2007a28bf75f0b7fc009f62679de4abbb" + integrity sha512-x9VuX+R/jcFj1DHo/fCp99esgGDWiHENrKxaCENuCxpoMCmAt/COCGVDwA7kleEpEzJjDnvh3yGoOuLu0Dtllw== + dependencies: + fast-deep-equal "^3.1.1" + json-schema-traverse "^1.0.0" + require-from-string "^2.0.2" + uri-js "^4.2.2" + alphanum-sort@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/alphanum-sort/-/alphanum-sort-1.0.2.tgz#97a1119649b211ad33691d9f9f486a8ec9fbe0a3" @@ -2667,6 +3674,14 @@ anymatch@~3.1.1: normalize-path "^3.0.0" picomatch "^2.0.4" +anymatch@~3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716" + integrity sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg== + dependencies: + normalize-path "^3.0.0" + picomatch "^2.0.4" + app-root-path@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/app-root-path/-/app-root-path-3.0.0.tgz#210b6f43873227e18a4b810a032283311555d5ad" @@ -2841,6 +3856,19 @@ autoprefixer@10.2.4: normalize-range "^0.1.2" postcss-value-parser "^4.1.0" +autoprefixer@^9.6.1: + version "9.8.8" + resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-9.8.8.tgz#fd4bd4595385fa6f06599de749a4d5f7a474957a" + integrity sha512-eM9d/swFopRt5gdJ7jrpCwgvEMIayITpojhkkSMRsFHYuH5bkSQ4p/9qTEHtmNudUZh22Tehu7I6CxAW0IXTKA== + dependencies: + browserslist "^4.12.0" + caniuse-lite "^1.0.30001109" + normalize-range "^0.1.2" + num2fraction "^1.2.2" + picocolors "^0.2.1" + postcss "^7.0.32" + postcss-value-parser "^4.1.0" + aws-sign2@~0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" @@ -2875,6 +3903,30 @@ babel-plugin-dynamic-import-node@^2.3.3: dependencies: object.assign "^4.1.0" +babel-plugin-polyfill-corejs2@^0.2.2: + version "0.2.3" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.2.3.tgz#6ed8e30981b062f8fe6aca8873a37ebcc8cc1c0f" + integrity sha512-NDZ0auNRzmAfE1oDDPW2JhzIMXUk+FFe2ICejmt5T4ocKgiQx3e0VCRx9NCAidcMtL2RUZaWtXnmjTCkx0tcbA== + dependencies: + "@babel/compat-data" "^7.13.11" + "@babel/helper-define-polyfill-provider" "^0.2.4" + semver "^6.1.1" + +babel-plugin-polyfill-corejs3@^0.2.2: + version "0.2.5" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.2.5.tgz#2779846a16a1652244ae268b1e906ada107faf92" + integrity sha512-ninF5MQNwAX9Z7c9ED+H2pGt1mXdP4TqzlHKyPIYmJIYz0N+++uwdM7RnJukklhzJ54Q84vA4ZJkgs7lu5vqcw== + dependencies: + "@babel/helper-define-polyfill-provider" "^0.2.2" + core-js-compat "^3.16.2" + +babel-plugin-polyfill-regenerator@^0.2.2: + version "0.2.3" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.2.3.tgz#2e9808f5027c4336c994992b48a4262580cb8d6d" + integrity sha512-JVE78oRZPKFIeUqFGrSORNzQnrDwZR16oiWeGM8ZyjBn2XAT5OjP+wXx5ESuo33nUsFUEJYjtklnsKbxW5L+7g== + dependencies: + "@babel/helper-define-polyfill-provider" "^0.2.4" + balanced-match@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" @@ -2895,7 +3947,7 @@ base64-js@^1.0.2: resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.1.tgz#58ece8cb75dd07e71ed08c736abc5fac4dbf8df1" integrity sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g== -base64-js@^1.3.1: +base64-js@^1.2.0, base64-js@^1.3.1: version "1.5.1" resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== @@ -2952,7 +4004,7 @@ bindings@^1.5.0: dependencies: file-uri-to-path "1.0.0" -bl@^4.0.3: +bl@^4.0.3, bl@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/bl/-/bl-4.1.0.tgz#451535264182bec2fbbc83a62ab98cf11d9f7b3a" integrity sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w== @@ -3123,6 +4175,17 @@ browserslist@^4.0.0, browserslist@^4.9.1: escalade "^3.1.0" node-releases "^1.1.61" +browserslist@^4.12.0, browserslist@^4.17.5, browserslist@^4.18.1, browserslist@^4.6.4: + version "4.18.1" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.18.1.tgz#60d3920f25b6860eb917c6c7b185576f4d8b017f" + integrity sha512-8ScCzdpPwR2wQh8IT82CA2VgDwjHyqMovPBZSNH54+tm4Jk2pCuv90gmAdH6J84OCRWi0b4gMe6O6XPXuJnjgQ== + dependencies: + caniuse-lite "^1.0.30001280" + electron-to-chromium "^1.3.896" + escalade "^3.1.1" + node-releases "^2.0.1" + picocolors "^1.0.0" + browserslist@^4.14.5, browserslist@^4.16.0, browserslist@^4.16.1, browserslist@^4.16.6: version "4.16.6" resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.16.6.tgz#d7901277a5a88e554ed305b183ec9b0c08f66fa2" @@ -3239,6 +4302,29 @@ cacache@15.0.5, cacache@^15.0.5: tar "^6.0.2" unique-filename "^1.1.1" +cacache@15.2.0: + version "15.2.0" + resolved "https://registry.yarnpkg.com/cacache/-/cacache-15.2.0.tgz#73af75f77c58e72d8c630a7a2858cb18ef523389" + integrity sha512-uKoJSHmnrqXgthDFx/IU6ED/5xd+NNGe+Bb+kLZy7Ku4P+BaiWEUflAKPZ7eAzsYGcsAGASJZsybXp+quEcHTw== + dependencies: + "@npmcli/move-file" "^1.0.1" + chownr "^2.0.0" + fs-minipass "^2.0.0" + glob "^7.1.4" + infer-owner "^1.0.4" + lru-cache "^6.0.0" + minipass "^3.1.1" + minipass-collect "^1.0.2" + minipass-flush "^1.0.5" + minipass-pipeline "^1.2.2" + mkdirp "^1.0.3" + p-map "^4.0.0" + promise-inflight "^1.0.1" + rimraf "^3.0.2" + ssri "^8.0.1" + tar "^6.0.2" + unique-filename "^1.1.1" + cacache@^12.0.2: version "12.0.4" resolved "https://registry.yarnpkg.com/cacache/-/cacache-12.0.4.tgz#668bcbd105aeb5f1d92fe25570ec9525c8faa40c" @@ -3260,6 +4346,30 @@ cacache@^12.0.2: unique-filename "^1.1.1" y18n "^4.0.0" +cacache@^15.2.0: + version "15.3.0" + resolved "https://registry.yarnpkg.com/cacache/-/cacache-15.3.0.tgz#dc85380fb2f556fe3dda4c719bfa0ec875a7f1eb" + integrity sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ== + dependencies: + "@npmcli/fs" "^1.0.0" + "@npmcli/move-file" "^1.0.1" + chownr "^2.0.0" + fs-minipass "^2.0.0" + glob "^7.1.4" + infer-owner "^1.0.4" + lru-cache "^6.0.0" + minipass "^3.1.1" + minipass-collect "^1.0.2" + minipass-flush "^1.0.5" + minipass-pipeline "^1.2.2" + mkdirp "^1.0.3" + p-map "^4.0.0" + promise-inflight "^1.0.1" + rimraf "^3.0.2" + ssri "^8.0.1" + tar "^6.0.2" + unique-filename "^1.1.1" + cache-base@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" @@ -3305,6 +4415,11 @@ caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001032, caniuse-lite@^1.0.30001135: resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001146.tgz#c61fcb1474520c1462913689201fb292ba6f447c" integrity sha512-VAy5RHDfTJhpxnDdp2n40GPPLp3KqNrXz1QqFv4J64HvArKs8nuNMOWkB3ICOaBTU/Aj4rYAo/ytdQDDFF/Pug== +caniuse-lite@^1.0.30000981, caniuse-lite@^1.0.30001109, caniuse-lite@^1.0.30001280: + version "1.0.30001283" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001283.tgz#8573685bdae4d733ef18f78d44ba0ca5fe9e896b" + integrity sha512-9RoKo841j1GQFSJz/nCXOj0sD7tHBtlowjYlrqIUS812x9/emfBLBt6IyMz1zIaYc/eRL8Cs6HPUVi2Hzq4sIg== + caniuse-lite@^1.0.30001181, caniuse-lite@^1.0.30001219: version "1.0.30001228" resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001228.tgz#bfdc5942cd3326fa51ee0b42fbef4da9d492a7fa" @@ -3353,6 +4468,14 @@ chalk@^4.0.0, chalk@^4.1.0: ansi-styles "^4.1.0" supports-color "^7.1.0" +chalk@^4.1.1: + version "4.1.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + chardet@^0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" @@ -3373,6 +4496,21 @@ chardet@^0.7.0: optionalDependencies: fsevents "~2.1.2" +"chokidar@>=3.0.0 <4.0.0": + version "3.5.2" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.2.tgz#dba3976fcadb016f66fd365021d91600d01c1e75" + integrity sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ== + dependencies: + anymatch "~3.1.2" + braces "~3.0.2" + glob-parent "~5.1.2" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.6.0" + optionalDependencies: + fsevents "~2.3.2" + chokidar@^2.1.8: version "2.1.8" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.1.8.tgz#804b3a7b6a99358c3c5c61e71d8728f041cff917" @@ -3596,6 +4734,11 @@ colord@^2.0.0: resolved "https://registry.yarnpkg.com/colord/-/colord-2.0.0.tgz#f8c19f2526b7dc5b22d6e57ef102f03a2a43a3d8" integrity sha512-WMDFJfoY3wqPZNpKUFdse3HhD5BHCbE9JCdxRzoVH+ywRITGOeWAHNkGEmyxLlErEpN9OLMWgdM9dWQtDk5dog== +colord@^2.9.1: + version "2.9.1" + resolved "https://registry.yarnpkg.com/colord/-/colord-2.9.1.tgz#c961ea0efeb57c9f0f4834458f26cb9cc4a3f90e" + integrity sha512-4LBMSt09vR0uLnPVkOUBnmxgoaeN4ewRbx801wY/bXcltXfpR/G46OdWn96XpYmCWuYvO46aBZP4NgX8HpNAcw== + colorette@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.2.1.tgz#4d0b921325c14faf92633086a536db6e89564b1b" @@ -3628,7 +4771,7 @@ commander@^6.0.0: resolved "https://registry.yarnpkg.com/commander/-/commander-6.2.1.tgz#0792eb682dfbc325999bb2b84fddddba110ac73c" integrity sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA== -commander@^7.1.0: +commander@^7.1.0, commander@^7.2.0: version "7.2.0" resolved "https://registry.yarnpkg.com/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7" integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw== @@ -3807,6 +4950,27 @@ copy-webpack-plugin@6.3.2: serialize-javascript "^5.0.1" webpack-sources "^1.4.3" +copy-webpack-plugin@9.0.1: + version "9.0.1" + resolved "https://registry.yarnpkg.com/copy-webpack-plugin/-/copy-webpack-plugin-9.0.1.tgz#b71d21991599f61a4ee00ba79087b8ba279bbb59" + integrity sha512-14gHKKdYIxF84jCEgPgYXCPpldbwpxxLbCmA7LReY7gvbaT555DgeBWBgBZM116tv/fO6RRJrsivBqRyRlukhw== + dependencies: + fast-glob "^3.2.5" + glob-parent "^6.0.0" + globby "^11.0.3" + normalize-path "^3.0.0" + p-limit "^3.1.0" + schema-utils "^3.0.0" + serialize-javascript "^6.0.0" + +core-js-compat@^3.15.0, core-js-compat@^3.16.2: + version "3.19.2" + resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.19.2.tgz#18066a3404a302433cb0aa8be82dd3d75c76e5c4" + integrity sha512-ObBY1W5vx/LFFMaL1P5Udo4Npib6fu+cMokeziWkA8Tns4FcDemKF5j9JvaI5JhdkW8EQJQGJN1EcrzmEwuAqQ== + dependencies: + browserslist "^4.18.1" + semver "7.0.0" + core-js-compat@^3.8.0: version "3.12.1" resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.12.1.tgz#2c302c4708505fa7072b0adb5156d26f7801a18b" @@ -3815,6 +4979,11 @@ core-js-compat@^3.8.0: browserslist "^4.16.6" semver "7.0.0" +core-js@3.16.0: + version "3.16.0" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.16.0.tgz#1d46fb33720bc1fa7f90d20431f36a5540858986" + integrity sha512-5+5VxRFmSf97nM8Jr2wzOwLqRo6zphH2aX+7KsAUONObyzakDNq2G/bgbhinxB4PoV9L3aXQYhiDKyIKWd2c8g== + core-js@3.8.3: version "3.8.3" resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.8.3.tgz#c21906e1f14f3689f93abcc6e26883550dd92dd0" @@ -3880,6 +5049,18 @@ create-hmac@^1.1.0, create-hmac@^1.1.4, create-hmac@^1.1.7: safe-buffer "^5.0.1" sha.js "^2.4.8" +critters@0.0.12: + version "0.0.12" + resolved "https://registry.yarnpkg.com/critters/-/critters-0.0.12.tgz#32baa87526e053a41b67e19921673ed92264e2ab" + integrity sha512-ujxKtKc/mWpjrOKeaACTaQ1aP0O31M0ZPWhfl85jZF1smPU4Ivb9va5Ox2poif4zVJQQo0LCFlzGtEZAsCAPcw== + dependencies: + chalk "^4.1.0" + css-select "^4.1.3" + parse5 "^6.0.1" + parse5-htmlparser2-tree-adapter "^6.0.1" + postcss "^8.3.7" + pretty-bytes "^5.3.0" + critters@0.0.7: version "0.0.7" resolved "https://registry.yarnpkg.com/critters/-/critters-0.0.7.tgz#548b470360f4f3c51e622de3b7aa733c8f0b17bf" @@ -3919,6 +5100,13 @@ crypto-browserify@^3.11.0: randombytes "^2.0.0" randomfill "^1.0.3" +css-blank-pseudo@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/css-blank-pseudo/-/css-blank-pseudo-0.1.4.tgz#dfdefd3254bf8a82027993674ccf35483bfcb3c5" + integrity sha512-LHz35Hr83dnFeipc7oqFDmsjHdljj3TQtxGGiNWSOsTLIAubSm4TEz8qCaKFpk7idaQ1GfWscF4E6mgpBysA1w== + dependencies: + postcss "^7.0.5" + css-color-names@^0.0.4: version "0.0.4" resolved "https://registry.yarnpkg.com/css-color-names/-/css-color-names-0.0.4.tgz#808adc2e79cf84738069b646cb20ec27beb629e0" @@ -3936,6 +5124,14 @@ css-declaration-sorter@^6.0.3: dependencies: timsort "^0.3.0" +css-has-pseudo@^0.10.0: + version "0.10.0" + resolved "https://registry.yarnpkg.com/css-has-pseudo/-/css-has-pseudo-0.10.0.tgz#3c642ab34ca242c59c41a125df9105841f6966ee" + integrity sha512-Z8hnfsZu4o/kt+AuFzeGpLVhFOGO9mluyHBaA2bA8aCGTwah5sT3WV/fTHH8UNZUytOIImuGPrl/prlb4oX4qQ== + dependencies: + postcss "^7.0.6" + postcss-selector-parser "^5.0.0-rc.4" + css-line-break@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/css-line-break/-/css-line-break-1.1.1.tgz#d5e9bdd297840099eb0503c7310fd34927a026ef" @@ -3961,6 +5157,33 @@ css-loader@5.0.1: schema-utils "^3.0.0" semver "^7.3.2" +css-loader@6.2.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-6.2.0.tgz#9663d9443841de957a3cb9bcea2eda65b3377071" + integrity sha512-/rvHfYRjIpymZblf49w8jYcRo2y9gj6rV8UroHGmBxKrIyGLokpycyKzp9OkitvqT29ZSpzJ0Ic7SpnJX3sC8g== + dependencies: + icss-utils "^5.1.0" + postcss "^8.2.15" + postcss-modules-extract-imports "^3.0.0" + postcss-modules-local-by-default "^4.0.0" + postcss-modules-scope "^3.0.0" + postcss-modules-values "^4.0.0" + postcss-value-parser "^4.1.0" + semver "^7.3.5" + +css-minimizer-webpack-plugin@3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/css-minimizer-webpack-plugin/-/css-minimizer-webpack-plugin-3.0.2.tgz#8fadbdf10128cb40227bff275a4bb47412534245" + integrity sha512-B3I5e17RwvKPJwsxjjWcdgpU/zqylzK1bPVghcmpFHRL48DXiBgrtqz1BJsn68+t/zzaLp9kYAaEDvQ7GyanFQ== + dependencies: + cssnano "^5.0.6" + jest-worker "^27.0.2" + p-limit "^3.0.2" + postcss "^8.3.5" + schema-utils "^3.0.0" + serialize-javascript "^6.0.0" + source-map "^0.6.1" + css-parse@~2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/css-parse/-/css-parse-2.0.0.tgz#a468ee667c16d81ccf05c58c38d2a97c780dbfd4" @@ -3968,6 +5191,13 @@ css-parse@~2.0.0: dependencies: css "^2.0.0" +css-prefers-color-scheme@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/css-prefers-color-scheme/-/css-prefers-color-scheme-3.1.1.tgz#6f830a2714199d4f0d0d0bb8a27916ed65cff1f4" + integrity sha512-MTu6+tMs9S3EUqzmqLXEcgNRbNkkD/TGFvowpeoWJn5Vfq7FMgsmRQs9X5NXAURiOBmOxm/lLjsDNXDE6k9bhg== + dependencies: + postcss "^7.0.5" + css-select@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/css-select/-/css-select-3.1.2.tgz#d52cbdc6fee379fba97fb0d3925abbd18af2d9d8" @@ -3979,6 +5209,17 @@ css-select@^3.1.2: domutils "^2.4.3" nth-check "^2.0.0" +css-select@^4.1.3: + version "4.1.3" + resolved "https://registry.yarnpkg.com/css-select/-/css-select-4.1.3.tgz#a70440f70317f2669118ad74ff105e65849c7067" + integrity sha512-gT3wBNd9Nj49rAbmtFHj1cljIAOLYSX1nZ8CB7TBO3INYckygm5B7LISU/szY//YmdiSLbJvDLOx9VnMVpMBxA== + dependencies: + boolbase "^1.0.0" + css-what "^5.0.0" + domhandler "^4.2.0" + domutils "^2.6.0" + nth-check "^2.0.0" + css-selector-tokenizer@^0.7.1: version "0.7.3" resolved "https://registry.yarnpkg.com/css-selector-tokenizer/-/css-selector-tokenizer-0.7.3.tgz#735f26186e67c749aaf275783405cf0661fae8f1" @@ -3987,7 +5228,7 @@ css-selector-tokenizer@^0.7.1: cssesc "^3.0.0" fastparse "^1.1.2" -css-tree@^1.1.2: +css-tree@^1.1.2, css-tree@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.1.3.tgz#eb4870fb6fd7707327ec95c2ff2ab09b5e8db91d" integrity sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q== @@ -4008,6 +5249,11 @@ css-what@^4.0.0: resolved "https://registry.yarnpkg.com/css-what/-/css-what-4.0.0.tgz#35e73761cab2eeb3d3661126b23d7aa0e8432233" integrity sha512-teijzG7kwYfNVsUh2H/YN62xW3KK9YhXEgSlbxMlcyjPNvdKJqFx5lrwlJgoFP1ZHlB89iGDlo/JyshKeRhv5A== +css-what@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/css-what/-/css-what-5.1.0.tgz#3f7b707aadf633baf62c2ceb8579b545bb40f7fe" + integrity sha512-arSMRWIIFY0hV8pIxZMEfmMI47Wj3R/aWpZDDxWYCPEiOMv6tfOrnpDtgxBYPEQD4V0Y/958+1TdC3iWTFcUPw== + css@^2.0.0: version "2.2.4" resolved "https://registry.yarnpkg.com/css/-/css-2.2.4.tgz#c646755c73971f2bba6a601e2cf2fd71b1298929" @@ -4034,6 +5280,16 @@ cssauron@^1.4.0: dependencies: through X.X.X +cssdb@^4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/cssdb/-/cssdb-4.4.0.tgz#3bf2f2a68c10f5c6a08abd92378331ee803cddb0" + integrity sha512-LsTAR1JPEM9TpGhl/0p3nQecC2LJ0kD8X5YARu1hk/9I1gril5vDtMZyNxcEpxxDj34YNck/ucjuoUd66K03oQ== + +cssesc@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-2.0.0.tgz#3b13bd1bb1cb36e1bcb5a4dcd27f54c5dcb35703" + integrity sha512-MsCAG1z9lPdoO/IUMLSBWBSVxVtJ1395VGIQ+Fc2gNdkQ1hNDnQdw3YhA71WJCBW1vdwA0cAnk/DnW6bqoEUYg== + cssesc@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" @@ -4047,17 +5303,52 @@ cssnano-preset-default@^5.0.1: css-declaration-sorter "^6.0.3" cssnano-utils "^2.0.1" postcss-calc "^8.0.0" - postcss-colormin "^5.1.1" - postcss-convert-values "^5.0.1" + postcss-colormin "^5.1.1" + postcss-convert-values "^5.0.1" + postcss-discard-comments "^5.0.1" + postcss-discard-duplicates "^5.0.1" + postcss-discard-empty "^5.0.1" + postcss-discard-overridden "^5.0.1" + postcss-merge-longhand "^5.0.2" + postcss-merge-rules "^5.0.1" + postcss-minify-font-values "^5.0.1" + postcss-minify-gradients "^5.0.1" + postcss-minify-params "^5.0.1" + postcss-minify-selectors "^5.1.0" + postcss-normalize-charset "^5.0.1" + postcss-normalize-display-values "^5.0.1" + postcss-normalize-positions "^5.0.1" + postcss-normalize-repeat-style "^5.0.1" + postcss-normalize-string "^5.0.1" + postcss-normalize-timing-functions "^5.0.1" + postcss-normalize-unicode "^5.0.1" + postcss-normalize-url "^5.0.1" + postcss-normalize-whitespace "^5.0.1" + postcss-ordered-values "^5.0.1" + postcss-reduce-initial "^5.0.1" + postcss-reduce-transforms "^5.0.1" + postcss-svgo "^5.0.1" + postcss-unique-selectors "^5.0.1" + +cssnano-preset-default@^5.1.8: + version "5.1.8" + resolved "https://registry.yarnpkg.com/cssnano-preset-default/-/cssnano-preset-default-5.1.8.tgz#7525feb1b72f7b06e57f55064cbdae341d79dea2" + integrity sha512-zWMlP0+AMPBVE852SqTrP0DnhTcTA2C1wAF92TKZ3Va+aUVqLIhkqKlnJIXXdqXD7RN+S1ujuWmNpvrJBiM/vg== + dependencies: + css-declaration-sorter "^6.0.3" + cssnano-utils "^2.0.1" + postcss-calc "^8.0.0" + postcss-colormin "^5.2.1" + postcss-convert-values "^5.0.2" postcss-discard-comments "^5.0.1" postcss-discard-duplicates "^5.0.1" postcss-discard-empty "^5.0.1" postcss-discard-overridden "^5.0.1" - postcss-merge-longhand "^5.0.2" - postcss-merge-rules "^5.0.1" + postcss-merge-longhand "^5.0.4" + postcss-merge-rules "^5.0.3" postcss-minify-font-values "^5.0.1" - postcss-minify-gradients "^5.0.1" - postcss-minify-params "^5.0.1" + postcss-minify-gradients "^5.0.3" + postcss-minify-params "^5.0.2" postcss-minify-selectors "^5.1.0" postcss-normalize-charset "^5.0.1" postcss-normalize-display-values "^5.0.1" @@ -4066,13 +5357,13 @@ cssnano-preset-default@^5.0.1: postcss-normalize-string "^5.0.1" postcss-normalize-timing-functions "^5.0.1" postcss-normalize-unicode "^5.0.1" - postcss-normalize-url "^5.0.1" + postcss-normalize-url "^5.0.3" postcss-normalize-whitespace "^5.0.1" - postcss-ordered-values "^5.0.1" - postcss-reduce-initial "^5.0.1" + postcss-ordered-values "^5.0.2" + postcss-reduce-initial "^5.0.2" postcss-reduce-transforms "^5.0.1" - postcss-svgo "^5.0.1" - postcss-unique-selectors "^5.0.1" + postcss-svgo "^5.0.3" + postcss-unique-selectors "^5.0.2" cssnano-utils@^2.0.1: version "2.0.1" @@ -4088,6 +5379,16 @@ cssnano@5.0.2: cssnano-preset-default "^5.0.1" is-resolvable "^1.1.0" +cssnano@^5.0.6: + version "5.0.12" + resolved "https://registry.yarnpkg.com/cssnano/-/cssnano-5.0.12.tgz#2c083a1c786fc9dc2d5522bd3c0e331b7cd302ab" + integrity sha512-U38V4x2iJ3ijPdeWqUrEr4eKBB5PbEKsNP5T8xcik2Au3LeMtiMHX0i2Hu9k51FcKofNZumbrcdC6+a521IUHg== + dependencies: + cssnano-preset-default "^5.1.8" + is-resolvable "^1.1.0" + lilconfig "^2.0.3" + yaml "^1.10.2" + csso@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/csso/-/csso-4.2.0.tgz#ea3a561346e8dc9f546d6febedd50187cf389529" @@ -4149,13 +5450,20 @@ debug@2.6.9, debug@^2.2.0, debug@^2.3.3: dependencies: ms "2.0.0" -debug@4, debug@4.3.1, debug@~4.3.1: +debug@4, debug@~4.3.1: version "4.3.1" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.1.tgz#f0d229c505e0c6d8c49ac553d1b13dc183f6b2ee" integrity sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ== dependencies: ms "2.1.2" +debug@4.3.2: + version "4.3.2" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.2.tgz#f0a49c18ac8779e31d4a0c6029dfb76873c7428b" + integrity sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw== + dependencies: + ms "2.1.2" + debug@^3.1.0, debug@^3.1.1: version "3.2.6" resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" @@ -4177,6 +5485,13 @@ debug@^4.1.0, debug@^4.1.1: dependencies: ms "2.1.2" +debug@^4.3.1: + version "4.3.3" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.3.tgz#04266e0b70a98d4462e6e288e38259213332b664" + integrity sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q== + dependencies: + ms "2.1.2" + debug@~3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" @@ -4226,6 +5541,11 @@ defaults@^1.0.3: dependencies: clone "^1.0.2" +define-lazy-prop@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz#3f7ae421129bcaaac9bc74905c98a0009ec9ee7f" + integrity sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og== + define-properties@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" @@ -4301,10 +5621,10 @@ depd@^1.1.2, depd@~1.1.2: resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= -dependency-graph@^0.7.2: - version "0.7.2" - resolved "https://registry.yarnpkg.com/dependency-graph/-/dependency-graph-0.7.2.tgz#91db9de6eb72699209d88aea4c1fd5221cac1c49" - integrity sha512-KqtH4/EZdtdfWX0p6MGP9jljvxSY6msy/pRUD4jgNwVpv3v1QmNLlsB3LDSSUg79BRVSn7jI1QPRtArGABovAQ== +dependency-graph@^0.11.0: + version "0.11.0" + resolved "https://registry.yarnpkg.com/dependency-graph/-/dependency-graph-0.11.0.tgz#ac0ce7ed68a54da22165a85e97a01d53f5eb2e27" + integrity sha512-JeMq7fEshyepOWDfcfHK06N3MhyPhz++vtqWhMT5O9A3K42rdsEDpfdVqjaqaAhsw6a+ZqeDvQVtD0hFHQWrzg== des.js@^1.0.0: version "1.0.1" @@ -4448,6 +5768,15 @@ domutils@^2.4.3: domelementtype "^2.2.0" domhandler "^4.2.0" +domutils@^2.6.0: + version "2.8.0" + resolved "https://registry.yarnpkg.com/domutils/-/domutils-2.8.0.tgz#4437def5db6e2d1f5d6ee859bd95ca7d02048135" + integrity sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A== + dependencies: + dom-serializer "^1.0.1" + domelementtype "^2.2.0" + domhandler "^4.2.0" + duplexify@^3.4.2, duplexify@^3.6.0: version "3.7.1" resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.7.1.tgz#2a4df5317f6ccfd91f86d6fd25d8d8a103b88309" @@ -4491,6 +5820,11 @@ electron-to-chromium@^1.3.723: resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.737.tgz#196f2e9656f4f3c31930750e1899c091b72d36b5" integrity sha512-P/B84AgUSQXaum7a8m11HUsYL8tj9h/Pt5f7Hg7Ty6bm5DxlFq+e5+ouHUoNQMsKDJ7u4yGfI8mOErCmSH9wyg== +electron-to-chromium@^1.3.896: + version "1.4.5" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.5.tgz#912e8fd1645edee2f0f212558f40916eb538b1f9" + integrity sha512-YKaB+t8ul5crdh6OeqT2qXdxJGI0fAYb6/X8pDIyye+c3a7ndOCk5gVeKX+ABwivCGNS56vOAif3TN0qJMpEHw== + elliptic@^6.5.3: version "6.5.3" resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.3.tgz#cb59eb2efdaf73a0bd78ccd7015a62ad6e0f93d6" @@ -4580,7 +5914,7 @@ enhanced-resolve@^4.3.0: memory-fs "^0.5.0" tapable "^1.0.0" -enhanced-resolve@^5.8.3: +enhanced-resolve@^5.8.0, enhanced-resolve@^5.8.3: version "5.8.3" resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.8.3.tgz#6d552d465cce0423f5b3d718511ea53826a7b2f0" integrity sha512-EGAbGvH7j7Xt2nc0E7D99La1OiEs8LnyimkRgwExpUMScN6O+3x9tIWs7PLQZVNx4YD+00skHXPXi1yQHpAmZA== @@ -4603,11 +5937,6 @@ env-paths@^2.2.0: resolved "https://registry.yarnpkg.com/env-paths/-/env-paths-2.2.1.tgz#420399d416ce1fbe9bc0a07c62fa68d67fd0f8f2" integrity sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A== -err-code@^1.0.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/err-code/-/err-code-1.1.2.tgz#06e0116d3028f6aef4806849eb0ea6a748ae6960" - integrity sha1-BuARbTAo9q70gGhJ6w6mp0iuaWA= - err-code@^2.0.2: version "2.0.3" resolved "https://registry.yarnpkg.com/err-code/-/err-code-2.0.3.tgz#23c2f3b756ffdfc608d30e27c9a941024807e7f9" @@ -4662,6 +5991,11 @@ es-abstract@^1.18.0-next.0, es-abstract@^1.18.0-next.1: string.prototype.trimend "^1.0.1" string.prototype.trimstart "^1.0.1" +es-module-lexer@^0.7.1: + version "0.7.1" + resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-0.7.1.tgz#c2c8e0f46f2df06274cdaf0dd3f3b33e0a0b267d" + integrity sha512-MgtWFl5No+4S3TmhDmCz2ObFGm6lEpTnzbQi+Dd+pw4mlTIZTmM2iAs5gRlmx5zS9luzobCSBSI90JM/1/JgOw== + es-module-lexer@^0.9.0: version "0.9.3" resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-0.9.3.tgz#6f13db00cc38417137daf74366f535c8eb438f19" @@ -4688,6 +6022,119 @@ es6-promisify@^5.0.0: dependencies: es6-promise "^4.0.3" +esbuild-android-arm64@0.13.8: + version "0.13.8" + resolved "https://registry.yarnpkg.com/esbuild-android-arm64/-/esbuild-android-arm64-0.13.8.tgz#c20e875c3c98164b1ffba9b28637bdf96f5e9e7c" + integrity sha512-AilbChndywpk7CdKkNSZ9klxl+9MboLctXd9LwLo3b0dawmOF/i/t2U5d8LM6SbT1Xw36F8yngSUPrd8yPs2RA== + +esbuild-darwin-64@0.13.8: + version "0.13.8" + resolved "https://registry.yarnpkg.com/esbuild-darwin-64/-/esbuild-darwin-64-0.13.8.tgz#f46e6b471ddbf62265234808a6a1aa91df18a417" + integrity sha512-b6sdiT84zV5LVaoF+UoMVGJzR/iE2vNUfUDfFQGrm4LBwM/PWXweKpuu6RD9mcyCq18cLxkP6w/LD/w9DtX3ng== + +esbuild-darwin-arm64@0.13.8: + version "0.13.8" + resolved "https://registry.yarnpkg.com/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.13.8.tgz#a991157a6013facd4f2e14159b7da52626c90154" + integrity sha512-R8YuPiiJayuJJRUBG4H0VwkEKo6AvhJs2m7Tl0JaIer3u1FHHXwGhMxjJDmK+kXwTFPriSysPvcobXC/UrrZCQ== + +esbuild-freebsd-64@0.13.8: + version "0.13.8" + resolved "https://registry.yarnpkg.com/esbuild-freebsd-64/-/esbuild-freebsd-64-0.13.8.tgz#301601d2e443ad458960e359b402a17d9500be9d" + integrity sha512-zBn6urrn8FnKC+YSgDxdof9jhPCeU8kR/qaamlV4gI8R3KUaUK162WYM7UyFVAlj9N0MyD3AtB+hltzu4cysTw== + +esbuild-freebsd-arm64@0.13.8: + version "0.13.8" + resolved "https://registry.yarnpkg.com/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.13.8.tgz#039a63acc12ec0892006c147ea221e55f9125a9f" + integrity sha512-pWW2slN7lGlkx0MOEBoUGwRX5UgSCLq3dy2c8RIOpiHtA87xAUpDBvZK10MykbT+aMfXc0NI2lu1X+6kI34xng== + +esbuild-linux-32@0.13.8: + version "0.13.8" + resolved "https://registry.yarnpkg.com/esbuild-linux-32/-/esbuild-linux-32-0.13.8.tgz#c537b67d7e694b60bfa2786581412838c6ba0284" + integrity sha512-T0I0ueeKVO/Is0CAeSEOG9s2jeNNb8jrrMwG9QBIm3UU18MRB60ERgkS2uV3fZ1vP2F8i3Z2e3Zju4lg9dhVmw== + +esbuild-linux-64@0.13.8: + version "0.13.8" + resolved "https://registry.yarnpkg.com/esbuild-linux-64/-/esbuild-linux-64-0.13.8.tgz#0092fc8a064001a777bfa0e3b425bb8be8f96e6a" + integrity sha512-Bm8SYmFtvfDCIu9sjKppFXzRXn2BVpuCinU1ChTuMtdKI/7aPpXIrkqBNOgPTOQO9AylJJc1Zw6EvtKORhn64w== + +esbuild-linux-arm64@0.13.8: + version "0.13.8" + resolved "https://registry.yarnpkg.com/esbuild-linux-arm64/-/esbuild-linux-arm64-0.13.8.tgz#5cd3f2bb924212971482e8dbc25c4afd09b28110" + integrity sha512-X4pWZ+SL+FJ09chWFgRNO3F+YtvAQRcWh0uxKqZSWKiWodAB20flsW/OWFYLXBKiVCTeoGMvENZS/GeVac7+tQ== + +esbuild-linux-arm@0.13.8: + version "0.13.8" + resolved "https://registry.yarnpkg.com/esbuild-linux-arm/-/esbuild-linux-arm-0.13.8.tgz#ad634f96bf2975536907aeb9fdb75a3194f4ddce" + integrity sha512-4/HfcC40LJ4GPyboHA+db0jpFarTB628D1ifU+/5bunIgY+t6mHkJWyxWxAAE8wl/ZIuRYB9RJFdYpu1AXGPdg== + +esbuild-linux-mips64le@0.13.8: + version "0.13.8" + resolved "https://registry.yarnpkg.com/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.13.8.tgz#57857edfebf9bf65766dc8be1637f2179c990572" + integrity sha512-o7e0D+sqHKT31v+mwFircJFjwSKVd2nbkHEn4l9xQ1hLR+Bv8rnt3HqlblY3+sBdlrOTGSwz0ReROlKUMJyldA== + +esbuild-linux-ppc64le@0.13.8: + version "0.13.8" + resolved "https://registry.yarnpkg.com/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.13.8.tgz#fdb82a059a5b86bb10fb42091b4ebcf488b9cd46" + integrity sha512-eZSQ0ERsWkukJp2px/UWJHVNuy0lMoz/HZcRWAbB6reoaBw7S9vMzYNUnflfL3XA6WDs+dZn3ekHE4Y2uWLGig== + +esbuild-netbsd-64@0.13.8: + version "0.13.8" + resolved "https://registry.yarnpkg.com/esbuild-netbsd-64/-/esbuild-netbsd-64-0.13.8.tgz#d7879e7123d3b2c04754ece8bd061aa6866deeff" + integrity sha512-gZX4kP7gVvOrvX0ZwgHmbuHczQUwqYppxqtoyC7VNd80t5nBHOFXVhWo2Ad/Lms0E8b+wwgI/WjZFTCpUHOg9Q== + +esbuild-openbsd-64@0.13.8: + version "0.13.8" + resolved "https://registry.yarnpkg.com/esbuild-openbsd-64/-/esbuild-openbsd-64-0.13.8.tgz#88b280b6cb0a3f6adb60abf27fc506c506a35cf0" + integrity sha512-afzza308X4WmcebexbTzAgfEWt9MUkdTvwIa8xOu4CM2qGbl2LanqEl8/LUs8jh6Gqw6WsicEK52GPrS9wvkcw== + +esbuild-sunos-64@0.13.8: + version "0.13.8" + resolved "https://registry.yarnpkg.com/esbuild-sunos-64/-/esbuild-sunos-64-0.13.8.tgz#229ae7c7703196a58acd0f0291ad9bebda815d63" + integrity sha512-mWPZibmBbuMKD+LDN23LGcOZ2EawMYBONMXXHmbuxeT0XxCNwadbCVwUQ/2p5Dp5Kvf6mhrlIffcnWOiCBpiVw== + +esbuild-wasm@0.13.8: + version "0.13.8" + resolved "https://registry.yarnpkg.com/esbuild-wasm/-/esbuild-wasm-0.13.8.tgz#f34134c187ffcfc22d476e925917f70bab40f8b0" + integrity sha512-UbD+3nloiSpJWXTCInZQrqPe8Y+RLfDkY/5kEHiXsw/lmaEvibe69qTzQu16m5R9je/0bF7VYQ5jaEOq0z9lLA== + +esbuild-windows-32@0.13.8: + version "0.13.8" + resolved "https://registry.yarnpkg.com/esbuild-windows-32/-/esbuild-windows-32-0.13.8.tgz#892d093e32a21c0c9135e5a0ffdc380aeb70e763" + integrity sha512-QsZ1HnWIcnIEApETZWw8HlOhDSWqdZX2SylU7IzGxOYyVcX7QI06ety/aDcn437mwyO7Ph4RrbhB+2ntM8kX8A== + +esbuild-windows-64@0.13.8: + version "0.13.8" + resolved "https://registry.yarnpkg.com/esbuild-windows-64/-/esbuild-windows-64-0.13.8.tgz#7defd8d79ae3bb7e6f53b65a7190be7daf901686" + integrity sha512-76Fb57B9eE/JmJi1QmUW0tRLQZfGo0it+JeYoCDTSlbTn7LV44ecOHIMJSSgZADUtRMWT9z0Kz186bnaB3amSg== + +esbuild-windows-arm64@0.13.8: + version "0.13.8" + resolved "https://registry.yarnpkg.com/esbuild-windows-arm64/-/esbuild-windows-arm64-0.13.8.tgz#e59ae004496fd8a5ab67bfc7945a2e47480d6fb9" + integrity sha512-HW6Mtq5eTudllxY2YgT62MrVcn7oq2o8TAoAvDUhyiEmRmDY8tPwAhb1vxw5/cdkbukM3KdMYtksnUhF/ekWeg== + +esbuild@0.13.8: + version "0.13.8" + resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.13.8.tgz#bd7cc51b881ab067789f88e17baca74724c1ec4f" + integrity sha512-A4af7G7YZLfG5OnARJRMtlpEsCkq/zHZQXewgPA864l9D6VjjbH1SuFYK/OSV6BtHwDGkdwyRrX0qQFLnMfUcw== + optionalDependencies: + esbuild-android-arm64 "0.13.8" + esbuild-darwin-64 "0.13.8" + esbuild-darwin-arm64 "0.13.8" + esbuild-freebsd-64 "0.13.8" + esbuild-freebsd-arm64 "0.13.8" + esbuild-linux-32 "0.13.8" + esbuild-linux-64 "0.13.8" + esbuild-linux-arm "0.13.8" + esbuild-linux-arm64 "0.13.8" + esbuild-linux-mips64le "0.13.8" + esbuild-linux-ppc64le "0.13.8" + esbuild-netbsd-64 "0.13.8" + esbuild-openbsd-64 "0.13.8" + esbuild-sunos-64 "0.13.8" + esbuild-windows-32 "0.13.8" + esbuild-windows-64 "0.13.8" + esbuild-windows-arm64 "0.13.8" + escalade@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.0.tgz#e8e2d7c7a8b76f6ee64c2181d6b8151441602d4e" @@ -4761,6 +6208,11 @@ eve-raphael@0.5.0: resolved "https://registry.yarnpkg.com/eve-raphael/-/eve-raphael-0.5.0.tgz#17c754b792beef3fa6684d79cf5a47c63c4cda30" integrity sha1-F8dUt5K+7z+maE15z1pHxjxM2jA= +eventemitter-asyncresource@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/eventemitter-asyncresource/-/eventemitter-asyncresource-1.0.0.tgz#734ff2e44bf448e627f7748f905d6bdd57bdb65b" + integrity sha512-39F7TBIV0G7gTelxwbEqnwhp90eqCPON1k0NwNfwhgKn4Co4ybUbj2pECcXT0B3ztRKZ7Pw1JujUUgmQJHcVAQ== + eventemitter3@^4.0.0: version "4.0.7" resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" @@ -4928,6 +6380,17 @@ fast-glob@^3.1.1, fast-glob@^3.2.4: micromatch "^4.0.2" picomatch "^2.2.1" +fast-glob@^3.2.5: + version "3.2.7" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.7.tgz#fd6cb7a2d7e9aa7a7846111e85a196d6b2f766a1" + integrity sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.2" + merge2 "^1.3.0" + micromatch "^4.0.4" + fast-json-stable-stringify@2.1.0, fast-json-stable-stringify@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" @@ -5059,6 +6522,11 @@ flatted@^2.0.1: resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.2.tgz#4575b21e2bcee7434aa9be662f4b7b5f9c2b5138" integrity sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA== +flatten@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/flatten/-/flatten-1.0.3.tgz#c1283ac9f27b368abc1e36d1ff7b04501a30356b" + integrity sha512-dVsPA/UwQ8+2uoFe5GHtiBMu48dWLTdsuEd7CKGlZlD78r1TTWBvDuFaFGKCo/ZfEr95Uk56vZoX86OsHkUeIg== + "flot.curvedlines@git://github.com/MichaelZinsmaier/CurvedLines.git#master": version "1.1.1" resolved "git://github.com/MichaelZinsmaier/CurvedLines.git#22ed1fc2a6ccafc816c2d07b36027cc123825c4b" @@ -5134,15 +6602,6 @@ from2@^2.1.0: inherits "^2.0.1" readable-stream "^2.0.0" -fs-extra@4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-4.0.2.tgz#f91704c53d1b461f893452b0c307d9997647ab6b" - integrity sha1-+RcExT0bRh+JNFKwwwfZmXZHq2s= - dependencies: - graceful-fs "^4.1.2" - jsonfile "^4.0.0" - universalify "^0.1.0" - fs-extra@^7.0.1: version "7.0.1" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-7.0.1.tgz#4f189c44aa123b895f722804f55ea23eadc348e9" @@ -5168,6 +6627,11 @@ fs-minipass@^2.0.0, fs-minipass@^2.1.0: dependencies: minipass "^3.0.0" +fs-monkey@1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/fs-monkey/-/fs-monkey-1.0.3.tgz#ae3ac92d53bb328efe0e9a1d9541f6ad8d48e2d3" + integrity sha512-cybjIfiiE+pTWicSCLFHSrXZ6EilF30oh91FDP9S2B051prEa7QWfrVTQm10/dDpswBDXZugPa1Ogu8Yh+HV0Q== + fs-write-stream-atomic@^1.0.8: version "1.0.10" resolved "https://registry.yarnpkg.com/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz#b47df53493ef911df75731e70a9ded0189db40c9" @@ -5196,7 +6660,7 @@ fsevents@~2.1.2: resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.1.3.tgz#fb738703ae8d2f9fe900c33836ddebee8b97f23e" integrity sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ== -fsevents@~2.3.1: +fsevents@~2.3.1, fsevents@~2.3.2: version "2.3.2" resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== @@ -5280,6 +6744,20 @@ glob-parent@^5.1.0, glob-parent@^5.1.1, glob-parent@~5.1.0: dependencies: is-glob "^4.0.1" +glob-parent@^5.1.2, glob-parent@~5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== + dependencies: + is-glob "^4.0.1" + +glob-parent@^6.0.0: + version "6.0.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3" + integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== + dependencies: + is-glob "^4.0.3" + glob-to-regexp@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e" @@ -5297,6 +6775,18 @@ glob@7.1.6, glob@^7.0.3, glob@^7.0.6, glob@^7.1.1, glob@^7.1.3, glob@^7.1.4, glo once "^1.3.0" path-is-absolute "^1.0.0" +glob@7.1.7: + version "7.1.7" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.7.tgz#3b193e9233f01d42d0b3f78294bbeeb418f94a90" + integrity sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + globals@^11.1.0: version "11.12.0" resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" @@ -5314,6 +6804,18 @@ globby@^11.0.1: merge2 "^1.3.0" slash "^3.0.0" +globby@^11.0.3: + version "11.0.4" + resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.4.tgz#2cbaff77c2f2a62e71e9b2813a67b97a3a3001a5" + integrity sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg== + dependencies: + array-union "^2.1.0" + dir-glob "^3.0.1" + fast-glob "^3.1.1" + ignore "^5.1.4" + merge2 "^1.3.0" + slash "^3.0.0" + globby@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/globby/-/globby-5.0.0.tgz#ebd84667ca0dbb330b99bcfc68eac2bc54370e0d" @@ -5459,6 +6961,20 @@ hash.js@^1.0.0, hash.js@^1.0.3: inherits "^2.0.3" minimalistic-assert "^1.0.1" +hdr-histogram-js@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/hdr-histogram-js/-/hdr-histogram-js-2.0.1.tgz#ecb1ff2bcb6181c3e93ff4af9472c28c7e97284e" + integrity sha512-uPZxl1dAFnjUFHWLZmt93vUUvtHeaBay9nVNHu38SdOjMSF/4KqJUqa1Seuj08ptU1rEb6AHvB41X8n/zFZ74Q== + dependencies: + "@assemblyscript/loader" "^0.10.1" + base64-js "^1.2.0" + pako "^1.0.3" + +hdr-histogram-percentiles-obj@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/hdr-histogram-percentiles-obj/-/hdr-histogram-percentiles-obj-3.0.0.tgz#9409f4de0c2dda78e61de2d9d78b1e9f3cba283c" + integrity sha512-7kIufnBqdsBGcSZLPJwqHT3yhk1QTsSlFsVD3kx5ixH/AlgBs9yM1q6DPhXZ8f8gtdqgh7N7/5btRLpQsS2gHw== + hex-color-regex@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/hex-color-regex/-/hex-color-regex-1.1.0.tgz#4c06fccb4602fe2602b3c93df82d7e7dbf1a8a8e" @@ -5487,13 +7003,6 @@ hosted-git-info@^3.0.2: dependencies: lru-cache "^6.0.0" -hosted-git-info@^3.0.6: - version "3.0.8" - resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-3.0.8.tgz#6e35d4cc87af2c5f816e4cb9ce350ba87a3f370d" - integrity sha512-aXpmwoOhRBrw6X3j0h5RloK4x1OzsxMPyxqIHyNfSe2pypkVTZFpEiRoSipPEPlMrh0HW/XsjkJ5WgnCirpNUw== - dependencies: - lru-cache "^6.0.0" - hosted-git-info@^4.0.1: version "4.0.2" resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-4.0.2.tgz#5e425507eede4fea846b7262f0838456c4209961" @@ -5669,7 +7178,7 @@ iconv-lite@^0.6.2: dependencies: safer-buffer ">= 2.1.2 < 3.0.0" -icss-utils@^5.0.0: +icss-utils@^5.0.0, icss-utils@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-5.1.0.tgz#c6be6858abd013d768e98366ae47e25d5887b1ae" integrity sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA== @@ -5806,6 +7315,26 @@ inquirer@7.3.3: strip-ansi "^6.0.0" through "^2.3.6" +inquirer@8.1.2: + version "8.1.2" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-8.1.2.tgz#65b204d2cd7fb63400edd925dfe428bafd422e3d" + integrity sha512-DHLKJwLPNgkfwNmsuEUKSejJFbkv0FMO9SMiQbjI3n5NQuCrSIBqP66ggqyz2a6t2qEolKrMjhQ3+W/xXgUQ+Q== + dependencies: + ansi-escapes "^4.2.1" + chalk "^4.1.1" + cli-cursor "^3.1.0" + cli-width "^3.0.0" + external-editor "^3.0.3" + figures "^3.0.0" + lodash "^4.17.21" + mute-stream "0.0.8" + ora "^5.3.0" + run-async "^2.4.0" + rxjs "^7.2.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + through "^2.3.6" + internal-ip@^4.3.0: version "4.3.0" resolved "https://registry.yarnpkg.com/internal-ip/-/internal-ip-4.3.0.tgz#845452baad9d2ca3b69c635a137acb9a0dad0907" @@ -5901,10 +7430,10 @@ is-color-stop@^1.1.0: rgb-regex "^1.0.1" rgba-regex "^1.0.0" -is-core-module@^2.1.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.4.0.tgz#8e9fc8e15027b011418026e98f0e6f4d86305cc1" - integrity sha512-6A2fkfq1rfeQZjxrZJGerpLCTHRNEBiSgnu0+obeJpEPZRUooHgsizvzv0ZjJwOz3iWIHdJtVWJ/tmPr3D21/A== +is-core-module@^2.2.0: + version "2.8.0" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.8.0.tgz#0321336c3d0925e497fd97f5d95cb114a5ccd548" + integrity sha512-vd15qHsaqrRL7dtH6QNuy0ndJmRDrS9HAM1CAiSifNUFv4x1a0CCVsj18hJ1mShxIG6T2i1sO78MkP56r0nYRw== dependencies: has "^1.0.3" @@ -5950,6 +7479,11 @@ is-docker@^2.0.0: resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.1.1.tgz#4125a88e44e450d384e09047ede71adc2d144156" integrity sha512-ZOoqiXfEwtGknTiuDEy8pN2CfE3TxMHprvNer1mXiqwkOT77Rw3YVrUQ52EqAOU3QAWDQ+bQdx7HJzrv7LS2Hw== +is-docker@^2.1.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa" + integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ== + is-extendable@^0.1.0, is-extendable@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" @@ -5998,6 +7532,13 @@ is-glob@^4.0.0, is-glob@^4.0.1, is-glob@~4.0.1: dependencies: is-extglob "^2.1.1" +is-glob@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + is-in-browser@^1.0.2, is-in-browser@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/is-in-browser/-/is-in-browser-1.1.3.tgz#56ff4db683a078c6082eb95dad7dc62e1d04f835" @@ -6104,6 +7645,11 @@ is-typedarray@~1.0.0: resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= +is-unicode-supported@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7" + integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw== + is-what@^3.12.0: version "3.14.1" resolved "https://registry.yarnpkg.com/is-what/-/is-what-3.14.1.tgz#e1222f46ddda85dead0fd1c9df131760e77755c1" @@ -6119,7 +7665,7 @@ is-wsl@^1.1.0: resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d" integrity sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0= -is-wsl@^2.1.1: +is-wsl@^2.1.1, is-wsl@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271" integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww== @@ -6256,7 +7802,7 @@ jest-worker@26.6.2, jest-worker@^26.5.0: merge-stream "^2.0.0" supports-color "^7.0.0" -jest-worker@^27.0.6: +jest-worker@^27.0.2, jest-worker@^27.0.6: version "27.4.0" resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.4.0.tgz#fa10dddc611cbb47a4153543dd16a0c7e7fd745c" integrity sha512-4WuKcUxtzxBoKOUFbt1MtTY9fJwPVD4aN/4Cgxee7OLetPZn5as2bjfZz98XSf2Zq1JFfhqPZpS+43BmWXKgCA== @@ -6346,6 +7892,11 @@ json-schema-traverse@^0.4.1: resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== +json-schema-traverse@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2" + integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== + json-schema@0.2.3: version "0.2.3" resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" @@ -6653,6 +8204,13 @@ leaflet@^1.7.1: resolved "https://registry.yarnpkg.com/leaflet/-/leaflet-1.7.1.tgz#10d684916edfe1bf41d688a3b97127c0322a2a19" integrity sha512-/xwPEBidtg69Q3HlqPdU3DnrXQOvQU/CCHA1tcDQVzOwm91YMYaILjNp7L4Eaw5Z4sOYdbBz6koWyibppd8Zqw== +less-loader@10.0.1: + version "10.0.1" + resolved "https://registry.yarnpkg.com/less-loader/-/less-loader-10.0.1.tgz#c05aaba68d00400820275f21c2ad87cb9fa9923f" + integrity sha512-Crln//HpW9M5CbtdfWm3IO66Cvx1WhZQvNybXgfB2dD/6Sav9ppw+IWqs/FQKPBFO4B6X0X28Z0WNznshgwUzA== + dependencies: + klona "^2.0.4" + less-loader@7.3.0: version "7.3.0" resolved "https://registry.yarnpkg.com/less-loader/-/less-loader-7.3.0.tgz#f9d6d36d18739d642067a05fb5bd70c8c61317e5" @@ -6687,6 +8245,14 @@ license-webpack-plugin@2.3.11: "@types/webpack-sources" "^0.1.5" webpack-sources "^1.2.0" +license-webpack-plugin@2.3.20: + version "2.3.20" + resolved "https://registry.yarnpkg.com/license-webpack-plugin/-/license-webpack-plugin-2.3.20.tgz#f51fb674ca31519dbedbe1c7aabc036e5a7f2858" + integrity sha512-AHVueg9clOKACSHkhmEI+PCC9x8+qsQVuKECZD3ETxETK5h/PCv5/MUzyG1gm8OMcip/s1tcNxqo9Qb7WhjGsg== + dependencies: + "@types/webpack-sources" "^0.1.5" + webpack-sources "^1.2.0" + lie@~3.3.0: version "3.3.0" resolved "https://registry.yarnpkg.com/lie/-/lie-3.3.0.tgz#dcf82dee545f46074daf200c7c1c5a08e0f40f6a" @@ -6694,6 +8260,11 @@ lie@~3.3.0: dependencies: immediate "~3.0.5" +lilconfig@^2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.0.4.tgz#f4507d043d7058b380b6a8f5cb7bcd4b34cee082" + integrity sha512-bfTIN7lEsiooCocSISTWXkiWJkRqtL9wYtYy+8EK3Y41qh3mpwPU0ycTOgjdY9ErwXCc8QyrQp82bdL0Xkm9yA== + lines-and-columns@^1.1.6: version "1.1.6" resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.1.6.tgz#1c00c743b433cd0a4e80758f7b64a57440d9ff00" @@ -6742,6 +8313,11 @@ locate-path@^5.0.0: dependencies: p-locate "^4.1.0" +lodash.debounce@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" + integrity sha1-gteb/zCmfEAF/9XiUVMArZyk168= + lodash.get@^4.4.2: version "4.4.2" resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99" @@ -6762,7 +8338,7 @@ lodash.uniq@^4.5.0: resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M= -lodash@4.17.21, lodash@^4.0.1, lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@~4.17.21: +lodash@4.17.21, lodash@^4.0.1, lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.21, lodash@~4.17.21: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== @@ -6774,6 +8350,14 @@ log-symbols@^4.0.0: dependencies: chalk "^4.0.0" +log-symbols@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.1.0.tgz#3fbdbb95b4683ac9fc785111e792e558d4abd503" + integrity sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg== + dependencies: + chalk "^4.1.0" + is-unicode-supported "^0.1.0" + log4js@^6.2.1: version "6.3.0" resolved "https://registry.yarnpkg.com/log4js/-/log4js-6.3.0.tgz#10dfafbb434351a3e30277a00b9879446f715bcb" @@ -6846,13 +8430,13 @@ make-error@^1.1.1: resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== -make-fetch-happen@^8.0.9: - version "8.0.14" - resolved "https://registry.yarnpkg.com/make-fetch-happen/-/make-fetch-happen-8.0.14.tgz#aaba73ae0ab5586ad8eaa68bd83332669393e222" - integrity sha512-EsS89h6l4vbfJEtBZnENTOFk8mCRpY5ru36Xe5bcX1KYIli2mkSHqoFsp5O1wMDvTJJzxe/4THpCTtygjeeGWQ== +make-fetch-happen@^9.0.1: + version "9.1.0" + resolved "https://registry.yarnpkg.com/make-fetch-happen/-/make-fetch-happen-9.1.0.tgz#53085a09e7971433e6765f7971bf63f4e05cb968" + integrity sha512-+zopwDy7DNknmwPQplem5lAZX/eCOzSvSNNcSKm5eVwTkOBzoktEfXsa9L23J/GIRhxRsaxzkPEhrJEpE2F4Gg== dependencies: agentkeepalive "^4.1.3" - cacache "^15.0.5" + cacache "^15.2.0" http-cache-semantics "^4.1.0" http-proxy-agent "^4.0.1" https-proxy-agent "^5.0.0" @@ -6863,8 +8447,9 @@ make-fetch-happen@^8.0.9: minipass-fetch "^1.3.2" minipass-flush "^1.0.5" minipass-pipeline "^1.2.4" + negotiator "^0.6.2" promise-retry "^2.0.1" - socks-proxy-agent "^5.0.0" + socks-proxy-agent "^6.0.0" ssri "^8.0.0" make-plural@^4.3.0: @@ -6874,6 +8459,13 @@ make-plural@^4.3.0: optionalDependencies: minimist "^1.2.0" +map-age-cleaner@^0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz#7d583a7306434c055fe474b0f45078e6e1b4b92a" + integrity sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w== + dependencies: + p-defer "^1.0.0" + map-cache@^0.2.2: version "0.2.2" resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" @@ -6915,6 +8507,21 @@ media-typer@0.3.0: resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= +mem@^8.1.1: + version "8.1.1" + resolved "https://registry.yarnpkg.com/mem/-/mem-8.1.1.tgz#cf118b357c65ab7b7e0817bdf00c8062297c0122" + integrity sha512-qFCFUDs7U3b8mBDPyz5EToEKoAkgCzqquIgi9nkkR9bixxOVOre+09lbuH7+9Kn2NFpm56M3GUWVbU2hQgdACA== + dependencies: + map-age-cleaner "^0.1.3" + mimic-fn "^3.1.0" + +memfs@^3.2.2: + version "3.4.0" + resolved "https://registry.yarnpkg.com/memfs/-/memfs-3.4.0.tgz#8bc12062b973be6b295d4340595736a656f0a257" + integrity sha512-o/RfP0J1d03YwsAxyHxAYs2kyJp55AFkMazlFAZFR2I2IXkxiUTXRabJ6RmNNCQ83LAD2jy52Khj0m3OffpNdA== + dependencies: + fs-monkey "1.0.3" + memory-fs@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.4.1.tgz#3a9a20b8462523e447cfbc7e8bb80ed667bfc552" @@ -7004,6 +8611,14 @@ micromatch@^4.0.2: braces "^3.0.1" picomatch "^2.0.5" +micromatch@^4.0.4: + version "4.0.4" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.4.tgz#896d519dfe9db25fce94ceb7a500919bf881ebf9" + integrity sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg== + dependencies: + braces "^3.0.1" + picomatch "^2.2.3" + miller-rabin@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.1.tgz#f080351c865b0dc562a8462966daa53543c78a4d" @@ -7034,7 +8649,7 @@ mime-types@^2.1.12, mime-types@~2.1.17, mime-types@~2.1.19, mime-types@~2.1.24: dependencies: mime-db "1.44.0" -mime-types@^2.1.27: +mime-types@^2.1.27, mime-types@^2.1.31: version "2.1.34" resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.34.tgz#5a712f9ec1503511a945803640fafe09d3793c24" integrity sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A== @@ -7056,6 +8671,11 @@ mimic-fn@^2.1.0: resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== +mimic-fn@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-3.1.0.tgz#65755145bbf3e36954b949c16450427451d5ca74" + integrity sha512-Ysbi9uYW9hFyfrThdDEQuykN4Ey6BuwPD2kpI5ES/nFTDn/98yxYNLZJcgUAKPT/mcrLLKaGzJR9YVxJrIdASQ== + mini-css-extract-plugin@1.3.5: version "1.3.5" resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-1.3.5.tgz#252166e78879c106e0130f229d44e0cbdfcebed3" @@ -7065,6 +8685,13 @@ mini-css-extract-plugin@1.3.5: schema-utils "^3.0.0" webpack-sources "^1.1.0" +mini-css-extract-plugin@2.4.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-2.4.2.tgz#b3508191ea479388a4715018c99dd3e6dd40d2d2" + integrity sha512-ZmqShkn79D36uerdED+9qdo1ZYG8C1YsWvXu0UMJxurZnSdgz7gQKO2EGv8T55MhDqG3DYmGtizZNpM/UbTlcA== + dependencies: + schema-utils "^3.1.0" + minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" @@ -7269,6 +8896,11 @@ nanoid@^3.1.22, nanoid@^3.1.23: resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.23.tgz#f744086ce7c2bc47ee0a8472574d5c78e4183a81" integrity sha512-FiB0kzdP0FFVGDKlRLEQ1BgDzU87dy5NnzjeW9YZNt+/c3+q82EQDUwniSAUxp/F0gFNI1ZhKU1FqYsMuqZVnw== +nanoid@^3.1.30: + version "3.1.30" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.30.tgz#63f93cc548d2a113dc5dfbc63bfa09e2b9b64362" + integrity sha512-zJpuPDwOv8D2zq2WRoMe1HsfZthVewpel9CAvTfc/2mBD1uUT/agc5f7GHGWXlYkFvi1mVxe4IjvP2HNrop7nQ== + nanomatch@^1.2.9: version "1.2.13" resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" @@ -7295,7 +8927,7 @@ needle@^2.5.2: iconv-lite "^0.4.4" sax "^1.2.4" -negotiator@0.6.2: +negotiator@0.6.2, negotiator@^0.6.2: version "0.6.2" resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw== @@ -7388,16 +9020,34 @@ ngx-window-token@>=4.0.0: dependencies: tslib "^2.0.0" +nice-napi@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/nice-napi/-/nice-napi-1.0.2.tgz#dc0ab5a1eac20ce548802fc5686eaa6bc654927b" + integrity sha512-px/KnJAJZf5RuBGcfD+Sp2pAKq0ytz8j+1NehvgIGFkvtvFrDM3T8E4x/JJODXK9WZow8RRGrbA9QQ3hs+pDhA== + dependencies: + node-addon-api "^3.0.0" + node-gyp-build "^4.2.2" + nice-try@^1.0.4: version "1.0.5" resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== +node-addon-api@^3.0.0: + version "3.2.1" + resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-3.2.1.tgz#81325e0a2117789c0128dab65e7e38f07ceba161" + integrity sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A== + node-forge@^0.10.0: version "0.10.0" resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.10.0.tgz#32dea2afb3e9926f02ee5ce8794902691a676bf3" integrity sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA== +node-gyp-build@^4.2.2: + version "4.3.0" + resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.3.0.tgz#9f256b03e5826150be39c764bf51e993946d71a3" + integrity sha512-iWjXZvmboq0ja1pUGULQBexmxq8CV4xBhX7VDOTbL7ZR4FOowwY/VOtRxBN/yKxmdGoIp4j5ysNT4u3S2pDQ3Q== + node-gyp@^7.1.0: version "7.1.2" resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-7.1.2.tgz#21a810aebb187120251c3bcec979af1587b188ae" @@ -7453,6 +9103,11 @@ node-releases@^1.1.71: resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.72.tgz#14802ab6b1039a79a0c7d662b610a5bbd76eacbe" integrity sha512-LLUo+PpH3dU6XizX3iVoubUNheF/owjXCZZ5yACDxNnPtgFuludV1ZL3ayK1kVep42Rmm0+R9/Y60NQbZ2bifw== +node-releases@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.1.tgz#3d1d395f204f1f2f29a54358b9fb678765ad2fc5" + integrity sha512-CqyzN6z7Q6aMeF/ktcMVTzhAHCEpf8SOarwpzpf8pNBY2k5/oM34UHldUwp8VKI7uxct2HxSRdJjBaZeESzcxA== + nopt@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/nopt/-/nopt-5.0.0.tgz#530942bb58a512fccafe53fe210f13a25355dc88" @@ -7482,6 +9137,11 @@ normalize-url@^4.5.0: resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-4.5.1.tgz#0dd90cf1288ee1d1313b87081c9a5932ee48518a" integrity sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA== +normalize-url@^6.0.1: + version "6.1.0" + resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-6.1.0.tgz#40d0885b535deffe3f3147bec877d05fe4c5668a" + integrity sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A== + npm-bundled@^1.1.1: version "1.1.2" resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.1.2.tgz#944c78789bd739035b70baa2ca5cc32b8d860bc1" @@ -7501,13 +9161,13 @@ npm-normalize-package-bin@^1.0.1: resolved "https://registry.yarnpkg.com/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz#6e79a41f23fd235c0623218228da7d9c23b8f6e2" integrity sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA== -npm-package-arg@8.1.0: - version "8.1.0" - resolved "https://registry.yarnpkg.com/npm-package-arg/-/npm-package-arg-8.1.0.tgz#b5f6319418c3246a1c38e1a8fbaa06231bc5308f" - integrity sha512-/ep6QDxBkm9HvOhOg0heitSd7JHA1U7y1qhhlRlteYYAi9Pdb/ZV7FW5aHpkrpM8+P+4p/jjR8zCyKPBMBjSig== +npm-package-arg@8.1.5: + version "8.1.5" + resolved "https://registry.yarnpkg.com/npm-package-arg/-/npm-package-arg-8.1.5.tgz#3369b2d5fe8fdc674baa7f1786514ddc15466e44" + integrity sha512-LhgZrg0n0VgvzVdSm1oiZworPbTxYHUJCgtsJW8mGvlDpxTM1vSJc3m5QZeUkhAHIzbz3VCHd/R4osi1L1Tg/Q== dependencies: - hosted-git-info "^3.0.6" - semver "^7.0.0" + hosted-git-info "^4.0.1" + semver "^7.3.4" validate-npm-package-name "^3.0.0" npm-package-arg@^8.0.0: @@ -7538,16 +9198,7 @@ npm-packlist@^2.1.4: npm-bundled "^1.1.1" npm-normalize-package-bin "^1.0.1" -npm-pick-manifest@6.1.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/npm-pick-manifest/-/npm-pick-manifest-6.1.0.tgz#2befed87b0fce956790f62d32afb56d7539c022a" - integrity sha512-ygs4k6f54ZxJXrzT0x34NybRlLeZ4+6nECAIbr2i0foTnijtS1TJiyzpqtuUAJOps/hO0tNDr8fRV5g+BtRlTw== - dependencies: - npm-install-checks "^4.0.0" - npm-package-arg "^8.0.0" - semver "^7.0.0" - -npm-pick-manifest@^6.0.0, npm-pick-manifest@^6.1.1: +npm-pick-manifest@6.1.1, npm-pick-manifest@^6.0.0, npm-pick-manifest@^6.1.1: version "6.1.1" resolved "https://registry.yarnpkg.com/npm-pick-manifest/-/npm-pick-manifest-6.1.1.tgz#7b5484ca2c908565f43b7f27644f36bb816f5148" integrity sha512-dBsdBtORT84S8V8UTad1WlUyKIY9iMsAmqxHbLdeEeBNMLQDlDWWra3wYUx9EBEIiG/YwAy0XyNHDd2goAsfuA== @@ -7557,14 +9208,12 @@ npm-pick-manifest@^6.0.0, npm-pick-manifest@^6.1.1: npm-package-arg "^8.1.2" semver "^7.3.4" -npm-registry-fetch@^9.0.0: - version "9.0.0" - resolved "https://registry.yarnpkg.com/npm-registry-fetch/-/npm-registry-fetch-9.0.0.tgz#86f3feb4ce00313bc0b8f1f8f69daae6face1661" - integrity sha512-PuFYYtnQ8IyVl6ib9d3PepeehcUeHN9IO5N/iCRhyg9tStQcqGQBRVHmfmMWPDERU3KwZoHFvbJ4FPXPspvzbA== +npm-registry-fetch@^11.0.0: + version "11.0.0" + resolved "https://registry.yarnpkg.com/npm-registry-fetch/-/npm-registry-fetch-11.0.0.tgz#68c1bb810c46542760d62a6a965f85a702d43a76" + integrity sha512-jmlgSxoDNuhAtxUIG6pVwwtz840i994dL14FoNVZisrmZW5kWd63IUTNv1m/hyRSGSqWjCUp/YZlS1BJyNp9XA== dependencies: - "@npmcli/ci-detect" "^1.0.0" - lru-cache "^6.0.0" - make-fetch-happen "^8.0.9" + make-fetch-happen "^9.0.1" minipass "^3.1.3" minipass-fetch "^1.3.0" minipass-json-stream "^1.0.1" @@ -7595,6 +9244,11 @@ nth-check@^2.0.0: dependencies: boolbase "^1.0.0" +num2fraction@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/num2fraction/-/num2fraction-1.2.2.tgz#6f682b6a027a4e9ddfa4564cd2589d1d4e669ede" + integrity sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4= + number-is-nan@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" @@ -7705,6 +9359,15 @@ open@7.4.0: is-docker "^2.0.0" is-wsl "^2.1.1" +open@8.2.1: + version "8.2.1" + resolved "https://registry.yarnpkg.com/open/-/open-8.2.1.tgz#82de42da0ccbf429bc12d099dad2e0975e14e8af" + integrity sha512-rXILpcQlkF/QuFez2BJDf3GsqpjGKbkUUToAIGo9A0Q6ZkoSGogZJulrUdwRkrAsoQvoZsrjCYt8+zblOk7JQQ== + dependencies: + define-lazy-prop "^2.0.0" + is-docker "^2.1.1" + is-wsl "^2.2.0" + open@^7.4.2: version "7.4.2" resolved "https://registry.yarnpkg.com/open/-/open-7.4.2.tgz#b8147e26dcf3e426316c730089fd71edd29c2321" @@ -7734,6 +9397,21 @@ ora@5.3.0: strip-ansi "^6.0.0" wcwidth "^1.0.1" +ora@5.4.1, ora@^5.3.0: + version "5.4.1" + resolved "https://registry.yarnpkg.com/ora/-/ora-5.4.1.tgz#1b2678426af4ac4a509008e5e4ac9e9959db9e18" + integrity sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ== + dependencies: + bl "^4.1.0" + chalk "^4.1.0" + cli-cursor "^3.1.0" + cli-spinners "^2.5.0" + is-interactive "^1.0.0" + is-unicode-supported "^0.1.0" + log-symbols "^4.1.0" + strip-ansi "^6.0.0" + wcwidth "^1.0.1" + original@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/original/-/original-1.0.2.tgz#e442a61cffe1c5fd20a65f3261c26663b303f25f" @@ -7751,6 +9429,11 @@ os-tmpdir@~1.0.1, os-tmpdir@~1.0.2: resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= +p-defer@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-defer/-/p-defer-1.0.0.tgz#9f6eb182f6c9aa8cd743004a7d4f96b196b0fb0c" + integrity sha1-n26xgvbJqozXQwBKfU+WsZaw+ww= + p-finally@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" @@ -7770,6 +9453,13 @@ p-limit@^3.0.2: dependencies: p-try "^2.0.0" +p-limit@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" + integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== + dependencies: + yocto-queue "^0.1.0" + p-locate@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4" @@ -7808,15 +9498,15 @@ p-try@^2.0.0: resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== -pacote@11.2.4: - version "11.2.4" - resolved "https://registry.yarnpkg.com/pacote/-/pacote-11.2.4.tgz#dc7ca740a573ed86a3bf863511d22c1d413ec82f" - integrity sha512-GfTeVQGJ6WyBQbQD4t3ocHbyOmTQLmWjkCKSZPmKiGFKYKNUaM5U2gbLzUW8WG1XmS9yQFnsTFA0k3o1+q4klQ== +pacote@11.3.5: + version "11.3.5" + resolved "https://registry.yarnpkg.com/pacote/-/pacote-11.3.5.tgz#73cf1fc3772b533f575e39efa96c50be8c3dc9d2" + integrity sha512-fT375Yczn4zi+6Hkk2TBe1x1sP8FgFsEIZ2/iWaXY2r/NkhDJfxbcn5paz1+RTFCyNf+dPnaoBDJoAxXSU8Bkg== dependencies: - "@npmcli/git" "^2.0.1" - "@npmcli/installed-package-contents" "^1.0.5" + "@npmcli/git" "^2.1.0" + "@npmcli/installed-package-contents" "^1.0.6" "@npmcli/promise-spawn" "^1.2.0" - "@npmcli/run-script" "^1.3.0" + "@npmcli/run-script" "^1.8.2" cacache "^15.0.5" chownr "^2.0.0" fs-minipass "^2.1.0" @@ -7826,14 +9516,14 @@ pacote@11.2.4: npm-package-arg "^8.0.1" npm-packlist "^2.1.4" npm-pick-manifest "^6.0.0" - npm-registry-fetch "^9.0.0" - promise-retry "^1.1.1" - read-package-json-fast "^1.1.3" + npm-registry-fetch "^11.0.0" + promise-retry "^2.0.1" + read-package-json-fast "^2.0.1" rimraf "^3.0.2" - ssri "^8.0.0" + ssri "^8.0.1" tar "^6.1.0" -pako@~1.0.2, pako@~1.0.5: +pako@^1.0.3, pako@~1.0.2, pako@~1.0.5: version "1.0.11" resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf" integrity sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw== @@ -8007,11 +9697,26 @@ performance-now@^2.1.0: resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= +picocolors@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-0.2.1.tgz#570670f793646851d1ba135996962abad587859f" + integrity sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA== + +picocolors@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" + integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== + picomatch@^2.0.4, picomatch@^2.0.5, picomatch@^2.2.1: version "2.2.2" resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.2.tgz#21f333e9b6b8eaff02468f5146ea406d345f4dad" integrity sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg== +picomatch@^2.2.3: + version "2.3.0" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.0.tgz#f1f061de8f6a4bf022892e2d128234fb98302972" + integrity sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw== + pify@^2.0.0, pify@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" @@ -8034,6 +9739,17 @@ pinkie@^2.0.0: resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" integrity sha1-clVrgM+g1IqXToDnckjoDtT3+HA= +piscina@3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/piscina/-/piscina-3.1.0.tgz#2333636865b6cb69c5a370bbc499a98cabcf3e04" + integrity sha512-KTW4sjsCD34MHrUbx9eAAbuUSpVj407hQSgk/6Epkg0pbRBmv4a3UX7Sr8wxm9xYqQLnsN4mFOjqGDzHAdgKQg== + dependencies: + eventemitter-asyncresource "^1.0.0" + hdr-histogram-js "^2.0.1" + hdr-histogram-percentiles-obj "^3.0.0" + optionalDependencies: + nice-napi "^1.0.2" + pkg-dir@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-3.0.0.tgz#2749020f239ed990881b1f71210d51eb6523bea3" @@ -8086,6 +9802,14 @@ posix-character-classes@^0.1.0: resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs= +postcss-attribute-case-insensitive@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-attribute-case-insensitive/-/postcss-attribute-case-insensitive-4.0.2.tgz#d93e46b504589e94ac7277b0463226c68041a880" + integrity sha512-clkFxk/9pcdb4Vkn0hAHq3YnxBQ2p0CGD1dy24jN+reBck+EWxMbxSUqN4Yj7t0w8csl87K6p0gxBe1utkJsYA== + dependencies: + postcss "^7.0.2" + postcss-selector-parser "^6.0.2" + postcss-calc@^8.0.0: version "8.0.0" resolved "https://registry.yarnpkg.com/postcss-calc/-/postcss-calc-8.0.0.tgz#a05b87aacd132740a5db09462a3612453e5df90a" @@ -8094,6 +9818,48 @@ postcss-calc@^8.0.0: postcss-selector-parser "^6.0.2" postcss-value-parser "^4.0.2" +postcss-color-functional-notation@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/postcss-color-functional-notation/-/postcss-color-functional-notation-2.0.1.tgz#5efd37a88fbabeb00a2966d1e53d98ced93f74e0" + integrity sha512-ZBARCypjEDofW4P6IdPVTLhDNXPRn8T2s1zHbZidW6rPaaZvcnCS2soYFIQJrMZSxiePJ2XIYTlcb2ztr/eT2g== + dependencies: + postcss "^7.0.2" + postcss-values-parser "^2.0.0" + +postcss-color-gray@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/postcss-color-gray/-/postcss-color-gray-5.0.0.tgz#532a31eb909f8da898ceffe296fdc1f864be8547" + integrity sha512-q6BuRnAGKM/ZRpfDascZlIZPjvwsRye7UDNalqVz3s7GDxMtqPY6+Q871liNxsonUw8oC61OG+PSaysYpl1bnw== + dependencies: + "@csstools/convert-colors" "^1.4.0" + postcss "^7.0.5" + postcss-values-parser "^2.0.0" + +postcss-color-hex-alpha@^5.0.3: + version "5.0.3" + resolved "https://registry.yarnpkg.com/postcss-color-hex-alpha/-/postcss-color-hex-alpha-5.0.3.tgz#a8d9ca4c39d497c9661e374b9c51899ef0f87388" + integrity sha512-PF4GDel8q3kkreVXKLAGNpHKilXsZ6xuu+mOQMHWHLPNyjiUBOr75sp5ZKJfmv1MCus5/DWUGcK9hm6qHEnXYw== + dependencies: + postcss "^7.0.14" + postcss-values-parser "^2.0.1" + +postcss-color-mod-function@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/postcss-color-mod-function/-/postcss-color-mod-function-3.0.3.tgz#816ba145ac11cc3cb6baa905a75a49f903e4d31d" + integrity sha512-YP4VG+xufxaVtzV6ZmhEtc+/aTXH3d0JLpnYfxqTvwZPbJhWqp8bSY3nfNzNRFLgB4XSaBA82OE4VjOOKpCdVQ== + dependencies: + "@csstools/convert-colors" "^1.4.0" + postcss "^7.0.2" + postcss-values-parser "^2.0.0" + +postcss-color-rebeccapurple@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-color-rebeccapurple/-/postcss-color-rebeccapurple-4.0.1.tgz#c7a89be872bb74e45b1e3022bfe5748823e6de77" + integrity sha512-aAe3OhkS6qJXBbqzvZth2Au4V3KieR5sRQ4ptb2b2O8wgvB3SJBsdG+jsn2BZbbwekDG8nTfcCNKcSfe/lEy8g== + dependencies: + postcss "^7.0.2" + postcss-values-parser "^2.0.0" + postcss-colormin@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/postcss-colormin/-/postcss-colormin-5.1.1.tgz#834d262f6021f832d9085e355f08ade288a92a1d" @@ -8103,6 +9869,16 @@ postcss-colormin@^5.1.1: colord "^2.0.0" postcss-value-parser "^4.1.0" +postcss-colormin@^5.2.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/postcss-colormin/-/postcss-colormin-5.2.1.tgz#6e444a806fd3c578827dbad022762df19334414d" + integrity sha512-VVwMrEYLcHYePUYV99Ymuoi7WhKrMGy/V9/kTS0DkCoJYmmjdOMneyhzYUxcNgteKDVbrewOkSM7Wje/MFwxzA== + dependencies: + browserslist "^4.16.6" + caniuse-api "^3.0.0" + colord "^2.9.1" + postcss-value-parser "^4.1.0" + postcss-convert-values@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/postcss-convert-values/-/postcss-convert-values-5.0.1.tgz#4ec19d6016534e30e3102fdf414e753398645232" @@ -8110,6 +9886,44 @@ postcss-convert-values@^5.0.1: dependencies: postcss-value-parser "^4.1.0" +postcss-convert-values@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/postcss-convert-values/-/postcss-convert-values-5.0.2.tgz#879b849dc3677c7d6bc94b6a2c1a3f0808798059" + integrity sha512-KQ04E2yadmfa1LqXm7UIDwW1ftxU/QWZmz6NKnHnUvJ3LEYbbcX6i329f/ig+WnEByHegulocXrECaZGLpL8Zg== + dependencies: + postcss-value-parser "^4.1.0" + +postcss-custom-media@^7.0.8: + version "7.0.8" + resolved "https://registry.yarnpkg.com/postcss-custom-media/-/postcss-custom-media-7.0.8.tgz#fffd13ffeffad73621be5f387076a28b00294e0c" + integrity sha512-c9s5iX0Ge15o00HKbuRuTqNndsJUbaXdiNsksnVH8H4gdc+zbLzr/UasOwNG6CTDpLFekVY4672eWdiiWu2GUg== + dependencies: + postcss "^7.0.14" + +postcss-custom-properties@^8.0.11: + version "8.0.11" + resolved "https://registry.yarnpkg.com/postcss-custom-properties/-/postcss-custom-properties-8.0.11.tgz#2d61772d6e92f22f5e0d52602df8fae46fa30d97" + integrity sha512-nm+o0eLdYqdnJ5abAJeXp4CEU1c1k+eB2yMCvhgzsds/e0umabFrN6HoTy/8Q4K5ilxERdl/JD1LO5ANoYBeMA== + dependencies: + postcss "^7.0.17" + postcss-values-parser "^2.0.1" + +postcss-custom-selectors@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/postcss-custom-selectors/-/postcss-custom-selectors-5.1.2.tgz#64858c6eb2ecff2fb41d0b28c9dd7b3db4de7fba" + integrity sha512-DSGDhqinCqXqlS4R7KGxL1OSycd1lydugJ1ky4iRXPHdBRiozyMHrdu0H3o7qNOCiZwySZTUI5MV0T8QhCLu+w== + dependencies: + postcss "^7.0.2" + postcss-selector-parser "^5.0.0-rc.3" + +postcss-dir-pseudo-class@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/postcss-dir-pseudo-class/-/postcss-dir-pseudo-class-5.0.0.tgz#6e3a4177d0edb3abcc85fdb6fbb1c26dabaeaba2" + integrity sha512-3pm4oq8HYWMZePJY+5ANriPs3P07q+LW6FAdTlkFH2XqDdP4HeeJYMOzn0HYLhRSjBO3fhiqSwwU9xEULSrPgw== + dependencies: + postcss "^7.0.2" + postcss-selector-parser "^5.0.0-rc.3" + postcss-discard-comments@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/postcss-discard-comments/-/postcss-discard-comments-5.0.1.tgz#9eae4b747cf760d31f2447c27f0619d5718901fe" @@ -8130,6 +9944,58 @@ postcss-discard-overridden@^5.0.1: resolved "https://registry.yarnpkg.com/postcss-discard-overridden/-/postcss-discard-overridden-5.0.1.tgz#454b41f707300b98109a75005ca4ab0ff2743ac6" integrity sha512-Y28H7y93L2BpJhrdUR2SR2fnSsT+3TVx1NmVQLbcnZWwIUpJ7mfcTC6Za9M2PG6w8j7UQRfzxqn8jU2VwFxo3Q== +postcss-double-position-gradients@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/postcss-double-position-gradients/-/postcss-double-position-gradients-1.0.0.tgz#fc927d52fddc896cb3a2812ebc5df147e110522e" + integrity sha512-G+nV8EnQq25fOI8CH/B6krEohGWnF5+3A6H/+JEpOncu5dCnkS1QQ6+ct3Jkaepw1NGVqqOZH6lqrm244mCftA== + dependencies: + postcss "^7.0.5" + postcss-values-parser "^2.0.0" + +postcss-env-function@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/postcss-env-function/-/postcss-env-function-2.0.2.tgz#0f3e3d3c57f094a92c2baf4b6241f0b0da5365d7" + integrity sha512-rwac4BuZlITeUbiBq60h/xbLzXY43qOsIErngWa4l7Mt+RaSkT7QBjXVGTcBHupykkblHMDrBFh30zchYPaOUw== + dependencies: + postcss "^7.0.2" + postcss-values-parser "^2.0.0" + +postcss-focus-visible@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-focus-visible/-/postcss-focus-visible-4.0.0.tgz#477d107113ade6024b14128317ade2bd1e17046e" + integrity sha512-Z5CkWBw0+idJHSV6+Bgf2peDOFf/x4o+vX/pwcNYrWpXFrSfTkQ3JQ1ojrq9yS+upnAlNRHeg8uEwFTgorjI8g== + dependencies: + postcss "^7.0.2" + +postcss-focus-within@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/postcss-focus-within/-/postcss-focus-within-3.0.0.tgz#763b8788596cee9b874c999201cdde80659ef680" + integrity sha512-W0APui8jQeBKbCGZudW37EeMCjDeVxKgiYfIIEo8Bdh5SpB9sxds/Iq8SEuzS0Q4YFOlG7EPFulbbxujpkrV2w== + dependencies: + postcss "^7.0.2" + +postcss-font-variant@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-font-variant/-/postcss-font-variant-4.0.1.tgz#42d4c0ab30894f60f98b17561eb5c0321f502641" + integrity sha512-I3ADQSTNtLTTd8uxZhtSOrTCQ9G4qUVKPjHiDk0bV75QSxXjVWiJVJ2VLdspGUi9fbW9BcjKJoRvxAH1pckqmA== + dependencies: + postcss "^7.0.2" + +postcss-gap-properties@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/postcss-gap-properties/-/postcss-gap-properties-2.0.0.tgz#431c192ab3ed96a3c3d09f2ff615960f902c1715" + integrity sha512-QZSqDaMgXCHuHTEzMsS2KfVDOq7ZFiknSpkrPJY6jmxbugUPTuSzs/vuE5I3zv0WAS+3vhrlqhijiprnuQfzmg== + dependencies: + postcss "^7.0.2" + +postcss-image-set-function@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/postcss-image-set-function/-/postcss-image-set-function-3.0.1.tgz#28920a2f29945bed4c3198d7df6496d410d3f288" + integrity sha512-oPTcFFip5LZy8Y/whto91L9xdRHCWEMs3e1MdJxhgt4jy2WYXfhkng59fH5qLXSCPN8k4n94p1Czrfe5IOkKUw== + dependencies: + postcss "^7.0.2" + postcss-values-parser "^2.0.0" + postcss-import@14.0.0: version "14.0.0" resolved "https://registry.yarnpkg.com/postcss-import/-/postcss-import-14.0.0.tgz#3ed1dadac5a16650bde3f4cdea6633b9c3c78296" @@ -8139,6 +10005,31 @@ postcss-import@14.0.0: read-cache "^1.0.0" resolve "^1.1.7" +postcss-import@14.0.2: + version "14.0.2" + resolved "https://registry.yarnpkg.com/postcss-import/-/postcss-import-14.0.2.tgz#60eff77e6be92e7b67fe469ec797d9424cae1aa1" + integrity sha512-BJ2pVK4KhUyMcqjuKs9RijV5tatNzNa73e/32aBVE/ejYPe37iH+6vAu9WvqUkB5OAYgLHzbSvzHnorybJCm9g== + dependencies: + postcss-value-parser "^4.0.0" + read-cache "^1.0.0" + resolve "^1.1.7" + +postcss-initial@^3.0.0: + version "3.0.4" + resolved "https://registry.yarnpkg.com/postcss-initial/-/postcss-initial-3.0.4.tgz#9d32069a10531fe2ecafa0b6ac750ee0bc7efc53" + integrity sha512-3RLn6DIpMsK1l5UUy9jxQvoDeUN4gP939tDcKUHD/kM8SGSKbFAnvkpFpj3Bhtz3HGk1jWY5ZNWX6mPta5M9fg== + dependencies: + postcss "^7.0.2" + +postcss-lab-function@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/postcss-lab-function/-/postcss-lab-function-2.0.1.tgz#bb51a6856cd12289ab4ae20db1e3821ef13d7d2e" + integrity sha512-whLy1IeZKY+3fYdqQFuDBf8Auw+qFuVnChWjmxm/UhHWqNHZx+B99EwxTvGYmUBqe3Fjxs4L1BoZTJmPu6usVg== + dependencies: + "@csstools/convert-colors" "^1.4.0" + postcss "^7.0.2" + postcss-values-parser "^2.0.0" + postcss-loader@4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/postcss-loader/-/postcss-loader-4.2.0.tgz#f6993ea3e0f46600fb3ee49bbd010448123a7db4" @@ -8150,6 +10041,29 @@ postcss-loader@4.2.0: schema-utils "^3.0.0" semver "^7.3.4" +postcss-loader@6.1.1: + version "6.1.1" + resolved "https://registry.yarnpkg.com/postcss-loader/-/postcss-loader-6.1.1.tgz#58dd0a3accd9bc87cc52eff75244db578d11301a" + integrity sha512-lBmJMvRh1D40dqpWKr9Rpygwxn8M74U9uaCSeYGNKLGInbk9mXBt1ultHf2dH9Ghk6Ue4UXlXWwGMH9QdUJ5ug== + dependencies: + cosmiconfig "^7.0.0" + klona "^2.0.4" + semver "^7.3.5" + +postcss-logical@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/postcss-logical/-/postcss-logical-3.0.0.tgz#2495d0f8b82e9f262725f75f9401b34e7b45d5b5" + integrity sha512-1SUKdJc2vuMOmeItqGuNaC+N8MzBWFWEkAnRnLpFYj1tGGa7NqyVBujfRtgNa2gXR+6RkGUiB2O5Vmh7E2RmiA== + dependencies: + postcss "^7.0.2" + +postcss-media-minmax@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-media-minmax/-/postcss-media-minmax-4.0.0.tgz#b75bb6cbc217c8ac49433e12f22048814a4f5ed5" + integrity sha512-fo9moya6qyxsjbFAYl97qKO9gyre3qvbMnkOZeZwlsW6XYFsvs2DMGDlchVLfAd8LHPZDxivu/+qW2SMQeTHBw== + dependencies: + postcss "^7.0.2" + postcss-merge-longhand@^5.0.2: version "5.0.2" resolved "https://registry.yarnpkg.com/postcss-merge-longhand/-/postcss-merge-longhand-5.0.2.tgz#277ada51d9a7958e8ef8cf263103c9384b322a41" @@ -8159,6 +10073,14 @@ postcss-merge-longhand@^5.0.2: postcss-value-parser "^4.1.0" stylehacks "^5.0.1" +postcss-merge-longhand@^5.0.4: + version "5.0.4" + resolved "https://registry.yarnpkg.com/postcss-merge-longhand/-/postcss-merge-longhand-5.0.4.tgz#41f4f3270282ea1a145ece078b7679f0cef21c32" + integrity sha512-2lZrOVD+d81aoYkZDpWu6+3dTAAGkCKbV5DoRhnIR7KOULVrI/R7bcMjhrH9KTRy6iiHKqmtG+n/MMj1WmqHFw== + dependencies: + postcss-value-parser "^4.1.0" + stylehacks "^5.0.1" + postcss-merge-rules@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/postcss-merge-rules/-/postcss-merge-rules-5.0.1.tgz#4ff61c5089d86845184a0f149e88d687028bef7e" @@ -8170,6 +10092,16 @@ postcss-merge-rules@^5.0.1: postcss-selector-parser "^6.0.5" vendors "^1.0.3" +postcss-merge-rules@^5.0.3: + version "5.0.3" + resolved "https://registry.yarnpkg.com/postcss-merge-rules/-/postcss-merge-rules-5.0.3.tgz#b5cae31f53129812a77e3eb1eeee448f8cf1a1db" + integrity sha512-cEKTMEbWazVa5NXd8deLdCnXl+6cYG7m2am+1HzqH0EnTdy8fRysatkaXb2dEnR+fdaDxTvuZ5zoBdv6efF6hg== + dependencies: + browserslist "^4.16.6" + caniuse-api "^3.0.0" + cssnano-utils "^2.0.1" + postcss-selector-parser "^6.0.5" + postcss-minify-font-values@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/postcss-minify-font-values/-/postcss-minify-font-values-5.0.1.tgz#a90cefbfdaa075bd3dbaa1b33588bb4dc268addf" @@ -8186,6 +10118,15 @@ postcss-minify-gradients@^5.0.1: is-color-stop "^1.1.0" postcss-value-parser "^4.1.0" +postcss-minify-gradients@^5.0.3: + version "5.0.3" + resolved "https://registry.yarnpkg.com/postcss-minify-gradients/-/postcss-minify-gradients-5.0.3.tgz#f970a11cc71e08e9095e78ec3a6b34b91c19550e" + integrity sha512-Z91Ol22nB6XJW+5oe31+YxRsYooxOdFKcbOqY/V8Fxse1Y3vqlNRpi1cxCqoACZTQEhl+xvt4hsbWiV5R+XI9Q== + dependencies: + colord "^2.9.1" + cssnano-utils "^2.0.1" + postcss-value-parser "^4.1.0" + postcss-minify-params@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/postcss-minify-params/-/postcss-minify-params-5.0.1.tgz#371153ba164b9d8562842fdcd929c98abd9e5b6c" @@ -8197,6 +10138,16 @@ postcss-minify-params@^5.0.1: postcss-value-parser "^4.1.0" uniqs "^2.0.0" +postcss-minify-params@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/postcss-minify-params/-/postcss-minify-params-5.0.2.tgz#1b644da903473fbbb18fbe07b8e239883684b85c" + integrity sha512-qJAPuBzxO1yhLad7h2Dzk/F7n1vPyfHfCCh5grjGfjhi1ttCnq4ZXGIW77GSrEbh9Hus9Lc/e/+tB4vh3/GpDg== + dependencies: + alphanum-sort "^1.0.2" + browserslist "^4.16.6" + cssnano-utils "^2.0.1" + postcss-value-parser "^4.1.0" + postcss-minify-selectors@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/postcss-minify-selectors/-/postcss-minify-selectors-5.1.0.tgz#4385c845d3979ff160291774523ffa54eafd5a54" @@ -8233,6 +10184,13 @@ postcss-modules-values@^4.0.0: dependencies: icss-utils "^5.0.0" +postcss-nesting@^7.0.0: + version "7.0.1" + resolved "https://registry.yarnpkg.com/postcss-nesting/-/postcss-nesting-7.0.1.tgz#b50ad7b7f0173e5b5e3880c3501344703e04c052" + integrity sha512-FrorPb0H3nuVq0Sff7W2rnc3SmIcruVC6YwpcS+k687VxyxO33iE1amna7wHuRVzM8vfiYofXSBHNAZ3QhLvYg== + dependencies: + postcss "^7.0.2" + postcss-normalize-charset@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/postcss-normalize-charset/-/postcss-normalize-charset-5.0.1.tgz#121559d1bebc55ac8d24af37f67bd4da9efd91d0" @@ -8293,6 +10251,15 @@ postcss-normalize-url@^5.0.1: normalize-url "^4.5.0" postcss-value-parser "^4.1.0" +postcss-normalize-url@^5.0.3: + version "5.0.3" + resolved "https://registry.yarnpkg.com/postcss-normalize-url/-/postcss-normalize-url-5.0.3.tgz#42eca6ede57fe69075fab0f88ac8e48916ef931c" + integrity sha512-qWiUMbvkRx3kc1Dp5opzUwc7MBWZcSDK2yofCmdvFBCpx+zFPkxBC1FASQ59Pt+flYfj/nTZSkmF56+XG5elSg== + dependencies: + is-absolute-url "^3.0.3" + normalize-url "^6.0.1" + postcss-value-parser "^4.1.0" + postcss-normalize-whitespace@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/postcss-normalize-whitespace/-/postcss-normalize-whitespace-5.0.1.tgz#b0b40b5bcac83585ff07ead2daf2dcfbeeef8e9a" @@ -8308,6 +10275,87 @@ postcss-ordered-values@^5.0.1: cssnano-utils "^2.0.1" postcss-value-parser "^4.1.0" +postcss-ordered-values@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/postcss-ordered-values/-/postcss-ordered-values-5.0.2.tgz#1f351426977be00e0f765b3164ad753dac8ed044" + integrity sha512-8AFYDSOYWebJYLyJi3fyjl6CqMEG/UVworjiyK1r573I56kb3e879sCJLGvR3merj+fAdPpVplXKQZv+ey6CgQ== + dependencies: + cssnano-utils "^2.0.1" + postcss-value-parser "^4.1.0" + +postcss-overflow-shorthand@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/postcss-overflow-shorthand/-/postcss-overflow-shorthand-2.0.0.tgz#31ecf350e9c6f6ddc250a78f0c3e111f32dd4c30" + integrity sha512-aK0fHc9CBNx8jbzMYhshZcEv8LtYnBIRYQD5i7w/K/wS9c2+0NSR6B3OVMu5y0hBHYLcMGjfU+dmWYNKH0I85g== + dependencies: + postcss "^7.0.2" + +postcss-page-break@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/postcss-page-break/-/postcss-page-break-2.0.0.tgz#add52d0e0a528cabe6afee8b46e2abb277df46bf" + integrity sha512-tkpTSrLpfLfD9HvgOlJuigLuk39wVTbbd8RKcy8/ugV2bNBUW3xU+AIqyxhDrQr1VUj1RmyJrBn1YWrqUm9zAQ== + dependencies: + postcss "^7.0.2" + +postcss-place@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-place/-/postcss-place-4.0.1.tgz#e9f39d33d2dc584e46ee1db45adb77ca9d1dcc62" + integrity sha512-Zb6byCSLkgRKLODj/5mQugyuj9bvAAw9LqJJjgwz5cYryGeXfFZfSXoP1UfveccFmeq0b/2xxwcTEVScnqGxBg== + dependencies: + postcss "^7.0.2" + postcss-values-parser "^2.0.0" + +postcss-preset-env@6.7.0: + version "6.7.0" + resolved "https://registry.yarnpkg.com/postcss-preset-env/-/postcss-preset-env-6.7.0.tgz#c34ddacf8f902383b35ad1e030f178f4cdf118a5" + integrity sha512-eU4/K5xzSFwUFJ8hTdTQzo2RBLbDVt83QZrAvI07TULOkmyQlnYlpwep+2yIK+K+0KlZO4BvFcleOCCcUtwchg== + dependencies: + autoprefixer "^9.6.1" + browserslist "^4.6.4" + caniuse-lite "^1.0.30000981" + css-blank-pseudo "^0.1.4" + css-has-pseudo "^0.10.0" + css-prefers-color-scheme "^3.1.1" + cssdb "^4.4.0" + postcss "^7.0.17" + postcss-attribute-case-insensitive "^4.0.1" + postcss-color-functional-notation "^2.0.1" + postcss-color-gray "^5.0.0" + postcss-color-hex-alpha "^5.0.3" + postcss-color-mod-function "^3.0.3" + postcss-color-rebeccapurple "^4.0.1" + postcss-custom-media "^7.0.8" + postcss-custom-properties "^8.0.11" + postcss-custom-selectors "^5.1.2" + postcss-dir-pseudo-class "^5.0.0" + postcss-double-position-gradients "^1.0.0" + postcss-env-function "^2.0.2" + postcss-focus-visible "^4.0.0" + postcss-focus-within "^3.0.0" + postcss-font-variant "^4.0.0" + postcss-gap-properties "^2.0.0" + postcss-image-set-function "^3.0.1" + postcss-initial "^3.0.0" + postcss-lab-function "^2.0.1" + postcss-logical "^3.0.0" + postcss-media-minmax "^4.0.0" + postcss-nesting "^7.0.0" + postcss-overflow-shorthand "^2.0.0" + postcss-page-break "^2.0.0" + postcss-place "^4.0.1" + postcss-pseudo-class-any-link "^6.0.0" + postcss-replace-overflow-wrap "^3.0.0" + postcss-selector-matches "^4.0.0" + postcss-selector-not "^4.0.0" + +postcss-pseudo-class-any-link@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/postcss-pseudo-class-any-link/-/postcss-pseudo-class-any-link-6.0.0.tgz#2ed3eed393b3702879dec4a87032b210daeb04d1" + integrity sha512-lgXW9sYJdLqtmw23otOzrtbDXofUdfYzNm4PIpNE322/swES3VU9XlXHeJS46zT2onFO7V1QFdD4Q9LiZj8mew== + dependencies: + postcss "^7.0.2" + postcss-selector-parser "^5.0.0-rc.3" + postcss-reduce-initial@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/postcss-reduce-initial/-/postcss-reduce-initial-5.0.1.tgz#9d6369865b0f6f6f6b165a0ef5dc1a4856c7e946" @@ -8316,6 +10364,14 @@ postcss-reduce-initial@^5.0.1: browserslist "^4.16.0" caniuse-api "^3.0.0" +postcss-reduce-initial@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/postcss-reduce-initial/-/postcss-reduce-initial-5.0.2.tgz#fa424ce8aa88a89bc0b6d0f94871b24abe94c048" + integrity sha512-v/kbAAQ+S1V5v9TJvbGkV98V2ERPdU6XvMcKMjqAlYiJ2NtsHGlKYLPjWWcXlaTKNxooId7BGxeraK8qXvzKtw== + dependencies: + browserslist "^4.16.6" + caniuse-api "^3.0.0" + postcss-reduce-transforms@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/postcss-reduce-transforms/-/postcss-reduce-transforms-5.0.1.tgz#93c12f6a159474aa711d5269923e2383cedcf640" @@ -8324,6 +10380,38 @@ postcss-reduce-transforms@^5.0.1: cssnano-utils "^2.0.1" postcss-value-parser "^4.1.0" +postcss-replace-overflow-wrap@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/postcss-replace-overflow-wrap/-/postcss-replace-overflow-wrap-3.0.0.tgz#61b360ffdaedca84c7c918d2b0f0d0ea559ab01c" + integrity sha512-2T5hcEHArDT6X9+9dVSPQdo7QHzG4XKclFT8rU5TzJPDN7RIRTbO9c4drUISOVemLj03aezStHCR2AIcr8XLpw== + dependencies: + postcss "^7.0.2" + +postcss-selector-matches@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-selector-matches/-/postcss-selector-matches-4.0.0.tgz#71c8248f917ba2cc93037c9637ee09c64436fcff" + integrity sha512-LgsHwQR/EsRYSqlwdGzeaPKVT0Ml7LAT6E75T8W8xLJY62CE4S/l03BWIt3jT8Taq22kXP08s2SfTSzaraoPww== + dependencies: + balanced-match "^1.0.0" + postcss "^7.0.2" + +postcss-selector-not@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-selector-not/-/postcss-selector-not-4.0.1.tgz#263016eef1cf219e0ade9a913780fc1f48204cbf" + integrity sha512-YolvBgInEK5/79C+bdFMyzqTg6pkYqDbzZIST/PDMqa/o3qtXenD05apBG2jLgT0/BQ77d4U2UK12jWpilqMAQ== + dependencies: + balanced-match "^1.0.0" + postcss "^7.0.2" + +postcss-selector-parser@^5.0.0-rc.3, postcss-selector-parser@^5.0.0-rc.4: + version "5.0.0" + resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-5.0.0.tgz#249044356697b33b64f1a8f7c80922dddee7195c" + integrity sha512-w+zLE5Jhg6Liz8+rQOWEAwtwkyqpfnmsinXjXg6cY7YIONZZtgvE0v2O0uhQBs0peNomOJwWRKt6JBfTdTd3OQ== + dependencies: + cssesc "^2.0.0" + indexes-of "^1.0.1" + uniq "^1.0.1" + postcss-selector-parser@^6.0.2: version "6.0.4" resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.4.tgz#56075a1380a04604c38b063ea7767a129af5c2b3" @@ -8350,6 +10438,14 @@ postcss-svgo@^5.0.1: postcss-value-parser "^4.1.0" svgo "^2.3.0" +postcss-svgo@^5.0.3: + version "5.0.3" + resolved "https://registry.yarnpkg.com/postcss-svgo/-/postcss-svgo-5.0.3.tgz#d945185756e5dfaae07f9edb0d3cae7ff79f9b30" + integrity sha512-41XZUA1wNDAZrQ3XgWREL/M2zSw8LJPvb5ZWivljBsUQAGoEKMYm6okHsTjJxKYI4M75RQEH4KYlEM52VwdXVA== + dependencies: + postcss-value-parser "^4.1.0" + svgo "^2.7.0" + postcss-unique-selectors@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/postcss-unique-selectors/-/postcss-unique-selectors-5.0.1.tgz#3be5c1d7363352eff838bd62b0b07a0abad43bfc" @@ -8359,11 +10455,28 @@ postcss-unique-selectors@^5.0.1: postcss-selector-parser "^6.0.5" uniqs "^2.0.0" +postcss-unique-selectors@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/postcss-unique-selectors/-/postcss-unique-selectors-5.0.2.tgz#5d6893daf534ae52626708e0d62250890108c0c1" + integrity sha512-w3zBVlrtZm7loQWRPVC0yjUwwpty7OM6DnEHkxcSQXO1bMS3RJ+JUS5LFMSDZHJcvGsRwhZinCWVqn8Kej4EDA== + dependencies: + alphanum-sort "^1.0.2" + postcss-selector-parser "^6.0.5" + postcss-value-parser@^4.0.0, postcss-value-parser@^4.0.2, postcss-value-parser@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz#443f6a20ced6481a2bda4fa8532a6e55d789a2cb" integrity sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ== +postcss-values-parser@^2.0.0, postcss-values-parser@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/postcss-values-parser/-/postcss-values-parser-2.0.1.tgz#da8b472d901da1e205b47bdc98637b9e9e550e5f" + integrity sha512-2tLuBsA6P4rYTNKCXYG/71C7j1pU6pK503suYOmn4xYrQIzW+opD+7FAFNuGSdZC/3Qfy334QbeMu7MEb8gOxg== + dependencies: + flatten "^1.0.2" + indexes-of "^1.0.1" + uniq "^1.0.1" + postcss@8.2.14: version "8.2.14" resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.2.14.tgz#dcf313eb8247b3ce8078d048c0e8262ca565ad2b" @@ -8373,6 +10486,23 @@ postcss@8.2.14: nanoid "^3.1.22" source-map "^0.6.1" +postcss@8.3.6: + version "8.3.6" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.3.6.tgz#2730dd76a97969f37f53b9a6096197be311cc4ea" + integrity sha512-wG1cc/JhRgdqB6WHEuyLTedf3KIRuD0hG6ldkFEZNCjRxiC+3i6kkWUUbiJQayP28iwG35cEmAbe98585BYV0A== + dependencies: + colorette "^1.2.2" + nanoid "^3.1.23" + source-map-js "^0.6.2" + +postcss@^7.0.14, postcss@^7.0.17, postcss@^7.0.2, postcss@^7.0.32, postcss@^7.0.5, postcss@^7.0.6: + version "7.0.39" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.39.tgz#9624375d965630e2e1f2c02a935c82a59cb48309" + integrity sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA== + dependencies: + picocolors "^0.2.1" + source-map "^0.6.1" + postcss@^7.0.35: version "7.0.35" resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.35.tgz#d2be00b998f7f211d8a276974079f2e92b970e24" @@ -8391,6 +10521,15 @@ postcss@^8.1.4: nanoid "^3.1.23" source-map-js "^0.6.2" +postcss@^8.2.15, postcss@^8.3.5, postcss@^8.3.7: + version "8.4.4" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.4.tgz#d53d4ec6a75fd62557a66bb41978bf47ff0c2869" + integrity sha512-joU6fBsN6EIer28Lj6GDFoC/5yOZzLCfn0zHAn/MYXI7aPt4m4hK5KC5ovEZXy+lnCjmYIbQWngvju2ddyEr8Q== + dependencies: + nanoid "^3.1.30" + picocolors "^1.0.0" + source-map-js "^1.0.1" + postinstall-prepare@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/postinstall-prepare/-/postinstall-prepare-2.0.0.tgz#2a6867c1a13a05502aa115d0495efbbd778769cb" @@ -8428,14 +10567,6 @@ promise-inflight@^1.0.1: resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3" integrity sha1-mEcocL8igTL8vdhoEputEsPAKeM= -promise-retry@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/promise-retry/-/promise-retry-1.1.1.tgz#6739e968e3051da20ce6497fb2b50f6911df3d6d" - integrity sha1-ZznpaOMFHaIM5kl/srUPaRHfPW0= - dependencies: - err-code "^1.0.0" - retry "^0.10.0" - promise-retry@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/promise-retry/-/promise-retry-2.0.1.tgz#ff747a13620ab57ba688f5fc67855410c370da22" @@ -8842,14 +10973,6 @@ read-cache@^1.0.0: dependencies: pify "^2.3.0" -read-package-json-fast@^1.1.3: - version "1.2.2" - resolved "https://registry.yarnpkg.com/read-package-json-fast/-/read-package-json-fast-1.2.2.tgz#fba77b0b0d66b1ab344e214cb0876577e749c423" - integrity sha512-39DbPJjkltEzfXJXB6D8/Ir3GFOU2YbSKa2HaB/Y3nKrc/zY+0XrALpID6/13ezWyzqvOHrBbR4t4cjQuTdBVQ== - dependencies: - json-parse-even-better-errors "^2.3.0" - npm-normalize-package-bin "^1.0.1" - read-package-json-fast@^2.0.1: version "2.0.2" resolved "https://registry.yarnpkg.com/read-package-json-fast/-/read-package-json-fast-2.0.2.tgz#2dcb24d9e8dd50fb322042c8c35a954e6cc7ac9e" @@ -8903,6 +11026,13 @@ readdirp@~3.5.0: dependencies: picomatch "^2.2.1" +readdirp@~3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" + integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== + dependencies: + picomatch "^2.2.1" + reflect-metadata@^0.1.2: version "0.1.13" resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.1.13.tgz#67ae3ca57c972a2aa1642b10fe363fe32d49dc08" @@ -8925,6 +11055,11 @@ regenerator-runtime@0.13.7, regenerator-runtime@^0.13.4: resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz#cac2dacc8a1ea675feaabaeb8ae833898ae46f55" integrity sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew== +regenerator-runtime@0.13.9: + version "0.13.9" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz#8925742a98ffd90814988d7566ad30ca3b263b52" + integrity sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA== + regenerator-transform@^0.14.2: version "0.14.5" resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.14.5.tgz#c98da154683671c9c4dcb16ece736517e1b7feb4" @@ -9023,6 +11158,11 @@ require-directory@^2.1.1: resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= +require-from-string@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" + integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== + require-main-filename@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" @@ -9071,12 +11211,12 @@ resolve-url@^0.2.1: resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= -resolve@1.19.0: - version "1.19.0" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.19.0.tgz#1af5bf630409734a067cae29318aac7fa29a267c" - integrity sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg== +resolve@1.20.0, resolve@^1.14.2: + version "1.20.0" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.20.0.tgz#629a013fb3f70755d6f0b7935cc1c2c5378b1975" + integrity sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A== dependencies: - is-core-module "^2.1.0" + is-core-module "^2.2.0" path-parse "^1.0.6" resolve@^1.1.7, resolve@^1.3.2: @@ -9099,11 +11239,6 @@ ret@~0.1.10: resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg== -retry@^0.10.0: - version "0.10.1" - resolved "https://registry.yarnpkg.com/retry/-/retry-0.10.1.tgz#e76388d217992c252750241d3d3956fed98d8ff4" - integrity sha1-52OI0heZLCUnUCQdPTlW/tmNj/Q= - retry@^0.12.0: version "0.12.0" resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b" @@ -9189,13 +11324,20 @@ rxjs@6.6.3, rxjs@^6.5.3, rxjs@^6.6.0: dependencies: tslib "^1.9.0" -rxjs@~6.6.7: +rxjs@6.6.7, rxjs@~6.6.7: version "6.6.7" resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.7.tgz#90ac018acabf491bf65044235d5863c4dab804c9" integrity sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ== dependencies: tslib "^1.9.0" +rxjs@^7.2.0: + version "7.4.0" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.4.0.tgz#a12a44d7eebf016f5ff2441b87f28c9a51cebc68" + integrity sha512-7SQDi7xeTMCJpqViXh8gL/lebcwlp3d831F05+9B44A4B0WfsEwUQHR64gsH1kvJ+Ep/J9K2+n1hVl1CsGN23w== + dependencies: + tslib "~2.1.0" + safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.2" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" @@ -9229,6 +11371,14 @@ sass-loader@10.1.1: schema-utils "^3.0.0" semver "^7.3.2" +sass-loader@12.1.0: + version "12.1.0" + resolved "https://registry.yarnpkg.com/sass-loader/-/sass-loader-12.1.0.tgz#b73324622231009da6fba61ab76013256380d201" + integrity sha512-FVJZ9kxVRYNZTIe2xhw93n3xJNYZADr+q69/s98l9nTCrWASo+DR2Ot0s5xTKQDDEosUkatsGeHxcH4QBp5bSg== + dependencies: + klona "^2.0.4" + neo-async "^2.6.2" + sass@1.32.6: version "1.32.6" resolved "https://registry.yarnpkg.com/sass/-/sass-1.32.6.tgz#e3646c8325cd97ff75a8a15226007f3ccd221393" @@ -9236,6 +11386,13 @@ sass@1.32.6: dependencies: chokidar ">=2.0.0 <4.0.0" +sass@1.36.0: + version "1.36.0" + resolved "https://registry.yarnpkg.com/sass/-/sass-1.36.0.tgz#5912ef9d5d16714171ba11cb17edb274c4bbc07e" + integrity sha512-fQzEjipfOv5kh930nu3Imzq3ie/sGDc/4KtQMJlt7RRdrkQSfe37Bwi/Rf/gfuYHsIuE1fIlDMvpyMcEwjnPvg== + dependencies: + chokidar ">=3.0.0 <4.0.0" + saucelabs@^1.5.0: version "1.5.0" resolved "https://registry.yarnpkg.com/saucelabs/-/saucelabs-1.5.0.tgz#9405a73c360d449b232839919a86c396d379fd9d" @@ -9338,13 +11495,6 @@ semver-dsl@^1.0.1: dependencies: semver "^5.3.0" -semver-intersect@1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/semver-intersect/-/semver-intersect-1.4.0.tgz#bdd9c06bedcdd2fedb8cd352c3c43ee8c61321f3" - integrity sha512-d8fvGg5ycKAq0+I6nfWeCx6ffaWJCsBYU0H2Rq56+/zFePYfT8mXkB3tWBSjR5BerkHNZ5eTPIk1/LBYas35xQ== - dependencies: - semver "^5.0.0" - semver@7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/semver/-/semver-7.0.0.tgz#5f3ca35761e47e05b206c6daff2cf814f0316b8e" @@ -9357,12 +11507,19 @@ semver@7.3.4: dependencies: lru-cache "^6.0.0" -semver@^5.0.0, semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.5.1, semver@^5.6.0: +semver@7.3.5, semver@^7.3.4, semver@^7.3.5: + version "7.3.5" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7" + integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ== + dependencies: + lru-cache "^6.0.0" + +semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.5.1, semver@^5.6.0: version "5.7.1" resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== -semver@^6.0.0, semver@^6.3.0: +semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.3.0: version "6.3.0" resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== @@ -9372,13 +11529,6 @@ semver@^7.0.0, semver@^7.1.1, semver@^7.3.2: resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.2.tgz#604962b052b81ed0786aae84389ffba70ffd3938" integrity sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ== -semver@^7.3.4, semver@^7.3.5: - version "7.3.5" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7" - integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ== - dependencies: - lru-cache "^6.0.0" - send@0.17.1: version "0.17.1" resolved "https://registry.yarnpkg.com/send/-/send-0.17.1.tgz#c1d8b059f7900f7466dd4938bdc44e11ddb376c8" @@ -9614,16 +11764,16 @@ sockjs@^0.3.21: uuid "^3.4.0" websocket-driver "^0.7.4" -socks-proxy-agent@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-5.0.0.tgz#7c0f364e7b1cf4a7a437e71253bed72e9004be60" - integrity sha512-lEpa1zsWCChxiynk+lCycKuC502RxDWLKJZoIhnxrWNjLSDGYRFflHA1/228VkRcnv9TIb8w98derGbpKxJRgA== +socks-proxy-agent@^6.0.0: + version "6.1.1" + resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-6.1.1.tgz#e664e8f1aaf4e1fb3df945f09e3d94f911137f87" + integrity sha512-t8J0kG3csjA4g6FTbsMOWws+7R7vuRC8aQ/wy3/1OWmsgwA68zs/+cExQ0koSitUDXqhufF/YJr9wtNMZHw5Ew== dependencies: - agent-base "6" - debug "4" - socks "^2.3.3" + agent-base "^6.0.2" + debug "^4.3.1" + socks "^2.6.1" -socks@^2.3.3: +socks@^2.6.1: version "2.6.1" resolved "https://registry.yarnpkg.com/socks/-/socks-2.6.1.tgz#989e6534a07cf337deb1b1c94aaa44296520d30e" integrity sha512-kLQ9N5ucj8uIcxrDwjm0Jsqk06xdpBjGNQtpXy4Q8/QY2k+fY7nZH8CARy+hkbG+SGAovmzzuauCpBlb8FrnBA== @@ -9641,6 +11791,11 @@ source-map-js@^0.6.2: resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-0.6.2.tgz#0bb5de631b41cfbda6cfba8bd05a80efdfd2385e" integrity sha512-/3GptzWzu0+0MBQFrDKzw/DvvMTUORvgY6k6jd/VS6iCR4RDTKWH6v6WPwQoUO8667uQEf9Oe38DxAYWY5F/Ug== +source-map-js@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.1.tgz#a1741c131e3c77d048252adfa24e23b908670caf" + integrity sha512-4+TN2b3tqOCd/kaGRJ/sTYA0tR0mdXx26ipdolxcwtJVqEnqNYvlCAt1q3ypy4QMlYus+Zh34RNtYLoq2oQ4IA== + source-map-loader@1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/source-map-loader/-/source-map-loader-1.1.3.tgz#7dbc2fe7ea09d3e43c51fd9fc478b7f016c1f820" @@ -9653,6 +11808,15 @@ source-map-loader@1.1.3: source-map "^0.6.1" whatwg-mimetype "^2.3.0" +source-map-loader@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/source-map-loader/-/source-map-loader-3.0.0.tgz#f2a04ee2808ad01c774dea6b7d2639839f3b3049" + integrity sha512-GKGWqWvYr04M7tn8dryIWvb0s8YM41z82iQv01yBtIylgxax0CwvSy6gc2Y02iuXwEfGWRlMicH0nvms9UZphw== + dependencies: + abab "^2.0.5" + iconv-lite "^0.6.2" + source-map-js "^0.6.2" + source-map-resolve@^0.5.0, source-map-resolve@^0.5.2: version "0.5.3" resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.3.tgz#190866bece7553e1f8f267a2ee82c606b5509a1a" @@ -9715,7 +11879,7 @@ source-map@^0.5.0, source-map@^0.5.6, source-map@^0.5.7: resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= -sourcemap-codec@^1.4.4, sourcemap-codec@^1.4.8: +sourcemap-codec@1.4.8, sourcemap-codec@^1.4.4, sourcemap-codec@^1.4.8: version "1.4.8" resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz#ea804bd94857402e6992d05a38ef1ae35a9ab4c4" integrity sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA== @@ -9806,6 +11970,13 @@ ssri@^8.0.0: dependencies: minipass "^3.1.1" +ssri@^8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/ssri/-/ssri-8.0.1.tgz#638e4e439e2ffbd2cd289776d5ca457c4f51a2af" + integrity sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ== + dependencies: + minipass "^3.1.1" + stable@^0.1.8: version "0.1.8" resolved "https://registry.yarnpkg.com/stable/-/stable-0.1.8.tgz#836eb3c8382fe2936feaf544631017ce7d47a3cf" @@ -9976,6 +12147,11 @@ style-loader@2.0.0: loader-utils "^2.0.0" schema-utils "^3.0.0" +style-loader@3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-3.2.1.tgz#63cb920ec145c8669e9a50e92961452a1ef5dcde" + integrity sha512-1k9ZosJCRFaRbY6hH49JFlRB0fVSbmnyq1iTPjNxUmGVjBNEmwrrHPenhlp+Lgo51BojHSf6pl2FcqYaN3PfVg== + stylehacks@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/stylehacks/-/stylehacks-5.0.1.tgz#323ec554198520986806388c7fdaebc38d2c06fb" @@ -9995,6 +12171,15 @@ stylus-loader@4.3.3: normalize-path "^3.0.0" schema-utils "^3.0.0" +stylus-loader@6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/stylus-loader/-/stylus-loader-6.1.0.tgz#7a3a719a27cb2b9617896d6da28fda94c3ed9762" + integrity sha512-qKO34QCsOtSJrXxQQmXsPeaVHh6hMumBAFIoJTcsSr2VzrA6o/CW9HCGR8spCjzJhN8oKQHdj/Ytx0wwXyElkw== + dependencies: + fast-glob "^3.2.5" + klona "^2.0.4" + normalize-path "^3.0.0" + stylus@0.54.8: version "0.54.8" resolved "https://registry.yarnpkg.com/stylus/-/stylus-0.54.8.tgz#3da3e65966bc567a7b044bfe0eece653e099d147" @@ -10055,15 +12240,28 @@ svgo@^2.3.0: csso "^4.2.0" stable "^0.1.8" +svgo@^2.7.0: + version "2.8.0" + resolved "https://registry.yarnpkg.com/svgo/-/svgo-2.8.0.tgz#4ff80cce6710dc2795f0c7c74101e6764cfccd24" + integrity sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg== + dependencies: + "@trysound/sax" "0.2.0" + commander "^7.2.0" + css-select "^4.1.3" + css-tree "^1.1.3" + csso "^4.2.0" + picocolors "^1.0.0" + stable "^0.1.8" + symbol-observable@1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804" integrity sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ== -symbol-observable@3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-3.0.0.tgz#eea8f6478c651018e059044268375c408c15c533" - integrity sha512-6tDOXSHiVjuCaasQSWTmHUWn4PuG7qa3+1WT031yTc/swT7+rLiw3GOrFxaH1E3lLP09dH3bVuVDf2gK5rxG3Q== +symbol-observable@4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-4.0.0.tgz#5b425f192279e87f2f9b937ac8540d1984b39205" + integrity sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ== systemjs@0.21.5: version "0.21.5" @@ -10124,6 +12322,18 @@ terser-webpack-plugin@4.2.3: terser "^5.3.4" webpack-sources "^1.4.3" +terser-webpack-plugin@5.1.4: + version "5.1.4" + resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.1.4.tgz#c369cf8a47aa9922bd0d8a94fe3d3da11a7678a1" + integrity sha512-C2WkFwstHDhVEmsmlCxrXUtVklS+Ir1A7twrYzrDrQQOIMOaVAYykaoo/Aq1K0QRkMoY2hhvDQY1cm4jnIMFwA== + dependencies: + jest-worker "^27.0.2" + p-limit "^3.1.0" + schema-utils "^3.0.0" + serialize-javascript "^6.0.0" + source-map "^0.6.1" + terser "^5.7.0" + terser-webpack-plugin@^1.4.3: version "1.4.5" resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-1.4.5.tgz#a217aefaea330e734ffacb6120ec1fa312d6040b" @@ -10159,6 +12369,15 @@ terser@5.5.1: source-map "~0.7.2" source-map-support "~0.5.19" +terser@5.7.1: + version "5.7.1" + resolved "https://registry.yarnpkg.com/terser/-/terser-5.7.1.tgz#2dc7a61009b66bb638305cb2a824763b116bf784" + integrity sha512-b3e+d5JbHAe/JSjwsC3Zn55wsBIM7AsHLjKxT31kGCldgbpFePaFo+PiddtO6uwRZWRw7sPXmAN8dTW61xmnSg== + dependencies: + commander "^2.20.0" + source-map "~0.7.2" + source-map-support "~0.5.19" + terser@^4.1.2: version "4.8.0" resolved "https://registry.yarnpkg.com/terser/-/terser-4.8.0.tgz#63056343d7c70bb29f3af665865a46fe03a0df17" @@ -10177,7 +12396,7 @@ terser@^5.3.4: source-map "~0.7.2" source-map-support "~0.5.19" -terser@^5.7.2: +terser@^5.7.0, terser@^5.7.2: version "5.10.0" resolved "https://registry.yarnpkg.com/terser/-/terser-5.10.0.tgz#b86390809c0389105eb0a0b62397563096ddafcc" integrity sha512-AMmF99DMfEDiRJfxfY5jj5wNH/bYO09cniSqhfoyxc8sFoYIgkJy86G04UoZU5VjlpnplVu0K6Tx6E9b5+DlHA== @@ -10348,11 +12567,16 @@ tsconfig-paths@^3.9.0: minimist "^1.2.0" strip-bom "^3.0.0" -tslib@2.1.0: +tslib@2.1.0, tslib@~2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.1.0.tgz#da60860f1c2ecaa5703ab7d39bc05b6bf988b97a" integrity sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A== +tslib@2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.0.tgz#803b8cdab3e12ba581a4ca41c8839bbb0dacb09e" + integrity sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg== + tslib@^1.10.0, tslib@^1.13.0, tslib@^1.8.1, tslib@^1.9.0: version "1.14.0" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.0.tgz#d624983f3e2c5e0b55307c3dd6c86acd737622c6" @@ -10444,10 +12668,10 @@ typescript@4.1.5: resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.1.5.tgz#123a3b214aaff3be32926f0d8f1f6e704eb89a72" integrity sha512-6OSu9PTIzmn9TCDiovULTnET6BgXtDYL4Gg4szY+cGsc3JP1dQL8qvE8kShTRx1NIw4Q9IBHlwODjkjWEtMUyA== -typescript@~4.0.3: - version "4.0.3" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.0.3.tgz#153bbd468ef07725c1df9c77e8b453f8d36abba5" - integrity sha512-tEu6DGxGgRJPb/mVPIZ48e69xCn2yRmCgYmDugAVwmJ6o+0u1RI18eO7E7WBTLYLaEVVOhwQmcdhQHweux/WPg== +typescript@4.3.5, typescript@~4.3.5: + version "4.3.5" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.3.5.tgz#4d1c37cc16e893973c45a06886b7113234f119f4" + integrity sha512-DqQgihaQ9cUrskJo9kIyW/+g0Vxsk8cDtZ52a3NGh0YNTfpUSArXSohyUGnvbPazEPLu398C0UxmKSOrPumUzA== ua-parser-js@^0.7.23: version "0.7.28" @@ -10511,15 +12735,6 @@ unique-slug@^2.0.0: dependencies: imurmurhash "^0.1.4" -universal-analytics@0.4.23: - version "0.4.23" - resolved "https://registry.yarnpkg.com/universal-analytics/-/universal-analytics-0.4.23.tgz#d915e676850c25c4156762471bdd7cf2eaaca8ac" - integrity sha512-lgMIH7XBI6OgYn1woDEmxhGdj8yDefMKg7GkWdeATAlQZFrMrNyxSkpDzY57iY0/6fdlzTbBV03OawvvzG+q7A== - dependencies: - debug "^4.1.1" - request "^2.88.2" - uuid "^3.0.0" - universalify@^0.1.0: version "0.1.2" resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" @@ -10613,7 +12828,7 @@ uuid@8.3.2: resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== -uuid@^3.0.0, uuid@^3.3.2, uuid@^3.4.0: +uuid@^3.3.2, uuid@^3.4.0: version "3.4.0" resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== @@ -10679,7 +12894,7 @@ watchpack@^1.7.4: chokidar "^3.4.1" watchpack-chokidar2 "^2.0.0" -watchpack@^2.3.0: +watchpack@^2.2.0, watchpack@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.3.0.tgz#a41bca3da6afaff31e92a433f4c856a0c25ea0c4" integrity sha512-MnN0Q1OsvB/GGHETrFeZPQaOelWh/7O+EiFlj8sM9GPjtQkis7k01aAxrg/18kTfoIVcLL+haEVFlXDaSRwKRw== @@ -10737,6 +12952,18 @@ webpack-dev-middleware@3.7.2, webpack-dev-middleware@^3.7.2: range-parser "^1.2.1" webpack-log "^2.0.0" +webpack-dev-middleware@5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-5.0.0.tgz#0abe825275720e0a339978aea5f0b03b140c1584" + integrity sha512-9zng2Z60pm6A98YoRcA0wSxw1EYn7B7y5owX/Tckyt9KGyULTkLtiavjaXlWqOMkM0YtqGgL3PvMOFgyFLq8vw== + dependencies: + colorette "^1.2.2" + mem "^8.1.1" + memfs "^3.2.2" + mime-types "^2.1.31" + range-parser "^1.2.1" + schema-utils "^3.0.0" + webpack-dev-server@3.11.2: version "3.11.2" resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-3.11.2.tgz#695ebced76a4929f0d5de7fd73fafe185fe33708" @@ -10792,6 +13019,14 @@ webpack-merge@5.7.3, webpack-merge@^5.7.3: clone-deep "^4.0.1" wildcard "^2.0.0" +webpack-merge@5.8.0: + version "5.8.0" + resolved "https://registry.yarnpkg.com/webpack-merge/-/webpack-merge-5.8.0.tgz#2b39dbf22af87776ad744c390223731d30a68f61" + integrity sha512-/SaI7xY0831XwP6kzuwhKWVKDP9t1QY1h65lAFLbZqMPIuYcD9QAW4u9STIbU9kaJbPBB/geU/gLr1wDjOhQ+Q== + dependencies: + clone-deep "^4.0.1" + wildcard "^2.0.0" + webpack-sources@2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-2.2.0.tgz#058926f39e3d443193b6c31547229806ffd02bac" @@ -10808,7 +13043,7 @@ webpack-sources@^1.1.0, webpack-sources@^1.2.0, webpack-sources@^1.3.0, webpack- source-list-map "^2.0.0" source-map "~0.6.1" -webpack-sources@^3.2.2: +webpack-sources@^3.2.0, webpack-sources@^3.2.2: version "3.2.2" resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.2.tgz#d88e3741833efec57c4c789b6010db9977545260" integrity sha512-cp5qdmHnu5T8wRg2G3vZZHoJPN14aqQ89SyQ11NpGH5zEMDCclt49rzo+MaRazk7/UeILhAI+/sEtcM+7Fr0nw== @@ -10849,6 +13084,36 @@ webpack@4.44.2: watchpack "^1.7.4" webpack-sources "^1.4.1" +webpack@5.50.0: + version "5.50.0" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.50.0.tgz#5562d75902a749eb4d75131f5627eac3a3192527" + integrity sha512-hqxI7t/KVygs0WRv/kTgUW8Kl3YC81uyWQSo/7WUs5LsuRw0htH/fCwbVBGCuiX/t4s7qzjXFcf41O8Reiypag== + dependencies: + "@types/eslint-scope" "^3.7.0" + "@types/estree" "^0.0.50" + "@webassemblyjs/ast" "1.11.1" + "@webassemblyjs/wasm-edit" "1.11.1" + "@webassemblyjs/wasm-parser" "1.11.1" + acorn "^8.4.1" + acorn-import-assertions "^1.7.6" + browserslist "^4.14.5" + chrome-trace-event "^1.0.2" + enhanced-resolve "^5.8.0" + es-module-lexer "^0.7.1" + eslint-scope "5.1.1" + events "^3.2.0" + glob-to-regexp "^0.4.1" + graceful-fs "^4.2.4" + json-parse-better-errors "^1.0.2" + loader-runner "^4.2.0" + mime-types "^2.1.27" + neo-async "^2.6.2" + schema-utils "^3.1.0" + tapable "^2.1.1" + terser-webpack-plugin "^5.1.3" + watchpack "^2.2.0" + webpack-sources "^3.2.0" + webpack@^5.64.4: version "5.64.4" resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.64.4.tgz#e1454b6a13009f57cc2c78e08416cd674622937b" @@ -11030,7 +13295,7 @@ yallist@^4.0.0: resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== -yaml@^1.10.0: +yaml@^1.10.0, yaml@^1.10.2: version "1.10.2" resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b" integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== @@ -11089,7 +13354,7 @@ yargs@^15.3.1: y18n "^4.0.0" yargs-parser "^18.1.2" -yargs@^16.1.1, yargs@^16.2.0: +yargs@^16.1.1: version "16.2.0" resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== @@ -11102,11 +13367,29 @@ yargs@^16.1.1, yargs@^16.2.0: y18n "^5.0.5" yargs-parser "^20.2.2" +yargs@^17.0.0: + version "17.2.1" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.2.1.tgz#e2c95b9796a0e1f7f3bf4427863b42e0418191ea" + integrity sha512-XfR8du6ua4K6uLGm5S6fA+FIJom/MdJcFNVY8geLlp2v8GYbOXD4EB1tPNZsRn4vBzKGMgb5DRZMeWuFc2GO8Q== + dependencies: + cliui "^7.0.2" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.0" + y18n "^5.0.5" + yargs-parser "^20.2.2" + yn@3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== +yocto-queue@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" + integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== + zone.js@~0.10.3: version "0.10.3" resolved "https://registry.yarnpkg.com/zone.js/-/zone.js-0.10.3.tgz#3e5e4da03c607c9dcd92e37dd35687a14a140c16" From 3992ddcadfc7d5cdbf5b220cfcdcde7b29d5a7f8 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Tue, 30 Nov 2021 09:53:21 +0200 Subject: [PATCH 176/432] Update flex-layout and datepicker --- ui-ngx/package.json | 6 +++--- ui-ngx/yarn.lock | 25 +++++++++++++++---------- 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/ui-ngx/package.json b/ui-ngx/package.json index 06ec15ace2..09daa6bc04 100644 --- a/ui-ngx/package.json +++ b/ui-ngx/package.json @@ -18,7 +18,7 @@ "@angular/common": "^12.2.13", "@angular/compiler": "^12.2.13", "@angular/core": "^12.2.13", - "@angular/flex-layout": "^11.0.0-beta.33", + "@angular/flex-layout": "^12.0.0-beta.35", "@angular/forms": "^12.2.13", "@angular/material": "^11.2.13", "@angular/platform-browser": "^12.2.13", @@ -30,7 +30,7 @@ "@flowjs/ngx-flow": "~0.4.6", "@geoman-io/leaflet-geoman-free": "^2.11.3", "@juggle/resize-observer": "^3.3.1", - "@mat-datetimepicker/core": "~6.0.2", + "@mat-datetimepicker/core": "~7.0.1", "@material-ui/core": "^4.11.4", "@material-ui/icons": "^4.11.2", "@material-ui/pickers": "^3.3.10", @@ -148,4 +148,4 @@ "resolutions": { "lodash": "~4.17.21" } -} \ No newline at end of file +} diff --git a/ui-ngx/yarn.lock b/ui-ngx/yarn.lock index b1b280a8bc..3b3bb0d055 100644 --- a/ui-ngx/yarn.lock +++ b/ui-ngx/yarn.lock @@ -356,12 +356,12 @@ dependencies: tslib "^2.2.0" -"@angular/flex-layout@^11.0.0-beta.33": - version "11.0.0-beta.33" - resolved "https://registry.yarnpkg.com/@angular/flex-layout/-/flex-layout-11.0.0-beta.33.tgz#c2d08f90164701b66a62b8c4365b4e22c1e95789" - integrity sha512-unfhw3abZuKtdwQicRStHCYGbANPTHYg4WNRQk/RC5Mxq+4WOp4Q8HI7GqRHCGUYDCGUP7w1sU/oDt8f09nM8w== +"@angular/flex-layout@^12.0.0-beta.35": + version "12.0.0-beta.35" + resolved "https://registry.yarnpkg.com/@angular/flex-layout/-/flex-layout-12.0.0-beta.35.tgz#b52c3c82608cbb92a119f8dcde2a5b98186fe558" + integrity sha512-nPi2MGDFuCacwWHqxF/G7lUJd2X99HbLjjUvKXnyLwyCIVgH1sfS52su2wYbVYWJRqAVAB2/VMlrtW8Khr8hDA== dependencies: - tslib "^2.0.0" + tslib "^2.1.0" "@angular/forms@^12.2.13": version "12.2.13" @@ -2442,12 +2442,12 @@ resolved "https://registry.yarnpkg.com/@juggle/resize-observer/-/resize-observer-3.3.1.tgz#b50a781709c81e10701004214340f25475a171a0" integrity sha512-zMM9Ds+SawiUkakS7y94Ymqx+S0ORzpG3frZirN3l+UlXUmSUR7hF4wxCVqW+ei94JzV5kt0uXBcoOEAuiydrw== -"@mat-datetimepicker/core@~6.0.2": - version "6.0.2" - resolved "https://registry.yarnpkg.com/@mat-datetimepicker/core/-/core-6.0.2.tgz#c4f00fee4780e116ad0b685dcdf1014ad81301c5" - integrity sha512-cBzbg9GNOcV3eyhXa/44TTlBIy0t4Qgp1agSrhUoMucnFzhlIcF0LrUswOOQaldXDw1FQUQE5VQz4KSFjac8+g== +"@mat-datetimepicker/core@~7.0.1": + version "7.0.1" + resolved "https://registry.yarnpkg.com/@mat-datetimepicker/core/-/core-7.0.1.tgz#dac547195f25d448cfeaa11e0384f59639065c5f" + integrity sha512-lTYFJYstVb5l5JuNwVVZeyMaDtkZIq+eKycUa+5aJBAPhjapwdJx6lHiaZODgydRNtzdw79pQcB00mufguv3ew== dependencies: - tslib "^2.0.0" + tslib "^2.3.0" "@material-ui/core@^4.11.4": version "4.11.4" @@ -12587,6 +12587,11 @@ tslib@^2.0.0, tslib@^2.0.1: resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.0.2.tgz#462295631185db44b21b1ea3615b63cd1c038242" integrity sha512-wAH28hcEKwna96/UacuWaVspVLkg4x1aDM9JlzqaQTOFczCktkVAb5fmXChgandR1EraDPs2w8P+ozM+oafwxg== +tslib@^2.1.0, tslib@^2.3.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01" + integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw== + tslib@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.2.0.tgz#fb2c475977e35e241311ede2693cee1ec6698f5c" From ac39ceab969bfe244a429585a12bac9fecd74368 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Tue, 30 Nov 2021 09:57:35 +0200 Subject: [PATCH 177/432] Update angular material 12 --- ui-ngx/package.json | 6 +-- ui-ngx/src/theme.scss | 106 +++++++++++++++++++++--------------------- ui-ngx/yarn.lock | 20 ++++---- 3 files changed, 66 insertions(+), 66 deletions(-) diff --git a/ui-ngx/package.json b/ui-ngx/package.json index 09daa6bc04..44cfd99ff5 100644 --- a/ui-ngx/package.json +++ b/ui-ngx/package.json @@ -14,13 +14,13 @@ "private": true, "dependencies": { "@angular/animations": "^12.2.13", - "@angular/cdk": "^11.2.13", + "@angular/cdk": "^12.2.13", "@angular/common": "^12.2.13", "@angular/compiler": "^12.2.13", "@angular/core": "^12.2.13", "@angular/flex-layout": "^12.0.0-beta.35", "@angular/forms": "^12.2.13", - "@angular/material": "^11.2.13", + "@angular/material": "^12.2.13", "@angular/platform-browser": "^12.2.13", "@angular/platform-browser-dynamic": "^12.2.13", "@angular/router": "^12.2.13", @@ -148,4 +148,4 @@ "resolutions": { "lodash": "~4.17.21" } -} +} \ No newline at end of file diff --git a/ui-ngx/src/theme.scss b/ui-ngx/src/theme.scss index 25e1131e63..fdad632bee 100644 --- a/ui-ngx/src/theme.scss +++ b/ui-ngx/src/theme.scss @@ -13,11 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -@import '~@angular/material/theming'; +@use '~@angular/material' as mat; @import '~@mat-datetimepicker/core/datetimepicker/datetimepicker-theme.scss'; @import './scss/constants'; -@include mat-core(); +@include mat.core(); $tb-primary-color: #305680; $tb-secondary-color: #527dad; @@ -41,39 +41,39 @@ $tb-mat-indigo: ( A400: #3d5afe, A700: #304ffe, contrast: ( - 50: $dark-primary-text, - 100: $dark-primary-text, - 200: $dark-primary-text, - 300: $light-primary-text, - 400: $light-primary-text, - 500: $light-primary-text, - 600: $light-primary-text, - 700: $light-primary-text, - 800: $light-primary-text, - 900: $light-primary-text, - A100: $dark-primary-text, - A200: $light-primary-text, - A400: $light-primary-text, - A700: $light-primary-text, + 50: rgba(black, 0.87), + 100: rgba(black, 0.87), + 200: rgba(black, 0.87), + 300: white, + 400: white, + 500: white, + 600: white, + 700: white, + 800: white, + 900: white, + A100: rgba(black, 0.87), + A200: white, + A400: white, + A700: white, ) ); -$tb-primary: mat-palette($tb-mat-indigo); -$tb-accent: mat-palette($mat-deep-orange); +$tb-primary: mat.define-palette($tb-mat-indigo); +$tb-accent: mat.define-palette(mat.$deep-orange-palette); -$background: (background: map_get($mat-grey, 200)); +$background: (background: map_get(mat.$grey-palette, 200)); -$tb-theme-background: map_merge($mat-light-theme-background, $background); +$tb-theme-background: map_merge(mat.$light-theme-background-palette, $background); -$tb-mat-theme: mat-light-theme( +$tb-mat-theme: mat.define-light-theme( $tb-primary, $tb-accent ); $tb-theme: map_merge($tb-mat-theme, (background: $tb-theme-background)); -$primary: mat-color($tb-primary); -$accent: mat-color($tb-accent); +$primary: mat.get-color-from-palette($tb-primary); +$accent: mat.get-color-from-palette($tb-accent); $tb-dark-mat-indigo: ( 50: #e8eaf6, @@ -91,24 +91,24 @@ $tb-dark-mat-indigo: ( A400: #3d5afe, A700: #304ffe, contrast: ( - 50: $dark-primary-text, - 100: $dark-primary-text, - 200: $dark-primary-text, - 300: $dark-primary-text, - 400: $dark-primary-text, + 50: rgba(black, 0.87), + 100: rgba(black, 0.87), + 200: rgba(black, 0.87), + 300: rgba(black, 0.87), + 400: rgba(black, 0.87), 500: map_get($tb-mat-indigo, 900), - 600: $light-primary-text, - 700: $light-primary-text, - 800: $light-primary-text, - 900: $light-primary-text, - A100: $dark-primary-text, - A200: $dark-primary-text, - A400: $dark-primary-text, - A700: $dark-primary-text, + 600: white, + 700: white, + 800: white, + 900: white, + A100: rgba(black, 0.87), + A200: rgba(black, 0.87), + A400: rgba(black, 0.87), + A700: rgba(black, 0.87), ) ); -$tb-dark-primary: mat-palette($tb-dark-mat-indigo); +$tb-dark-primary: mat.define-palette($tb-dark-mat-indigo); $tb-dark-theme-background: ( status-bar: black, @@ -119,22 +119,22 @@ $tb-dark-theme-background: ( dialog: map_get($tb-dark-mat-indigo, 800), disabled-button: rgba(white, 0.12), raised-button: map-get($tb-dark-mat-indigo, 50), - focused-button: $light-focused, + focused-button: rgba(white, 0.12), selected-button: map_get($tb-dark-mat-indigo, 900), selected-disabled-button: map_get($tb-dark-mat-indigo, 800), disabled-button-toggle: black, unselected-chip: map_get($tb-dark-mat-indigo, 700), disabled-list-option: black, - tooltip: map_get($mat-grey, 700), + tooltip: map_get(mat.$grey-palette, 700), ); -@function get-tb-dark-theme($primary, $accent, $warn: mat-palette($mat-red)) { +@function get-tb-dark-theme($primary, $accent, $warn: mat.define-palette(mat.$red-palette)) { @return ( primary: $primary, accent: $accent, warn: $warn, is-dark: true, - foreground: $mat-dark-theme-foreground, + foreground: mat.$dark-theme-foreground-palette, background: $tb-dark-theme-background, ); } @@ -153,8 +153,8 @@ $tb-dark-theme: get-tb-dark-theme( mat-fab-toolbar { .mat-fab-toolbar-background { - background: mat-color($background, app-bar); - color: mat-color($foreground, text); + background: mat.get-color-from-palette($background, app-bar); + color: mat.get-color-from-palette($foreground, text); } &.mat-primary { .mat-fab-toolbar-background { @@ -175,8 +175,8 @@ $tb-dark-theme: get-tb-dark-theme( } @mixin _mat-toolbar-inverse-color($palette) { - background: mat-color($palette, default-contrast); - color: $dark-primary-text; + background: mat.get-color-from-palette($palette, default-contrast); + color: rgba(black, 0.87); } @mixin mat-fab-toolbar-inverse-theme($theme) { @@ -188,8 +188,8 @@ $tb-dark-theme: get-tb-dark-theme( mat-fab-toolbar { .mat-fab-toolbar-background { - background: mat-color($background, app-bar); - color: mat-color($foreground, text); + background: mat.get-color-from-palette($background, app-bar); + color: mat.get-color-from-palette($foreground, text); } &.mat-primary { .mat-fab-toolbar-background { @@ -201,15 +201,15 @@ $tb-dark-theme: get-tb-dark-theme( @include _mat-toolbar-inverse-color($primary); button.mat-icon-button { mat-icon { - color: mat-color($primary); + color: mat.get-color-from-palette($primary); } } } } .mat-fab { &.mat-primary { - background: mat-color($primary, default-contrast); - color: mat-color($primary); + background: mat.get-color-from-palette($primary, default-contrast); + color: mat.get-color-from-palette($primary); } } } @@ -221,7 +221,7 @@ $tb-dark-theme: get-tb-dark-theme( mat-toolbar{ &.mat-hue-3 { - background-color: mat-color($primary, 'A100'); + background-color: mat.get-color-from-palette($primary, 'A100'); } } @@ -233,12 +233,12 @@ $tb-dark-theme: get-tb-dark-theme( } .tb-default { - @include angular-material-theme($tb-theme); + @include mat.all-component-themes($tb-theme); @include mat-datetimepicker-theme($tb-theme); @include tb-components-theme($tb-theme); } .tb-dark { - @include angular-material-theme($tb-dark-theme); + @include mat.all-component-themes($tb-dark-theme); } diff --git a/ui-ngx/yarn.lock b/ui-ngx/yarn.lock index 3b3bb0d055..9aae7fabc0 100644 --- a/ui-ngx/yarn.lock +++ b/ui-ngx/yarn.lock @@ -271,12 +271,12 @@ dependencies: tslib "^2.2.0" -"@angular/cdk@^11.2.13": - version "11.2.13" - resolved "https://registry.yarnpkg.com/@angular/cdk/-/cdk-11.2.13.tgz#d54c9187e3b8cf3f8ba190b1edddc08ed2b740de" - integrity sha512-FkE4iCwoLbQxLDUOjV1I7M/6hmpyb7erAjEdWgch7nGRNxF1hqX5Bqf1lvLFKPNCbx5NRI5K7YVAdIUQUR8vug== +"@angular/cdk@^12.2.13": + version "12.2.13" + resolved "https://registry.yarnpkg.com/@angular/cdk/-/cdk-12.2.13.tgz#1fdbe814adfd6b4ff906c6d9c4c6df07b83f09d8" + integrity sha512-zSKRhECyFqhingIeyRInIyTvYErt4gWo+x5DQr0b7YLUbU8DZSwWnG4w76Ke2s4U8T7ry1jpJBHoX/e8YBpGMg== dependencies: - tslib "^2.0.0" + tslib "^2.2.0" optionalDependencies: parse5 "^5.0.0" @@ -375,12 +375,12 @@ resolved "https://registry.yarnpkg.com/@angular/language-service/-/language-service-12.2.13.tgz#326045a328f8a962287037d7a85be8120074421c" integrity sha512-jb9s3IJuWNKTRcM90NOwvMfiy85nnKfTxxLVn8/QFMO6+Ps/hsVZNp+W/TmAEDvCkon+9q0O4hwa4MY1m/Dlkw== -"@angular/material@^11.2.13": - version "11.2.13" - resolved "https://registry.yarnpkg.com/@angular/material/-/material-11.2.13.tgz#99960316d3ce58aac7497d7bb8b0c05468f502b9" - integrity sha512-FqFdGSkOtqsmeLyTSousodDGUy2NqbtxCIKv2rwbsIRwHNKB0KpR/UQhA2gMRuGa5hxhMJ0DW0Tf9neMRuLCTg== +"@angular/material@^12.2.13": + version "12.2.13" + resolved "https://registry.yarnpkg.com/@angular/material/-/material-12.2.13.tgz#7f92f95002a2abaa8bb115ca8f0809bdc3f7d3fc" + integrity sha512-6g2GyN4qp2D+DqY2AwrQuPB3cd9gybvQVXvNRbTPXEulHr+LgGei00ySdFHFp6RvdGSMZ4i3LM1Fq3VkFxhCfQ== dependencies: - tslib "^2.0.0" + tslib "^2.2.0" "@angular/platform-browser-dynamic@^12.2.13": version "12.2.13" From abe7055b8b84f4a1fbc1b2e12463e9503aea3c7c Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Tue, 30 Nov 2021 10:00:06 +0200 Subject: [PATCH 178/432] Remove ie11 support --- ui-ngx/src/.browserslistrc | 1 - 1 file changed, 1 deletion(-) diff --git a/ui-ngx/src/.browserslistrc b/ui-ngx/src/.browserslistrc index 0209813ebf..6ef5d1aee4 100644 --- a/ui-ngx/src/.browserslistrc +++ b/ui-ngx/src/.browserslistrc @@ -8,4 +8,3 @@ last 2 versions Firefox ESR not dead -IE 11 From 935770e1a799e3e0f2ca8b2e6fa62ddc2d7b2af1 Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Tue, 30 Nov 2021 11:16:51 +0200 Subject: [PATCH 179/432] refactored --- .../lwm2m/server/client/LwM2mClientContextImpl.java | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java index 823f16a99a..e2b05847f7 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java @@ -22,10 +22,7 @@ import org.eclipse.leshan.core.model.ResourceModel; import org.eclipse.leshan.core.node.LwM2mPath; import org.eclipse.leshan.server.registration.Registration; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.context.event.ApplicationReadyEvent; import org.springframework.context.annotation.Lazy; -import org.springframework.context.event.EventListener; -import org.springframework.core.annotation.Order; import org.springframework.stereotype.Service; import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.device.data.PowerMode; @@ -36,6 +33,7 @@ import org.thingsboard.server.common.transport.TransportDeviceProfileCache; import org.thingsboard.server.common.transport.TransportServiceCallback; import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse; import org.thingsboard.server.gen.transport.TransportProtos; +import org.thingsboard.server.queue.util.AfterStartUp; import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; import org.thingsboard.server.transport.lwm2m.config.LwM2mVersion; @@ -90,8 +88,7 @@ public class LwM2mClientContextImpl implements LwM2mClientContext { private final Map lwM2mClientsByRegistrationId = new ConcurrentHashMap<>(); private final Map profiles = new ConcurrentHashMap<>(); - @EventListener(ApplicationReadyEvent.class) - @Order(Integer.MAX_VALUE - 1) + @AfterStartUp(order = Integer.MAX_VALUE - 1) public void init() { String nodeId = context.getNodeId(); Set fetchedClients = clientStore.getAll(); From 105806167252a309229434dd77d900ee1f3fb360 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Tue, 30 Nov 2021 11:17:35 +0200 Subject: [PATCH 180/432] lwm2m - fix bug credentials if bootstrap.enabled = false or lwm2m.enabled = false in *.yml --- .../server/controller/Lwm2mController.java | 4 +-- .../service/lwm2m/LwM2MServiceImpl.java | 34 ++++++++++++------- .../src/main/resources/thingsboard.yml | 2 +- .../TbLwM2mBootstrapTransportComponent.java | 26 ++++++++++++++ .../LwM2MTransportBootstrapService.java | 6 ++-- .../store/LwM2MBootstrapSecurityStore.java | 4 +-- .../LwM2MInMemoryBootstrapConfigStore.java | 4 +-- .../config/LwM2MTransportBootstrapConfig.java | 4 +-- .../config/LwM2MTransportServerConfig.java | 9 ++--- .../server/adaptors/LwM2MJsonAdaptor.java | 4 +-- .../src/main/resources/tb-lwm2m-transport.yml | 2 +- 11 files changed, 64 insertions(+), 35 deletions(-) create mode 100644 common/queue/src/main/java/org/thingsboard/server/queue/util/TbLwM2mBootstrapTransportComponent.java diff --git a/application/src/main/java/org/thingsboard/server/controller/Lwm2mController.java b/application/src/main/java/org/thingsboard/server/controller/Lwm2mController.java index 5870c7304c..4d0e6fac1a 100644 --- a/application/src/main/java/org/thingsboard/server/controller/Lwm2mController.java +++ b/application/src/main/java/org/thingsboard/server/controller/Lwm2mController.java @@ -32,7 +32,7 @@ import org.thingsboard.server.common.data.SaveDeviceWithCredentialsRequest; import org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap.LwM2MServerSecurityConfigDefault; import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.security.DeviceCredentials; -import org.thingsboard.server.queue.util.TbCoreComponent; +import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; import org.thingsboard.server.service.lwm2m.LwM2MService; import java.util.Map; @@ -42,7 +42,7 @@ import static org.thingsboard.server.controller.ControllerConstants.TENANT_OR_CU @Slf4j @RestController -@TbCoreComponent +@TbLwM2mTransportComponent @RequestMapping("/api") public class Lwm2mController extends BaseController { diff --git a/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MServiceImpl.java b/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MServiceImpl.java index 5178cbf191..e74f616bf0 100644 --- a/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MServiceImpl.java +++ b/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MServiceImpl.java @@ -18,38 +18,46 @@ package org.thingsboard.server.service.lwm2m; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.commons.codec.binary.Base64; -import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.stereotype.Service; import org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap.LwM2MServerSecurityConfigDefault; import org.thingsboard.server.common.transport.config.ssl.SslCredentials; +import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; import org.thingsboard.server.transport.lwm2m.config.LwM2MSecureServerConfig; import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportBootstrapConfig; import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; +import java.util.Optional; + @Slf4j @Service @RequiredArgsConstructor -@ConditionalOnExpression("('${service.type:null}'=='tb-transport' && '${transport.lwm2m.enabled:false}'=='true') || '${service.type:null}'=='monolith' || '${service.type:null}'=='tb-core'") +@TbLwM2mTransportComponent public class LwM2MServiceImpl implements LwM2MService { private final LwM2MTransportServerConfig serverConfig; - private final LwM2MTransportBootstrapConfig bootstrapConfig; + private final Optional bootstrapConfig; @Override public LwM2MServerSecurityConfigDefault getServerSecurityInfo(boolean bootstrapServer) { - LwM2MServerSecurityConfigDefault result = getServerSecurityConfig(bootstrapServer ? bootstrapConfig : serverConfig); - result.setBootstrapServerIs(bootstrapServer); - return result; + LwM2MSecureServerConfig bsServerConfig = bootstrapServer ? bootstrapConfig.isPresent() ? bootstrapConfig.get() : null : serverConfig; + if (bsServerConfig!= null) { + LwM2MServerSecurityConfigDefault result = getServerSecurityConfig(bsServerConfig); + result.setBootstrapServerIs(bootstrapServer); + return result; + } + else { + return null; + } } - private LwM2MServerSecurityConfigDefault getServerSecurityConfig(LwM2MSecureServerConfig serverConfig) { + private LwM2MServerSecurityConfigDefault getServerSecurityConfig(LwM2MSecureServerConfig bsServerConfig) { LwM2MServerSecurityConfigDefault bsServ = new LwM2MServerSecurityConfigDefault(); - bsServ.setShortServerId(serverConfig.getId()); - bsServ.setHost(serverConfig.getHost()); - bsServ.setPort(serverConfig.getPort()); - bsServ.setSecurityHost(serverConfig.getSecureHost()); - bsServ.setSecurityPort(serverConfig.getSecurePort()); - byte[] publicKeyBase64 = getPublicKey(serverConfig); + bsServ.setShortServerId(bsServerConfig.getId()); + bsServ.setHost(bsServerConfig.getHost()); + bsServ.setPort(bsServerConfig.getPort()); + bsServ.setSecurityHost(bsServerConfig.getSecureHost()); + bsServ.setSecurityPort(bsServerConfig.getSecurePort()); + byte[] publicKeyBase64 = getPublicKey(bsServerConfig); if (publicKeyBase64 == null) { bsServ.setServerPublicKey(""); } else { diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index de7db7ded7..c924e109d7 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -757,7 +757,7 @@ transport: # Only Certificate_x509: skip_validity_check_for_client_cert: "${TB_LWM2M_SERVER_SECURITY_SKIP_VALIDITY_CHECK_FOR_CLIENT_CERT:false}" bootstrap: - enable: "${LWM2M_ENABLED_BS:true}" + enabled: "${LWM2M_ENABLED_BS:true}" id: "${LWM2M_SERVER_ID_BS:111}" bind_address: "${LWM2M_BS_BIND_ADDRESS:0.0.0.0}" bind_port: "${LWM2M_BS_BIND_PORT:5687}" diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/util/TbLwM2mBootstrapTransportComponent.java b/common/queue/src/main/java/org/thingsboard/server/queue/util/TbLwM2mBootstrapTransportComponent.java new file mode 100644 index 0000000000..cd9473ecfa --- /dev/null +++ b/common/queue/src/main/java/org/thingsboard/server/queue/util/TbLwM2mBootstrapTransportComponent.java @@ -0,0 +1,26 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.queue.util; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +@Retention(RetentionPolicy.RUNTIME) +@ConditionalOnExpression("('${service.type:null}'=='tb-transport' && '${transport.lwm2m.enabled:false}'=='true' && '${transport.lwm2m.bootstrap.enabled:false}'=='true') || ('${service.type:null}'=='monolith' && '${transport.lwm2m.enabled}'=='true' && '${transport.lwm2m.bootstrap.enabled}'=='true')") +public @interface TbLwM2mBootstrapTransportComponent { +} diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportBootstrapService.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportBootstrapService.java index ee14a9265d..bc2bd9b9aa 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportBootstrapService.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportBootstrapService.java @@ -21,13 +21,13 @@ import org.eclipse.californium.scandium.config.DtlsConnectorConfig; import org.eclipse.leshan.server.bootstrap.BootstrapSessionManager; import org.eclipse.leshan.server.californium.bootstrap.LeshanBootstrapServer; import org.eclipse.leshan.server.californium.bootstrap.LeshanBootstrapServerBuilder; -import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.stereotype.Component; import org.thingsboard.server.common.transport.TransportService; import org.thingsboard.server.common.transport.config.ssl.SslCredentials; +import org.thingsboard.server.queue.util.TbLwM2mBootstrapTransportComponent; +import org.thingsboard.server.transport.lwm2m.bootstrap.secure.LwM2mDefaultBootstrapSessionManager; import org.thingsboard.server.transport.lwm2m.bootstrap.store.LwM2MBootstrapSecurityStore; import org.thingsboard.server.transport.lwm2m.bootstrap.store.LwM2MInMemoryBootstrapConfigStore; -import org.thingsboard.server.transport.lwm2m.bootstrap.secure.LwM2mDefaultBootstrapSessionManager; import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportBootstrapConfig; import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; import org.thingsboard.server.transport.lwm2m.server.DefaultLwM2mTransportService; @@ -40,7 +40,7 @@ import static org.thingsboard.server.transport.lwm2m.server.LwM2MNetworkConfig.g @Slf4j @Component -@ConditionalOnExpression("('${service.type:null}'=='tb-transport' && '${transport.lwm2m.enabled:false}'=='true' && '${transport.lwm2m.bootstrap.enable:false}'=='true') || ('${service.type:null}'=='monolith' && '${transport.lwm2m.enabled:false}'=='true'&& '${transport.lwm2m.bootstrap.enable:false}'=='true')") +@TbLwM2mBootstrapTransportComponent @RequiredArgsConstructor public class LwM2MTransportBootstrapService { private boolean pskMode = false; diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MBootstrapSecurityStore.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MBootstrapSecurityStore.java index 74e5061166..1c40ae943b 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MBootstrapSecurityStore.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MBootstrapSecurityStore.java @@ -21,12 +21,12 @@ import org.eclipse.leshan.server.bootstrap.EditableBootstrapConfigStore; import org.eclipse.leshan.server.bootstrap.InvalidConfigurationException; import org.eclipse.leshan.server.security.BootstrapSecurityStore; import org.eclipse.leshan.server.security.SecurityInfo; -import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.stereotype.Service; import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MSecurityMode; import org.thingsboard.server.common.data.device.profile.Lwm2mDeviceProfileTransportConfiguration; import org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap.AbstractLwM2MBootstrapServerCredential; import org.thingsboard.server.gen.transport.TransportProtos; +import org.thingsboard.server.queue.util.TbLwM2mBootstrapTransportComponent; import org.thingsboard.server.transport.lwm2m.bootstrap.secure.LwM2MBootstrapConfig; import org.thingsboard.server.transport.lwm2m.secure.LwM2mCredentialsSecurityInfoValidator; import org.thingsboard.server.transport.lwm2m.secure.TbLwM2MSecurityInfo; @@ -48,7 +48,7 @@ import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.LO @Slf4j @Service("LwM2MBootstrapSecurityStore") -@ConditionalOnExpression("('${service.type:null}'=='tb-transport' && '${transport.lwm2m.enabled:false}'=='true' && '${transport.lwm2m.bootstrap.enable:false}'=='true') || ('${service.type:null}'=='monolith' && '${transport.lwm2m.enabled}'=='true' && '${transport.lwm2m.bootstrap.enable}'=='true')") +@TbLwM2mBootstrapTransportComponent public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore { private final EditableBootstrapConfigStore bootstrapConfigStore; diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MInMemoryBootstrapConfigStore.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MInMemoryBootstrapConfigStore.java index 485a8946f7..54120d5c1e 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MInMemoryBootstrapConfigStore.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MInMemoryBootstrapConfigStore.java @@ -22,8 +22,8 @@ import org.eclipse.leshan.server.bootstrap.BootstrapSession; import org.eclipse.leshan.server.bootstrap.ConfigurationChecker; import org.eclipse.leshan.server.bootstrap.InMemoryBootstrapConfigStore; import org.eclipse.leshan.server.bootstrap.InvalidConfigurationException; -import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.stereotype.Component; +import org.thingsboard.server.queue.util.TbLwM2mBootstrapTransportComponent; import java.util.Map; import java.util.concurrent.locks.Lock; @@ -32,7 +32,7 @@ import java.util.concurrent.locks.ReentrantReadWriteLock; @Slf4j @Component("LwM2MInMemoryBootstrapConfigStore") -@ConditionalOnExpression("('${service.type:null}'=='tb-transport' && '${transport.lwm2m.enabled:false}'=='true' && '${transport.lwm2m.bootstrap.enable:false}'=='true') || ('${service.type:null}'=='monolith' && '${transport.lwm2m.enabled}'=='true'&& '${transport.lwm2m.bootstrap.enable}'=='true')") +@TbLwM2mBootstrapTransportComponent public class LwM2MInMemoryBootstrapConfigStore extends InMemoryBootstrapConfigStore { private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock(); private final Lock readLock = readWriteLock.readLock(); diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/config/LwM2MTransportBootstrapConfig.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/config/LwM2MTransportBootstrapConfig.java index 749f7352ba..0955ab3f12 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/config/LwM2MTransportBootstrapConfig.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/config/LwM2MTransportBootstrapConfig.java @@ -20,16 +20,16 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Component; import org.thingsboard.server.common.transport.config.ssl.SslCredentials; import org.thingsboard.server.common.transport.config.ssl.SslCredentialsConfig; +import org.thingsboard.server.queue.util.TbLwM2mBootstrapTransportComponent; @Slf4j @Component -@ConditionalOnExpression("('${service.type:null}'=='tb-transport' && '${transport.lwm2m.enabled:false}'=='true') || '${service.type:null}'=='monolith' || '${service.type:null}'=='tb-core'") +@TbLwM2mBootstrapTransportComponent public class LwM2MTransportBootstrapConfig implements LwM2MSecureServerConfig { @Getter diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/config/LwM2MTransportServerConfig.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/config/LwM2MTransportServerConfig.java index a1504040a5..6c04e6ab7d 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/config/LwM2MTransportServerConfig.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/config/LwM2MTransportServerConfig.java @@ -16,25 +16,20 @@ package org.thingsboard.server.transport.lwm2m.config; import lombok.Getter; -import lombok.Setter; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Component; import org.thingsboard.server.common.transport.config.ssl.SslCredentials; import org.thingsboard.server.common.transport.config.ssl.SslCredentialsConfig; - -import javax.annotation.PostConstruct; -import java.io.InputStream; -import java.security.KeyStore; +import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; @Slf4j @Component -@ConditionalOnExpression("('${service.type:null}'=='tb-transport' && '${transport.lwm2m.enabled:false}'=='true') || '${service.type:null}'=='monolith' || '${service.type:null}'=='tb-core'") +@TbLwM2mTransportComponent public class LwM2MTransportServerConfig implements LwM2MSecureServerConfig { @Getter diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/adaptors/LwM2MJsonAdaptor.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/adaptors/LwM2MJsonAdaptor.java index 9c192ae801..fbda86629a 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/adaptors/LwM2MJsonAdaptor.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/adaptors/LwM2MJsonAdaptor.java @@ -18,18 +18,18 @@ package org.thingsboard.server.transport.lwm2m.server.adaptors; import com.google.gson.JsonElement; import com.google.gson.JsonSyntaxException; import lombok.extern.slf4j.Slf4j; -import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.stereotype.Component; import org.thingsboard.server.common.transport.adaptor.AdaptorException; import org.thingsboard.server.common.transport.adaptor.JsonConverter; import org.thingsboard.server.gen.transport.TransportProtos; +import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; import java.util.Collection; import java.util.Random; @Slf4j @Component("LwM2MJsonAdaptor") -@ConditionalOnExpression("('${service.type:null}'=='tb-transport' && '${transport.lwm2m.enabled:false}'=='true' )|| ('${service.type:null}'=='monolith' && '${transport.lwm2m.enabled}'=='true')") +@TbLwM2mTransportComponent public class LwM2MJsonAdaptor implements LwM2MTransportAdaptor { @Override diff --git a/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml b/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml index 1c4dc550a7..14366f18c6 100644 --- a/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml +++ b/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml @@ -140,7 +140,7 @@ transport: # Only Certificate_x509: skip_validity_check_for_client_cert: "${TB_LWM2M_SERVER_SECURITY_SKIP_VALIDITY_CHECK_FOR_CLIENT_CERT:false}" bootstrap: - enable: "${LWM2M_ENABLED_BS:true}" + enabled: "${LWM2M_ENABLED_BS:true}" id: "${LWM2M_SERVER_ID_BS:111}" bind_address: "${LWM2M_BS_BIND_ADDRESS:0.0.0.0}" bind_port: "${LWM2M_BS_BIND_PORT:5687}" From 2f1b61b90fa9282ad39b94075e0598a97a762d60 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Tue, 30 Nov 2021 11:46:06 +0200 Subject: [PATCH 181/432] lwm2m - fix bug Lwm2mController if bootstrap.enabled = false or lwm2m.enabled = false in *.yml --- .../org/thingsboard/server/controller/Lwm2mController.java | 4 ++-- .../thingsboard/server/service/lwm2m/LwM2MServiceImpl.java | 4 ++-- .../server/queue/util/TbLwM2mTransportComponent.java | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/Lwm2mController.java b/application/src/main/java/org/thingsboard/server/controller/Lwm2mController.java index 4d0e6fac1a..424e7d04ff 100644 --- a/application/src/main/java/org/thingsboard/server/controller/Lwm2mController.java +++ b/application/src/main/java/org/thingsboard/server/controller/Lwm2mController.java @@ -20,6 +20,7 @@ import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiParam; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestBody; @@ -32,7 +33,6 @@ import org.thingsboard.server.common.data.SaveDeviceWithCredentialsRequest; import org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap.LwM2MServerSecurityConfigDefault; import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.security.DeviceCredentials; -import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; import org.thingsboard.server.service.lwm2m.LwM2MService; import java.util.Map; @@ -42,7 +42,7 @@ import static org.thingsboard.server.controller.ControllerConstants.TENANT_OR_CU @Slf4j @RestController -@TbLwM2mTransportComponent +@ConditionalOnExpression("('${service.type:null}'=='monolith' || '${service.type:null}'=='tb-core') && '${transport.lwm2m.enabled:false}'=='true'") @RequestMapping("/api") public class Lwm2mController extends BaseController { diff --git a/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MServiceImpl.java b/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MServiceImpl.java index e74f616bf0..9e0efa831d 100644 --- a/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MServiceImpl.java +++ b/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MServiceImpl.java @@ -18,10 +18,10 @@ package org.thingsboard.server.service.lwm2m; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.commons.codec.binary.Base64; +import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.stereotype.Service; import org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap.LwM2MServerSecurityConfigDefault; import org.thingsboard.server.common.transport.config.ssl.SslCredentials; -import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; import org.thingsboard.server.transport.lwm2m.config.LwM2MSecureServerConfig; import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportBootstrapConfig; import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; @@ -31,7 +31,7 @@ import java.util.Optional; @Slf4j @Service @RequiredArgsConstructor -@TbLwM2mTransportComponent +@ConditionalOnExpression("('${service.type:null}'=='monolith' || '${service.type:null}'=='tb-core') && '${transport.lwm2m.enabled:false}'=='true'") public class LwM2MServiceImpl implements LwM2MService { private final LwM2MTransportServerConfig serverConfig; diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/util/TbLwM2mTransportComponent.java b/common/queue/src/main/java/org/thingsboard/server/queue/util/TbLwM2mTransportComponent.java index 638f9f6fb2..1bc700b74a 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/util/TbLwM2mTransportComponent.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/util/TbLwM2mTransportComponent.java @@ -21,6 +21,6 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @Retention(RetentionPolicy.RUNTIME) -@ConditionalOnExpression("('${service.type:null}'=='tb-transport' && '${transport.lwm2m.enabled:false}'=='true') || ('${service.type:null}'=='monolith' && '${transport.lwm2m.enabled}'=='true')") +@ConditionalOnExpression("('${service.type:null}'=='tb-transport' && '${transport.lwm2m.enabled:false}'=='true') || ('${service.type:null}'=='monolith' && '${transport.lwm2m.enabled:false}'=='true')") public @interface TbLwM2mTransportComponent { } From 61e7dc4a90a104d6c04dd7649c10ed2167ae3961 Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Tue, 23 Nov 2021 16:08:00 +0200 Subject: [PATCH 182/432] fixed lwm2m device or profile update notifications --- .../uplink/DefaultLwM2MUplinkMsgHandler.java | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/DefaultLwM2MUplinkMsgHandler.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/DefaultLwM2MUplinkMsgHandler.java index 7a2d27d548..dc96b1a9d2 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/DefaultLwM2MUplinkMsgHandler.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/DefaultLwM2MUplinkMsgHandler.java @@ -378,9 +378,13 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl List clients = clientContext.getLwM2mClients() .stream().filter(e -> e.getProfileId() != null) .filter(e -> e.getProfileId().equals(deviceProfile.getUuidId())).collect(Collectors.toList()); - clients.forEach(client -> client.onDeviceProfileUpdate(deviceProfile)); + clients.forEach(client -> { + this.securityStore.remove(client.getEndpoint(), client.getRegistration().getId()); + client.onDeviceProfileUpdate(deviceProfile); + }); if (clients.size() > 0) { - this.onDeviceProfileUpdate(clients, deviceProfile); + var oldProfile = clientContext.getProfile(deviceProfile.getUuidId()); + this.onDeviceProfileUpdate(clients, oldProfile, deviceProfile); } } catch (Exception e) { log.warn("[{}] failed to update profile: {}", deviceProfile.getId(), deviceProfile); @@ -392,6 +396,7 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl try { LwM2mClient client = clientContext.getClientByDeviceId(device.getUuidId()); if (client != null) { + this.securityStore.remove(client.getEndpoint(), client.getRegistration().getId()); this.onDeviceUpdate(client, device, deviceProfileOpt); } } catch (Exception e) { @@ -645,7 +650,8 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl } private void onDeviceUpdate(LwM2mClient lwM2MClient, Device device, Optional deviceProfileOpt) { - deviceProfileOpt.ifPresent(deviceProfile -> this.onDeviceProfileUpdate(Collections.singletonList(lwM2MClient), deviceProfile)); + var oldProfile = clientContext.getProfile(lwM2MClient.getProfileId()); + deviceProfileOpt.ifPresent(deviceProfile -> this.onDeviceProfileUpdate(Collections.singletonList(lwM2MClient), oldProfile, deviceProfile)); lwM2MClient.onDeviceUpdate(device, deviceProfileOpt); } @@ -754,8 +760,7 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl } //TODO: review and optimize the logic to minimize number of the requests to device. - private void onDeviceProfileUpdate(List clients, DeviceProfile deviceProfile) { - var oldProfile = clientContext.getProfile(deviceProfile.getUuidId()); + private void onDeviceProfileUpdate(List clients, Lwm2mDeviceProfileTransportConfiguration oldProfile, DeviceProfile deviceProfile) { if (clientContext.profileUpdate(deviceProfile) != null) { // #1 TelemetryMappingConfiguration oldTelemetryParams = oldProfile.getObserveAttr(); From d024c69a0cfcd37c2d39d2e7c0e30cee53dc038c Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Tue, 30 Nov 2021 12:50:02 +0200 Subject: [PATCH 183/432] improvements (remove security if a new device profile has been set) --- .../lwm2m/server/uplink/DefaultLwM2MUplinkMsgHandler.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/DefaultLwM2MUplinkMsgHandler.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/DefaultLwM2MUplinkMsgHandler.java index dc96b1a9d2..3a24a19d9b 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/DefaultLwM2MUplinkMsgHandler.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/DefaultLwM2MUplinkMsgHandler.java @@ -392,12 +392,14 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl } @Override - public void onDeviceUpdate(SessionInfoProto sessionInfo, Device device, Optional deviceProfileOpt) { + public void onDeviceUpdate(SessionInfoProto sessionInfo, Device device, Optional newDeviceProfileOpt) { try { LwM2mClient client = clientContext.getClientByDeviceId(device.getUuidId()); if (client != null) { - this.securityStore.remove(client.getEndpoint(), client.getRegistration().getId()); - this.onDeviceUpdate(client, device, deviceProfileOpt); + if (newDeviceProfileOpt.isPresent()) { + this.securityStore.remove(client.getEndpoint(), client.getRegistration().getId()); + } + this.onDeviceUpdate(client, device, newDeviceProfileOpt); } } catch (Exception e) { log.warn("[{}] failed to update device: {}", device.getId(), device); From 301d29680ab06632656022951016fc08cec08515 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Tue, 30 Nov 2021 13:22:27 +0200 Subject: [PATCH 184/432] lwm2m - fix bug Annotation for config --- .../thingsboard/server/service/lwm2m/LwM2MServiceImpl.java | 2 +- .../server/queue/util/TbLwM2mBootstrapTransportComponent.java | 2 +- .../server/queue/util/TbLwM2mTransportComponent.java | 2 +- .../transport/lwm2m/config/LwM2MTransportBootstrapConfig.java | 4 ++-- .../transport/lwm2m/config/LwM2MTransportServerConfig.java | 4 ++-- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MServiceImpl.java b/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MServiceImpl.java index 9e0efa831d..b5ec5cc654 100644 --- a/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MServiceImpl.java +++ b/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MServiceImpl.java @@ -39,7 +39,7 @@ public class LwM2MServiceImpl implements LwM2MService { @Override public LwM2MServerSecurityConfigDefault getServerSecurityInfo(boolean bootstrapServer) { - LwM2MSecureServerConfig bsServerConfig = bootstrapServer ? bootstrapConfig.isPresent() ? bootstrapConfig.get() : null : serverConfig; + LwM2MSecureServerConfig bsServerConfig = bootstrapServer ? bootstrapConfig.orElse(null) : serverConfig; if (bsServerConfig!= null) { LwM2MServerSecurityConfigDefault result = getServerSecurityConfig(bsServerConfig); result.setBootstrapServerIs(bootstrapServer); diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/util/TbLwM2mBootstrapTransportComponent.java b/common/queue/src/main/java/org/thingsboard/server/queue/util/TbLwM2mBootstrapTransportComponent.java index cd9473ecfa..938aaf3c78 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/util/TbLwM2mBootstrapTransportComponent.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/util/TbLwM2mBootstrapTransportComponent.java @@ -21,6 +21,6 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @Retention(RetentionPolicy.RUNTIME) -@ConditionalOnExpression("('${service.type:null}'=='tb-transport' && '${transport.lwm2m.enabled:false}'=='true' && '${transport.lwm2m.bootstrap.enabled:false}'=='true') || ('${service.type:null}'=='monolith' && '${transport.lwm2m.enabled}'=='true' && '${transport.lwm2m.bootstrap.enabled}'=='true')") +@ConditionalOnExpression("('${service.type:null}'=='tb-transport' || '${service.type:}'=='monolith') && '${transport.lwm2m.enabled:false}'=='true' && '${transport.lwm2m.bootstrap.enabled:false}'=='true'") public @interface TbLwM2mBootstrapTransportComponent { } diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/util/TbLwM2mTransportComponent.java b/common/queue/src/main/java/org/thingsboard/server/queue/util/TbLwM2mTransportComponent.java index 1bc700b74a..fd1f729bec 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/util/TbLwM2mTransportComponent.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/util/TbLwM2mTransportComponent.java @@ -21,6 +21,6 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @Retention(RetentionPolicy.RUNTIME) -@ConditionalOnExpression("('${service.type:null}'=='tb-transport' && '${transport.lwm2m.enabled:false}'=='true') || ('${service.type:null}'=='monolith' && '${transport.lwm2m.enabled:false}'=='true')") +@ConditionalOnExpression("('${service.type:null}'=='tb-transport' || '${service.type:}'=='monolith') && '${transport.lwm2m.enabled:false}'=='true'") public @interface TbLwM2mTransportComponent { } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/config/LwM2MTransportBootstrapConfig.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/config/LwM2MTransportBootstrapConfig.java index 0955ab3f12..83383f6950 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/config/LwM2MTransportBootstrapConfig.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/config/LwM2MTransportBootstrapConfig.java @@ -20,16 +20,16 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Component; import org.thingsboard.server.common.transport.config.ssl.SslCredentials; import org.thingsboard.server.common.transport.config.ssl.SslCredentialsConfig; -import org.thingsboard.server.queue.util.TbLwM2mBootstrapTransportComponent; @Slf4j @Component -@TbLwM2mBootstrapTransportComponent +@ConditionalOnExpression("('${service.type:null}'=='tb-transport' || '${service.type:null}'=='monolith' || '${service.type:null}'=='tb-core') && '${transport.lwm2m.enabled:false}'=='true' && '${transport.lwm2m.bootstrap.enabled:false}'=='true'") public class LwM2MTransportBootstrapConfig implements LwM2MSecureServerConfig { @Getter diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/config/LwM2MTransportServerConfig.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/config/LwM2MTransportServerConfig.java index 6c04e6ab7d..0f45d45fc4 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/config/LwM2MTransportServerConfig.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/config/LwM2MTransportServerConfig.java @@ -20,16 +20,16 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Component; import org.thingsboard.server.common.transport.config.ssl.SslCredentials; import org.thingsboard.server.common.transport.config.ssl.SslCredentialsConfig; -import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; @Slf4j @Component -@TbLwM2mTransportComponent +@ConditionalOnExpression("('${service.type:null}'=='tb-transport' || '${service.type:null}'=='monolith' || '${service.type:null}'=='tb-core') && '${transport.lwm2m.enabled:false}'=='true'") public class LwM2MTransportServerConfig implements LwM2MSecureServerConfig { @Getter From bed77a4e6ce89d8cdb131bcfe37b40753c219ae0 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Tue, 30 Nov 2021 14:00:58 +0200 Subject: [PATCH 185/432] lwm2m - fix bug test without bootstrap --- application/src/test/resources/application-test.properties | 1 + 1 file changed, 1 insertion(+) diff --git a/application/src/test/resources/application-test.properties b/application/src/test/resources/application-test.properties index 6b2e8d154b..651b00ed67 100644 --- a/application/src/test/resources/application-test.properties +++ b/application/src/test/resources/application-test.properties @@ -4,6 +4,7 @@ transport.lwm2m.server.security.credentials.keystore.store_file=lwm2m/credential transport.lwm2m.server.security.credentials.keystore.store_password=server transport.lwm2m.server.security.credentials.keystore.key_alias=server transport.lwm2m.server.security.credentials.keystore.key_password=server +transport.lwm2m.bootstrap.enabled=false transport.lwm2m.bootstrap.security.credentials.enabled=true transport.lwm2m.bootstrap.security.credentials.type=KEYSTORE transport.lwm2m.bootstrap.security.credentials.keystore.store_file=lwm2m/credentials/serverKeyStore.jks From 0909603ae5c03d1f33eba6b5a7762105586cb34f Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Tue, 30 Nov 2021 14:39:24 +0200 Subject: [PATCH 186/432] added description for the network config --- application/src/main/resources/thingsboard.yml | 6 +++--- transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index 1273555176..c5f4eaf6a0 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -819,9 +819,9 @@ transport: log_max_length: "${LWM2M_LOG_MAX_LENGTH:1024}" # Use redis for Security and Registration stores redis.enabled: "${LWM2M_REDIS_ENABLED:false}" - network_config: - - key: "PROTOCOL_STAGE_THREAD_COUNT" - value: "${LWM2M_PROTOCOL_STAGE_THREAD_COUNT:12}" + network_config: # In this section you can specify custom parameters for LwM2M network configuration and expose the env variables to configure outside +# - key: "PROTOCOL_STAGE_THREAD_COUNT" +# value: "${LWM2M_PROTOCOL_STAGE_THREAD_COUNT:4}" snmp: enabled: "${SNMP_ENABLED:true}" response_processing: diff --git a/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml b/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml index 34c08029b0..fd7c905263 100644 --- a/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml +++ b/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml @@ -204,9 +204,9 @@ transport: paging_transmission_window: "${LWM2M_PAGING_TRANSMISSION_WINDOW:10000}" # Use redis for Security and Registration stores redis.enabled: "${LWM2M_REDIS_ENABLED:false}" - network_config: - - key: "PROTOCOL_STAGE_THREAD_COUNT" - value: "${LWM2M_PROTOCOL_STAGE_THREAD_COUNT:12}" + network_config: # In this section you can specify custom parameters for LwM2M network configuration and expose the env variables to configure outside + # - key: "PROTOCOL_STAGE_THREAD_COUNT" + # value: "${LWM2M_PROTOCOL_STAGE_THREAD_COUNT:4}" stats: enabled: "${TB_TRANSPORT_STATS_ENABLED:true}" print-interval-ms: "${TB_TRANSPORT_STATS_PRINT_INTERVAL_MS:60000}" From 4c05c48cc90178eb7340747ea79643b9bf7924cf Mon Sep 17 00:00:00 2001 From: desoliture Date: Tue, 30 Nov 2021 16:20:44 +0200 Subject: [PATCH 187/432] add tests to RpcV2Controller --- .../server/controller/RpcV2Controller.java | 2 +- .../controller/BaseRpcControllerTest.java | 184 ++++++++++++++++++ .../controller/ControllerSqlTestSuite.java | 2 +- .../ComponentDescriptorControllerSqlTest.java | 3 - .../controller/sql/RpcControllerTest.java | 23 +++ 5 files changed, 209 insertions(+), 5 deletions(-) create mode 100644 application/src/test/java/org/thingsboard/server/controller/BaseRpcControllerTest.java create mode 100644 application/src/test/java/org/thingsboard/server/controller/sql/RpcControllerTest.java diff --git a/application/src/main/java/org/thingsboard/server/controller/RpcV2Controller.java b/application/src/main/java/org/thingsboard/server/controller/RpcV2Controller.java index cd3195c9f1..6eb5eb3f6a 100644 --- a/application/src/main/java/org/thingsboard/server/controller/RpcV2Controller.java +++ b/application/src/main/java/org/thingsboard/server/controller/RpcV2Controller.java @@ -225,7 +225,7 @@ public class RpcV2Controller extends AbstractRpcController { @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") @RequestMapping(value = "/persistent/{rpcId}", method = RequestMethod.DELETE) @ResponseBody - public void deleteResource( + public void deleteRpc( @ApiParam(value = RPC_ID_PARAM_DESCRIPTION, required = true) @PathVariable(RPC_ID) String strRpc) throws ThingsboardException { checkParameter("RpcId", strRpc); diff --git a/application/src/test/java/org/thingsboard/server/controller/BaseRpcControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/BaseRpcControllerTest.java new file mode 100644 index 0000000000..106bfcb238 --- /dev/null +++ b/application/src/test/java/org/thingsboard/server/controller/BaseRpcControllerTest.java @@ -0,0 +1,184 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.controller; + +import com.datastax.oss.driver.api.core.uuid.Uuids; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ObjectNode; +import org.apache.commons.lang3.RandomStringUtils; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.springframework.test.web.servlet.MvcResult; +import org.springframework.test.web.servlet.ResultActions; +import org.springframework.util.ReflectionUtils; +import org.thingsboard.common.util.JacksonUtil; +import org.thingsboard.server.common.data.*; +import org.thingsboard.server.common.data.edge.Edge; +import org.thingsboard.server.common.data.id.CustomerId; +import org.thingsboard.server.common.data.id.DeviceCredentialsId; +import org.thingsboard.server.common.data.id.DeviceId; +import org.thingsboard.server.common.data.page.PageData; +import org.thingsboard.server.common.data.page.PageLink; +import org.thingsboard.server.common.data.relation.EntityRelation; +import org.thingsboard.server.common.data.relation.RelationTypeGroup; +import org.thingsboard.server.common.data.rpc.Rpc; +import org.thingsboard.server.common.data.rpc.RpcStatus; +import org.thingsboard.server.common.data.security.Authority; +import org.thingsboard.server.common.data.security.DeviceCredentials; +import org.thingsboard.server.common.data.security.DeviceCredentialsType; +import org.thingsboard.server.dao.model.ModelConstants; + +import java.lang.reflect.Method; +import java.util.*; +import java.util.concurrent.CountDownLatch; + +import static org.hamcrest.Matchers.containsString; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.asyncDispatch; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID; + +public abstract class BaseRpcControllerTest extends AbstractControllerTest { + + private Tenant savedTenant; + private User tenantAdmin; + + @Before + public void beforeTest() throws Exception { + loginSysAdmin(); + + Tenant tenant = new Tenant(); + tenant.setTitle("My tenant"); + savedTenant = doPost("/api/tenant", tenant, Tenant.class); + Assert.assertNotNull(savedTenant); + + tenantAdmin = new User(); + tenantAdmin.setAuthority(Authority.TENANT_ADMIN); + tenantAdmin.setTenantId(savedTenant.getId()); + tenantAdmin.setEmail("tenant2@thingsboard.org"); + tenantAdmin.setFirstName("Joe"); + tenantAdmin.setLastName("Downs"); + + tenantAdmin = createUserAndLogin(tenantAdmin, "testPassword1"); + } + + @After + public void afterTest() throws Exception { + loginSysAdmin(); + + doDelete("/api/tenant/" + savedTenant.getId().getId().toString()) + .andExpect(status().isOk()); + } + + @Test + public void testSaveRpc() throws Exception { + Device device = new Device(); + device.setName("My device"); + device.setType("default"); + Device savedDevice = doPost("/api/device", device, Device.class); + + //Creating RPC + ObjectNode rpc = JacksonUtil.newObjectNode(); + rpc.put("method", "setGpio"); + + ObjectNode params = JacksonUtil.newObjectNode(); + + params.put("pin", 7); + params.put("value", 1); + + rpc.set("params", params); + rpc.put("persistent", true); + rpc.put("timeout", 5000); + + String url = "/api/rpc/oneway/" + savedDevice.getId().getId().toString(); + + //Send one-way RPC + String result = doPostAsync(url, JacksonUtil.toString(rpc), String.class, status().isOk()); + String rpcId = JacksonUtil.fromString(result, JsonNode.class) + .get("rpcId") + .asText(); + + //Get RPC by id + url = "/api/rpc/persistent/" + rpcId; + Rpc savedRpc = doGet(url, Rpc.class); + + //Assertion + Assert.assertNotNull(savedRpc); + Assert.assertEquals(savedDevice.getId(), savedRpc.getDeviceId()); + } + + @Test + public void testDeleteRpc() throws Exception { + Device device = new Device(); + device.setName("My device"); + device.setType("default"); + Device savedDevice = doPost("/api/device", device, Device.class); + + //Creating RPC + ObjectNode rpc = JacksonUtil.newObjectNode(); + rpc.put("method", "setGpio"); + + ObjectNode params = JacksonUtil.newObjectNode(); + + params.put("pin", 7); + params.put("value", 1); + + rpc.set("params", params); + rpc.put("persistent", true); + rpc.put("timeout", 5000); + + String url = "/api/rpc/oneway/" + savedDevice.getId().getId().toString(); + + //Send one-way RPC + String result = doPostAsync(url, JacksonUtil.toString(rpc), String.class, status().isOk()); + String rpcId = JacksonUtil.fromString(result, JsonNode.class) + .get("rpcId") + .asText(); + + //Get RPC by id + url = "/api/rpc/persistent/" + rpcId; + Rpc savedRpc = doGet(url, Rpc.class); + + //Deleting RPC + url = "/api/rpc/persistent/" + savedRpc.getId().getId().toString(); + MvcResult mvcResult = doDelete(url).andReturn(); + + //Try to get deleted RPC + url = "/api/rpc/persistent/" + rpcId; + MvcResult res = doGet(url).andExpect(status().isNotFound()).andReturn(); + + //Getting statusCode from delete-response + JsonNode deleteResponse = JacksonUtil.fromString(res.getResponse().getContentAsString(), JsonNode.class); + int status = deleteResponse.get("status").asInt(); + + //Assert it + Assert.assertEquals(404, status); + + //Try to get deleted RPC by device + url = "/api/rpc/persistent/device/" + savedDevice.getUuidId() + + "?" + "page=0" + "&" + + "pageSize=" + Integer.MAX_VALUE + "&" + + "rpcStatus=" + RpcStatus.DELETED.name(); + MvcResult byDeviceResult = doGet(url).andReturn(); + JsonNode byDeviceResponse = JacksonUtil.fromString(byDeviceResult.getResponse().getContentAsString(), JsonNode.class); + status = byDeviceResponse.get("status").asInt(); + + //Assert 2 + Assert.assertEquals(500, status); + } +} diff --git a/application/src/test/java/org/thingsboard/server/controller/ControllerSqlTestSuite.java b/application/src/test/java/org/thingsboard/server/controller/ControllerSqlTestSuite.java index e30ef07b5b..1973cccc46 100644 --- a/application/src/test/java/org/thingsboard/server/controller/ControllerSqlTestSuite.java +++ b/application/src/test/java/org/thingsboard/server/controller/ControllerSqlTestSuite.java @@ -30,7 +30,7 @@ import java.util.Arrays; // "org.thingsboard.server.controller.sql.EntityQueryControllerSqlTest", // "org.thingsboard.server.controller.sql.TbResourceControllerSqlTest", // "org.thingsboard.server.controller.sql.DeviceProfileControllerSqlTest", - "org.thingsboard.server.controller.sql.*Test", + "org.thingsboard.server.controller.sql.RpcControllerTest", }) public class ControllerSqlTestSuite { diff --git a/application/src/test/java/org/thingsboard/server/controller/sql/ComponentDescriptorControllerSqlTest.java b/application/src/test/java/org/thingsboard/server/controller/sql/ComponentDescriptorControllerSqlTest.java index 48a6dd0fc4..8ebf01f48a 100644 --- a/application/src/test/java/org/thingsboard/server/controller/sql/ComponentDescriptorControllerSqlTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/sql/ComponentDescriptorControllerSqlTest.java @@ -18,9 +18,6 @@ package org.thingsboard.server.controller.sql; import org.thingsboard.server.controller.BaseComponentDescriptorControllerTest; import org.thingsboard.server.dao.service.DaoSqlTest; -/** - * Created by Valerii Sosliuk on 6/28/2017. - */ @DaoSqlTest public class ComponentDescriptorControllerSqlTest extends BaseComponentDescriptorControllerTest { } diff --git a/application/src/test/java/org/thingsboard/server/controller/sql/RpcControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/sql/RpcControllerTest.java new file mode 100644 index 0000000000..2d2b58e41d --- /dev/null +++ b/application/src/test/java/org/thingsboard/server/controller/sql/RpcControllerTest.java @@ -0,0 +1,23 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.controller.sql; + +import org.thingsboard.server.controller.BaseRpcControllerTest; +import org.thingsboard.server.dao.service.DaoSqlTest; + +@DaoSqlTest +public class RpcControllerTest extends BaseRpcControllerTest { +} From 2a3f17a00fd2f0b22d7023a1dbb0539a3c1a3b77 Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Tue, 30 Nov 2021 17:35:49 +0200 Subject: [PATCH 188/432] Remove redundant parameter --- application/src/main/resources/thingsboard.yml | 1 - .../transport/lwm2m/config/LwM2MTransportServerConfig.java | 4 ---- transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml | 1 - 3 files changed, 6 deletions(-) diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index 85394e67a8..69bfd06bc8 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -816,7 +816,6 @@ transport: downlink_pool_size: "${LWM2M_DOWNLINK_POOL_SIZE:10}" ota_pool_size: "${LWM2M_OTA_POOL_SIZE:10}" clean_period_in_sec: "${LWM2M_CLEAN_PERIOD_IN_SEC:2}" - log_max_length: "${LWM2M_LOG_MAX_LENGTH:1024}" # Use redis for Security and Registration stores redis.enabled: "${LWM2M_REDIS_ENABLED:false}" snmp: diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/config/LwM2MTransportServerConfig.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/config/LwM2MTransportServerConfig.java index f444b74c2b..5c0c744eaf 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/config/LwM2MTransportServerConfig.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/config/LwM2MTransportServerConfig.java @@ -90,10 +90,6 @@ public class LwM2MTransportServerConfig implements LwM2MSecureServerConfig { @Value("${transport.lwm2m.server.security.bind_port:}") private Integer securePort; - @Getter - @Value("${transport.lwm2m.log_max_length:}") - private int logMaxLength; - @Getter @Value("${transport.lwm2m.psm_activity_timer:10000}") private long psmActivityTimer; diff --git a/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml b/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml index 8864b99e8c..52abec8f2d 100644 --- a/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml +++ b/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml @@ -199,7 +199,6 @@ transport: downlink_pool_size: "${LWM2M_DOWNLINK_POOL_SIZE:10}" ota_pool_size: "${LWM2M_OTA_POOL_SIZE:10}" clean_period_in_sec: "${LWM2M_CLEAN_PERIOD_IN_SEC:2}" - log_max_length: "${LWM2M_LOG_MAX_LENGTH:1024}" psm_activity_timer: "${LWM2M_PSM_ACTIVITY_TIMER:10000}" paging_transmission_window: "${LWM2M_PAGING_TRANSMISSION_WINDOW:10000}" # Use redis for Security and Registration stores From aa395e3c513fa6595083a34465cf9a1b4951c228 Mon Sep 17 00:00:00 2001 From: desoliture Date: Tue, 30 Nov 2021 17:55:30 +0200 Subject: [PATCH 189/432] add test for getting rpcs by device_id; refactor test class for RpcController --- .../controller/BaseRpcControllerTest.java | 156 ++++++++++-------- 1 file changed, 85 insertions(+), 71 deletions(-) diff --git a/application/src/test/java/org/thingsboard/server/controller/BaseRpcControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/BaseRpcControllerTest.java index 106bfcb238..69db64eeae 100644 --- a/application/src/test/java/org/thingsboard/server/controller/BaseRpcControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/BaseRpcControllerTest.java @@ -15,43 +15,24 @@ */ package org.thingsboard.server.controller; -import com.datastax.oss.driver.api.core.uuid.Uuids; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.ObjectNode; -import org.apache.commons.lang3.RandomStringUtils; import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.springframework.test.web.servlet.MvcResult; -import org.springframework.test.web.servlet.ResultActions; -import org.springframework.util.ReflectionUtils; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.*; -import org.thingsboard.server.common.data.edge.Edge; -import org.thingsboard.server.common.data.id.CustomerId; -import org.thingsboard.server.common.data.id.DeviceCredentialsId; -import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.page.PageData; -import org.thingsboard.server.common.data.page.PageLink; -import org.thingsboard.server.common.data.relation.EntityRelation; -import org.thingsboard.server.common.data.relation.RelationTypeGroup; import org.thingsboard.server.common.data.rpc.Rpc; import org.thingsboard.server.common.data.rpc.RpcStatus; import org.thingsboard.server.common.data.security.Authority; -import org.thingsboard.server.common.data.security.DeviceCredentials; -import org.thingsboard.server.common.data.security.DeviceCredentialsType; -import org.thingsboard.server.dao.model.ModelConstants; -import java.lang.reflect.Method; -import java.util.*; -import java.util.concurrent.CountDownLatch; +import java.util.List; -import static org.hamcrest.Matchers.containsString; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.asyncDispatch; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; -import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID; public abstract class BaseRpcControllerTest extends AbstractControllerTest { @@ -85,14 +66,15 @@ public abstract class BaseRpcControllerTest extends AbstractControllerTest { .andExpect(status().isOk()); } - @Test - public void testSaveRpc() throws Exception { + private Device createDefaultDevice() { Device device = new Device(); device.setName("My device"); device.setType("default"); - Device savedDevice = doPost("/api/device", device, Device.class); - //Creating RPC + return device; + } + + private ObjectNode createDefaultRpc() { ObjectNode rpc = JacksonUtil.newObjectNode(); rpc.put("method", "setGpio"); @@ -105,17 +87,41 @@ public abstract class BaseRpcControllerTest extends AbstractControllerTest { rpc.put("persistent", true); rpc.put("timeout", 5000); - String url = "/api/rpc/oneway/" + savedDevice.getId().getId().toString(); + return rpc; + } - //Send one-way RPC - String result = doPostAsync(url, JacksonUtil.toString(rpc), String.class, status().isOk()); + private Rpc getRpcById(String rpcId) throws Exception { + return doGet("/api/rpc/persistent/" + rpcId, Rpc.class); + } + + private MvcResult removeRpcById(String rpcId) throws Exception { + return doDelete("/api/rpc/persistent/" + rpcId).andReturn(); + } + + private MvcResult getRpcByDeviceId(String deviceId) throws Exception { + String url = "/api/rpc/persistent/device/" + deviceId + + "?" + "page=0" + "&" + + "pageSize=" + Integer.MAX_VALUE + "&" + + "rpcStatus=" + RpcStatus.DELETED.name(); + return doGet(url).andReturn(); + } + + @Test + public void testSaveRpc() throws Exception { + Device device = createDefaultDevice(); + Device savedDevice = doPost("/api/device", device, Device.class); + + ObjectNode rpc = createDefaultRpc(); + String result = doPostAsync( + "/api/rpc/oneway/" + savedDevice.getId().getId().toString(), + JacksonUtil.toString(rpc), + String.class, + status().isOk() + ); String rpcId = JacksonUtil.fromString(result, JsonNode.class) .get("rpcId") .asText(); - - //Get RPC by id - url = "/api/rpc/persistent/" + rpcId; - Rpc savedRpc = doGet(url, Rpc.class); + Rpc savedRpc = getRpcById(rpcId); //Assertion Assert.assertNotNull(savedRpc); @@ -124,61 +130,69 @@ public abstract class BaseRpcControllerTest extends AbstractControllerTest { @Test public void testDeleteRpc() throws Exception { - Device device = new Device(); - device.setName("My device"); - device.setType("default"); + Device device = createDefaultDevice(); Device savedDevice = doPost("/api/device", device, Device.class); - //Creating RPC - ObjectNode rpc = JacksonUtil.newObjectNode(); - rpc.put("method", "setGpio"); + ObjectNode rpc = createDefaultRpc(); + String result = doPostAsync( + "/api/rpc/oneway/" + savedDevice.getId().getId().toString(), + JacksonUtil.toString(rpc), + String.class, + status().isOk() + ); + String rpcId = JacksonUtil.fromString(result, JsonNode.class) + .get("rpcId") + .asText(); + Rpc savedRpc = getRpcById(rpcId); - ObjectNode params = JacksonUtil.newObjectNode(); + MvcResult mvcResult = removeRpcById(savedRpc.getId().getId().toString()); + MvcResult res = doGet("/api/rpc/persistent/" + rpcId) + .andExpect(status().isNotFound()) + .andReturn(); - params.put("pin", 7); - params.put("value", 1); + JsonNode deleteResponse = JacksonUtil.fromString(res.getResponse().getContentAsString(), JsonNode.class); + Assert.assertEquals(404, deleteResponse.get("status").asInt()); - rpc.set("params", params); - rpc.put("persistent", true); - rpc.put("timeout", 5000); + MvcResult byDeviceResult = getRpcByDeviceId(savedDevice.getUuidId().toString()); + JsonNode byDeviceResponse = JacksonUtil.fromString(byDeviceResult.getResponse().getContentAsString(), JsonNode.class); + + Assert.assertEquals(500, byDeviceResponse.get("status").asInt()); + } + + @Test + public void testGetRpcsByDeviceId() throws Exception { + Device device = createDefaultDevice(); + Device savedDevice = doPost("/api/device", device, Device.class); - String url = "/api/rpc/oneway/" + savedDevice.getId().getId().toString(); + ObjectNode rpc = createDefaultRpc(); - //Send one-way RPC - String result = doPostAsync(url, JacksonUtil.toString(rpc), String.class, status().isOk()); + String result = doPostAsync( + "/api/rpc/oneway/" + savedDevice.getId().getId().toString(), + JacksonUtil.toString(rpc), + String.class, + status().isOk() + ); String rpcId = JacksonUtil.fromString(result, JsonNode.class) .get("rpcId") .asText(); - //Get RPC by id - url = "/api/rpc/persistent/" + rpcId; - Rpc savedRpc = doGet(url, Rpc.class); - - //Deleting RPC - url = "/api/rpc/persistent/" + savedRpc.getId().getId().toString(); - MvcResult mvcResult = doDelete(url).andReturn(); + String url = "/api/rpc/persistent/device/" + savedDevice.getId().getId() + + "?" + "page=0" + "&" + + "pageSize=" + Integer.MAX_VALUE + "&" + + "rpcStatus=" + RpcStatus.QUEUED; - //Try to get deleted RPC - url = "/api/rpc/persistent/" + rpcId; - MvcResult res = doGet(url).andExpect(status().isNotFound()).andReturn(); + MvcResult byDeviceResult = doGetAsync(url).andReturn(); - //Getting statusCode from delete-response - JsonNode deleteResponse = JacksonUtil.fromString(res.getResponse().getContentAsString(), JsonNode.class); - int status = deleteResponse.get("status").asInt(); + String rpcs = byDeviceResult.getResponse().getContentAsString(); + PageData byDeviceResponse = JacksonUtil.fromString(byDeviceResult.getResponse().getContentAsString(), new TypeReference>() {}); - //Assert it - Assert.assertEquals(404, status); + List byDeviceRpcs = byDeviceResponse.getData(); - //Try to get deleted RPC by device - url = "/api/rpc/persistent/device/" + savedDevice.getUuidId() - + "?" + "page=0" + "&" + - "pageSize=" + Integer.MAX_VALUE + "&" + - "rpcStatus=" + RpcStatus.DELETED.name(); - MvcResult byDeviceResult = doGet(url).andReturn(); - JsonNode byDeviceResponse = JacksonUtil.fromString(byDeviceResult.getResponse().getContentAsString(), JsonNode.class); - status = byDeviceResponse.get("status").asInt(); + boolean found = byDeviceRpcs.stream().anyMatch(r -> + r.getUuidId().toString().equals(rpcId) + && r.getDeviceId().equals(savedDevice.getId()) + ); - //Assert 2 - Assert.assertEquals(500, status); + Assert.assertTrue(found); } } From d854bab8cbd1861fd1ba3939a7156c373317dcdd Mon Sep 17 00:00:00 2001 From: desoliture Date: Wed, 1 Dec 2021 11:13:39 +0200 Subject: [PATCH 190/432] refactor RpcController tests --- .../controller/BaseRpcControllerTest.java | 24 +++++++++---------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/application/src/test/java/org/thingsboard/server/controller/BaseRpcControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/BaseRpcControllerTest.java index 69db64eeae..2881a5194a 100644 --- a/application/src/test/java/org/thingsboard/server/controller/BaseRpcControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/BaseRpcControllerTest.java @@ -98,14 +98,6 @@ public abstract class BaseRpcControllerTest extends AbstractControllerTest { return doDelete("/api/rpc/persistent/" + rpcId).andReturn(); } - private MvcResult getRpcByDeviceId(String deviceId) throws Exception { - String url = "/api/rpc/persistent/device/" + deviceId - + "?" + "page=0" + "&" + - "pageSize=" + Integer.MAX_VALUE + "&" + - "rpcStatus=" + RpcStatus.DELETED.name(); - return doGet(url).andReturn(); - } - @Test public void testSaveRpc() throws Exception { Device device = createDefaultDevice(); @@ -123,7 +115,6 @@ public abstract class BaseRpcControllerTest extends AbstractControllerTest { .asText(); Rpc savedRpc = getRpcById(rpcId); - //Assertion Assert.assertNotNull(savedRpc); Assert.assertEquals(savedDevice.getId(), savedRpc.getDeviceId()); } @@ -153,7 +144,11 @@ public abstract class BaseRpcControllerTest extends AbstractControllerTest { JsonNode deleteResponse = JacksonUtil.fromString(res.getResponse().getContentAsString(), JsonNode.class); Assert.assertEquals(404, deleteResponse.get("status").asInt()); - MvcResult byDeviceResult = getRpcByDeviceId(savedDevice.getUuidId().toString()); + String url = "/api/rpc/persistent/device/" + savedDevice.getUuidId().toString() + + "?" + "page=0" + "&" + + "pageSize=" + Integer.MAX_VALUE + "&" + + "rpcStatus=" + RpcStatus.DELETED.name(); + MvcResult byDeviceResult = doGet(url).andReturn(); JsonNode byDeviceResponse = JacksonUtil.fromString(byDeviceResult.getResponse().getContentAsString(), JsonNode.class); Assert.assertEquals(500, byDeviceResponse.get("status").asInt()); @@ -183,10 +178,13 @@ public abstract class BaseRpcControllerTest extends AbstractControllerTest { MvcResult byDeviceResult = doGetAsync(url).andReturn(); - String rpcs = byDeviceResult.getResponse().getContentAsString(); - PageData byDeviceResponse = JacksonUtil.fromString(byDeviceResult.getResponse().getContentAsString(), new TypeReference>() {}); + List byDeviceRpcs = JacksonUtil.fromString( + byDeviceResult + .getResponse() + .getContentAsString(), + new TypeReference>() {} + ).getData(); - List byDeviceRpcs = byDeviceResponse.getData(); boolean found = byDeviceRpcs.stream().anyMatch(r -> r.getUuidId().toString().equals(rpcId) From 3f67de38426dd649a1611c74eb50dddef8c5112f Mon Sep 17 00:00:00 2001 From: desoliture Date: Wed, 1 Dec 2021 11:30:16 +0200 Subject: [PATCH 191/432] refactor --- .../java/org/thingsboard/server/controller/RpcV2Controller.java | 1 + .../thingsboard/server/controller/ControllerSqlTestSuite.java | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/RpcV2Controller.java b/application/src/main/java/org/thingsboard/server/controller/RpcV2Controller.java index 6eb5eb3f6a..35968fed22 100644 --- a/application/src/main/java/org/thingsboard/server/controller/RpcV2Controller.java +++ b/application/src/main/java/org/thingsboard/server/controller/RpcV2Controller.java @@ -241,6 +241,7 @@ public class RpcV2Controller extends AbstractRpcController { } rpcService.deleteRpc(getTenantId(), rpcId); + rpc.setStatus(RpcStatus.DELETED); TbMsg msg = TbMsg.newMsg(RPC_DELETED, rpc.getDeviceId(), TbMsgMetaData.EMPTY, JacksonUtil.toString(rpc)); tbClusterService.pushMsgToRuleEngine(getTenantId(), rpc.getDeviceId(), msg, null); diff --git a/application/src/test/java/org/thingsboard/server/controller/ControllerSqlTestSuite.java b/application/src/test/java/org/thingsboard/server/controller/ControllerSqlTestSuite.java index 1973cccc46..e30ef07b5b 100644 --- a/application/src/test/java/org/thingsboard/server/controller/ControllerSqlTestSuite.java +++ b/application/src/test/java/org/thingsboard/server/controller/ControllerSqlTestSuite.java @@ -30,7 +30,7 @@ import java.util.Arrays; // "org.thingsboard.server.controller.sql.EntityQueryControllerSqlTest", // "org.thingsboard.server.controller.sql.TbResourceControllerSqlTest", // "org.thingsboard.server.controller.sql.DeviceProfileControllerSqlTest", - "org.thingsboard.server.controller.sql.RpcControllerTest", + "org.thingsboard.server.controller.sql.*Test", }) public class ControllerSqlTestSuite { From 05408d357ed2cbd396a40a1dc9b16930923e687c Mon Sep 17 00:00:00 2001 From: ArtemDzhereleiko Date: Wed, 1 Dec 2021 11:32:32 +0200 Subject: [PATCH 192/432] UI: On tables hide page size option on mobile view --- .../attribute/attribute-table.component.html | 1 + .../attribute/attribute-table.component.ts | 23 ++++++++++-- .../entity/entities-table.component.html | 1 + .../entity/entities-table.component.ts | 21 ++++++++++- .../relation/relation-table.component.html | 3 +- .../relation/relation-table.component.ts | 35 +++++++++++++++++-- .../lib/alarms-table-widget.component.html | 3 +- .../lib/alarms-table-widget.component.ts | 15 ++++++++ .../lib/entities-table-widget.component.html | 3 +- .../lib/entities-table-widget.component.ts | 20 +++++++++++ .../timeseries-table-widget.component.html | 3 +- .../lib/timeseries-table-widget.component.ts | 15 ++++++++ 12 files changed, 133 insertions(+), 10 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/attribute/attribute-table.component.html b/ui-ngx/src/app/modules/home/components/attribute/attribute-table.component.html index ead92fda03..c0612646f3 100644 --- a/ui-ngx/src/app/modules/home/components/attribute/attribute-table.component.html +++ b/ui-ngx/src/app/modules/home/components/attribute/attribute-table.component.html @@ -196,6 +196,7 @@ [pageIndex]="pageLink.page" [pageSize]="pageLink.pageSize" [pageSizeOptions]="[10, 20, 30]" + [hidePageSize]="hidePageSize" showFirstLastButtons> , private attributeService: AttributeService, private telemetryWsService: TelemetryWebsocketService, @@ -184,7 +189,8 @@ export class AttributeTableComponent extends PageComponent implements AfterViewI private dashboardUtils: DashboardUtilsService, private widgetService: WidgetService, private zone: NgZone, - private cd: ChangeDetectorRef) { + private cd: ChangeDetectorRef, + private breakpointObserver: BreakpointObserver) { super(store); this.dirtyValue = !this.activeValue; const sortOrder: SortOrder = { property: 'key', direction: Direction.ASC }; @@ -193,6 +199,19 @@ export class AttributeTableComponent extends PageComponent implements AfterViewI } ngOnInit() { + this.breakpointObserverSubscription$ = this.breakpointObserver + .observe(MediaBreakpoints['gt-xs']).subscribe( + () => { + this.hidePageSize = !this.breakpointObserver.isMatched(MediaBreakpoints['gt-xs']); + this.cd.detectChanges(); + } + ); + } + + ngOnDestroy() { + if (this.breakpointObserverSubscription$) { + this.breakpointObserverSubscription$.unsubscribe(); + } } attributeScopeChanged(attributeScope: TelemetryType) { diff --git a/ui-ngx/src/app/modules/home/components/entity/entities-table.component.html b/ui-ngx/src/app/modules/home/components/entity/entities-table.component.html index c4f470bbd2..a7b15670bb 100644 --- a/ui-ngx/src/app/modules/home/components/entity/entities-table.component.html +++ b/ui-ngx/src/app/modules/home/components/entity/entities-table.component.html @@ -266,6 +266,7 @@ [pageIndex]="pageLink.page" [pageSize]="pageLink.pageSize" [pageSizeOptions]="pageSizeOptions" + [hidePageSize]="hidePageSize" showFirstLastButtons> diff --git a/ui-ngx/src/app/modules/home/components/entity/entities-table.component.ts b/ui-ngx/src/app/modules/home/components/entity/entities-table.component.ts index 49386db131..cca386570d 100644 --- a/ui-ngx/src/app/modules/home/components/entity/entities-table.component.ts +++ b/ui-ngx/src/app/modules/home/components/entity/entities-table.component.ts @@ -64,6 +64,8 @@ import { DomSanitizer, SafeHtml } from '@angular/platform-browser'; import { TbAnchorComponent } from '@shared/components/tb-anchor.component'; import { isDefined, isUndefined } from '@core/utils'; import { HasUUID } from '@shared/models/id/has-uuid'; +import { MediaBreakpoints } from '@shared/models/constants'; +import { BreakpointObserver } from '@angular/cdk/layout'; @Component({ selector: 'tb-entities-table', @@ -120,6 +122,9 @@ export class EntitiesTableComponent extends PageComponent implements AfterViewIn private updateDataSubscription: Subscription; private viewInited = false; + private breakpointObserverSubscription$: Subscription; + public hidePageSize = true; + constructor(protected store: Store, public route: ActivatedRoute, public translate: TranslateService, @@ -127,7 +132,8 @@ export class EntitiesTableComponent extends PageComponent implements AfterViewIn private dialogService: DialogService, private domSanitizer: DomSanitizer, private cd: ChangeDetectorRef, - private componentFactoryResolver: ComponentFactoryResolver) { + private componentFactoryResolver: ComponentFactoryResolver, + private breakpointObserver: BreakpointObserver) { super(store); } @@ -137,6 +143,19 @@ export class EntitiesTableComponent extends PageComponent implements AfterViewIn } else { this.init(this.route.snapshot.data.entitiesTableConfig); } + this.breakpointObserverSubscription$ = this.breakpointObserver + .observe(MediaBreakpoints['gt-xs']).subscribe( + () => { + this.hidePageSize = !this.breakpointObserver.isMatched(MediaBreakpoints['gt-xs']); + this.cd.detectChanges(); + } + ); + } + + ngOnDestroy() { + if (this.breakpointObserverSubscription$) { + this.breakpointObserverSubscription$.unsubscribe(); + } } ngOnChanges(changes: SimpleChanges): void { diff --git a/ui-ngx/src/app/modules/home/components/relation/relation-table.component.html b/ui-ngx/src/app/modules/home/components/relation/relation-table.component.html index 01c2e0e4ab..b5ae8c2d52 100644 --- a/ui-ngx/src/app/modules/home/components/relation/relation-table.component.html +++ b/ui-ngx/src/app/modules/home/components/relation/relation-table.component.html @@ -165,6 +165,7 @@ + [pageSizeOptions]="[10, 20, 30]" + [hidePageSize]="hidePageSize"> diff --git a/ui-ngx/src/app/modules/home/components/relation/relation-table.component.ts b/ui-ngx/src/app/modules/home/components/relation/relation-table.component.ts index b10ed82249..2ea0ccfa12 100644 --- a/ui-ngx/src/app/modules/home/components/relation/relation-table.component.ts +++ b/ui-ngx/src/app/modules/home/components/relation/relation-table.component.ts @@ -14,7 +14,16 @@ /// limitations under the License. /// -import { AfterViewInit, ChangeDetectionStrategy, Component, ElementRef, Input, OnInit, ViewChild } from '@angular/core'; +import { + AfterViewInit, + ChangeDetectionStrategy, + ChangeDetectorRef, + Component, + ElementRef, + Input, + OnInit, + ViewChild +} from '@angular/core'; import { PageComponent } from '@shared/components/page.component'; import { PageLink } from '@shared/models/page/page-link'; import { MatPaginator } from '@angular/material/paginator'; @@ -26,7 +35,7 @@ import { MatDialog } from '@angular/material/dialog'; import { DialogService } from '@core/services/dialog.service'; import { EntityRelationService } from '@core/http/entity-relation.service'; import { Direction, SortOrder } from '@shared/models/page/sort-order'; -import { forkJoin, fromEvent, merge, Observable } from 'rxjs'; +import { forkJoin, fromEvent, merge, Observable, Subscription } from 'rxjs'; import { debounceTime, distinctUntilChanged, tap } from 'rxjs/operators'; import { EntityRelation, @@ -38,6 +47,8 @@ import { import { EntityId } from '@shared/models/id/entity-id'; import { RelationsDatasource } from '../../models/datasource/relation-datasource'; import { RelationDialogComponent, RelationDialogData } from '@home/components/relation/relation-dialog.component'; +import { MediaBreakpoints } from '@shared/models/constants'; +import { BreakpointObserver } from '@angular/cdk/layout'; @Component({ selector: 'tb-relation-table', @@ -65,6 +76,9 @@ export class RelationTableComponent extends PageComponent implements AfterViewIn viewsInited = false; + private breakpointObserverSubscription$: Subscription; + public hidePageSize = true; + @Input() set active(active: boolean) { if (this.activeValue !== active) { @@ -100,7 +114,9 @@ export class RelationTableComponent extends PageComponent implements AfterViewIn private entityRelationService: EntityRelationService, public translate: TranslateService, public dialog: MatDialog, - private dialogService: DialogService) { + private dialogService: DialogService, + private cd: ChangeDetectorRef, + private breakpointObserver: BreakpointObserver) { super(store); this.dirtyValue = !this.activeValue; const sortOrder: SortOrder = { property: 'type', direction: Direction.ASC }; @@ -111,6 +127,19 @@ export class RelationTableComponent extends PageComponent implements AfterViewIn } ngOnInit() { + this.breakpointObserverSubscription$ = this.breakpointObserver + .observe(MediaBreakpoints['gt-xs']).subscribe( + () => { + this.hidePageSize = !this.breakpointObserver.isMatched(MediaBreakpoints['gt-xs']); + this.cd.detectChanges(); + } + ); + } + + ngOnDestroy() { + if (this.breakpointObserverSubscription$) { + this.breakpointObserverSubscription$.unsubscribe(); + } } updateColumns() { diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.html index a86da23f59..872e040bad 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.html @@ -15,7 +15,7 @@ limitations under the License. --> -
+
@@ -147,6 +147,7 @@ [pageIndex]="pageLink.page" [pageSize]="pageLink.pageSize" [pageSizeOptions]="pageSizeOptions" + [hidePageSize]="hidePageSize" showFirstLastButtons>
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.ts index 7b32d84e71..73c7ea20cd 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.ts @@ -123,6 +123,7 @@ import { } from '@home/components/widget/lib/alarm-filter-panel.component'; import { entityFields } from '@shared/models/entity.models'; import { coerceBooleanProperty } from '@angular/cdk/coercion'; +import { ResizeObserver } from '@juggle/resize-observer'; interface AlarmsTableWidgetSettings extends TableWidgetSettings { alarmsTitle: string; @@ -152,6 +153,7 @@ export class AlarmsTableWidgetComponent extends PageComponent implements OnInit, @Input() ctx: WidgetContext; + @ViewChild('alarmWidgetContainer', {static: true}) alarmWidgetContainerRef: ElementRef; @ViewChild('searchInput') searchInputField: ElementRef; @ViewChild(MatPaginator) paginator: MatPaginator; @ViewChild(MatSort) sort: MatSort; @@ -168,6 +170,7 @@ export class AlarmsTableWidgetComponent extends PageComponent implements OnInit, public displayedColumns: string[] = []; public alarmsDatasource: AlarmsDatasource; public noDataDisplayMessageText: string; + public hidePageSize = false; private setCellButtonAction: boolean; private cellContentCache: Array = []; @@ -177,6 +180,7 @@ export class AlarmsTableWidgetComponent extends PageComponent implements OnInit, private settings: AlarmsTableWidgetSettings; private widgetConfig: WidgetConfig; private subscription: IWidgetSubscription; + private widgetResize$: ResizeObserver; private alarmsTitlePattern: string; @@ -257,6 +261,14 @@ export class AlarmsTableWidgetComponent extends PageComponent implements OnInit, this.widgetTimewindowChanged$ = this.ctx.defaultSubscription.widgetTimewindowChanged$.subscribe( () => this.pageLink.page = 0 ); + this.widgetResize$ = new ResizeObserver(() => { + const showHidePageSize = this.ctx.$container[0].offsetWidth < 450; + if (showHidePageSize !== this.hidePageSize) { + this.hidePageSize = showHidePageSize; + this.ctx.detectChanges(); + } + }); + this.widgetResize$.observe(this.alarmWidgetContainerRef.nativeElement); } } @@ -265,6 +277,9 @@ export class AlarmsTableWidgetComponent extends PageComponent implements OnInit, this.widgetTimewindowChanged$.unsubscribe(); this.widgetTimewindowChanged$ = null; } + if (this.widgetResize$) { + this.widgetResize$.disconnect(); + } } ngAfterViewInit(): void { diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.html index 74ccd53ec2..7f8ae9b9b1 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.html @@ -15,7 +15,7 @@ limitations under the License. --> -
+
@@ -106,6 +106,7 @@ [pageIndex]="pageLink.page" [pageSize]="pageLink.pageSize" [pageSizeOptions]="pageSizeOptions" + [hidePageSize]="hidePageSize" showFirstLastButtons>
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.ts index bd52f2ab9b..a89c1ebe82 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.ts @@ -107,6 +107,7 @@ import { sortItems } from '@shared/models/page/page-link'; import { entityFields } from '@shared/models/entity.models'; import { DatePipe } from '@angular/common'; import { coerceBooleanProperty } from '@angular/cdk/coercion'; +import { ResizeObserver } from '@juggle/resize-observer'; interface EntitiesTableWidgetSettings extends TableWidgetSettings { entitiesTitle: string; @@ -129,6 +130,7 @@ export class EntitiesTableWidgetComponent extends PageComponent implements OnIni @Input() ctx: WidgetContext; + @ViewChild('entitiesWidgetContainer', {static: true}) entitiesWidgetContainerRef: ElementRef; @ViewChild('searchInput') searchInputField: ElementRef; @ViewChild(MatPaginator) paginator: MatPaginator; @ViewChild(MatSort) sort: MatSort; @@ -144,6 +146,7 @@ export class EntitiesTableWidgetComponent extends PageComponent implements OnIni public displayedColumns: string[] = []; public entityDatasource: EntityDatasource; public noDataDisplayMessageText: string; + public hidePageSize = false; private setCellButtonAction: boolean; private cellContentCache: Array = []; @@ -153,6 +156,7 @@ export class EntitiesTableWidgetComponent extends PageComponent implements OnIni private settings: EntitiesTableWidgetSettings; private widgetConfig: WidgetConfig; private subscription: IWidgetSubscription; + private widgetResize$: ResizeObserver; private entitiesTitlePattern: string; @@ -211,6 +215,22 @@ export class EntitiesTableWidgetComponent extends PageComponent implements OnIni this.initializeConfig(); this.updateDatasources(); this.ctx.updateWidgetParams(); + if (this.displayPagination) { + this.widgetResize$ = new ResizeObserver(() => { + const showHidePageSize = this.ctx.$container[0].offsetWidth < 450; + if (showHidePageSize !== this.hidePageSize) { + this.hidePageSize = showHidePageSize; + this.ctx.detectChanges(); + } + }); + this.widgetResize$.observe(this.entitiesWidgetContainerRef.nativeElement); + } + } + + ngOnDestroy(): void { + if (this.widgetResize$) { + this.widgetResize$.disconnect(); + } } ngAfterViewInit(): void { diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.html index 8c3b9084b0..236d81036c 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.html @@ -15,7 +15,7 @@ limitations under the License. --> -
+
@@ -112,6 +112,7 @@ [pageIndex]="source.pageLink.page" [pageSize]="source.pageLink.pageSize" [pageSizeOptions]="pageSizeOptions" + [hidePageSize]="hidePageSize" showFirstLastButtons> diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.ts index de8cec8dc7..183832ae90 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.ts @@ -71,6 +71,7 @@ import { SubscriptionEntityInfo } from '@core/api/widget-api.models'; import { DatePipe } from '@angular/common'; import { parseData } from '@home/components/widget/lib/maps/common-maps-utils'; import { coerceBooleanProperty } from '@angular/cdk/coercion'; +import { ResizeObserver } from '@juggle/resize-observer'; export interface TimeseriesTableWidgetSettings extends TableWidgetSettings { showTimestamp: boolean; @@ -115,6 +116,7 @@ export class TimeseriesTableWidgetComponent extends PageComponent implements OnI @Input() ctx: WidgetContext; + @ViewChild('timeseriesWidgetContainer', {static: true}) timeseriesWidgetContainerRef: ElementRef; @ViewChild('searchInput') searchInputField: ElementRef; @ViewChildren(MatPaginator) paginators: QueryList; @ViewChildren(MatSort) sorts: QueryList; @@ -128,6 +130,7 @@ export class TimeseriesTableWidgetComponent extends PageComponent implements OnI public sources: TimeseriesTableSource[]; public sourceIndex: number; public noDataDisplayMessageText: string; + public hidePageSize = false; private setCellButtonAction: boolean; private cellContentCache: Array = []; @@ -150,6 +153,7 @@ export class TimeseriesTableWidgetComponent extends PageComponent implements OnI private subscriptions: Subscription[] = []; private widgetTimewindowChanged$: Subscription; + private widgetResize$: ResizeObserver; private searchAction: WidgetAction = { name: 'action.search', @@ -190,6 +194,14 @@ export class TimeseriesTableWidgetComponent extends PageComponent implements OnI }); } ); + this.widgetResize$ = new ResizeObserver(() => { + const showHidePageSize = this.ctx.$container[0].offsetWidth < 450; + if (showHidePageSize !== this.hidePageSize) { + this.hidePageSize = showHidePageSize; + this.ctx.detectChanges(); + } + }); + this.widgetResize$.observe(this.timeseriesWidgetContainerRef.nativeElement); } } @@ -198,6 +210,9 @@ export class TimeseriesTableWidgetComponent extends PageComponent implements OnI this.widgetTimewindowChanged$.unsubscribe(); this.widgetTimewindowChanged$ = null; } + if (this.widgetResize$) { + this.widgetResize$.disconnect(); + } } ngAfterViewInit(): void { From 5f11fa9b6cd04370d85a7075fe00ae85880e8035 Mon Sep 17 00:00:00 2001 From: ArtemDzhereleiko Date: Wed, 1 Dec 2021 12:23:06 +0200 Subject: [PATCH 193/432] UI: On tables hide page size option on mobile view --- .../home/components/widget/lib/alarms-table-widget.component.ts | 2 +- .../components/widget/lib/entities-table-widget.component.ts | 2 +- .../components/widget/lib/timeseries-table-widget.component.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.ts index 73c7ea20cd..8f003141e8 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.ts @@ -262,7 +262,7 @@ export class AlarmsTableWidgetComponent extends PageComponent implements OnInit, () => this.pageLink.page = 0 ); this.widgetResize$ = new ResizeObserver(() => { - const showHidePageSize = this.ctx.$container[0].offsetWidth < 450; + const showHidePageSize = this.ctx.$container[0].offsetWidth < 500; if (showHidePageSize !== this.hidePageSize) { this.hidePageSize = showHidePageSize; this.ctx.detectChanges(); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.ts index a89c1ebe82..2c887a1668 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.ts @@ -217,7 +217,7 @@ export class EntitiesTableWidgetComponent extends PageComponent implements OnIni this.ctx.updateWidgetParams(); if (this.displayPagination) { this.widgetResize$ = new ResizeObserver(() => { - const showHidePageSize = this.ctx.$container[0].offsetWidth < 450; + const showHidePageSize = this.ctx.$container[0].offsetWidth < 500; if (showHidePageSize !== this.hidePageSize) { this.hidePageSize = showHidePageSize; this.ctx.detectChanges(); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.ts index 183832ae90..cc35c481a8 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.ts @@ -195,7 +195,7 @@ export class TimeseriesTableWidgetComponent extends PageComponent implements OnI } ); this.widgetResize$ = new ResizeObserver(() => { - const showHidePageSize = this.ctx.$container[0].offsetWidth < 450; + const showHidePageSize = this.ctx.$container[0].offsetWidth < 500; if (showHidePageSize !== this.hidePageSize) { this.hidePageSize = showHidePageSize; this.ctx.detectChanges(); From 12dcbf0e5e7e73abd3920b18dfaa74273a7f4006 Mon Sep 17 00:00:00 2001 From: ArtemDzhereleiko Date: Wed, 1 Dec 2021 12:37:30 +0200 Subject: [PATCH 194/432] UI: Hide pageSizeOption on persistent table widget --- .../lib/rpc/persistent-table.component.html | 3 ++- .../lib/rpc/persistent-table.component.ts | 20 +++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-table.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-table.component.html index c4fc2428be..fd86fd92cc 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-table.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-table.component.html @@ -15,7 +15,7 @@ limitations under the License. --> -
+
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-table.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-table.component.ts index 8f5ccab14b..f2c6f9e13f 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-table.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-table.component.ts @@ -67,6 +67,7 @@ import { PERSISTENT_FILTER_PANEL_DATA, PersistentFilterPanelComponent, PersistentFilterPanelData } from '@home/components/widget/lib/rpc/persistent-filter-panel.component'; import { PersistentAddDialogComponent } from '@home/components/widget/lib/rpc/persistent-add-dialog.component'; +import { ResizeObserver } from '@juggle/resize-observer'; interface PersistentTableWidgetSettings extends TableWidgetSettings { defaultSortOrder: string; @@ -97,6 +98,7 @@ export class PersistentTableComponent extends PageComponent implements OnInit { @Input() ctx: WidgetContext; + @ViewChild('persistentWidgetContainer', {static: true}) persistentWidgetContainerRef: ElementRef; @ViewChild(MatPaginator) paginator: MatPaginator; @ViewChild(MatSort) sort: MatSort; @@ -111,6 +113,7 @@ export class PersistentTableComponent extends PageComponent implements OnInit { private displayDetails = true; private allowDelete = true; private displayTableColumns: string[]; + private widgetResize$: ResizeObserver; public persistentDatasource: PersistentDatasource; public noDataDisplayMessageText: string; @@ -123,6 +126,7 @@ export class PersistentTableComponent extends PageComponent implements OnInit { public pageSizeOptions; public actionCellButtonAction: PersistentTableWidgetActionDescriptor[] = []; public displayedColumns: string[]; + public hidePageSize = false; constructor(protected store: Store, private elementRef: ElementRef, @@ -143,6 +147,22 @@ export class PersistentTableComponent extends PageComponent implements OnInit { this.subscription = this.ctx.defaultSubscription; this.initializeConfig(); this.ctx.updateWidgetParams(); + if (this.displayPagination) { + this.widgetResize$ = new ResizeObserver(() => { + const showHidePageSize = this.ctx.$container[0].offsetWidth < 500; + if (showHidePageSize !== this.hidePageSize) { + this.hidePageSize = showHidePageSize; + this.ctx.detectChanges(); + } + }); + this.widgetResize$.observe(this.persistentWidgetContainerRef.nativeElement); + } + } + + ngOnDestroy() { + if (this.widgetResize$) { + this.widgetResize$.disconnect(); + } } ngAfterViewInit(): void { From 046ca0b26498ae2a74d9f6861e60c14fbc910061 Mon Sep 17 00:00:00 2001 From: desoliture Date: Wed, 1 Dec 2021 13:11:29 +0200 Subject: [PATCH 195/432] improve devices search --- .../server/dao/sql/device/DeviceRepository.java | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/device/DeviceRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/device/DeviceRepository.java index 2deae0bbe1..7eaf5eec00 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/device/DeviceRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/device/DeviceRepository.java @@ -19,7 +19,6 @@ import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; -import org.springframework.data.repository.PagingAndSortingRepository; import org.springframework.data.repository.query.Param; import org.thingsboard.server.common.data.DeviceTransportType; import org.thingsboard.server.dao.model.sql.DeviceEntity; @@ -83,7 +82,10 @@ public interface DeviceRepository extends JpaRepository { "LEFT JOIN CustomerEntity c on c.id = d.customerId " + "LEFT JOIN DeviceProfileEntity p on p.id = d.deviceProfileId " + "WHERE d.tenantId = :tenantId " + - "AND LOWER(d.searchText) LIKE LOWER(CONCAT('%', :textSearch, '%'))") + "AND (LOWER(d.searchText) LIKE LOWER(CONCAT('%', :textSearch, '%')) " + + "OR LOWER(d.label) LIKE LOWER(CONCAT('%', :textSearch, '%')) " + + "OR LOWER(p.searchText) LIKE LOWER(CONCAT('%', :textSearch, '%')) " + + "OR LOWER(c.searchText) LIKE LOWER(CONCAT('%', :textSearch, '%')))") Page findDeviceInfosByTenantId(@Param("tenantId") UUID tenantId, @Param("textSearch") String textSearch, Pageable pageable); @@ -132,7 +134,9 @@ public interface DeviceRepository extends JpaRepository { "LEFT JOIN DeviceProfileEntity p on p.id = d.deviceProfileId " + "WHERE d.tenantId = :tenantId " + "AND d.type = :type " + - "AND LOWER(d.searchText) LIKE LOWER(CONCAT('%', :textSearch, '%'))") + "AND (LOWER(d.searchText) LIKE LOWER(CONCAT('%', :textSearch, '%')) " + + "OR LOWER(d.label) LIKE LOWER(CONCAT('%', :textSearch, '%')) " + + "OR LOWER(c.searchText) LIKE LOWER(CONCAT('%', :textSearch, '%')))") Page findDeviceInfosByTenantIdAndType(@Param("tenantId") UUID tenantId, @Param("type") String type, @Param("textSearch") String textSearch, @@ -144,7 +148,9 @@ public interface DeviceRepository extends JpaRepository { "LEFT JOIN DeviceProfileEntity p on p.id = d.deviceProfileId " + "WHERE d.tenantId = :tenantId " + "AND d.deviceProfileId = :deviceProfileId " + - "AND LOWER(d.searchText) LIKE LOWER(CONCAT('%', :textSearch, '%'))") + "AND (LOWER(d.searchText) LIKE LOWER(CONCAT('%', :textSearch, '%')) " + + "OR LOWER(d.label) LIKE LOWER(CONCAT('%', :textSearch, '%')) " + + "OR LOWER(c.searchText) LIKE LOWER(CONCAT('%', :textSearch, '%')))") Page findDeviceInfosByTenantIdAndDeviceProfileId(@Param("tenantId") UUID tenantId, @Param("deviceProfileId") UUID deviceProfileId, @Param("textSearch") String textSearch, From a760aa6ac28f913f9206a71a16f2adad97965a3d Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Wed, 1 Dec 2021 14:41:02 +0200 Subject: [PATCH 196/432] Input and Output rule nodes and message routing --- .../actors/ruleChain/DefaultTbContext.java | 20 ++++ .../actors/ruleChain/RuleChainActor.java | 6 ++ .../RuleChainActorMessageProcessor.java | 71 +++++++++----- .../actors/ruleChain/RuleChainInputMsg.java | 41 ++++++++ .../actors/ruleChain/RuleChainOutputMsg.java | 49 ++++++++++ .../ruleChain/RuleChainToRuleChainMsg.java | 18 +--- .../ruleChain/TbToRuleChainActorMsg.java | 50 ++++++++++ .../server/actors/tenant/TenantActor.java | 4 + .../server/common/msg/MsgType.java | 10 ++ .../thingsboard/server/common/msg/TbMsg.java | 74 ++++++++++----- .../server/common/msg/TbMsgProcessingCtx.java | 94 +++++++++++++++++++ .../common/msg/TbMsgProcessingStackItem.java | 38 ++++++++ .../common/msg/queue/RuleNodeException.java | 3 +- common/message/src/main/proto/tbmsg.proto | 19 +++- .../rule/engine/api/TbContext.java | 19 ++++ .../engine/flow/TbRuleChainInputNode.java | 65 +++++++++++++ .../TbRuleChainInputNodeConfiguration.java | 32 +++++++ .../engine/flow/TbRuleChainOutputNode.java | 58 ++++++++++++ .../TbRuleChainOutputNodeConfiguration.java | 35 +++++++ 19 files changed, 642 insertions(+), 64 deletions(-) create mode 100644 application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleChainInputMsg.java create mode 100644 application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleChainOutputMsg.java create mode 100644 application/src/main/java/org/thingsboard/server/actors/ruleChain/TbToRuleChainActorMsg.java create mode 100644 common/message/src/main/java/org/thingsboard/server/common/msg/TbMsgProcessingCtx.java create mode 100644 common/message/src/main/java/org/thingsboard/server/common/msg/TbMsgProcessingStackItem.java create mode 100644 rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbRuleChainInputNode.java create mode 100644 rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbRuleChainInputNodeConfiguration.java create mode 100644 rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbRuleChainOutputNode.java create mode 100644 rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbRuleChainOutputNodeConfiguration.java diff --git a/application/src/main/java/org/thingsboard/server/actors/ruleChain/DefaultTbContext.java b/application/src/main/java/org/thingsboard/server/actors/ruleChain/DefaultTbContext.java index e3896b87a9..38d6f4bccb 100644 --- a/application/src/main/java/org/thingsboard/server/actors/ruleChain/DefaultTbContext.java +++ b/application/src/main/java/org/thingsboard/server/actors/ruleChain/DefaultTbContext.java @@ -56,6 +56,7 @@ import org.thingsboard.server.common.data.rule.RuleNodeState; import org.thingsboard.server.common.msg.TbActorMsg; import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsgMetaData; +import org.thingsboard.server.common.msg.TbMsgProcessingStackItem; import org.thingsboard.server.common.msg.queue.ServiceQueue; import org.thingsboard.server.common.msg.queue.ServiceType; import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; @@ -134,6 +135,25 @@ class DefaultTbContext implements TbContext { scheduleMsgWithDelay(new RuleNodeToSelfMsg(this, msg), delayMs, nodeCtx.getSelfActor()); } + @Override + public void input(TbMsg msg, RuleChainId ruleChainId) { + msg.pushToStack(nodeCtx.getSelf().getRuleChainId(), nodeCtx.getSelf().getId()); + nodeCtx.getChainActor().tell(new RuleChainInputMsg(ruleChainId, msg)); + } + + @Override + public void output(TbMsg msg, String relationType) { + TbMsgProcessingStackItem item = msg.popFormStack(); + if (item == null) { + ack(msg); + } else { + if (nodeCtx.getSelf().isDebugMode()) { + mainCtx.persistDebugOutput(nodeCtx.getTenantId(), nodeCtx.getSelf().getId(), msg, relationType); + } + nodeCtx.getChainActor().tell(new RuleChainOutputMsg(item.getRuleChainId(), item.getRuleNodeId(), relationType, msg)); + } + } + @Override public void enqueue(TbMsg tbMsg, Runnable onSuccess, Consumer onFailure) { TopicPartitionInfo tpi = mainCtx.resolve(ServiceType.TB_RULE_ENGINE, getTenantId(), tbMsg.getOriginator()); diff --git a/application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleChainActor.java b/application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleChainActor.java index c019e64e1f..48785bda75 100644 --- a/application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleChainActor.java +++ b/application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleChainActor.java @@ -60,6 +60,12 @@ public class RuleChainActor extends ComponentActor { + private static final String NA_RELATION_TYPE = ""; private final TbActorRef parent; private final TbActorRef self; private final Map nodeActors; @@ -201,33 +202,58 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor 0) { @@ -167,7 +173,7 @@ public final class TbMsg implements Serializable { this.data = data; this.ruleChainId = ruleChainId; this.ruleNodeId = ruleNodeId; - this.ruleNodeExecCounter = new AtomicInteger(ruleNodeExecCounter); + this.ctx = ctx != null ? ctx : new TbMsgProcessingCtx(); if (callback != null) { this.callback = callback; } else { @@ -209,7 +215,8 @@ public final class TbMsg implements Serializable { builder.setDataType(msg.getDataType().ordinal()); builder.setData(msg.getData()); - builder.setRuleNodeExecCounter(msg.ruleNodeExecCounter.get()); + + builder.setCtx(msg.ctx.toProto()); return builder.build().toByteArray(); } @@ -231,8 +238,17 @@ public final class TbMsg implements Serializable { ruleNodeId = new RuleNodeId(new UUID(proto.getRuleNodeIdMSB(), proto.getRuleNodeIdLSB())); } + TbMsgProcessingCtx ctx; + if (proto.hasCtx()) { + ctx = TbMsgProcessingCtx.fromProto(proto.getCtx()); + } else { + // Backward compatibility with unprocessed messages fetched from queue after update. + ctx = new TbMsgProcessingCtx(proto.getRuleNodeExecCounter()); + } + TbMsgDataType dataType = TbMsgDataType.values()[proto.getDataType()]; - return new TbMsg(queueName, UUID.fromString(proto.getId()), proto.getTs(), proto.getType(), entityId, customerId, metaData, dataType, proto.getData(), ruleChainId, ruleNodeId, proto.getRuleNodeExecCounter(), callback); + return new TbMsg(queueName, UUID.fromString(proto.getId()), proto.getTs(), proto.getType(), entityId, customerId, + metaData, dataType, proto.getData(), ruleChainId, ruleNodeId, ctx, callback); } catch (InvalidProtocolBufferException e) { throw new IllegalStateException("Could not parse protobuf for TbMsg", e); } @@ -243,11 +259,13 @@ public final class TbMsg implements Serializable { } public TbMsg copyWithRuleChainId(RuleChainId ruleChainId, UUID msgId) { - return new TbMsg(this.queueName, msgId, this.ts, this.type, this.originator, this.customerId, this.metaData, this.dataType, this.data, ruleChainId, null, this.ruleNodeExecCounter.get(), callback); + return new TbMsg(this.queueName, msgId, this.ts, this.type, this.originator, this.customerId, + this.metaData, this.dataType, this.data, ruleChainId, null, this.ctx, callback); } public TbMsg copyWithRuleNodeId(RuleChainId ruleChainId, RuleNodeId ruleNodeId, UUID msgId) { - return new TbMsg(this.queueName, msgId, this.ts, this.type, this.originator, this.customerId, this.metaData, this.dataType, this.data, ruleChainId, ruleNodeId, this.ruleNodeExecCounter.get(), callback); + return new TbMsg(this.queueName, msgId, this.ts, this.type, this.originator, this.customerId, + this.metaData, this.dataType, this.data, ruleChainId, ruleNodeId, this.ctx, callback); } public TbMsgCallback getCallback() { @@ -262,4 +280,12 @@ public final class TbMsg implements Serializable { public String getQueueName() { return queueName != null ? queueName : ServiceQueue.MAIN; } + + public void pushToStack(RuleChainId ruleChainId, RuleNodeId ruleNodeId) { + ctx.push(ruleChainId, ruleNodeId); + } + + public TbMsgProcessingStackItem popFormStack() { + return ctx.pop(); + } } diff --git a/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsgProcessingCtx.java b/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsgProcessingCtx.java new file mode 100644 index 0000000000..9f3b78fffa --- /dev/null +++ b/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsgProcessingCtx.java @@ -0,0 +1,94 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.common.msg; + +import org.thingsboard.server.common.data.id.RuleChainId; +import org.thingsboard.server.common.data.id.RuleNodeId; +import org.thingsboard.server.common.msg.gen.MsgProtos; + +import java.io.Serializable; +import java.util.LinkedList; +import java.util.List; +import java.util.UUID; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * Created by ashvayka on 13.01.18. + */ +public final class TbMsgProcessingCtx implements Serializable { + + private final AtomicInteger ruleNodeExecCounter; + private volatile LinkedList stack; + + public TbMsgProcessingCtx() { + this(0); + } + + public TbMsgProcessingCtx(int ruleNodeExecCounter) { + this(ruleNodeExecCounter, null); + } + + protected TbMsgProcessingCtx(int ruleNodeExecCounter, LinkedList stack) { + this.ruleNodeExecCounter = new AtomicInteger(ruleNodeExecCounter); + this.stack = stack; + } + + public int getAndIncrementRuleNodeCounter() { + return ruleNodeExecCounter.getAndIncrement(); + } + + public TbMsgProcessingCtx copy() { + return new TbMsgProcessingCtx(ruleNodeExecCounter.get()); + } + + public void push(RuleChainId ruleChainId, RuleNodeId ruleNodeId) { + if (stack == null) { + stack = new LinkedList<>(); + } + stack.add(new TbMsgProcessingStackItem(ruleChainId, ruleNodeId)); + } + + public TbMsgProcessingStackItem pop() { + return !stack.isEmpty() ? stack.removeLast() : null; + } + + public static TbMsgProcessingCtx fromProto(MsgProtos.TbMsgProcessingCtxProto ctx) { + int ruleNodeExecCounter = ctx.getRuleNodeExecCounter(); + if (ctx.getStackCount() > 0) { + LinkedList stack = new LinkedList<>(); + for (MsgProtos.TbMsgProcessingStackItemProto item : ctx.getStackList()) { + stack.add(new TbMsgProcessingStackItem( + new RuleChainId(new UUID(item.getRuleChainIdMSB(), item.getRuleChainIdLSB())), + new RuleNodeId(new UUID(item.getRuleNodeIdMSB(), item.getRuleNodeIdLSB())) + )); + } + return new TbMsgProcessingCtx(ruleNodeExecCounter, stack); + } else { + return new TbMsgProcessingCtx(ruleNodeExecCounter); + } + } + + public MsgProtos.TbMsgProcessingCtxProto toProto() { + var ctxBuilder = MsgProtos.TbMsgProcessingCtxProto.newBuilder(); + ctxBuilder.setRuleNodeExecCounter(ruleNodeExecCounter.get()); + if (stack != null) { + for (TbMsgProcessingStackItem item : stack) { + ctxBuilder.addStack(item.toProto()); + } + } + return ctxBuilder.build(); + } +} diff --git a/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsgProcessingStackItem.java b/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsgProcessingStackItem.java new file mode 100644 index 0000000000..ff765594fe --- /dev/null +++ b/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsgProcessingStackItem.java @@ -0,0 +1,38 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.common.msg; + +import lombok.Data; +import org.thingsboard.server.common.data.id.RuleChainId; +import org.thingsboard.server.common.data.id.RuleNodeId; +import org.thingsboard.server.common.msg.gen.MsgProtos; + +@Data +public class TbMsgProcessingStackItem { + + private final RuleChainId ruleChainId; + private final RuleNodeId ruleNodeId; + + MsgProtos.TbMsgProcessingStackItemProto toProto() { + return MsgProtos.TbMsgProcessingStackItemProto.newBuilder() + .setRuleChainIdMSB(ruleChainId.getId().getMostSignificantBits()) + .setRuleChainIdLSB(ruleChainId.getId().getLeastSignificantBits()) + .setRuleNodeIdMSB(ruleNodeId.getId().getMostSignificantBits()) + .setRuleNodeIdLSB(ruleNodeId.getId().getLeastSignificantBits()) + .build(); + } + +} diff --git a/common/message/src/main/java/org/thingsboard/server/common/msg/queue/RuleNodeException.java b/common/message/src/main/java/org/thingsboard/server/common/msg/queue/RuleNodeException.java index cd073f3a6e..44e30487d6 100644 --- a/common/message/src/main/java/org/thingsboard/server/common/msg/queue/RuleNodeException.java +++ b/common/message/src/main/java/org/thingsboard/server/common/msg/queue/RuleNodeException.java @@ -26,6 +26,7 @@ import org.thingsboard.server.common.data.rule.RuleNode; public class RuleNodeException extends RuleEngineException { private static final long serialVersionUID = -1776681087370749776L; + public static final String UNKNOWN = "Unknown"; @Getter private final String ruleChainName; @@ -45,7 +46,7 @@ public class RuleNodeException extends RuleEngineException { this.ruleChainId = ruleNode.getRuleChainId(); this.ruleNodeId = ruleNode.getId(); } else { - ruleNodeName = "Unknown"; + ruleNodeName = UNKNOWN; ruleChainId = new RuleChainId(RuleChainId.NULL_UUID); ruleNodeId = new RuleNodeId(RuleNodeId.NULL_UUID); } diff --git a/common/message/src/main/proto/tbmsg.proto b/common/message/src/main/proto/tbmsg.proto index 75f5051fbf..4d7682634b 100644 --- a/common/message/src/main/proto/tbmsg.proto +++ b/common/message/src/main/proto/tbmsg.proto @@ -19,10 +19,24 @@ package msgqueue; option java_package = "org.thingsboard.server.common.msg.gen"; option java_outer_classname = "MsgProtos"; +// Stores message metadata as map of strings message TbMsgMetaDataProto { map data = 1; } +// Stores stack of nested (caller) rule chains +message TbMsgProcessingStackItemProto { + int64 ruleChainIdMSB = 1; + int64 ruleChainIdLSB = 2; + int64 ruleNodeIdMSB = 3; + int64 ruleNodeIdLSB = 4; +} + +message TbMsgProcessingCtxProto { + int32 ruleNodeExecCounter = 1; + repeated TbMsgProcessingStackItemProto stack = 2; +} + message TbMsgProto { string id = 1; string type = 2; @@ -39,14 +53,17 @@ message TbMsgProto { TbMsgMetaDataProto metaData = 11; - //Transaction Data (12) was removed in 2.5 + // Transaction Data (12) was removed in 2.5 int32 dataType = 13; string data = 14; int64 ts = 15; + // Will be removed in 3.4. Moved to processing context int32 ruleNodeExecCounter = 16; int64 customerIdMSB = 17; int64 customerIdLSB = 18; + + TbMsgProcessingCtxProto ctx = 19; } \ No newline at end of file diff --git a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbContext.java b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbContext.java index 239c86ed57..206256e190 100644 --- a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbContext.java +++ b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbContext.java @@ -29,6 +29,7 @@ import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.id.RuleChainId; import org.thingsboard.server.common.data.id.RuleNodeId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.PageData; @@ -121,6 +122,24 @@ public interface TbContext { */ void enqueue(TbMsg msg, Runnable onSuccess, Consumer onFailure); + /** + * Sends message to the nested rule chain. + * Fails processing of the message if the nested rule chain is not found. + * + * @param msg - the message + * @param ruleChainId - the id of a nested rule chain + */ + void input(TbMsg msg, RuleChainId ruleChainId); + + /** + * Sends message to the caller rule chain. + * Acknowledge the message if no caller rule chain is present in processing stack + * + * @param msg - the message + * @param relationType - the relation type that will be used to route messages in the caller rule chain + */ + void output(TbMsg msg, String relationType); + /** * Puts new message to custom queue for processing * diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbRuleChainInputNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbRuleChainInputNode.java new file mode 100644 index 0000000000..c30dac406c --- /dev/null +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbRuleChainInputNode.java @@ -0,0 +1,65 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.rule.engine.flow; + +import lombok.extern.slf4j.Slf4j; +import org.thingsboard.rule.engine.api.RuleNode; +import org.thingsboard.rule.engine.api.TbContext; +import org.thingsboard.rule.engine.api.TbNode; +import org.thingsboard.rule.engine.api.TbNodeConfiguration; +import org.thingsboard.rule.engine.api.TbNodeException; +import org.thingsboard.rule.engine.api.TbRelationTypes; +import org.thingsboard.rule.engine.api.util.TbNodeUtils; +import org.thingsboard.server.common.data.EntityType; +import org.thingsboard.server.common.data.id.EntityIdFactory; +import org.thingsboard.server.common.data.id.RuleChainId; +import org.thingsboard.server.common.data.plugin.ComponentType; +import org.thingsboard.server.common.msg.TbMsg; + +import java.util.UUID; + +@Slf4j +@RuleNode( + type = ComponentType.ACTION, + name = "rule chain input", + configClazz = TbRuleChainInputNodeConfiguration.class, + nodeDescription = "transfers the message to another rule chain", + nodeDetails = "Allows to nest the rule chain similar to single rule node. " + + "The incoming message is forwarded to the input node of the specified target rule chain. " + + "The target rule chain may produce multiple labeled outputs. " + + "You may use the outputs to forward the results of processing to other rule nodes.", + customRelations = true +) +public class TbRuleChainInputNode implements TbNode { + + private TbRuleChainInputNodeConfiguration config; + private RuleChainId ruleChainId; + + @Override + public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException { + this.config = TbNodeUtils.convert(configuration, TbRuleChainInputNodeConfiguration.class); + this.ruleChainId = new RuleChainId(UUID.fromString(config.getRuleChainId())); + } + + @Override + public void onMsg(TbContext ctx, TbMsg msg) { + ctx.input(msg, ruleChainId); + } + + @Override + public void destroy() { + } +} diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbRuleChainInputNodeConfiguration.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbRuleChainInputNodeConfiguration.java new file mode 100644 index 0000000000..b990411216 --- /dev/null +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbRuleChainInputNodeConfiguration.java @@ -0,0 +1,32 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.rule.engine.flow; + +import lombok.Data; +import org.thingsboard.rule.engine.api.NodeConfiguration; +import org.thingsboard.server.common.data.id.RuleChainId; + +@Data +public class TbRuleChainInputNodeConfiguration implements NodeConfiguration { + + private String ruleChainId; + + @Override + public TbRuleChainInputNodeConfiguration defaultConfiguration() { + return new TbRuleChainInputNodeConfiguration(); + } + +} diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbRuleChainOutputNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbRuleChainOutputNode.java new file mode 100644 index 0000000000..b09f1bbca5 --- /dev/null +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbRuleChainOutputNode.java @@ -0,0 +1,58 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.rule.engine.flow; + +import lombok.extern.slf4j.Slf4j; +import org.thingsboard.rule.engine.api.RuleNode; +import org.thingsboard.rule.engine.api.TbContext; +import org.thingsboard.rule.engine.api.TbNode; +import org.thingsboard.rule.engine.api.TbNodeConfiguration; +import org.thingsboard.rule.engine.api.TbNodeException; +import org.thingsboard.rule.engine.api.TbRelationTypes; +import org.thingsboard.rule.engine.api.util.TbNodeUtils; +import org.thingsboard.server.common.data.plugin.ComponentType; +import org.thingsboard.server.common.msg.TbMsg; + +@Slf4j +@RuleNode( + type = ComponentType.ACTION, + name = "rule chain output", + configClazz = TbRuleChainOutputNodeConfiguration.class, + nodeDescription = "transfers the message to the caller rule chain", + nodeDetails = "Produces output of the rule chain processing. " + + "The output is forwarded to the caller rule chain, as an output of the corresponding \"input\" rule node. " + + "The rule node configuration contains the \"label\" parameter. " + + "This parameter corresponds to the relation type of the output message, and it is used to forward messages to other rule nodes in the caller rule chain. ", + outEnabled = false +) +public class TbRuleChainOutputNode implements TbNode { + + private TbRuleChainOutputNodeConfiguration config; + + @Override + public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException { + this.config = TbNodeUtils.convert(configuration, TbRuleChainOutputNodeConfiguration.class); + } + + @Override + public void onMsg(TbContext ctx, TbMsg msg) { + ctx.output(msg, config.getLabel()); + } + + @Override + public void destroy() { + } +} diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbRuleChainOutputNodeConfiguration.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbRuleChainOutputNodeConfiguration.java new file mode 100644 index 0000000000..8d220530c3 --- /dev/null +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbRuleChainOutputNodeConfiguration.java @@ -0,0 +1,35 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.rule.engine.flow; + +import lombok.Data; +import org.thingsboard.rule.engine.api.NodeConfiguration; +import org.thingsboard.rule.engine.api.TbRelationTypes; +import org.thingsboard.server.common.data.DataConstants; + +@Data +public class TbRuleChainOutputNodeConfiguration implements NodeConfiguration { + + private String label; + + @Override + public TbRuleChainOutputNodeConfiguration defaultConfiguration() { + var result = new TbRuleChainOutputNodeConfiguration(); + result.setLabel(TbRelationTypes.SUCCESS); + return result; + } + +} From d070d834584fb7cf577bff40df89b65e298910b1 Mon Sep 17 00:00:00 2001 From: desoliture Date: Wed, 1 Dec 2021 14:49:50 +0200 Subject: [PATCH 197/432] add tests --- .../dao/service/BaseDeviceServiceTest.java | 211 +++++++++++++++--- 1 file changed, 183 insertions(+), 28 deletions(-) diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseDeviceServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseDeviceServiceTest.java index 48b8b427e0..1a9432419e 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseDeviceServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseDeviceServiceTest.java @@ -245,7 +245,7 @@ public abstract class BaseDeviceServiceTest extends AbstractServiceTest { thrown.expectMessage("Can't assign firmware with different deviceProfile!"); deviceService.saveDevice(savedDevice); } - + @Test(expected = DataValidationException.class) public void testSaveDeviceWithEmptyName() { Device device = new Device(); @@ -324,24 +324,24 @@ public abstract class BaseDeviceServiceTest extends AbstractServiceTest { public void testFindDeviceTypesByTenantId() throws Exception { List devices = new ArrayList<>(); try { - for (int i=0;i<3;i++) { + for (int i = 0; i < 3; i++) { Device device = new Device(); device.setTenantId(tenantId); - device.setName("My device B"+i); + device.setName("My device B" + i); device.setType("typeB"); devices.add(deviceService.saveDevice(device)); } - for (int i=0;i<7;i++) { + for (int i = 0; i < 7; i++) { Device device = new Device(); device.setTenantId(tenantId); - device.setName("My device C"+i); + device.setName("My device C" + i); device.setType("typeC"); devices.add(deviceService.saveDevice(device)); } - for (int i=0;i<9;i++) { + for (int i = 0; i < 9; i++) { Device device = new Device(); device.setTenantId(tenantId); - device.setName("My device A"+i); + device.setName("My device A" + i); device.setType("typeA"); devices.add(deviceService.saveDevice(device)); } @@ -352,7 +352,9 @@ public abstract class BaseDeviceServiceTest extends AbstractServiceTest { Assert.assertEquals("typeB", deviceTypes.get(1).getType()); Assert.assertEquals("typeC", deviceTypes.get(2).getType()); } finally { - devices.forEach((device) -> { deviceService.deleteDevice(tenantId, device.getId()); }); + devices.forEach((device) -> { + deviceService.deleteDevice(tenantId, device.getId()); + }); } } @@ -381,10 +383,10 @@ public abstract class BaseDeviceServiceTest extends AbstractServiceTest { TenantId tenantId = tenant.getId(); List devices = new ArrayList<>(); - for (int i=0;i<178;i++) { + for (int i = 0; i < 178; i++) { Device device = new Device(); device.setTenantId(tenantId); - device.setName("Device"+i); + device.setName("Device" + i); device.setType("default"); devices.add(deviceService.saveDevice(device)); } @@ -419,11 +421,11 @@ public abstract class BaseDeviceServiceTest extends AbstractServiceTest { public void testFindDevicesByTenantIdAndName() { String title1 = "Device title 1"; List devicesTitle1 = new ArrayList<>(); - for (int i=0;i<143;i++) { + for (int i = 0; i < 143; i++) { Device device = new Device(); device.setTenantId(tenantId); String suffix = RandomStringUtils.randomAlphanumeric(15); - String name = title1+suffix; + String name = title1 + suffix; name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase(); device.setName(name); device.setType("default"); @@ -431,11 +433,11 @@ public abstract class BaseDeviceServiceTest extends AbstractServiceTest { } String title2 = "Device title 2"; List devicesTitle2 = new ArrayList<>(); - for (int i=0;i<175;i++) { + for (int i = 0; i < 175; i++) { Device device = new Device(); device.setTenantId(tenantId); String suffix = RandomStringUtils.randomAlphanumeric(15); - String name = title2+suffix; + String name = title2 + suffix; name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase(); device.setName(name); device.setType("default"); @@ -497,11 +499,11 @@ public abstract class BaseDeviceServiceTest extends AbstractServiceTest { String title1 = "Device title 1"; String type1 = "typeA"; List devicesType1 = new ArrayList<>(); - for (int i=0;i<143;i++) { + for (int i = 0; i < 143; i++) { Device device = new Device(); device.setTenantId(tenantId); String suffix = RandomStringUtils.randomAlphanumeric(15); - String name = title1+suffix; + String name = title1 + suffix; name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase(); device.setName(name); device.setType(type1); @@ -510,11 +512,11 @@ public abstract class BaseDeviceServiceTest extends AbstractServiceTest { String title2 = "Device title 2"; String type2 = "typeB"; List devicesType2 = new ArrayList<>(); - for (int i=0;i<175;i++) { + for (int i = 0; i < 175; i++) { Device device = new Device(); device.setTenantId(tenantId); String suffix = RandomStringUtils.randomAlphanumeric(15); - String name = title2+suffix; + String name = title2 + suffix; name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase(); device.setName(name); device.setType(type2); @@ -586,10 +588,10 @@ public abstract class BaseDeviceServiceTest extends AbstractServiceTest { CustomerId customerId = customer.getId(); List devices = new ArrayList<>(); - for (int i=0;i<278;i++) { + for (int i = 0; i < 278; i++) { Device device = new Device(); device.setTenantId(tenantId); - device.setName("Device"+i); + device.setName("Device" + i); device.setType("default"); device = deviceService.saveDevice(device); devices.add(new DeviceInfo(deviceService.assignDeviceToCustomer(tenantId, device.getId(), customerId), customer.getTitle(), customer.isPublic(), "default")); @@ -632,11 +634,11 @@ public abstract class BaseDeviceServiceTest extends AbstractServiceTest { String title1 = "Device title 1"; List devicesTitle1 = new ArrayList<>(); - for (int i=0;i<175;i++) { + for (int i = 0; i < 175; i++) { Device device = new Device(); device.setTenantId(tenantId); String suffix = RandomStringUtils.randomAlphanumeric(15); - String name = title1+suffix; + String name = title1 + suffix; name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase(); device.setName(name); device.setType("default"); @@ -645,11 +647,11 @@ public abstract class BaseDeviceServiceTest extends AbstractServiceTest { } String title2 = "Device title 2"; List devicesTitle2 = new ArrayList<>(); - for (int i=0;i<143;i++) { + for (int i = 0; i < 143; i++) { Device device = new Device(); device.setTenantId(tenantId); String suffix = RandomStringUtils.randomAlphanumeric(15); - String name = title2+suffix; + String name = title2 + suffix; name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase(); device.setName(name); device.setType("default"); @@ -720,11 +722,11 @@ public abstract class BaseDeviceServiceTest extends AbstractServiceTest { String title1 = "Device title 1"; String type1 = "typeC"; List devicesType1 = new ArrayList<>(); - for (int i=0;i<175;i++) { + for (int i = 0; i < 175; i++) { Device device = new Device(); device.setTenantId(tenantId); String suffix = RandomStringUtils.randomAlphanumeric(15); - String name = title1+suffix; + String name = title1 + suffix; name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase(); device.setName(name); device.setType(type1); @@ -734,11 +736,11 @@ public abstract class BaseDeviceServiceTest extends AbstractServiceTest { String title2 = "Device title 2"; String type2 = "typeD"; List devicesType2 = new ArrayList<>(); - for (int i=0;i<143;i++) { + for (int i = 0; i < 143; i++) { Device device = new Device(); device.setTenantId(tenantId); String suffix = RandomStringUtils.randomAlphanumeric(15); - String name = title2+suffix; + String name = title2 + suffix; name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase(); device.setName(name); device.setType(type2); @@ -818,4 +820,157 @@ public abstract class BaseDeviceServiceTest extends AbstractServiceTest { Assert.assertNull("Can't find device by name in cache if it was renamed", renamedDevice); deviceService.deleteDevice(tenantId, savedDevice.getId()); } + + @Test + public void testFindDeviceInfoByTenantId() { + Customer customer = new Customer(); + customer.setTitle("Customer X"); + customer.setTenantId(tenantId); + Customer savedCustomer = customerService.saveCustomer(customer); + + Device device = new Device(); + device.setTenantId(tenantId); + device.setName("default"); + device.setType("default"); + device.setLabel("label"); + device.setCustomerId(savedCustomer.getId()); + + Device savedDevice = deviceService.saveDevice(device); + + PageLink pageLinkWithLabel = new PageLink(100, 0, "label"); + List deviceInfosWithLabel = deviceService + .findDeviceInfosByTenantId(tenantId, pageLinkWithLabel).getData(); + + Assert.assertFalse(deviceInfosWithLabel.isEmpty()); + Assert.assertTrue( + deviceInfosWithLabel.stream() + .anyMatch( + d -> d.getId().equals(savedDevice.getId()) + && d.getTenantId().equals(tenantId) + && d.getLabel().equals(savedDevice.getLabel()) + ) + ); + + PageLink pageLinkWithCustomer = new PageLink(100, 0, savedCustomer.getSearchText()); + List deviceInfosWithCustomer = deviceService + .findDeviceInfosByTenantId(tenantId, pageLinkWithCustomer).getData(); + + Assert.assertFalse(deviceInfosWithCustomer.isEmpty()); + Assert.assertTrue( + deviceInfosWithCustomer.stream() + .anyMatch( + d -> d.getId().equals(savedDevice.getId()) + && d.getTenantId().equals(tenantId) + && d.getCustomerId().equals(savedCustomer.getId()) + && d.getCustomerTitle().equals(savedCustomer.getTitle()) + ) + ); + + PageLink pageLinkWithType = new PageLink(100, 0, device.getType()); + List deviceInfosWithType = deviceService + .findDeviceInfosByTenantId(tenantId, pageLinkWithType).getData(); + + Assert.assertFalse(deviceInfosWithType.isEmpty()); + Assert.assertTrue( + deviceInfosWithType.stream() + .anyMatch( + d -> d.getId().equals(savedDevice.getId()) + && d.getTenantId().equals(tenantId) + && d.getType().equals(device.getType()) + ) + ); + } + + @Test + public void testFindDeviceInfoByTenantIdAndType() { + Customer customer = new Customer(); + customer.setTitle("Customer X"); + customer.setTenantId(tenantId); + Customer savedCustomer = customerService.saveCustomer(customer); + + Device device = new Device(); + device.setTenantId(tenantId); + device.setName("default"); + device.setType("default"); + device.setLabel("label"); + device.setCustomerId(savedCustomer.getId()); + Device savedDevice = deviceService.saveDevice(device); + + PageLink pageLinkWithLabel = new PageLink(100, 0, "label"); + List deviceInfosWithLabel = deviceService + .findDeviceInfosByTenantIdAndType(tenantId, device.getType(), pageLinkWithLabel).getData(); + + Assert.assertFalse(deviceInfosWithLabel.isEmpty()); + Assert.assertTrue( + deviceInfosWithLabel.stream() + .anyMatch( + d -> d.getId().equals(savedDevice.getId()) + && d.getTenantId().equals(tenantId) + && d.getDeviceProfileName().equals(savedDevice.getType()) + && d.getLabel().equals(savedDevice.getLabel()) + ) + ); + + PageLink pageLinkWithCustomer = new PageLink(100, 0, savedCustomer.getSearchText()); + List deviceInfosWithCustomer = deviceService + .findDeviceInfosByTenantIdAndType(tenantId, device.getType(), pageLinkWithCustomer).getData(); + + Assert.assertFalse(deviceInfosWithCustomer.isEmpty()); + Assert.assertTrue( + deviceInfosWithCustomer.stream() + .anyMatch( + d -> d.getId().equals(savedDevice.getId()) + && d.getTenantId().equals(tenantId) + && d.getDeviceProfileName().equals(savedDevice.getType()) + && d.getCustomerId().equals(savedCustomer.getId()) + && d.getCustomerTitle().equals(savedCustomer.getTitle()) + ) + ); + } + + @Test + public void testFindDeviceInfoByTenantIdAndDeviceProfileId() { + Customer customer = new Customer(); + customer.setTitle("Customer X"); + customer.setTenantId(tenantId); + Customer savedCustomer = customerService.saveCustomer(customer); + + Device device = new Device(); + device.setTenantId(tenantId); + device.setName("default"); + device.setLabel("label"); + device.setCustomerId(savedCustomer.getId()); + Device savedDevice = deviceService.saveDevice(device); + + PageLink pageLinkWithLabel = new PageLink(100, 0, "label"); + List deviceInfosWithLabel = deviceService + .findDeviceInfosByTenantIdAndDeviceProfileId(tenantId, savedDevice.getDeviceProfileId(), pageLinkWithLabel).getData(); + + Assert.assertFalse(deviceInfosWithLabel.isEmpty()); + Assert.assertTrue( + deviceInfosWithLabel.stream() + .anyMatch( + d -> d.getId().equals(savedDevice.getId()) + && d.getTenantId().equals(tenantId) + && d.getDeviceProfileId().equals(savedDevice.getDeviceProfileId()) + && d.getLabel().equals(savedDevice.getLabel()) + ) + ); + + PageLink pageLinkWithCustomer = new PageLink(100, 0, savedCustomer.getSearchText()); + List deviceInfosWithCustomer = deviceService + .findDeviceInfosByTenantIdAndDeviceProfileId(tenantId, savedDevice.getDeviceProfileId(), pageLinkWithCustomer).getData(); + + Assert.assertFalse(deviceInfosWithCustomer.isEmpty()); + Assert.assertTrue( + deviceInfosWithCustomer.stream() + .anyMatch( + d -> d.getId().equals(savedDevice.getId()) + && d.getTenantId().equals(tenantId) + && d.getDeviceProfileId().equals(savedDevice.getDeviceProfileId()) + && d.getCustomerId().equals(savedCustomer.getId()) + && d.getCustomerTitle().equals(savedCustomer.getTitle()) + ) + ); + } } From bac828decad0d0d0fed295513c99240b59c98a3b Mon Sep 17 00:00:00 2001 From: desoliture Date: Wed, 1 Dec 2021 16:16:33 +0200 Subject: [PATCH 198/432] fix null response when get timeout on rpc with zero retries --- .../server/actors/device/DeviceActorMessageProcessor.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/application/src/main/java/org/thingsboard/server/actors/device/DeviceActorMessageProcessor.java b/application/src/main/java/org/thingsboard/server/actors/device/DeviceActorMessageProcessor.java index 41d99a682b..f677d76ee7 100644 --- a/application/src/main/java/org/thingsboard/server/actors/device/DeviceActorMessageProcessor.java +++ b/application/src/main/java/org/thingsboard/server/actors/device/DeviceActorMessageProcessor.java @@ -596,6 +596,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { ToDeviceRpcRequestMetadata md = toDeviceRpcPendingMap.get(responseMsg.getRequestId()); if (md != null) { + JsonNode response = null; if (status.equals(RpcStatus.DELIVERED)) { if (md.getMsg().getMsg().isOneway()) { toDeviceRpcPendingMap.remove(responseMsg.getRequestId()); @@ -611,13 +612,14 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { if (maxRpcRetries <= md.getRetries()) { toDeviceRpcPendingMap.remove(responseMsg.getRequestId()); status = RpcStatus.FAILED; + response = JacksonUtil.newObjectNode().put("error", "There was a Timeout and all retry attempts have been exhausted. Retry attempts set: " + maxRpcRetries); } else { md.setRetries(md.getRetries() + 1); } } if (md.getMsg().getMsg().isPersisted()) { - systemContext.getTbRpcService().save(tenantId, new RpcId(rpcId), status, null); + systemContext.getTbRpcService().save(tenantId, new RpcId(rpcId), status, response); } if (status != RpcStatus.SENT) { sendNextPendingRequest(context); From 9d4b994ccc141ac077f03b3bbb2a1176ee0c572a Mon Sep 17 00:00:00 2001 From: desoliture Date: Wed, 1 Dec 2021 15:52:34 +0200 Subject: [PATCH 199/432] change search filter to substring in swagger api docs --- .../server/controller/AlarmController.java | 2 +- .../controller/ControllerConstants.java | 30 +++++++++---------- .../controller/EdgeEventController.java | 2 +- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/AlarmController.java b/application/src/main/java/org/thingsboard/server/controller/AlarmController.java index 9920e232de..b36b5eaa73 100644 --- a/application/src/main/java/org/thingsboard/server/controller/AlarmController.java +++ b/application/src/main/java/org/thingsboard/server/controller/AlarmController.java @@ -80,7 +80,7 @@ public class AlarmController extends BaseController { private static final String ALARM_QUERY_SEARCH_STATUS_ALLOWABLE_VALUES = "ANY, ACTIVE, CLEARED, ACK, UNACK"; private static final String ALARM_QUERY_STATUS_DESCRIPTION = "A string value representing one of the AlarmStatus enumeration value"; private static final String ALARM_QUERY_STATUS_ALLOWABLE_VALUES = "ACTIVE_UNACK, ACTIVE_ACK, CLEARED_UNACK, CLEARED_ACK"; - private static final String ALARM_QUERY_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on of next alarm fields: type, severity or status"; + private static final String ALARM_QUERY_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'substring' filter based on of next alarm fields: type, severity or status"; private static final String ALARM_QUERY_START_TIME_DESCRIPTION = "The start timestamp in milliseconds of the search time range over the Alarm class field: 'createdTime'."; private static final String ALARM_QUERY_END_TIME_DESCRIPTION = "The end timestamp in milliseconds of the search time range over the Alarm class field: 'createdTime'."; private static final String ALARM_QUERY_FETCH_ORIGINATOR_DESCRIPTION = "A boolean value to specify if the alarm originator name will be " + diff --git a/application/src/main/java/org/thingsboard/server/controller/ControllerConstants.java b/application/src/main/java/org/thingsboard/server/controller/ControllerConstants.java index c2f965beba..17d12262c0 100644 --- a/application/src/main/java/org/thingsboard/server/controller/ControllerConstants.java +++ b/application/src/main/java/org/thingsboard/server/controller/ControllerConstants.java @@ -63,21 +63,21 @@ public class ControllerConstants { protected static final String ASSET_TYPE_DESCRIPTION = "Asset type"; protected static final String EDGE_TYPE_DESCRIPTION = "A string value representing the edge type. For example, 'default'"; protected static final String RULE_CHAIN_TYPE_DESCRIPTION = "Rule chain type (CORE or EDGE)"; - protected static final String ASSET_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the asset name."; - protected static final String DASHBOARD_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the dashboard title."; - protected static final String WIDGET_BUNDLE_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the widget bundle title."; + protected static final String ASSET_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'substring' filter based on the asset name."; + protected static final String DASHBOARD_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'substring' filter based on the dashboard title."; + protected static final String WIDGET_BUNDLE_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'substring' filter based on the widget bundle title."; protected static final String RPC_TEXT_SEARCH_DESCRIPTION = "Not implemented. Leave empty."; - protected static final String DEVICE_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the device name."; - protected static final String ENTITY_VIEW_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the entity view name."; - protected static final String USER_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the user email."; - protected static final String TENANT_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the tenant name."; - protected static final String TENANT_PROFILE_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the tenant profile name."; - protected static final String RULE_CHAIN_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the rule chain name."; - protected static final String DEVICE_PROFILE_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the device profile name."; - protected static final String CUSTOMER_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the customer title."; - protected static final String EDGE_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the edge name."; + protected static final String DEVICE_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'substring' filter based on the device name."; + protected static final String ENTITY_VIEW_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'substring' filter based on the entity view name."; + protected static final String USER_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'substring' filter based on the user email."; + protected static final String TENANT_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'substring' filter based on the tenant name."; + protected static final String TENANT_PROFILE_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'substring' filter based on the tenant profile name."; + protected static final String RULE_CHAIN_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'substring' filter based on the rule chain name."; + protected static final String DEVICE_PROFILE_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'substring' filter based on the device profile name."; + protected static final String CUSTOMER_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'substring' filter based on the customer title."; + protected static final String EDGE_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'substring' filter based on the edge name."; protected static final String EVENT_TEXT_SEARCH_DESCRIPTION = "The value is not used in searching."; - protected static final String AUDIT_LOG_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on one of the next properties: entityType, entityName, userName, actionType, actionStatus."; + protected static final String AUDIT_LOG_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'substring' filter based on one of the next properties: entityType, entityName, userName, actionType, actionStatus."; protected static final String SORT_PROPERTY_DESCRIPTION = "Property of entity to sort by"; protected static final String DASHBOARD_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, title"; protected static final String CUSTOMER_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, title, email, country, city"; @@ -114,12 +114,12 @@ public class ControllerConstants { protected static final String OTA_PACKAGE_INFO_DESCRIPTION = "OTA Package Info is a lightweight object that includes main information about the OTA Package excluding the heavyweight data. "; protected static final String OTA_PACKAGE_DESCRIPTION = "OTA Package is a heavyweight object that includes main information about the OTA Package and also data. "; protected static final String OTA_PACKAGE_CHECKSUM_ALGORITHM_ALLOWABLE_VALUES = "MD5, SHA256, SHA384, SHA512, CRC32, MURMUR3_32, MURMUR3_128"; - protected static final String OTA_PACKAGE_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the ota package title."; + protected static final String OTA_PACKAGE_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'substring' filter based on the ota package title."; protected static final String OTA_PACKAGE_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, type, title, version, tag, url, fileName, dataSize, checksum"; protected static final String RESOURCE_INFO_DESCRIPTION = "Resource Info is a lightweight object that includes main information about the Resource excluding the heavyweight data. "; protected static final String RESOURCE_DESCRIPTION = "Resource is a heavyweight object that includes main information about the Resource and also data. "; - protected static final String RESOURCE_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the resource title."; + protected static final String RESOURCE_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'substring' filter based on the resource title."; protected static final String RESOURCE_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, title, resourceType, tenantId"; protected static final String LWM2M_OBJECT_DESCRIPTION = "LwM2M Object is a object that includes information about the LwM2M model which can be used in transport configuration for the LwM2M device profile. "; protected static final String LWM2M_OBJECT_SORT_PROPERTY_ALLOWABLE_VALUES = "id, name"; diff --git a/application/src/main/java/org/thingsboard/server/controller/EdgeEventController.java b/application/src/main/java/org/thingsboard/server/controller/EdgeEventController.java index 72fbba0fe6..d4c3fb2d96 100644 --- a/application/src/main/java/org/thingsboard/server/controller/EdgeEventController.java +++ b/application/src/main/java/org/thingsboard/server/controller/EdgeEventController.java @@ -70,7 +70,7 @@ public class EdgeEventController extends BaseController { @RequestParam int pageSize, @ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true) @RequestParam int page, - @ApiParam(value = "The case insensitive 'startsWith' filter based on the edge event type name.") + @ApiParam(value = "The case insensitive 'substring' filter based on the edge event type name.") @RequestParam(required = false) String textSearch, @ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = EDGE_SORT_PROPERTY_ALLOWABLE_VALUES) @RequestParam(required = false) String sortProperty, From c0f0b8d43c6d4b67faa9143841c9616b685f85c9 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Wed, 1 Dec 2021 17:54:37 +0200 Subject: [PATCH 200/432] lwm2m - cert trust must be signed cert with 'CN' = ...sub..{CN by server} --- .../TbLwM2MDtlsCertificateVerifier.java | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MDtlsCertificateVerifier.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MDtlsCertificateVerifier.java index 5daf639f29..f3819edd7f 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MDtlsCertificateVerifier.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MDtlsCertificateVerifier.java @@ -120,7 +120,7 @@ public class TbLwM2MDtlsCertificateVerifier implements NewAdvancedCertificateVer TbLwM2MSecurityInfo securityInfo = null; // verify if trust if (config.getTrustSslCredentials().getTrustedCertificates().length > 0) { - if (searchIssuer(cert, config.getTrustSslCredentials().getTrustedCertificates()) != null) { + if (verifyIssuer(cert, config.getTrustSslCredentials().getTrustedCertificates()) != null) { String endpoint = config.getTrustSslCredentials().getValueFromSubjectNameByKey(cert.getSubjectX500Principal().getName(), "CN"); securityInfo = StringUtils.isNotEmpty(endpoint) ? securityInfoValidator.getEndpointSecurityInfoByCredentialsId(endpoint, CLIENT) : null; } @@ -193,13 +193,16 @@ public class TbLwM2MDtlsCertificateVerifier implements NewAdvancedCertificateVer } - private static X509Certificate searchIssuer(X509Certificate certificate, X509Certificate[] certificates) { - X500Principal subject = certificate.getIssuerX500Principal(); - for (int index = 0; index < certificates.length; ++index) { - X509Certificate trust = certificates[index]; - if (trust != null && subject.equals(trust.getIssuerX500Principal())) { - if (verifyCertificate(certificate)) { - return certificate; + private X509Certificate verifyIssuer(X509Certificate certificate, X509Certificate[] certificates) { + String issuerCN = config.getTrustSslCredentials().getValueFromSubjectNameByKey(certificate.getIssuerX500Principal().getName(), "CN"); + if (!StringUtils.isBlank(issuerCN)) { + for (int index = 0; index < certificates.length; ++index) { + X509Certificate trust = certificates[index]; + String trustCN = config.getTrustSslCredentials().getValueFromSubjectNameByKey(trust.getSubjectX500Principal().getName(), "CN"); + if (!StringUtils.isBlank(trustCN) && issuerCN.length() > trustCN.length() && issuerCN.substring(issuerCN.length()-trustCN.length()).equals(trustCN)) { + if (verifyCertificate(certificate)) { + return certificate; + } } } } From f0d3e31e17b97b236bc1f994909f5d97519a7659 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Wed, 1 Dec 2021 20:45:32 +0200 Subject: [PATCH 201/432] lwm2m - cert trust must be signed certServer with 'CN' = {CN by server} --- .../TbLwM2MDtlsCertificateVerifier.java | 2 +- transport/lwm2m/src/main/data/lwm2mserver.jks | Bin 3849 -> 4017 bytes 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MDtlsCertificateVerifier.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MDtlsCertificateVerifier.java index f3819edd7f..bae7522c78 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MDtlsCertificateVerifier.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MDtlsCertificateVerifier.java @@ -199,7 +199,7 @@ public class TbLwM2MDtlsCertificateVerifier implements NewAdvancedCertificateVer for (int index = 0; index < certificates.length; ++index) { X509Certificate trust = certificates[index]; String trustCN = config.getTrustSslCredentials().getValueFromSubjectNameByKey(trust.getSubjectX500Principal().getName(), "CN"); - if (!StringUtils.isBlank(trustCN) && issuerCN.length() > trustCN.length() && issuerCN.substring(issuerCN.length()-trustCN.length()).equals(trustCN)) { + if (!StringUtils.isBlank(trustCN) && issuerCN.length() >= trustCN.length() && issuerCN.substring(issuerCN.length()-trustCN.length()).equals(trustCN)) { if (verifyCertificate(certificate)) { return certificate; } diff --git a/transport/lwm2m/src/main/data/lwm2mserver.jks b/transport/lwm2m/src/main/data/lwm2mserver.jks index 5fab824aa1b19928fe711701cd27857472a9e739..301f4e2c3ab90931eb166859e71b2c443fa35660 100644 GIT binary patch delta 3823 zcmVWMD_g+32hTgPAJ05L*Niz9d9Mp8eln zER&vN-Bs7nKyQw-PaFr8pvA=YW=JfN93(|(9P-FTu?lIDEm z;qOV$p<9tIz1Z41eM2n*0|3KN1c8{Xv4)Ij8iCt87v5-`igiWSfMtOlA10>Z!-&%M zARu94wV@adaLThd?Op@@q14J-tH`q`DXyi--VL7SgL_sk)Ew`7)DiOy(ym)CNF6anR zB**apRJ1%bqFGPBAa=fpGrLgdlQ{xCDKj`TI5ROdGB7weFoF#11_>&LNQU3HM3fk(JM(lIwZAEnkaB3Cw>R<@r5F;U+IL z9J~~BwU91fbA0XccZh83R1M%S*x~}?`7t}?FRy+g)`~nE5I5$>iB6~Zi^_3hJYX)0 zK%)|`hzun%NINB(Q92Z-w0Iv%>TY;tn*FjSuppzi@p9z2t$~?h5k$azsDHwB*R3!i zm?pt_y%Z_?&Z%}v{+oZsrX>xxmGH**I%%#b-Kl(KczW9e{^rLzKw0~OnWmLgvD{m) zHhX0eB1EcKH6;o_D@3dM{KA$9RQkxZ#8ZgUX7q#@{0p^T%E>+O@H!4tBgGh_Rs3%H z_!rc4l}HyDHpXllw;LHV$f|HQCL#5$gx5l4m+&>+ywmjQ37CI3U+X3lvc0MHK6Co; z8l#<}y8++-sI8}j({cpr4_m&XD~>rf!fv{N4{=EnmGI_XNEI7E=Cgll0-CiN-b(|% z4G7*7%GkcRa7VV&CqpGaru;+-yDm}lvN1$y7v8#6Pz*txugZS@U}NIHJOF+J1SSY&UMmt0FY12=-FS0e8n_fPofT_H11CM_|of}oS^I>nIG##8r0B2Oh(N7_2 zP}d!QJQ)1eue$to#XsW=0ajbIL$pya#{bsowmLe6ekKNFBDuX)?cXLtxzC07g)F*4GiLVTHa;v<( zxMd?ZQp&N+cTX^(((Ns+^+yI`#mND+_jhG)3@I?L78XrUl1;4;P zslAs@J|aD%8!%Rq*14g!@ttN2&#sd$aK3qqzBQLBe+I$RS8jv zBNy1UtI!@#FE2Dn!7#U((&&MUnW(G9qx0;RpDJRH0pjth7jIlXhl%F5n?e#>Nu||J zn2!$CXIs$*jkQUx9Vcw-ZAovAEKYyg()qcHuD6Ya;`D%KeYiJ;RowIN-hv_^Bj^&W zmz0}EiUqz*PO2lKa{Q?@@W35sZa(xIA6TqZ?X(rT0AJ0-4xL)`{Z&(4r*W6^Jl9D2 zhNTbjcx)dT6WS<{_%H0x8kOqcyMxr@SWC9u-C!K#S$%@Mj z!13GPa#eK4#yL4EvM-aL+~t-Em$dscbFq9_I2|^fFcU{&`p7Kehcud;#g!Y^fy#kA zh8y#?2X>SgqLvu+WbV|6TBURBX({GN{QypdjauJ9cCtYnRY6e2d^eU|{D|!fkT888 zib2zeRsa42oWnYQyqWKOQORPIoEIcZi4E;En;F3RM5x_;JQTL?2%0`9I_+|JVjuKc~;{xy`dSJ#GdJ-_iIU3t>sfBZTi}fZ2JDBg1z*XSn5PXtULFa#?2gqbwdzYvk z+Rr^YRD;=tMm<@s{A4IxPP`iqtKOT=ZOG@sFJ^jnupTZ-UAQw<5Mr@Ms1JP2T04)g zvH0KDF@rkW3aWoB@WUUv3k6-ZF&2R?%w4@lynoPW1M2yvR2lOAPIw0J#&QUObEP%Z(i4 z)mS%jG-c7VvJqs__r+YNni@9So@NrC<#WL%wcj$(&lhLz&} zAQXUYgzo-GI4SpYxx+TgQ#;;)Crd z)oMzon#t4RmZn%%YKzy*euq%2mNuXS3+gj6WIcZwdKrKFd0BwhKIOI58tF{m455H( z3m!zcY;ak;`bAufY3*DxY1wj#_@_^*s^9bxU~1#zI+iZckFP{%`nh&>c2dZ6v~E{; z{Hd4q8#MP8uJS81DibWeiE;5D4vb|U^pw)E%TAhiC2u3}wLh$t6ElcmXG4>0g$u)v zJtUSV(c6D@0z{+9@rO+|ff>B=&e_J&pC|~&WNu}Z%C!e-`RZMuW*W(I=vx1K(n@0W zowg34XVX`#MJ)3~4Ux5&sHR@pvH&+J0Hl8Hjt?l^rCfOs0;@@>SP%qgG{T~f&+?Jl zw2tG)3Z~<=2tm)#DNYIf80^B!GlLDe%9B?^b&`KLe~GMq))>XA5#3uAtP9y4%;|If zG;74=+}sOsYqEdjzt^Fl!d6%kK<`nCJcEP2v*8c+YbRqP54IO=%|?BfUb z#Ht^asaHztHUUPj;OY`eA6~usaj<43kG2aAp{i0>8pTEYb2QMY-lVg^96zvDoe-$R zwcvl@FAcG75;E(~oZk<2J~=n8iDpm60I|B3c3ZouzJBU6w2<>g;fJ0wVNFtRh4FdT z%Rx1hYEK@eS>p7OR^BVW&QdbelbxiazB#5RZ-?*fMvx-x`K9cmhN-g=dII30DXsBN z$9VTtNG03mPbespBIDle>X=JEu%9*w>r8*l(WQUS+$G5^#Y~lm&tYt_rspz4LsTfG zOHBpn7cuO<=4zr8)^XMXP(@K)PcRKCseC|;Z5WjZeYV2B9 z1P1bsc{{f+WThuKmu^;KzdBdw_6vWb0)G0ZNY>9FLFivdvi5srB&(llk^K4=oC}1- z_}M1rMAo(=X@5Jbh1za6g6}-f;@?$ix*l5X*=Gi|AwBw7FFLc`3Z=T1e>fcN1&3bq zn@coh9C}mcZd4-|f}HkHC~n1@#D1(}h6Bl2A@@%Q@N}!Lf3&zv*75mS4kmxC@I}oA zzj2|SDP9yv;DYAVi5P$nz|=b-gw93E9h7@!U8}NDXm)2g@Mz`$C_E~pf2sbe$VNxNWg7CwD5uTlTd647vCxxS`5^~+i%3oo$<=Ut7 z96^zpSju@r$84gNVErKYNtV0q%r!bu0bINIX>{=o{Yo;qIe}jww@|a@ui(dgepJ8kd7lOaQD49BSZNR~ob$&O zk7x0cF9b%YM6(;R& z>c*G%1)}{X$%f_0t8V_&LNQU|0xkI3^#2v9Vh5%nhr zdsYmeWIv&B_#`cG{+tpJXY%zh<=zWf`~HA8b=FeEgQU!~(4G ztKp3!X7^z8TDs_-``@hRMC~tFi0__dxX*0}y=Ku+K_v3MQFss)6Mo3)N80o-GGc*W zqtL?nMDyA^8LxWo6s#(8BiGE*b(LJ80%S2I&;7tsS(Iud<2!Pq_7 z>J=D1|4`9nwAA=Bq*ee8T-oXYHqazGaBBxrAXf*xG306XETw{w1^@SbxoZrvB@7;< zIy#$$kn-oXcBOFb)gkUIjST)S6{Ak92W>iRfVl+>usEb%U`2m36mhpc(00T)sv9GL zZ$jfE=kcjZc;`J2HCB6CQ+Eo7vSpHPUfWuethbwDt_0oBbK8itz))(CMpr(R5B)?P zr~DX{n}1`D_WP?4W03usm03LnEe=atcZtA`B*4ji@MFI(hQ39`@cD~Jm?|Q>hp}MW zBP@1lTH|X@8(n|F3|tdOGU;dyMo*r%EEoj4(AO?W6L_WzK@B8a=dAk*lyd}Y<7RD8 zDR_+ERe&|!dTY>%hp9MP7c&=^FE3G%ga}k|^ApCxZyug=Q~wXW5j~F7WcH?x(18$d$?BpD-!$GC$eMt*93*}cRz@aC95vE zbo>Sjw~sSB?w+EcFhyjs5{!UFV^-YTX%vVAhx>n^P-^UJXp-RJAa8XB*qyRCj4cb- zRtI9BFx%wgz?Us z>oeetM}}cMV%1rd6J2x=wbRcLN|8R~st2r>ihqh38kECo?4fkJ)xNFJY}~=Z($G^E zA4-3tRMmld%nq7rkiC7%j-v#>2eMo|rUrNcT5$ea>7}Xj%0nMK0{lqoAh{EZWMFU2 z?!>~Mgb!SzeS4;xt}k}YQPqtxR@Yn-@Hk5Wx~hyDCk?gu)|OLkjL1s{>wRy@#2VmJ znoX1$=4b9mXv3K@I|f|Vd$T-lnF@i5Gpv7p{faHOI1{2$$;VcAM3>05@M7iAS`rs$ z*>pBhPp@>$(p>6^lmSApfZ%ati8_sF%z5n?;Gd^})wsAe;;qNqGJ5EEVj_h^rjoiWJAij^KT^KiemaQ*LCt~Vc3%5HuZn3TM|`;hAj3=a2h^{>eVrKIz$R}Fvl zJmCbxlRb|8U1EGj>#%#?-0qpbg5%1jjtN{&7vZS1JWUwzOU*9CNd2I*Bh-IfF^e%EmB7aaH-T0k*XL=`2^+C)>&jSZDe07V z|I4%HQH%Z1cDBB=vQ{6O*i<~L$P2-tsvZF+z6@(L<9ULG}>YN;%*B} zo&7)}<#)+(z{3{ma15xSj5$<%gE8F$A`EY_1d*@2ih?hm5)@&g{7Mb)ksyDSG8&tf zy48HrJ=34^yU*BnZ-6)`d`kR{RlA-@FbKSdbT#z*a`oMRyDQ}(Y!Qz!7PXIi?fNU+8JZJq?OJ9`gFo!Nn# zJCbbf)Pv82Lg$-wQ^T0FuBCqjsZnQZ_=7L}nJGtg^kAfH_h>wCtmB=X(v5|JM&@4J z*!#O;?Iq-XrN~m6R?p#9m)=}89sSH4jHKB;+L4A}Oi}=aCpZbb)W4d$ycoK`a@(&nXPD_7-8se;v2?#i@ z5|D*$W`hvY#F2L^dgS||;U-%m<8vK$+$eenj(YkZGz`+!`utjH=I*+sSFly$5KZK- zFSX4GPUe4~V!<7M_@B_sv@R4UoRo~)Ch$#3{30wRJ}2$##*6+N0F0Nv8NK-)mpX% z@4ostl_4ISiSl`rqt%-|_XE@aqA8<&YKiWy4$Z;oCpZ5nke+|c+~anTHd3P{mchxm ziE75=L4LzN-xtubZ8rc8A5+5}2#^ait_(WiB%^Z9ZWf=I=!O~HFS36eL^p6)v7Y5I zHz=sWEy^;s*M!^Fc)G|#SVGq}IHPJQOMBumSC^kVQ=~>gBr+a+Rq^?u{AGuFAQC@k zga)8!>>xqoC)nH6A<3~Y3s`@$#AV!Yr@k@`^o)oX>E1sT~Ag1wYDw5<6 zKV?q$Z-+AvG4p83!1rXSjAb!yr3$w4j0RBTz~66KXsds>x#XDMYi3=pj>usTFx|%e z2eODYW|KtQ`#XAByPJWfo?Pl>Y`FFf85H$>vVpi1+tlTD%@T}rSh`0Qj&hHNA4Y?| zOPd^d=-Zj_qh z)daLS3Q_pFP7FV!9CMWn*||txn|zMf8}{Jbz&sV9Q4sV%qUMzf@94TQ9jiR|;Qyr6 zb5g1e=SHGl^<8Y;LJ>?l!$^!hP=4 zWm$j!_x{)#<)ro~78OK;d#S{RBNWNJ;i?W`h9Q=9m(#`#uhmanl9}D7KVW!QHs`I- zt_jMk?j3^zaB9wh8rlvdeMQfNAe?3OXp#e_MLJ>nJ;)IVeyYZ8MSt`=*@GH-9sr@< zs-P+(o5bz0Fg`FLFbM_)D-Ht!8U+9Z6xYT>#LaQo(*VtnzN_qMP4M!Fhy)b<1nu-# X_d}DEK0Izji}dfgHE9+C0|ADh?iv+( From a65af3774e4e69fb5a0252e61aa1087e3e801a46 Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Thu, 2 Dec 2021 11:24:47 +0200 Subject: [PATCH 202/432] UI: Fixed incorrect disable polygon-editor in trip animation widgets --- .../widget/trip-animation/trip-animation.component.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/trip-animation/trip-animation.component.ts b/ui-ngx/src/app/modules/home/components/widget/trip-animation/trip-animation.component.ts index dfa630b3ad..aeadf378d2 100644 --- a/ui-ngx/src/app/modules/home/components/widget/trip-animation/trip-animation.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/trip-animation/trip-animation.component.ts @@ -49,7 +49,7 @@ import { } from '@home/components/widget/lib/maps/common-maps-utils'; import { JsonSettingsSchema, WidgetConfig } from '@shared/models/widget.models'; import moment from 'moment'; -import { isDefined, isUndefined } from '@core/utils'; +import { deepClone, isDefined, isUndefined } from '@core/utils'; import { ResizeObserver } from '@juggle/resize-observer'; import { MapWidgetInterface } from '@home/components/widget/lib/maps/map-widget.interface'; @@ -100,7 +100,7 @@ export class TripAnimationComponent implements OnInit, AfterViewInit, OnDestroy addGroupInfo(schema, 'Path Settings'); addToSchema(schema, addCondition(pointSchema, 'model.showPoints === true', ['showPoints'])); addGroupInfo(schema, 'Path Points Settings'); - const mapPolygonSchemaWithoutEdit = mapPolygonSchema; + const mapPolygonSchemaWithoutEdit = deepClone(mapPolygonSchema); delete mapPolygonSchemaWithoutEdit.schema.properties.editablePolygon; mapPolygonSchemaWithoutEdit.form.splice(mapPolygonSchemaWithoutEdit.form.indexOf('editablePolygon'), 1); addToSchema(schema, addCondition(mapPolygonSchemaWithoutEdit, 'model.showPolygon === true', ['showPolygon'])); From 33508f558e531b10801408b6b42a415ec368a96b Mon Sep 17 00:00:00 2001 From: ArtemDzhereleiko Date: Thu, 2 Dec 2021 13:18:42 +0200 Subject: [PATCH 203/432] UI: Hide pageSizeOption on persistent table widget --- .../components/widget/lib/rpc/persistent-table.component.ts | 3 ++- ui-ngx/src/app/shared/models/constants.ts | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-table.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-table.component.ts index f2c6f9e13f..c7d4da0295 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-table.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-table.component.ts @@ -68,6 +68,7 @@ import { } from '@home/components/widget/lib/rpc/persistent-filter-panel.component'; import { PersistentAddDialogComponent } from '@home/components/widget/lib/rpc/persistent-add-dialog.component'; import { ResizeObserver } from '@juggle/resize-observer'; +import { hidePageSizePixelValue } from '@shared/models/constants'; interface PersistentTableWidgetSettings extends TableWidgetSettings { defaultSortOrder: string; @@ -149,7 +150,7 @@ export class PersistentTableComponent extends PageComponent implements OnInit { this.ctx.updateWidgetParams(); if (this.displayPagination) { this.widgetResize$ = new ResizeObserver(() => { - const showHidePageSize = this.ctx.$container[0].offsetWidth < 500; + const showHidePageSize = this.persistentWidgetContainerRef.nativeElement.offsetWidth < hidePageSizePixelValue; if (showHidePageSize !== this.hidePageSize) { this.hidePageSize = showHidePageSize; this.ctx.detectChanges(); diff --git a/ui-ngx/src/app/shared/models/constants.ts b/ui-ngx/src/app/shared/models/constants.ts index 03b38345ca..4699a6338c 100644 --- a/ui-ngx/src/app/shared/models/constants.ts +++ b/ui-ngx/src/app/shared/models/constants.ts @@ -241,6 +241,7 @@ export const contentTypesMap = new Map( ] ); +export const hidePageSizePixelValue = 550; export const customTranslationsPrefix = 'custom.'; export const i18nPrefix = 'i18n'; From 76dccab3f7326698d03f6f3c1473e35e0237d7d5 Mon Sep 17 00:00:00 2001 From: ArtemDzhereleiko Date: Thu, 2 Dec 2021 13:53:00 +0200 Subject: [PATCH 204/432] UI: On tables hide page size option on mobile view --- .../attribute/attribute-table.component.html | 2 +- .../attribute/attribute-table.component.ts | 33 ++++++++++--------- .../entity/entities-table.component.html | 2 +- .../entity/entities-table.component.ts | 32 +++++++++--------- .../relation/relation-table.component.html | 2 +- .../relation/relation-table.component.ts | 33 ++++++++++--------- .../manage-widget-actions.component.html | 2 +- .../action/manage-widget-actions.component.ts | 31 +++++++++++++++-- .../lib/alarms-table-widget.component.ts | 3 +- .../lib/entities-table-widget.component.ts | 3 +- .../lib/timeseries-table-widget.component.ts | 3 +- ui-ngx/src/app/shared/models/constants.ts | 1 + 12 files changed, 91 insertions(+), 56 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/attribute/attribute-table.component.html b/ui-ngx/src/app/modules/home/components/attribute/attribute-table.component.html index c0612646f3..493bfe3e2d 100644 --- a/ui-ngx/src/app/modules/home/components/attribute/attribute-table.component.html +++ b/ui-ngx/src/app/modules/home/components/attribute/attribute-table.component.html @@ -15,7 +15,7 @@ limitations under the License. --> -
+
diff --git a/ui-ngx/src/app/modules/home/components/attribute/attribute-table.component.ts b/ui-ngx/src/app/modules/home/components/attribute/attribute-table.component.ts index e4a41251d8..1bd4dea53f 100644 --- a/ui-ngx/src/app/modules/home/components/attribute/attribute-table.component.ts +++ b/ui-ngx/src/app/modules/home/components/attribute/attribute-table.component.ts @@ -38,7 +38,7 @@ import { TranslateService } from '@ngx-translate/core'; import { MatDialog } from '@angular/material/dialog'; import { DialogService } from '@core/services/dialog.service'; import { Direction, SortOrder } from '@shared/models/page/sort-order'; -import { fromEvent, merge, Subscription } from 'rxjs'; +import { fromEvent, merge } from 'rxjs'; import { debounceTime, distinctUntilChanged, tap } from 'rxjs/operators'; import { EntityId } from '@shared/models/id/entity-id'; import { @@ -84,8 +84,8 @@ import { } from '@home/components/attribute/add-widget-to-dashboard-dialog.component'; import { deepClone } from '@core/utils'; import { Filters } from '@shared/models/query/query.models'; -import { MediaBreakpoints } from '@shared/models/constants'; -import { BreakpointObserver } from '@angular/cdk/layout'; +import { hidePageSizePixelValue } from '@shared/models/constants'; +import { ResizeObserver } from '@juggle/resize-observer'; @Component({ @@ -168,13 +168,14 @@ export class AttributeTableComponent extends PageComponent implements AfterViewI @Input() entityName: string; + @ViewChild('attributeTableContainer', {static: true}) attributeTableContainerRef: ElementRef; @ViewChild('searchInput') searchInputField: ElementRef; @ViewChild(MatPaginator) paginator: MatPaginator; @ViewChild(MatSort) sort: MatSort; - private breakpointObserverSubscription$: Subscription; - public hidePageSize = true; + public hidePageSize = false; + private widgetResize$: ResizeObserver; constructor(protected store: Store, private attributeService: AttributeService, @@ -189,8 +190,7 @@ export class AttributeTableComponent extends PageComponent implements AfterViewI private dashboardUtils: DashboardUtilsService, private widgetService: WidgetService, private zone: NgZone, - private cd: ChangeDetectorRef, - private breakpointObserver: BreakpointObserver) { + private cd: ChangeDetectorRef) { super(store); this.dirtyValue = !this.activeValue; const sortOrder: SortOrder = { property: 'key', direction: Direction.ASC }; @@ -199,18 +199,19 @@ export class AttributeTableComponent extends PageComponent implements AfterViewI } ngOnInit() { - this.breakpointObserverSubscription$ = this.breakpointObserver - .observe(MediaBreakpoints['gt-xs']).subscribe( - () => { - this.hidePageSize = !this.breakpointObserver.isMatched(MediaBreakpoints['gt-xs']); - this.cd.detectChanges(); - } - ); + this.widgetResize$ = new ResizeObserver(() => { + const showHidePageSize = this.attributeTableContainerRef.nativeElement.offsetWidth < hidePageSizePixelValue; + if (showHidePageSize !== this.hidePageSize) { + this.hidePageSize = showHidePageSize; + this.cd.detectChanges(); + } + }); + this.widgetResize$.observe(this.attributeTableContainerRef.nativeElement); } ngOnDestroy() { - if (this.breakpointObserverSubscription$) { - this.breakpointObserverSubscription$.unsubscribe(); + if (this.widgetResize$) { + this.widgetResize$.disconnect(); } } diff --git a/ui-ngx/src/app/modules/home/components/entity/entities-table.component.html b/ui-ngx/src/app/modules/home/components/entity/entities-table.component.html index a7b15670bb..aa86660ebe 100644 --- a/ui-ngx/src/app/modules/home/components/entity/entities-table.component.html +++ b/ui-ngx/src/app/modules/home/components/entity/entities-table.component.html @@ -32,7 +32,7 @@ -
+
diff --git a/ui-ngx/src/app/modules/home/components/entity/entities-table.component.ts b/ui-ngx/src/app/modules/home/components/entity/entities-table.component.ts index cca386570d..1851d5e085 100644 --- a/ui-ngx/src/app/modules/home/components/entity/entities-table.component.ts +++ b/ui-ngx/src/app/modules/home/components/entity/entities-table.component.ts @@ -64,8 +64,8 @@ import { DomSanitizer, SafeHtml } from '@angular/platform-browser'; import { TbAnchorComponent } from '@shared/components/tb-anchor.component'; import { isDefined, isUndefined } from '@core/utils'; import { HasUUID } from '@shared/models/id/has-uuid'; -import { MediaBreakpoints } from '@shared/models/constants'; -import { BreakpointObserver } from '@angular/cdk/layout'; +import { ResizeObserver } from '@juggle/resize-observer'; +import { hidePageSizePixelValue } from '@shared/models/constants'; @Component({ selector: 'tb-entities-table', @@ -111,6 +111,8 @@ export class EntitiesTableComponent extends PageComponent implements AfterViewIn isDetailsOpen = false; detailsPanelOpened = new EventEmitter(); + @ViewChild('entitiesTableContainer', {static: true}) entitiesTableContainerRef: ElementRef; + @ViewChild('entityTableHeader', {static: true}) entityTableHeaderAnchor: TbAnchorComponent; @ViewChild('searchInput') searchInputField: ElementRef; @@ -122,8 +124,8 @@ export class EntitiesTableComponent extends PageComponent implements AfterViewIn private updateDataSubscription: Subscription; private viewInited = false; - private breakpointObserverSubscription$: Subscription; - public hidePageSize = true; + private widgetResize$: ResizeObserver; + public hidePageSize = false; constructor(protected store: Store, public route: ActivatedRoute, @@ -132,8 +134,7 @@ export class EntitiesTableComponent extends PageComponent implements AfterViewIn private dialogService: DialogService, private domSanitizer: DomSanitizer, private cd: ChangeDetectorRef, - private componentFactoryResolver: ComponentFactoryResolver, - private breakpointObserver: BreakpointObserver) { + private componentFactoryResolver: ComponentFactoryResolver) { super(store); } @@ -143,18 +144,19 @@ export class EntitiesTableComponent extends PageComponent implements AfterViewIn } else { this.init(this.route.snapshot.data.entitiesTableConfig); } - this.breakpointObserverSubscription$ = this.breakpointObserver - .observe(MediaBreakpoints['gt-xs']).subscribe( - () => { - this.hidePageSize = !this.breakpointObserver.isMatched(MediaBreakpoints['gt-xs']); - this.cd.detectChanges(); - } - ); + this.widgetResize$ = new ResizeObserver(() => { + const showHidePageSize = this.entitiesTableContainerRef.nativeElement.offsetWidth < hidePageSizePixelValue; + if (showHidePageSize !== this.hidePageSize) { + this.hidePageSize = showHidePageSize; + this.cd.detectChanges(); + } + }); + this.widgetResize$.observe(this.entitiesTableContainerRef.nativeElement); } ngOnDestroy() { - if (this.breakpointObserverSubscription$) { - this.breakpointObserverSubscription$.unsubscribe(); + if (this.widgetResize$) { + this.widgetResize$.disconnect(); } } diff --git a/ui-ngx/src/app/modules/home/components/relation/relation-table.component.html b/ui-ngx/src/app/modules/home/components/relation/relation-table.component.html index b5ae8c2d52..edf5d1d04d 100644 --- a/ui-ngx/src/app/modules/home/components/relation/relation-table.component.html +++ b/ui-ngx/src/app/modules/home/components/relation/relation-table.component.html @@ -15,7 +15,7 @@ limitations under the License. --> -
+
diff --git a/ui-ngx/src/app/modules/home/components/relation/relation-table.component.ts b/ui-ngx/src/app/modules/home/components/relation/relation-table.component.ts index 2ea0ccfa12..8f0b503717 100644 --- a/ui-ngx/src/app/modules/home/components/relation/relation-table.component.ts +++ b/ui-ngx/src/app/modules/home/components/relation/relation-table.component.ts @@ -35,7 +35,7 @@ import { MatDialog } from '@angular/material/dialog'; import { DialogService } from '@core/services/dialog.service'; import { EntityRelationService } from '@core/http/entity-relation.service'; import { Direction, SortOrder } from '@shared/models/page/sort-order'; -import { forkJoin, fromEvent, merge, Observable, Subscription } from 'rxjs'; +import { forkJoin, fromEvent, merge, Observable } from 'rxjs'; import { debounceTime, distinctUntilChanged, tap } from 'rxjs/operators'; import { EntityRelation, @@ -47,8 +47,8 @@ import { import { EntityId } from '@shared/models/id/entity-id'; import { RelationsDatasource } from '../../models/datasource/relation-datasource'; import { RelationDialogComponent, RelationDialogData } from '@home/components/relation/relation-dialog.component'; -import { MediaBreakpoints } from '@shared/models/constants'; -import { BreakpointObserver } from '@angular/cdk/layout'; +import { hidePageSizePixelValue } from '@shared/models/constants'; +import { ResizeObserver } from '@juggle/resize-observer'; @Component({ selector: 'tb-relation-table', @@ -76,8 +76,8 @@ export class RelationTableComponent extends PageComponent implements AfterViewIn viewsInited = false; - private breakpointObserverSubscription$: Subscription; - public hidePageSize = true; + private widgetResize$: ResizeObserver; + public hidePageSize = false; @Input() set active(active: boolean) { @@ -105,6 +105,7 @@ export class RelationTableComponent extends PageComponent implements AfterViewIn } } + @ViewChild('relationTableContainer', {static: true}) relationTableContainerRef: ElementRef; @ViewChild('searchInput') searchInputField: ElementRef; @ViewChild(MatPaginator) paginator: MatPaginator; @@ -115,8 +116,7 @@ export class RelationTableComponent extends PageComponent implements AfterViewIn public translate: TranslateService, public dialog: MatDialog, private dialogService: DialogService, - private cd: ChangeDetectorRef, - private breakpointObserver: BreakpointObserver) { + private cd: ChangeDetectorRef) { super(store); this.dirtyValue = !this.activeValue; const sortOrder: SortOrder = { property: 'type', direction: Direction.ASC }; @@ -127,18 +127,19 @@ export class RelationTableComponent extends PageComponent implements AfterViewIn } ngOnInit() { - this.breakpointObserverSubscription$ = this.breakpointObserver - .observe(MediaBreakpoints['gt-xs']).subscribe( - () => { - this.hidePageSize = !this.breakpointObserver.isMatched(MediaBreakpoints['gt-xs']); - this.cd.detectChanges(); - } - ); + this.widgetResize$ = new ResizeObserver(() => { + const showHidePageSize = this.relationTableContainerRef.nativeElement.offsetWidth < hidePageSizePixelValue; + if (showHidePageSize !== this.hidePageSize) { + this.hidePageSize = showHidePageSize; + this.cd.detectChanges(); + } + }); + this.widgetResize$.observe(this.relationTableContainerRef.nativeElement); } ngOnDestroy() { - if (this.breakpointObserverSubscription$) { - this.breakpointObserverSubscription$.unsubscribe(); + if (this.widgetResize$) { + this.widgetResize$.disconnect(); } } diff --git a/ui-ngx/src/app/modules/home/components/widget/action/manage-widget-actions.component.html b/ui-ngx/src/app/modules/home/components/widget/action/manage-widget-actions.component.html index 53523bc0cf..d0c1db566c 100644 --- a/ui-ngx/src/app/modules/home/components/widget/action/manage-widget-actions.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/action/manage-widget-actions.component.html @@ -15,7 +15,7 @@ limitations under the License. --> -
+
diff --git a/ui-ngx/src/app/modules/home/components/widget/action/manage-widget-actions.component.ts b/ui-ngx/src/app/modules/home/components/widget/action/manage-widget-actions.component.ts index d3fdd47bba..5173e00954 100644 --- a/ui-ngx/src/app/modules/home/components/widget/action/manage-widget-actions.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/action/manage-widget-actions.component.ts @@ -14,7 +14,17 @@ /// limitations under the License. /// -import { AfterViewInit, Component, ElementRef, forwardRef, Input, OnDestroy, OnInit, ViewChild } from '@angular/core'; +import { + AfterViewInit, + ChangeDetectorRef, + Component, + ElementRef, + forwardRef, + Input, + OnDestroy, + OnInit, + ViewChild +} from '@angular/core'; import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; import { TranslateService } from '@ngx-translate/core'; import { PageComponent } from '@shared/components/page.component'; @@ -43,6 +53,8 @@ import { } from '@home/components/widget/action/widget-action-dialog.component'; import { deepClone } from '@core/utils'; import { widgetType } from '@shared/models/widget.models'; +import { ResizeObserver } from '@juggle/resize-observer'; +import { hidePageSizePixelValue } from '@shared/models/constants'; @Component({ selector: 'tb-manage-widget-actions', @@ -73,7 +85,10 @@ export class ManageWidgetActionsComponent extends PageComponent implements OnIni viewsInited = false; dirtyValue = false; + public hidePageSize = false; + private widgetResize$: ResizeObserver; + @ViewChild('manageActionWidgetContainer', {static: true}) manageActionWidgetContainerRef: ElementRef; @ViewChild('searchInput') searchInputField: ElementRef; @ViewChild(MatPaginator) paginator: MatPaginator; @@ -85,7 +100,8 @@ export class ManageWidgetActionsComponent extends PageComponent implements OnIni private translate: TranslateService, private utils: UtilsService, private dialog: MatDialog, - private dialogs: DialogService) { + private dialogs: DialogService, + private cd: ChangeDetectorRef) { super(store); const sortOrder: SortOrder = { property: 'actionSourceName', direction: Direction.ASC }; this.pageLink = new PageLink(10, 0, null, sortOrder); @@ -94,9 +110,20 @@ export class ManageWidgetActionsComponent extends PageComponent implements OnIni } ngOnInit(): void { + this.widgetResize$ = new ResizeObserver(() => { + const showHidePageSize = this.manageActionWidgetContainerRef.nativeElement.offsetWidth < hidePageSizePixelValue; + if (showHidePageSize !== this.hidePageSize) { + this.hidePageSize = showHidePageSize; + this.cd.detectChanges(); + } + }); + this.widgetResize$.observe(this.manageActionWidgetContainerRef.nativeElement); } ngOnDestroy(): void { + if (this.widgetResize$) { + this.widgetResize$.disconnect(); + } } ngAfterViewInit() { diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.ts index 8f003141e8..e12fcfcebd 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.ts @@ -124,6 +124,7 @@ import { import { entityFields } from '@shared/models/entity.models'; import { coerceBooleanProperty } from '@angular/cdk/coercion'; import { ResizeObserver } from '@juggle/resize-observer'; +import { hidePageSizePixelValue } from '@shared/models/constants'; interface AlarmsTableWidgetSettings extends TableWidgetSettings { alarmsTitle: string; @@ -262,7 +263,7 @@ export class AlarmsTableWidgetComponent extends PageComponent implements OnInit, () => this.pageLink.page = 0 ); this.widgetResize$ = new ResizeObserver(() => { - const showHidePageSize = this.ctx.$container[0].offsetWidth < 500; + const showHidePageSize = this.alarmWidgetContainerRef.nativeElement.offsetWidth < hidePageSizePixelValue; if (showHidePageSize !== this.hidePageSize) { this.hidePageSize = showHidePageSize; this.ctx.detectChanges(); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.ts index 2c887a1668..32a07cecb8 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.ts @@ -108,6 +108,7 @@ import { entityFields } from '@shared/models/entity.models'; import { DatePipe } from '@angular/common'; import { coerceBooleanProperty } from '@angular/cdk/coercion'; import { ResizeObserver } from '@juggle/resize-observer'; +import { hidePageSizePixelValue } from '@shared/models/constants'; interface EntitiesTableWidgetSettings extends TableWidgetSettings { entitiesTitle: string; @@ -217,7 +218,7 @@ export class EntitiesTableWidgetComponent extends PageComponent implements OnIni this.ctx.updateWidgetParams(); if (this.displayPagination) { this.widgetResize$ = new ResizeObserver(() => { - const showHidePageSize = this.ctx.$container[0].offsetWidth < 500; + const showHidePageSize = this.entitiesWidgetContainerRef.nativeElement.offsetWidth < hidePageSizePixelValue; if (showHidePageSize !== this.hidePageSize) { this.hidePageSize = showHidePageSize; this.ctx.detectChanges(); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.ts index cc35c481a8..a5a2cbc12e 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.ts @@ -72,6 +72,7 @@ import { DatePipe } from '@angular/common'; import { parseData } from '@home/components/widget/lib/maps/common-maps-utils'; import { coerceBooleanProperty } from '@angular/cdk/coercion'; import { ResizeObserver } from '@juggle/resize-observer'; +import { hidePageSizePixelValue } from '@shared/models/constants'; export interface TimeseriesTableWidgetSettings extends TableWidgetSettings { showTimestamp: boolean; @@ -195,7 +196,7 @@ export class TimeseriesTableWidgetComponent extends PageComponent implements OnI } ); this.widgetResize$ = new ResizeObserver(() => { - const showHidePageSize = this.ctx.$container[0].offsetWidth < 500; + const showHidePageSize = this.timeseriesWidgetContainerRef.nativeElement.offsetWidth < hidePageSizePixelValue; if (showHidePageSize !== this.hidePageSize) { this.hidePageSize = showHidePageSize; this.ctx.detectChanges(); diff --git a/ui-ngx/src/app/shared/models/constants.ts b/ui-ngx/src/app/shared/models/constants.ts index 03b38345ca..4699a6338c 100644 --- a/ui-ngx/src/app/shared/models/constants.ts +++ b/ui-ngx/src/app/shared/models/constants.ts @@ -241,6 +241,7 @@ export const contentTypesMap = new Map( ] ); +export const hidePageSizePixelValue = 550; export const customTranslationsPrefix = 'custom.'; export const i18nPrefix = 'i18n'; From 73f37271febf8bbbadbb9ed94933c5cc3bc5d9fd Mon Sep 17 00:00:00 2001 From: van-vanich Date: Thu, 2 Dec 2021 18:05:03 +0200 Subject: [PATCH 205/432] fix the issue, when we don't can set keyspace name for Cassandra --- .../CassandraAbstractDatabaseSchemaService.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/application/src/main/java/org/thingsboard/server/service/install/CassandraAbstractDatabaseSchemaService.java b/application/src/main/java/org/thingsboard/server/service/install/CassandraAbstractDatabaseSchemaService.java index 1a44d9d61a..7580180a18 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/CassandraAbstractDatabaseSchemaService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/CassandraAbstractDatabaseSchemaService.java @@ -18,6 +18,7 @@ package org.thingsboard.server.service.install; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.beans.factory.annotation.Value; import org.thingsboard.server.dao.cassandra.CassandraInstallCluster; import org.thingsboard.server.service.install.cql.CQLStatementsParser; @@ -29,6 +30,7 @@ import java.util.List; public abstract class CassandraAbstractDatabaseSchemaService implements DatabaseSchemaService { private static final String CASSANDRA_DIR = "cassandra"; + private static final String CASSANDRA_STANDARD_KEYSPACE = "thingsboard"; @Autowired @Qualifier("CassandraInstallCluster") @@ -37,6 +39,9 @@ public abstract class CassandraAbstractDatabaseSchemaService implements Database @Autowired private InstallScripts installScripts; + @Value("${cassandra.keyspace_name}") + private String keyspaceName; + private final String schemaCql; protected CassandraAbstractDatabaseSchemaService(String schemaCql) { @@ -61,6 +66,10 @@ public abstract class CassandraAbstractDatabaseSchemaService implements Database private void loadCql(Path cql) throws Exception { List statements = new CQLStatementsParser(cql).getStatements(); - statements.forEach(statement -> cluster.getSession().execute(statement)); + statements.forEach(statement -> cluster.getSession().execute(getCassandraKeyspaceName(statement))); + } + + private String getCassandraKeyspaceName(String statement) { + return statement.replaceFirst(CASSANDRA_STANDARD_KEYSPACE, keyspaceName); } } From c3fa9b9f43403c3da00bd3da26f0e9303cdc9b94 Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Thu, 2 Dec 2021 19:13:18 +0200 Subject: [PATCH 206/432] Nested rule chains --- .../controller/RuleChainController.java | 69 +++++++- .../rule/DefaultTbRuleChainService.java | 157 ++++++++++++++++++ .../service/rule/TbRuleChainService.java | 19 +++ .../server/dao/rule/RuleChainService.java | 5 +- .../common/data/rule/RuleChainMetaData.java | 1 + .../data/rule/RuleChainOutputLabelsUsage.java | 45 +++++ .../data/rule/RuleChainUpdateResult.java | 44 +++++ .../data/rule/RuleNodeUpdateResult.java | 32 ++++ .../server/common/msg/TbMsgProcessingCtx.java | 13 +- .../common/msg/TbMsgProcessingStackItem.java | 9 + .../server/dao/rule/BaseRuleChainService.java | 28 +++- .../server/dao/rule/RuleChainDao.java | 3 + .../server/dao/rule/RuleNodeDao.java | 4 + .../server/dao/sql/rule/JpaRuleChainDao.java | 7 + .../server/dao/sql/rule/JpaRuleNodeDao.java | 9 +- .../dao/sql/rule/RuleNodeRepository.java | 10 ++ .../dao/service/BaseRuleChainServiceTest.java | 4 +- 17 files changed, 439 insertions(+), 20 deletions(-) create mode 100644 application/src/main/java/org/thingsboard/server/service/rule/DefaultTbRuleChainService.java create mode 100644 application/src/main/java/org/thingsboard/server/service/rule/TbRuleChainService.java create mode 100644 common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleChainOutputLabelsUsage.java create mode 100644 common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleChainUpdateResult.java create mode 100644 common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleNodeUpdateResult.java diff --git a/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java b/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java index 2a8dcc3593..8345a8beef 100644 --- a/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java +++ b/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java @@ -5,7 +5,7 @@ * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -28,7 +28,6 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; @@ -37,12 +36,16 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestController; +import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.rule.engine.api.ScriptEngine; +import org.thingsboard.rule.engine.flow.TbRuleChainOutputNode; +import org.thingsboard.rule.engine.flow.TbRuleChainOutputNodeConfiguration; import org.thingsboard.server.actors.ActorSystemContext; import org.thingsboard.server.actors.tenant.DebugTbRateLimits; import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.Event; +import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.edge.Edge; import org.thingsboard.server.common.data.edge.EdgeEventActionType; @@ -60,14 +63,18 @@ import org.thingsboard.server.common.data.rule.RuleChain; import org.thingsboard.server.common.data.rule.RuleChainData; import org.thingsboard.server.common.data.rule.RuleChainImportResult; import org.thingsboard.server.common.data.rule.RuleChainMetaData; +import org.thingsboard.server.common.data.rule.RuleChainOutputLabelsUsage; import org.thingsboard.server.common.data.rule.RuleChainType; +import org.thingsboard.server.common.data.rule.RuleChainUpdateResult; import org.thingsboard.server.common.data.rule.RuleNode; import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsgDataType; import org.thingsboard.server.common.msg.TbMsgMetaData; import org.thingsboard.server.dao.event.EventService; +import org.thingsboard.server.dao.rule.RuleChainService; import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.service.install.InstallScripts; +import org.thingsboard.server.service.rule.TbRuleChainService; import org.thingsboard.server.service.script.JsInvokeService; import org.thingsboard.server.service.script.RuleNodeJsScriptEngine; import org.thingsboard.server.service.security.permission.Operation; @@ -77,6 +84,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.TreeSet; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; @@ -137,6 +145,9 @@ public class RuleChainController extends BaseController { + MARKDOWN_CODE_BLOCK_END + "\n\n Expected result JSON contains \"output\" and \"error\"."; + @Autowired + protected TbRuleChainService tbRuleChainService; + @Autowired private InstallScripts installScripts; @@ -169,6 +180,44 @@ public class RuleChainController extends BaseController { } } + @ApiOperation(value = "Get Rule Chain output labels (getRuleChainOutputLabels)", + notes = "Fetch the unique labels for the \"output\" Rule Nodes that belong to the Rule Chain based on the provided Rule Chain Id. " + + RULE_CHAIN_DESCRIPTION + TENANT_AUTHORITY_PARAGRAPH) + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") + @RequestMapping(value = "/ruleChain/{ruleChainId}/output/labels", method = RequestMethod.GET) + @ResponseBody + public Set getRuleChainOutputLabels( + @ApiParam(value = RULE_CHAIN_ID_PARAM_DESCRIPTION) + @PathVariable(RULE_CHAIN_ID) String strRuleChainId) throws ThingsboardException { + checkParameter(RULE_CHAIN_ID, strRuleChainId); + try { + RuleChainId ruleChainId = new RuleChainId(toUUID(strRuleChainId)); + checkRuleChain(ruleChainId, Operation.READ); + return tbRuleChainService.getRuleChainOutputLabels(getTenantId(), ruleChainId); + } catch (Exception e) { + throw handleException(e); + } + } + + @ApiOperation(value = "Get output labels usage (getRuleChainOutputLabelsUsage)", + notes = "Fetch the list of rule chains and the relation types (labels) they use to process output of the current rule chain based on the provided Rule Chain Id. " + + RULE_CHAIN_DESCRIPTION + TENANT_AUTHORITY_PARAGRAPH) + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") + @RequestMapping(value = "/ruleChain/{ruleChainId}/output/labels/usage", method = RequestMethod.GET) + @ResponseBody + public List getRuleChainOutputLabelsUsage( + @ApiParam(value = RULE_CHAIN_ID_PARAM_DESCRIPTION) + @PathVariable(RULE_CHAIN_ID) String strRuleChainId) throws ThingsboardException { + checkParameter(RULE_CHAIN_ID, strRuleChainId); + try { + RuleChainId ruleChainId = new RuleChainId(toUUID(strRuleChainId)); + checkRuleChain(ruleChainId, Operation.READ); + return tbRuleChainService.getOutputLabelUsage(getCurrentUser().getTenantId(), ruleChainId); + } catch (Exception e) { + throw handleException(e); + } + } + @ApiOperation(value = "Get Rule Chain (getRuleChainById)", notes = "Fetch the Rule Chain Metadata object based on the provided Rule Chain Id. " + RULE_CHAIN_METADATA_DESCRIPTION + TENANT_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") @@ -310,7 +359,11 @@ public class RuleChainController extends BaseController { @ResponseBody public RuleChainMetaData saveRuleChainMetaData( @ApiParam(value = "A JSON value representing the rule chain metadata.") - @RequestBody RuleChainMetaData ruleChainMetaData) throws ThingsboardException { + @RequestBody RuleChainMetaData ruleChainMetaData, + @ApiParam(value = "Update related rule nodes.") + //TODO: change default value to "false" before merge + @RequestParam(value = "updateRelated", required = false, defaultValue = "true") boolean updateRelated + ) throws ThingsboardException { try { TenantId tenantId = getTenantId(); if (debugPerTenantEnabled) { @@ -322,7 +375,13 @@ public class RuleChainController extends BaseController { } RuleChain ruleChain = checkRuleChain(ruleChainMetaData.getRuleChainId(), Operation.WRITE); - checkNotNull(ruleChainService.saveRuleChainMetaData(tenantId, ruleChainMetaData) ? true : null); + RuleChainUpdateResult result = ruleChainService.saveRuleChainMetaData(tenantId, ruleChainMetaData); + checkNotNull(result.isSuccess() ? true : null); + + if (updateRelated && result.isSuccess()) { + tbRuleChainService.updateRelatedRuleChains(tenantId, ruleChainMetaData.getRuleChainId(), result); + } + RuleChainMetaData savedRuleChainMetaData = checkNotNull(ruleChainService.loadRuleChainMetaData(tenantId, ruleChainMetaData.getRuleChainId())); if (RuleChainType.CORE.equals(ruleChain.getType())) { @@ -681,7 +740,7 @@ public class RuleChainController extends BaseController { } @ApiOperation(value = "Get Edge Rule Chains (getEdgeRuleChains)", - notes = "Returns a page of Rule Chains assigned to the specified edge. " + RULE_CHAIN_DESCRIPTION + PAGE_DATA_PARAMETERS + TENANT_AUTHORITY_PARAGRAPH) + notes = "Returns a page of Rule Chains assigned to the specified edge. " + RULE_CHAIN_DESCRIPTION + PAGE_DATA_PARAMETERS + TENANT_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") @RequestMapping(value = "/edge/{edgeId}/ruleChains", params = {"pageSize", "page"}, method = RequestMethod.GET) @ResponseBody diff --git a/application/src/main/java/org/thingsboard/server/service/rule/DefaultTbRuleChainService.java b/application/src/main/java/org/thingsboard/server/service/rule/DefaultTbRuleChainService.java new file mode 100644 index 0000000000..a76b448611 --- /dev/null +++ b/application/src/main/java/org/thingsboard/server/service/rule/DefaultTbRuleChainService.java @@ -0,0 +1,157 @@ +package org.thingsboard.server.service.rule; + +import com.fasterxml.jackson.core.JsonProcessingException; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.thingsboard.common.util.JacksonUtil; +import org.thingsboard.rule.engine.flow.TbRuleChainInputNode; +import org.thingsboard.rule.engine.flow.TbRuleChainInputNodeConfiguration; +import org.thingsboard.rule.engine.flow.TbRuleChainOutputNode; +import org.thingsboard.rule.engine.flow.TbRuleChainOutputNodeConfiguration; +import org.thingsboard.server.common.data.StringUtils; +import org.thingsboard.server.common.data.id.RuleChainId; +import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.relation.EntityRelation; +import org.thingsboard.server.common.data.rule.RuleChain; +import org.thingsboard.server.common.data.rule.RuleChainMetaData; +import org.thingsboard.server.common.data.rule.RuleChainOutputLabelsUsage; +import org.thingsboard.server.common.data.rule.RuleChainUpdateResult; +import org.thingsboard.server.common.data.rule.RuleNode; +import org.thingsboard.server.common.data.rule.RuleNodeUpdateResult; +import org.thingsboard.server.dao.rule.RuleChainService; +import org.thingsboard.server.queue.util.TbCoreComponent; +import org.thingsboard.server.service.security.permission.Operation; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeSet; +import java.util.stream.Collectors; + +@RequiredArgsConstructor +@Service +@TbCoreComponent +@Slf4j +public class DefaultTbRuleChainService implements TbRuleChainService { + + private final RuleChainService ruleChainService; + + @Override + public Set getRuleChainOutputLabels(TenantId tenantId, RuleChainId ruleChainId) { + RuleChainMetaData metaData = ruleChainService.loadRuleChainMetaData(tenantId, ruleChainId); + Set outputLabels = new TreeSet<>(); + for (RuleNode ruleNode : metaData.getNodes()) { + if (isOutputRuleNode(ruleNode)) { + try { + var configuration = JacksonUtil.treeToValue(ruleNode.getConfiguration(), TbRuleChainOutputNodeConfiguration.class); + if (StringUtils.isNotEmpty(configuration.getLabel())) { + outputLabels.add(configuration.getLabel()); + } + } catch (Exception e) { + log.warn("[{}][{}] Failed to decode rule node configuration", tenantId, ruleChainId, e); + } + } + } + return outputLabels; + } + + @Override + public List getOutputLabelUsage(TenantId tenantId, RuleChainId ruleChainId) { + List ruleNodes = ruleChainService.findRuleNodesByTenantIdAndType(tenantId, TbRuleChainInputNode.class.getName(), ruleChainId.getId().toString()); + Map ruleChainNamesCache = new HashMap<>(); + // Additional filter, "just in case" the structure of the JSON configuration will change. + var filteredRuleNodes = ruleNodes.stream().filter(node -> { + try { + TbRuleChainInputNodeConfiguration configuration = JacksonUtil.treeToValue(node.getConfiguration(), TbRuleChainInputNodeConfiguration.class); + return ruleChainId.getId().toString().equals(configuration.getRuleChainId()); + } catch (Exception e) { + log.warn("[{}][{}] Failed to decode rule node configuration", tenantId, ruleChainId, e); + return false; + } + }).collect(Collectors.toList()); + + + return filteredRuleNodes.stream() + .map(ruleNode -> { + RuleChainOutputLabelsUsage usage = new RuleChainOutputLabelsUsage(); + usage.setRuleNodeId(ruleNode.getId()); + usage.setRuleNodeName(ruleNode.getName()); + usage.setRuleChainId(ruleNode.getRuleChainId()); + List relations = ruleChainService.getRuleNodeRelations(tenantId, ruleNode.getId()); + if (relations != null && !relations.isEmpty()) { + usage.setLabels(relations.stream().map(EntityRelation::getType).collect(Collectors.toSet())); + } + return usage; + }) + .filter(usage -> usage.getLabels() != null) + .peek(usage -> { + String ruleChainName = ruleChainNamesCache.computeIfAbsent(usage.getRuleChainId(), + id -> ruleChainService.findRuleChainById(tenantId, id).getName()); + usage.setRuleChainName(ruleChainName); + }) + .sorted(Comparator + .comparing(RuleChainOutputLabelsUsage::getRuleChainName) + .thenComparing(RuleChainOutputLabelsUsage::getRuleNodeName)) + .collect(Collectors.toList()); + } + + @Override + public void updateRelatedRuleChains(TenantId tenantId, RuleChainId ruleChainId, RuleChainUpdateResult result) { + log.debug("[{}][{}] Going to update links in related rule chains", tenantId, ruleChainId); + if (result.getUpdatedRuleNodes() == null || result.getUpdatedRuleNodes().isEmpty()) { + return; + } + + Set oldLabels = new HashSet<>(); + Set newLabels = new HashSet<>(); + Set confusedLabels = new HashSet<>(); + Map updatedLabels = new HashMap<>(); + for (RuleNodeUpdateResult update : result.getUpdatedRuleNodes()) { + var node = update.getNewRuleNode(); + if (isOutputRuleNode(node)) { + try { + TbRuleChainOutputNodeConfiguration oldConf = JacksonUtil.treeToValue(update.getOldConfiguration(), TbRuleChainOutputNodeConfiguration.class); + TbRuleChainOutputNodeConfiguration newConf = JacksonUtil.treeToValue(node.getConfiguration(), TbRuleChainOutputNodeConfiguration.class); + oldLabels.add(oldConf.getLabel()); + newLabels.add(newConf.getLabel()); + if (!oldConf.getLabel().equals(newConf.getLabel())) { + String oldLabel = oldConf.getLabel(); + String newLabel = newConf.getLabel(); + if (updatedLabels.containsKey(oldLabel)) { + confusedLabels.add(oldLabel); + } else { + updatedLabels.put(oldLabel, newLabel); + } + + } + } catch (Exception e) { + log.warn("[{}][{}][{}] Failed to decode rule node configuration", tenantId, ruleChainId, node.getId(), e); + } + } + } + // Remove all labels that are renamed to two or more different labels, since we don't which new label to use; + confusedLabels.forEach(updatedLabels::remove); + // Remove all labels that are renamed to different new labels; + newLabels.forEach(updatedLabels::remove); + if (!oldLabels.equals(newLabels)) { + for (upda) + } + } + + private boolean isOutputRuleNode(RuleNode ruleNode) { + return isRuleNode(ruleNode, TbRuleChainOutputNode.class); + } + + private boolean isInputRuleNode(RuleNode ruleNode) { + return isRuleNode(ruleNode, TbRuleChainInputNode.class); + } + + private boolean isRuleNode(RuleNode ruleNode, Class clazz) { + return ruleNode.getType().equals(clazz.getName()); + } +} diff --git a/application/src/main/java/org/thingsboard/server/service/rule/TbRuleChainService.java b/application/src/main/java/org/thingsboard/server/service/rule/TbRuleChainService.java new file mode 100644 index 0000000000..06f8c73dad --- /dev/null +++ b/application/src/main/java/org/thingsboard/server/service/rule/TbRuleChainService.java @@ -0,0 +1,19 @@ +package org.thingsboard.server.service.rule; + +import com.fasterxml.jackson.core.JsonProcessingException; +import org.thingsboard.server.common.data.id.RuleChainId; +import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.rule.RuleChainOutputLabelsUsage; +import org.thingsboard.server.common.data.rule.RuleChainUpdateResult; + +import java.util.List; +import java.util.Set; + +public interface TbRuleChainService { + + Set getRuleChainOutputLabels(TenantId tenantId, RuleChainId ruleChainId); + + List getOutputLabelUsage(TenantId tenantId, RuleChainId ruleChainId); + + void updateRelatedRuleChains(TenantId tenantId, RuleChainId ruleChainId, RuleChainUpdateResult result); +} diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/rule/RuleChainService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/rule/RuleChainService.java index e089d7bf47..f46393b5d1 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/rule/RuleChainService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/rule/RuleChainService.java @@ -28,7 +28,9 @@ import org.thingsboard.server.common.data.rule.RuleChain; import org.thingsboard.server.common.data.rule.RuleChainData; import org.thingsboard.server.common.data.rule.RuleChainImportResult; import org.thingsboard.server.common.data.rule.RuleChainMetaData; +import org.thingsboard.server.common.data.rule.RuleChainOutputLabelsUsage; import org.thingsboard.server.common.data.rule.RuleChainType; +import org.thingsboard.server.common.data.rule.RuleChainUpdateResult; import org.thingsboard.server.common.data.rule.RuleNode; import java.util.List; @@ -42,7 +44,7 @@ public interface RuleChainService { boolean setRootRuleChain(TenantId tenantId, RuleChainId ruleChainId); - boolean saveRuleChainMetaData(TenantId tenantId, RuleChainMetaData ruleChainMetaData); + RuleChainUpdateResult saveRuleChainMetaData(TenantId tenantId, RuleChainMetaData ruleChainMetaData); RuleChainMetaData loadRuleChainMetaData(TenantId tenantId, RuleChainId ruleChainId); @@ -88,4 +90,5 @@ public interface RuleChainService { PageData findAutoAssignToEdgeRuleChainsByTenantId(TenantId tenantId, PageLink pageLink); + List findRuleNodesByTenantIdAndType(TenantId tenantId, String name, String toString); } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleChainMetaData.java b/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleChainMetaData.java index 00b64ba9a9..2193e86f66 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleChainMetaData.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleChainMetaData.java @@ -24,6 +24,7 @@ import org.thingsboard.server.common.data.id.RuleChainId; import javax.validation.Valid; import java.util.ArrayList; import java.util.List; +import java.util.Map; /** * Created by igor on 3/13/18. diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleChainOutputLabelsUsage.java b/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleChainOutputLabelsUsage.java new file mode 100644 index 0000000000..0283dbf517 --- /dev/null +++ b/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleChainOutputLabelsUsage.java @@ -0,0 +1,45 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.common.data.rule; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.extern.slf4j.Slf4j; +import org.jetbrains.annotations.NotNull; +import org.thingsboard.server.common.data.id.RuleChainId; +import org.thingsboard.server.common.data.id.RuleNodeId; + +import java.util.Set; + +@ApiModel +@Data +@Slf4j +public class RuleChainOutputLabelsUsage { + + @ApiModelProperty(position = 1, required = true, value = "Rule Chain Id", accessMode = ApiModelProperty.AccessMode.READ_ONLY) + private RuleChainId ruleChainId; + @ApiModelProperty(position = 2, required = true, value = "Rule Node Id", accessMode = ApiModelProperty.AccessMode.READ_ONLY) + private RuleNodeId ruleNodeId; + + @ApiModelProperty(position = 3, required = true, value = "Rule Chain Name", accessMode = ApiModelProperty.AccessMode.READ_ONLY) + private String ruleChainName; + @ApiModelProperty(position = 4, required = true, value = "Rule Node Name", accessMode = ApiModelProperty.AccessMode.READ_ONLY) + private String ruleNodeName; + @ApiModelProperty(position = 5, required = true, value = "Output labels", accessMode = ApiModelProperty.AccessMode.READ_ONLY) + private Set labels; + +} diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleChainUpdateResult.java b/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleChainUpdateResult.java new file mode 100644 index 0000000000..76e6ce9870 --- /dev/null +++ b/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleChainUpdateResult.java @@ -0,0 +1,44 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.common.data.rule; + +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Data; +import org.thingsboard.server.common.data.id.RuleNodeId; + +import java.util.List; +import java.util.Map; + +/** + * Created by igor on 3/13/18. + */ +@Data +@AllArgsConstructor(access = AccessLevel.PRIVATE) +public class RuleChainUpdateResult { + + private final boolean success; + private final List updatedRuleNodes; + + public static RuleChainUpdateResult failed(){ + return new RuleChainUpdateResult(false, null); + } + + public static RuleChainUpdateResult successful(List updatedRuleNodes){ + return new RuleChainUpdateResult(true, updatedRuleNodes); + } + +} diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleNodeUpdateResult.java b/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleNodeUpdateResult.java new file mode 100644 index 0000000000..a279533138 --- /dev/null +++ b/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleNodeUpdateResult.java @@ -0,0 +1,32 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.common.data.rule; + +import com.fasterxml.jackson.databind.JsonNode; +import lombok.Data; +import org.thingsboard.server.common.data.id.RuleNodeId; + +import java.util.Map; + +/** + * Created by igor on 3/13/18. + */ +@Data +public class RuleNodeUpdateResult { + + private final JsonNode oldConfiguration; + private final RuleNode newRuleNode; +} diff --git a/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsgProcessingCtx.java b/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsgProcessingCtx.java index 9f3b78fffa..7d65108b1f 100644 --- a/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsgProcessingCtx.java +++ b/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsgProcessingCtx.java @@ -5,7 +5,7 @@ * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -51,7 +51,11 @@ public final class TbMsgProcessingCtx implements Serializable { } public TbMsgProcessingCtx copy() { - return new TbMsgProcessingCtx(ruleNodeExecCounter.get()); + if (stack == null || stack.isEmpty()) { + return new TbMsgProcessingCtx(ruleNodeExecCounter.get()); + } else { + return new TbMsgProcessingCtx(ruleNodeExecCounter.get(), new LinkedList<>(stack)); + } } public void push(RuleChainId ruleChainId, RuleNodeId ruleNodeId) { @@ -70,10 +74,7 @@ public final class TbMsgProcessingCtx implements Serializable { if (ctx.getStackCount() > 0) { LinkedList stack = new LinkedList<>(); for (MsgProtos.TbMsgProcessingStackItemProto item : ctx.getStackList()) { - stack.add(new TbMsgProcessingStackItem( - new RuleChainId(new UUID(item.getRuleChainIdMSB(), item.getRuleChainIdLSB())), - new RuleNodeId(new UUID(item.getRuleNodeIdMSB(), item.getRuleNodeIdLSB())) - )); + stack.add(TbMsgProcessingStackItem.fromProto(item)); } return new TbMsgProcessingCtx(ruleNodeExecCounter, stack); } else { diff --git a/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsgProcessingStackItem.java b/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsgProcessingStackItem.java index ff765594fe..6490ddf547 100644 --- a/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsgProcessingStackItem.java +++ b/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsgProcessingStackItem.java @@ -20,6 +20,8 @@ import org.thingsboard.server.common.data.id.RuleChainId; import org.thingsboard.server.common.data.id.RuleNodeId; import org.thingsboard.server.common.msg.gen.MsgProtos; +import java.util.UUID; + @Data public class TbMsgProcessingStackItem { @@ -35,4 +37,11 @@ public class TbMsgProcessingStackItem { .build(); } + static TbMsgProcessingStackItem fromProto(MsgProtos.TbMsgProcessingStackItemProto item){ + return new TbMsgProcessingStackItem( + new RuleChainId(new UUID(item.getRuleChainIdMSB(), item.getRuleChainIdLSB())), + new RuleNodeId(new UUID(item.getRuleNodeIdMSB(), item.getRuleNodeIdLSB())) + ); + } + } diff --git a/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java b/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java index 32dbe39502..a2378225e4 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java @@ -5,7 +5,7 @@ * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -47,8 +47,11 @@ import org.thingsboard.server.common.data.rule.RuleChainConnectionInfo; import org.thingsboard.server.common.data.rule.RuleChainData; import org.thingsboard.server.common.data.rule.RuleChainImportResult; import org.thingsboard.server.common.data.rule.RuleChainMetaData; +import org.thingsboard.server.common.data.rule.RuleChainOutputLabelsUsage; import org.thingsboard.server.common.data.rule.RuleChainType; +import org.thingsboard.server.common.data.rule.RuleChainUpdateResult; import org.thingsboard.server.common.data.rule.RuleNode; +import org.thingsboard.server.common.data.rule.RuleNodeUpdateResult; import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileConfiguration; import org.thingsboard.server.dao.entity.AbstractEntityService; import org.thingsboard.server.dao.exception.DataValidationException; @@ -72,6 +75,7 @@ import java.util.stream.Collectors; import static org.thingsboard.server.common.data.DataConstants.TENANT; import static org.thingsboard.server.dao.service.Validator.validateId; +import static org.thingsboard.server.dao.service.Validator.validateString; /** * Created by igor on 3/12/18. @@ -130,13 +134,14 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC @Override @Transactional - public boolean saveRuleChainMetaData(TenantId tenantId, RuleChainMetaData ruleChainMetaData) { + public RuleChainUpdateResult saveRuleChainMetaData(TenantId tenantId, RuleChainMetaData ruleChainMetaData) { Validator.validateId(ruleChainMetaData.getRuleChainId(), "Incorrect rule chain id."); RuleChain ruleChain = findRuleChainById(tenantId, ruleChainMetaData.getRuleChainId()); if (ruleChain == null) { - return false; + return RuleChainUpdateResult.failed(); } ConstraintValidator.validateFields(ruleChainMetaData); + List updatedRuleNodes = new ArrayList<>(); if (CollectionUtils.isNotEmpty(ruleChainMetaData.getConnections())) { validateCircles(ruleChainMetaData.getConnections()); @@ -161,11 +166,15 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC for (RuleNode existingNode : existingRuleNodes) { deleteEntityRelations(tenantId, existingNode.getId()); Integer index = ruleNodeIndexMap.get(existingNode.getId()); + RuleNode newRuleNode = null; if (index != null) { - toAddOrUpdate.add(ruleChainMetaData.getNodes().get(index)); + newRuleNode = ruleChainMetaData.getNodes().get(index); + toAddOrUpdate.add(newRuleNode); } else { + updatedRuleNodes.add(new RuleNodeUpdateResult(existingNode.getConfiguration(), null)); toDelete.add(existingNode); } + updatedRuleNodes.add(new RuleNodeUpdateResult(existingNode.getConfiguration(), newRuleNode)); } if (nodes != null) { for (RuleNode node : toAddOrUpdate) { @@ -209,7 +218,7 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC } } - return true; + return RuleChainUpdateResult.successful(updatedRuleNodes); } private void validateCircles(List connectionInfos) { @@ -652,6 +661,15 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC return ruleChainDao.findAutoAssignToEdgeRuleChainsByTenantId(tenantId.getId(), pageLink); } + @Override + public List findRuleNodesByTenantIdAndType(TenantId tenantId, String type, String search) { + log.trace("Executing findRuleNodes, tenantId [{}], type {}, search {}", tenantId, type, search); + validateId(tenantId, INCORRECT_TENANT_ID + tenantId); + validateString(type, "Incorrect type of the rule node"); + validateString(search, "Incorrect search text"); + return ruleNodeDao.findRuleNodesByTenantIdAndType(tenantId, type, search); + } + private void checkRuleNodesAndDelete(TenantId tenantId, RuleChainId ruleChainId) { try { ruleChainDao.removeById(tenantId, ruleChainId.getId()); diff --git a/dao/src/main/java/org/thingsboard/server/dao/rule/RuleChainDao.java b/dao/src/main/java/org/thingsboard/server/dao/rule/RuleChainDao.java index 03fd25e944..bf036a8105 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/rule/RuleChainDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/rule/RuleChainDao.java @@ -19,11 +19,13 @@ import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.rule.RuleChain; +import org.thingsboard.server.common.data.rule.RuleChainOutputLabelsUsage; import org.thingsboard.server.common.data.rule.RuleChainType; import org.thingsboard.server.dao.Dao; import org.thingsboard.server.dao.TenantEntityDao; import java.util.Collection; +import java.util.List; import java.util.UUID; /** @@ -79,4 +81,5 @@ public interface RuleChainDao extends Dao, TenantEntityDao { Collection findByTenantIdAndTypeAndName(TenantId tenantId, RuleChainType type, String name); + List getOutputLabelUsage(UUID id, UUID id1); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/rule/RuleNodeDao.java b/dao/src/main/java/org/thingsboard/server/dao/rule/RuleNodeDao.java index 46bfefc15e..4002867ba9 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/rule/RuleNodeDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/rule/RuleNodeDao.java @@ -15,12 +15,16 @@ */ package org.thingsboard.server.dao.rule; +import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.rule.RuleNode; import org.thingsboard.server.dao.Dao; +import java.util.List; + /** * Created by igor on 3/12/18. */ public interface RuleNodeDao extends Dao { + List findRuleNodesByTenantIdAndType(TenantId tenantId, String type, String search); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/rule/JpaRuleChainDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/rule/JpaRuleChainDao.java index 483ab39f06..b432b04f04 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/rule/JpaRuleChainDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/rule/JpaRuleChainDao.java @@ -23,6 +23,7 @@ import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.rule.RuleChain; +import org.thingsboard.server.common.data.rule.RuleChainOutputLabelsUsage; import org.thingsboard.server.common.data.rule.RuleChainType; import org.thingsboard.server.dao.DaoUtil; import org.thingsboard.server.dao.model.sql.RuleChainEntity; @@ -30,6 +31,7 @@ import org.thingsboard.server.dao.rule.RuleChainDao; import org.thingsboard.server.dao.sql.JpaAbstractSearchTextDao; import java.util.Collection; +import java.util.List; import java.util.Objects; import java.util.UUID; @@ -103,6 +105,11 @@ public class JpaRuleChainDao extends JpaAbstractSearchTextDao getOutputLabelUsage(UUID tenantId, UUID ruleChainId) { + return null; + } + @Override public Long countByTenantId(TenantId tenantId) { return ruleChainRepository.countByTenantId(tenantId.getId()); diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/rule/JpaRuleNodeDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/rule/JpaRuleNodeDao.java index 362299f9b3..4b541f8df5 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/rule/JpaRuleNodeDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/rule/JpaRuleNodeDao.java @@ -5,7 +5,7 @@ * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -19,11 +19,14 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.repository.CrudRepository; import org.springframework.stereotype.Component; +import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.rule.RuleNode; +import org.thingsboard.server.dao.DaoUtil; import org.thingsboard.server.dao.model.sql.RuleNodeEntity; import org.thingsboard.server.dao.rule.RuleNodeDao; import org.thingsboard.server.dao.sql.JpaAbstractSearchTextDao; +import java.util.List; import java.util.UUID; @Slf4j @@ -43,4 +46,8 @@ public class JpaRuleNodeDao extends JpaAbstractSearchTextDao findRuleNodesByTenantIdAndType(TenantId tenantId, String type, String search) { + return DaoUtil.convertDataList(ruleNodeRepository.findRuleNodesByTenantIdAndType(tenantId.getId(), type, search)); + } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/rule/RuleNodeRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/rule/RuleNodeRepository.java index 09e4bb55ae..77bd5d4a38 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/rule/RuleNodeRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/rule/RuleNodeRepository.java @@ -15,11 +15,21 @@ */ package org.thingsboard.server.dao.sql.rule; +import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.CrudRepository; +import org.springframework.data.repository.query.Param; import org.thingsboard.server.dao.model.sql.RuleNodeEntity; +import java.util.List; import java.util.UUID; public interface RuleNodeRepository extends CrudRepository { + @Query("SELECT r FROM RuleNodeEntity r WHERE r.ruleChainId in " + + "(select id from RuleChainEntity rc WHERE rc.tenantId = :tenantId) " + + "AND r.type = :ruleType AND LOWER(r.configuration) LIKE LOWER(CONCAT('%', :searchText, '%')) ") + List findRuleNodesByTenantIdAndType(@Param("tenantId") UUID tenantId, + @Param("ruleType") String ruleType, + @Param("searchText") String searchText); + } diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseRuleChainServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseRuleChainServiceTest.java index 109814d330..c1635a6281 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseRuleChainServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseRuleChainServiceTest.java @@ -293,7 +293,7 @@ public abstract class BaseRuleChainServiceTest extends AbstractServiceTest { ruleNodes.set(name3Index, ruleNode4); - Assert.assertTrue(ruleChainService.saveRuleChainMetaData(tenantId, savedRuleChainMetaData)); + Assert.assertTrue(ruleChainService.saveRuleChainMetaData(tenantId, savedRuleChainMetaData).isSuccess()); RuleChainMetaData updatedRuleChainMetaData = ruleChainService.loadRuleChainMetaData(tenantId, savedRuleChainMetaData.getRuleChainId()); Assert.assertEquals(3, updatedRuleChainMetaData.getNodes().size()); @@ -406,7 +406,7 @@ public abstract class BaseRuleChainServiceTest extends AbstractServiceTest { ruleChainMetaData.addConnectionInfo(0,2,"fail"); ruleChainMetaData.addConnectionInfo(1,2,"success"); - Assert.assertTrue(ruleChainService.saveRuleChainMetaData(tenantId, ruleChainMetaData)); + Assert.assertTrue(ruleChainService.saveRuleChainMetaData(tenantId, ruleChainMetaData).isSuccess()); return ruleChainService.loadRuleChainMetaData(tenantId, ruleChainMetaData.getRuleChainId()); } From 9cf0ab69001f3a798c1a093513ebfccdf0a826b2 Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Thu, 2 Dec 2021 20:00:24 +0200 Subject: [PATCH 207/432] Rename of the related rule chains when customer renames the output label --- .../controller/RuleChainController.java | 2 +- .../rule/DefaultTbRuleChainService.java | 49 +++++++++++++++++-- .../service/rule/TbRuleChainService.java | 15 ++++++ .../data/rule/RuleChainOutputLabelsUsage.java | 2 +- .../server/common/msg/TbMsgProcessingCtx.java | 2 +- .../server/dao/rule/BaseRuleChainService.java | 2 +- .../server/dao/sql/rule/JpaRuleNodeDao.java | 2 +- 7 files changed, 65 insertions(+), 9 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java b/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java index 8345a8beef..9122990339 100644 --- a/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java +++ b/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java @@ -5,7 +5,7 @@ * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, diff --git a/application/src/main/java/org/thingsboard/server/service/rule/DefaultTbRuleChainService.java b/application/src/main/java/org/thingsboard/server/service/rule/DefaultTbRuleChainService.java index a76b448611..414abcb0ef 100644 --- a/application/src/main/java/org/thingsboard/server/service/rule/DefaultTbRuleChainService.java +++ b/application/src/main/java/org/thingsboard/server/service/rule/DefaultTbRuleChainService.java @@ -1,3 +1,18 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.thingsboard.server.service.rule; import com.fasterxml.jackson.core.JsonProcessingException; @@ -11,6 +26,7 @@ import org.thingsboard.rule.engine.flow.TbRuleChainOutputNode; import org.thingsboard.rule.engine.flow.TbRuleChainOutputNodeConfiguration; import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.data.id.RuleChainId; +import org.thingsboard.server.common.data.id.RuleNodeId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.relation.EntityRelation; import org.thingsboard.server.common.data.rule.RuleChain; @@ -19,6 +35,7 @@ import org.thingsboard.server.common.data.rule.RuleChainOutputLabelsUsage; import org.thingsboard.server.common.data.rule.RuleChainUpdateResult; import org.thingsboard.server.common.data.rule.RuleNode; import org.thingsboard.server.common.data.rule.RuleNodeUpdateResult; +import org.thingsboard.server.dao.relation.RelationService; import org.thingsboard.server.dao.rule.RuleChainService; import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.service.security.permission.Operation; @@ -40,6 +57,7 @@ import java.util.stream.Collectors; public class DefaultTbRuleChainService implements TbRuleChainService { private final RuleChainService ruleChainService; + private final RelationService relationService; @Override public Set getRuleChainOutputLabels(TenantId tenantId, RuleChainId ruleChainId) { @@ -122,8 +140,9 @@ public class DefaultTbRuleChainService implements TbRuleChainService { if (!oldConf.getLabel().equals(newConf.getLabel())) { String oldLabel = oldConf.getLabel(); String newLabel = newConf.getLabel(); - if (updatedLabels.containsKey(oldLabel)) { + if (updatedLabels.containsKey(oldLabel) && !updatedLabels.get(oldLabel).equals(newLabel)) { confusedLabels.add(oldLabel); + log.warn("[{}][{}] Can't automatically rename the label from [{}] to [{}] due to conflict [{}]", tenantId, ruleChainId, oldLabel, newLabel, updatedLabels.get(oldLabel)); } else { updatedLabels.put(oldLabel, newLabel); } @@ -134,12 +153,34 @@ public class DefaultTbRuleChainService implements TbRuleChainService { } } } - // Remove all labels that are renamed to two or more different labels, since we don't which new label to use; + // Remove all output labels that are renamed to two or more different labels, since we don't which new label to use; confusedLabels.forEach(updatedLabels::remove); - // Remove all labels that are renamed to different new labels; + // Remove all output labels that are renamed but still present in the rule chain; newLabels.forEach(updatedLabels::remove); if (!oldLabels.equals(newLabels)) { - for (upda) + updateRelatedRuleChains(tenantId, ruleChainId, updatedLabels); + } + } + + public void updateRelatedRuleChains(TenantId tenantId, RuleChainId ruleChainId, Map labelsMap) { + List usageList = getOutputLabelUsage(tenantId, ruleChainId); + for (RuleChainOutputLabelsUsage usage : usageList) { + labelsMap.forEach((oldLabel, newLabel) -> { + if (usage.getLabels().contains(oldLabel)) { + renameOutgoingLinks(tenantId, usage.getRuleNodeId(), oldLabel, newLabel); + } + }); + } + } + + private void renameOutgoingLinks(TenantId tenantId, RuleNodeId ruleNodeId, String oldLabel, String newLabel) { + List relations = ruleChainService.getRuleNodeRelations(tenantId, ruleNodeId); + for (EntityRelation relation : relations) { + if (relation.getType().equals(oldLabel)) { + relationService.deleteRelation(tenantId, relation); + relation.setType(newLabel); + relationService.saveRelation(tenantId, relation); + } } } diff --git a/application/src/main/java/org/thingsboard/server/service/rule/TbRuleChainService.java b/application/src/main/java/org/thingsboard/server/service/rule/TbRuleChainService.java index 06f8c73dad..d08f234d8e 100644 --- a/application/src/main/java/org/thingsboard/server/service/rule/TbRuleChainService.java +++ b/application/src/main/java/org/thingsboard/server/service/rule/TbRuleChainService.java @@ -1,3 +1,18 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.thingsboard.server.service.rule; import com.fasterxml.jackson.core.JsonProcessingException; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleChainOutputLabelsUsage.java b/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleChainOutputLabelsUsage.java index 0283dbf517..3e0bde1c94 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleChainOutputLabelsUsage.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleChainOutputLabelsUsage.java @@ -5,7 +5,7 @@ * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, diff --git a/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsgProcessingCtx.java b/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsgProcessingCtx.java index 7d65108b1f..47bcf683b0 100644 --- a/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsgProcessingCtx.java +++ b/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsgProcessingCtx.java @@ -5,7 +5,7 @@ * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, diff --git a/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java b/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java index a2378225e4..b747fd4851 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java @@ -5,7 +5,7 @@ * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/rule/JpaRuleNodeDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/rule/JpaRuleNodeDao.java index 4b541f8df5..2e7d796cb3 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/rule/JpaRuleNodeDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/rule/JpaRuleNodeDao.java @@ -5,7 +5,7 @@ * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, From bbd1d8ae8683890d8aa0ea1971e3d63668e2aefc Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Fri, 3 Dec 2021 11:57:31 +0200 Subject: [PATCH 208/432] Migration script --- .../install/ThingsboardInstallService.java | 3 + .../update/DefaultDataUpdateService.java | 84 +++++++++++++++++++ .../rule/DefaultTbRuleChainService.java | 2 +- .../server/dao/relation/RelationService.java | 6 ++ .../server/dao/rule/RuleChainService.java | 2 + .../dao/relation/BaseRelationService.java | 17 +++- .../server/dao/relation/RelationDao.java | 5 +- .../server/dao/rule/BaseRuleChainService.java | 6 ++ .../dao/sql/relation/JpaRelationDao.java | 9 +- .../dao/sql/relation/RelationRepository.java | 21 +++++ .../dao/sql/rule/RuleChainRepository.java | 5 ++ 11 files changed, 153 insertions(+), 7 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java b/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java index ccdac8b363..702a73decc 100644 --- a/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java +++ b/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java @@ -210,6 +210,9 @@ public class ThingsboardInstallService { log.info("Upgrading ThingsBoard from version 3.3.0 to 3.3.1 ..."); case "3.3.1": log.info("Upgrading ThingsBoard from version 3.3.1 to 3.3.2 ..."); + case "3.3.2": + log.info("Upgrading ThingsBoard from version 3.3.2 to 3.3.3 ..."); + dataUpdateService.updateData("3.3.2"); log.info("Updating system data..."); systemDataLoaderService.updateSystemWidgets(); break; diff --git a/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java b/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java index de483dfda8..e244a0f0b0 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java @@ -25,6 +25,8 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Profile; import org.springframework.stereotype.Service; import org.thingsboard.common.util.JacksonUtil; +import org.thingsboard.rule.engine.flow.TbRuleChainInputNode; +import org.thingsboard.rule.engine.flow.TbRuleChainInputNodeConfiguration; import org.thingsboard.rule.engine.profile.TbDeviceProfileNode; import org.thingsboard.rule.engine.profile.TbDeviceProfileNodeConfiguration; import org.thingsboard.server.common.data.EntityView; @@ -34,6 +36,8 @@ import org.thingsboard.server.common.data.alarm.AlarmInfo; import org.thingsboard.server.common.data.alarm.AlarmQuery; import org.thingsboard.server.common.data.alarm.AlarmSeverity; import org.thingsboard.server.common.data.id.EntityViewId; +import org.thingsboard.server.common.data.id.RuleChainId; +import org.thingsboard.server.common.data.id.RuleNodeId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.kv.BaseReadTsKvQuery; import org.thingsboard.server.common.data.kv.ReadTsKvQuery; @@ -43,8 +47,11 @@ import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.page.TimePageLink; import org.thingsboard.server.common.data.query.DynamicValue; import org.thingsboard.server.common.data.query.FilterPredicateValue; +import org.thingsboard.server.common.data.relation.EntityRelation; +import org.thingsboard.server.common.data.relation.RelationTypeGroup; import org.thingsboard.server.common.data.rule.RuleChain; import org.thingsboard.server.common.data.rule.RuleChainMetaData; +import org.thingsboard.server.common.data.rule.RuleChainType; import org.thingsboard.server.common.data.rule.RuleNode; import org.thingsboard.server.dao.DaoUtil; import org.thingsboard.server.dao.alarm.AlarmDao; @@ -52,7 +59,9 @@ import org.thingsboard.server.dao.alarm.AlarmService; import org.thingsboard.server.dao.entity.EntityService; import org.thingsboard.server.dao.entityview.EntityViewService; import org.thingsboard.server.dao.model.sql.DeviceProfileEntity; +import org.thingsboard.server.dao.model.sql.RelationEntity; import org.thingsboard.server.dao.oauth2.OAuth2Service; +import org.thingsboard.server.dao.relation.RelationService; import org.thingsboard.server.dao.rule.RuleChainService; import org.thingsboard.server.dao.sql.device.DeviceProfileRepository; import org.thingsboard.server.dao.tenant.TenantService; @@ -76,6 +85,9 @@ public class DefaultDataUpdateService implements DataUpdateService { @Autowired private TenantService tenantService; + @Autowired + private RelationService relationService; + @Autowired private RuleChainService ruleChainService; @@ -125,6 +137,10 @@ public class DefaultDataUpdateService implements DataUpdateService { deviceProfileEntityDynamicConditionsUpdater.updateEntities(null); updateOAuth2Params(); break; + case "3.3.2": + log.info("Updating data from version 3.3.2 to 3.3.3 ..."); + nestedRuleNodeUpdater.updateEntities(null); + break; default: throw new RuntimeException("Unable to update data, unsupported fromVersion: " + fromVersion); } @@ -209,6 +225,74 @@ public class DefaultDataUpdateService implements DataUpdateService { } }; + private final PaginatedUpdater nestedRuleNodeUpdater = + new PaginatedUpdater<>() { + + @Override + protected String getName() { + return "Tenants nested rule chain updater"; + } + + @Override + protected boolean forceReportTotal() { + return true; + } + + @Override + protected PageData findEntities(String region, PageLink pageLink) { + return tenantService.findTenants(pageLink); + } + + @Override + protected void updateEntity(Tenant tenant) { + try { + var tenantId = tenant.getId(); + var packSize = 1024; + boolean hasNext = true; + while (hasNext) { + List relations = relationService.findRuleNodeToRuleChainRelations(tenantId, RuleChainType.CORE, packSize); + hasNext = relations.size() == packSize; + for (EntityRelation relation : relations) { + + RuleNode sourceNode = ruleChainService.findRuleNodeById(tenantId, new RuleNodeId(relation.getFrom().getId())); + RuleChainId sourceRuleChainId = sourceNode.getRuleChainId(); + RuleChain targetRuleChain = ruleChainService.findRuleChainById(tenantId, new RuleChainId(relation.getTo().getId())); + RuleNode targetNode = new RuleNode(); + targetNode.setName(targetRuleChain.getName()); + targetNode.setRuleChainId(sourceRuleChainId); + targetNode.setType(TbRuleChainInputNode.class.getName()); + TbRuleChainInputNodeConfiguration configuration = new TbRuleChainInputNodeConfiguration(); + configuration.setRuleChainId(targetRuleChain.getId().toString()); + targetNode.setConfiguration(JacksonUtil.valueToTree(configuration)); + targetNode.setAdditionalInfo(relation.getAdditionalInfo()); + targetNode.setDebugMode(false); + targetNode = ruleChainService.saveRuleNode(tenantId, targetNode); + + EntityRelation sourceRuleChainToRuleNode = new EntityRelation(); + sourceRuleChainToRuleNode.setFrom(sourceRuleChainId); + sourceRuleChainToRuleNode.setTo(targetNode.getId()); + sourceRuleChainToRuleNode.setType(EntityRelation.CONTAINS_TYPE); + sourceRuleChainToRuleNode.setTypeGroup(RelationTypeGroup.RULE_CHAIN); + relationService.saveRelation(tenantId, sourceRuleChainToRuleNode); + + EntityRelation sourceRuleNodeToTargetRuleNode = new EntityRelation(); + sourceRuleNodeToTargetRuleNode.setFrom(sourceNode.getId()); + sourceRuleNodeToTargetRuleNode.setTo(targetNode.getId()); + sourceRuleNodeToTargetRuleNode.setType(relation.getType()); + sourceRuleNodeToTargetRuleNode.setTypeGroup(RelationTypeGroup.RULE_NODE); + sourceRuleNodeToTargetRuleNode.setAdditionalInfo(relation.getAdditionalInfo()); + relationService.saveRelation(tenantId, sourceRuleNodeToTargetRuleNode); + + //Delete old relation + relationService.deleteRelation(tenantId, relation); + } + } + } catch (Exception e) { + log.error("Unable to update Tenant", e); + } + } + }; + private final PaginatedUpdater tenantsDefaultEdgeRuleChainUpdater = new PaginatedUpdater<>() { diff --git a/application/src/main/java/org/thingsboard/server/service/rule/DefaultTbRuleChainService.java b/application/src/main/java/org/thingsboard/server/service/rule/DefaultTbRuleChainService.java index 414abcb0ef..e6d1ba1d8a 100644 --- a/application/src/main/java/org/thingsboard/server/service/rule/DefaultTbRuleChainService.java +++ b/application/src/main/java/org/thingsboard/server/service/rule/DefaultTbRuleChainService.java @@ -193,6 +193,6 @@ public class DefaultTbRuleChainService implements TbRuleChainService { } private boolean isRuleNode(RuleNode ruleNode, Class clazz) { - return ruleNode.getType().equals(clazz.getName()); + return ruleNode != null && ruleNode.getType().equals(clazz.getName()); } } diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/relation/RelationService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/relation/RelationService.java index c8f2a38005..87ac26b41e 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/relation/RelationService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/relation/RelationService.java @@ -16,12 +16,16 @@ package org.thingsboard.server.dao.relation; import com.google.common.util.concurrent.ListenableFuture; +import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.page.PageData; +import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.relation.EntityRelation; import org.thingsboard.server.common.data.relation.EntityRelationInfo; import org.thingsboard.server.common.data.relation.EntityRelationsQuery; import org.thingsboard.server.common.data.relation.RelationTypeGroup; +import org.thingsboard.server.common.data.rule.RuleChainType; import java.util.List; @@ -78,6 +82,8 @@ public interface RelationService { void removeRelations(TenantId tenantId, EntityId entityId); + List findRuleNodeToRuleChainRelations(TenantId tenantId, RuleChainType ruleChainType, int limit); + // TODO: This method may be useful for some validations in the future // ListenableFuture checkRecursiveRelation(EntityId from, EntityId to); diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/rule/RuleChainService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/rule/RuleChainService.java index f46393b5d1..48f16215bb 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/rule/RuleChainService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/rule/RuleChainService.java @@ -91,4 +91,6 @@ public interface RuleChainService { PageData findAutoAssignToEdgeRuleChainsByTenantId(TenantId tenantId, PageLink pageLink); List findRuleNodesByTenantIdAndType(TenantId tenantId, String name, String toString); + + RuleNode saveRuleNode(TenantId tenantId, RuleNode ruleNode); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/relation/BaseRelationService.java b/dao/src/main/java/org/thingsboard/server/dao/relation/BaseRelationService.java index 2be2331a99..1e1d0eee18 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/relation/BaseRelationService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/relation/BaseRelationService.java @@ -30,8 +30,11 @@ import org.springframework.cache.annotation.Caching; import org.springframework.dao.ConcurrencyFailureException; import org.springframework.stereotype.Service; import org.springframework.util.StringUtils; +import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.page.PageData; +import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.relation.EntityRelation; import org.thingsboard.server.common.data.relation.EntityRelationInfo; import org.thingsboard.server.common.data.relation.EntityRelationsQuery; @@ -39,6 +42,7 @@ import org.thingsboard.server.common.data.relation.EntitySearchDirection; import org.thingsboard.server.common.data.relation.RelationEntityTypeFilter; import org.thingsboard.server.common.data.relation.RelationTypeGroup; import org.thingsboard.server.common.data.relation.RelationsSearchParameters; +import org.thingsboard.server.common.data.rule.RuleChainType; import org.thingsboard.server.dao.entity.EntityService; import org.thingsboard.server.dao.exception.DataValidationException; import org.thingsboard.server.dao.service.ConstraintValidator; @@ -54,6 +58,7 @@ import java.util.concurrent.ExecutionException; import java.util.function.BiConsumer; import static org.thingsboard.server.common.data.CacheConstants.RELATIONS_CACHE; +import static org.thingsboard.server.dao.service.Validator.validateId; /** * Created by ashvayka on 28.04.17. @@ -194,11 +199,11 @@ public class BaseRelationService implements RelationService { outboundRelations.addAll(relationDao.findAllByFrom(tenantId, entityId, typeGroup)); } - for (EntityRelation relation : inboundRelations){ + for (EntityRelation relation : inboundRelations) { delete(tenantId, cache, relation, true); } - for (EntityRelation relation : outboundRelations){ + for (EntityRelation relation : outboundRelations) { delete(tenantId, cache, relation, false); } @@ -556,6 +561,14 @@ public class BaseRelationService implements RelationService { } } + @Override + public List findRuleNodeToRuleChainRelations(TenantId tenantId, RuleChainType ruleChainType, int limit) { + log.trace("Executing findRuleNodeToRuleChainRelations, tenantId [{}] and limit {}", + tenantId, limit); + validateId(tenantId, "Invalid tenant id: " + tenantId); + return relationDao.findRuleNodeToRuleChainRelations(tenantId, ruleChainType, limit); + } + protected void validate(EntityRelation relation) { if (relation == null) { throw new DataValidationException("Relation type should be specified!"); diff --git a/dao/src/main/java/org/thingsboard/server/dao/relation/RelationDao.java b/dao/src/main/java/org/thingsboard/server/dao/relation/RelationDao.java index d60f176832..efb516af3e 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/relation/RelationDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/relation/RelationDao.java @@ -16,13 +16,11 @@ package org.thingsboard.server.dao.relation; import com.google.common.util.concurrent.ListenableFuture; -import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; -import org.thingsboard.server.common.data.page.PageData; -import org.thingsboard.server.common.data.page.TimePageLink; import org.thingsboard.server.common.data.relation.EntityRelation; import org.thingsboard.server.common.data.relation.RelationTypeGroup; +import org.thingsboard.server.common.data.rule.RuleChainType; import java.util.List; @@ -63,4 +61,5 @@ public interface RelationDao { ListenableFuture deleteOutboundRelationsAsync(TenantId tenantId, EntityId entity); + List findRuleNodeToRuleChainRelations(TenantId tenantId, RuleChainType ruleChainType, int limit); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java b/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java index b747fd4851..e1aaa31d3c 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java @@ -28,6 +28,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.BaseData; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.Tenant; @@ -670,6 +671,11 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC return ruleNodeDao.findRuleNodesByTenantIdAndType(tenantId, type, search); } + @Override + public RuleNode saveRuleNode(TenantId tenantId, RuleNode ruleNode) { + return ruleNodeDao.save(tenantId, ruleNode); + } + private void checkRuleNodesAndDelete(TenantId tenantId, RuleChainId ruleChainId) { try { ruleChainDao.removeById(tenantId, ruleChainId.getId()); diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/relation/JpaRelationDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/relation/JpaRelationDao.java index 2eaa5c28a2..5291da6669 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/relation/JpaRelationDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/relation/JpaRelationDao.java @@ -19,6 +19,7 @@ import com.google.common.util.concurrent.ListenableFuture; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.dao.ConcurrencyFailureException; +import org.springframework.data.domain.PageRequest; import org.springframework.data.jpa.domain.Specification; import org.springframework.stereotype.Component; import org.thingsboard.server.common.data.EntityType; @@ -26,6 +27,7 @@ import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.relation.EntityRelation; import org.thingsboard.server.common.data.relation.RelationTypeGroup; +import org.thingsboard.server.common.data.rule.RuleChainType; import org.thingsboard.server.dao.DaoUtil; import org.thingsboard.server.dao.model.sql.RelationCompositeKey; import org.thingsboard.server.dao.model.sql.RelationEntity; @@ -196,11 +198,16 @@ public class JpaRelationDao extends JpaAbstractDaoListeningExecutorService imple }); } + @Override + public List findRuleNodeToRuleChainRelations(TenantId tenantId, RuleChainType ruleChainType, int limit) { + return DaoUtil.convertDataList(relationRepository.findRuleNodeToRuleChainRelations(tenantId.getId(), ruleChainType, PageRequest.of(0, limit))); + } + private Specification getEntityFieldsSpec(EntityId from, String relationType, RelationTypeGroup typeGroup, EntityType childType) { return (root, criteriaQuery, criteriaBuilder) -> { List predicates = new ArrayList<>(); if (from != null) { - Predicate fromIdPredicate = criteriaBuilder.equal(root.get("fromId"), from.getId()); + Predicate fromIdPredicate = criteriaBuilder.equal(root.get("fromId"), from.getId()); predicates.add(fromIdPredicate); Predicate fromEntityTypePredicate = criteriaBuilder.equal(root.get("fromType"), from.getEntityType().name()); predicates.add(fromEntityTypePredicate); diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/relation/RelationRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/relation/RelationRepository.java index c5a1774ae6..28b125ac3c 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/relation/RelationRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/relation/RelationRepository.java @@ -15,11 +15,20 @@ */ package org.thingsboard.server.dao.sql.relation; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; +import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.CrudRepository; +import org.springframework.data.repository.query.Param; import org.springframework.transaction.annotation.Transactional; +import org.thingsboard.server.common.data.EntityType; +import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.relation.RelationTypeGroup; +import org.thingsboard.server.common.data.rule.RuleChainType; import org.thingsboard.server.dao.model.sql.RelationCompositeKey; import org.thingsboard.server.dao.model.sql.RelationEntity; +import org.thingsboard.server.dao.model.sql.RuleChainEntity; import java.util.List; import java.util.UUID; @@ -48,6 +57,17 @@ public interface RelationRepository List findAllByFromIdAndFromType(UUID fromId, String fromType); + @Query("SELECT r FROM RelationEntity r WHERE " + + "r.fromId in (SELECT id from RuleNodeEntity where ruleChainId in " + + "(SELECT id from RuleChainEntity where tenantId = :tenantId and type = :ruleChainType ))" + + "AND r.fromType = 'RULE_NODE' " + + "AND r.toType = 'RULE_CHAIN' " + + "AND r.relationTypeGroup = 'RULE_NODE'") + List findRuleNodeToRuleChainRelations( + @Param("tenantId") UUID tenantId, + @Param("ruleChainType") RuleChainType ruleChainType, + Pageable page); + @Transactional S save(S entity); @@ -56,4 +76,5 @@ public interface RelationRepository @Transactional void deleteByFromIdAndFromType(UUID fromId, String fromType); + } diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/rule/RuleChainRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/rule/RuleChainRepository.java index 750b59e363..9b80dad34f 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/rule/RuleChainRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/rule/RuleChainRepository.java @@ -20,7 +20,11 @@ import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.PagingAndSortingRepository; import org.springframework.data.repository.query.Param; +import org.thingsboard.server.common.data.EntityType; +import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.relation.RelationTypeGroup; import org.thingsboard.server.common.data.rule.RuleChainType; +import org.thingsboard.server.dao.model.sql.RelationEntity; import org.thingsboard.server.dao.model.sql.RuleChainEntity; import java.util.List; @@ -59,6 +63,7 @@ public interface RuleChainRepository extends PagingAndSortingRepository Date: Fri, 3 Dec 2021 14:04:31 +0200 Subject: [PATCH 209/432] logging improvements --- .../java/org/thingsboard/server/common/data/DeviceProfile.java | 2 ++ .../org/thingsboard/server/common/data/DeviceProfileInfo.java | 2 +- .../server/queue/usagestats/DefaultTbApiUsageClient.java | 2 +- .../server/transport/lwm2m/server/client/LwM2mClient.java | 2 ++ .../common/transport/service/DefaultTransportService.java | 2 +- 5 files changed, 7 insertions(+), 3 deletions(-) diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/DeviceProfile.java b/common/data/src/main/java/org/thingsboard/server/common/data/DeviceProfile.java index 8a815547d6..cf916d9c74 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/DeviceProfile.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/DeviceProfile.java @@ -21,6 +21,7 @@ import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import lombok.EqualsAndHashCode; +import lombok.ToString; import lombok.extern.slf4j.Slf4j; import org.thingsboard.server.common.data.device.profile.DeviceProfileData; import org.thingsboard.server.common.data.id.DashboardId; @@ -39,6 +40,7 @@ import static org.thingsboard.server.common.data.SearchTextBasedWithAdditionalIn @ApiModel @Data +@ToString(exclude = {"image", "profileDataBytes"}) @EqualsAndHashCode(callSuper = true) @Slf4j public class DeviceProfile extends SearchTextBased implements HasName, HasTenantId, HasOtaPackage { diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/DeviceProfileInfo.java b/common/data/src/main/java/org/thingsboard/server/common/data/DeviceProfileInfo.java index a35b281a46..e9f4cc0100 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/DeviceProfileInfo.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/DeviceProfileInfo.java @@ -29,7 +29,7 @@ import java.util.UUID; @Value @EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) +@ToString(callSuper = true, exclude = "image") public class DeviceProfileInfo extends EntityInfo { @ApiModelProperty(position = 3, value = "Either URL or Base64 data of the icon. Used in the mobile application to visualize set of device profiles in the grid view. ") diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/usagestats/DefaultTbApiUsageClient.java b/common/queue/src/main/java/org/thingsboard/server/queue/usagestats/DefaultTbApiUsageClient.java index 370de259ef..92890da39f 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/usagestats/DefaultTbApiUsageClient.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/usagestats/DefaultTbApiUsageClient.java @@ -125,7 +125,7 @@ public class DefaultTbApiUsageClient implements TbApiUsageClient { })); if (!report.isEmpty()) { - log.info("Reporting API usage statistics for {} tenants and customers", report.size()); + log.debug("Reporting API usage statistics for {} tenants and customers", report.size()); } } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java index 9534be8516..331881a327 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java @@ -18,6 +18,7 @@ package org.thingsboard.server.transport.lwm2m.server.client; import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.Setter; +import lombok.ToString; import lombok.extern.slf4j.Slf4j; import org.eclipse.leshan.core.model.ObjectModel; import org.eclipse.leshan.core.model.ResourceModel; @@ -64,6 +65,7 @@ import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.g @Slf4j @EqualsAndHashCode(of = {"endpoint"}) +@ToString(of = "endpoint") public class LwM2mClient implements Serializable { private static final long serialVersionUID = 8793482946289222623L; diff --git a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java index d83aa4d4d9..52e52c30f1 100644 --- a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java +++ b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java @@ -1184,7 +1184,7 @@ public class DefaultTransportService implements TransportService { @Scheduled(fixedDelayString = "${transport.stats.print-interval-ms:60000}") public void printStats() { - if (statsEnabled) { + if (statsEnabled && !statsMap.isEmpty()) { String values = statsMap.entrySet().stream() .map(kv -> kv.getKey() + " [" + kv.getValue() + "]").collect(Collectors.joining(", ")); log.info("Transport Stats: {}", values); From a69551f067d8ee857bd456805d294f3bc752da3e Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Mon, 6 Dec 2021 12:54:48 +0200 Subject: [PATCH 210/432] Angular 12 migration --- .../static/rulenode/rulenode-core-config.js | 4190 +++++++++++- ui-ngx/.browserslistrc | 16 + ui-ngx/angular.json | 40 +- ui-ngx/extra-webpack.config.js | 14 +- ui-ngx/package.json | 112 +- ui-ngx/src/.browserslistrc | 10 - .../src/app/core/http/rule-chain.service.ts | 13 +- .../app/core/services/resources.service.ts | 119 +- .../app/modules/common/modules-map.models.ts | 19 + ui-ngx/src/app/modules/common/modules-map.ts | 579 +- .../states/states-controller.module.ts | 6 +- .../device/device-credentials.module.ts | 10 +- .../entity/entities-table.component.ts | 3 +- ...mplex-filter-predicate-dialog.component.ts | 20 +- .../complex-filter-predicate.component.ts | 16 +- .../filter/filter-component.models.ts | 29 + .../filter/filter-predicate-list.component.ts | 14 +- .../home/components/home-components.module.ts | 8 +- .../common/device-profile-common.module.ts | 4 +- .../lwm2m/lwm2m-profile-components.module.ts | 22 +- .../snmp-device-profile-transport.module.ts | 4 +- .../shared-home-components.module.ts | 4 + .../src/app/modules/home/components/tokens.ts | 27 + .../widget/dialog/custom-dialog.service.ts | 22 +- .../components/widget/lib/maps/leaflet-map.ts | 1 + .../lib/rpc/led-indicator.component.scss | 1 - .../lib/rpc/round-switch.component.scss | 1 - .../widget/widget-component.service.ts | 3 +- .../widget/widget-components.module.ts | 10 +- .../components/widget/widget.component.ts | 7 +- ui-ngx/src/app/modules/home/home.component.ts | 4 +- .../entity/entities-table-config.models.ts | 4 +- .../entity/entity-table-component.models.ts | 85 + .../rulechain/rulechain-routing.module.ts | 3 +- .../shared/components/cheatsheet.component.ts | 2 + .../components/fab-toolbar.component.scss | 13 +- .../shared/components/hotkeys.directive.ts | 3 +- .../json-form/react/json-form-react.tsx | 4 +- .../components/json-form/react/json-form.scss | 1 - .../react/styles/thingsboardTheme.ts | 2 +- .../shared/components/nav-tree.component.ts | 10 +- .../shared/components/popover.component.scss | 2 +- ui-ngx/src/app/shared/components/tokens.ts | 2 +- ui-ngx/src/app/shared/models/constants.ts | 3 +- ui-ngx/src/app/shared/shared.module.ts | 4 +- ui-ngx/src/scss/animations.scss | 1 - ui-ngx/src/scss/mixins.scss | 4 +- ui-ngx/src/theme.scss | 9 +- ui-ngx/src/tsconfig.app.json | 2 +- ui-ngx/tsconfig.json | 20 +- ui-ngx/yarn.lock | 5614 ++++------------- 51 files changed, 6361 insertions(+), 4755 deletions(-) create mode 100644 ui-ngx/.browserslistrc delete mode 100644 ui-ngx/src/.browserslistrc create mode 100644 ui-ngx/src/app/modules/common/modules-map.models.ts create mode 100644 ui-ngx/src/app/modules/home/components/filter/filter-component.models.ts create mode 100644 ui-ngx/src/app/modules/home/components/tokens.ts create mode 100644 ui-ngx/src/app/modules/home/models/entity/entity-table-component.models.ts diff --git a/rule-engine/rule-engine-components/src/main/resources/public/static/rulenode/rulenode-core-config.js b/rule-engine/rule-engine-components/src/main/resources/public/static/rulenode/rulenode-core-config.js index 3505c30a5a..8236c14be8 100644 --- a/rule-engine/rule-engine-components/src/main/resources/public/static/rulenode/rulenode-core-config.js +++ b/rule-engine/rule-engine-components/src/main/resources/public/static/rulenode/rulenode-core-config.js @@ -1,16 +1,4174 @@ -!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports,require("@angular/core"),require("@angular/common"),require("@ngx-translate/core"),require("@shared/public-api"),require("@ngrx/store"),require("@angular/forms"),require("@home/components/public-api"),require("@core/public-api"),require("@angular/cdk/keycodes"),require("@angular/cdk/coercion"),require("@angular/material/chips"),require("@angular/material/autocomplete"),require("rxjs"),require("rxjs/operators"),require("@angular/platform-browser")):"function"==typeof define&&define.amd?define("rulenode-core-config",["exports","@angular/core","@angular/common","@ngx-translate/core","@shared/public-api","@ngrx/store","@angular/forms","@home/components/public-api","@core/public-api","@angular/cdk/keycodes","@angular/cdk/coercion","@angular/material/chips","@angular/material/autocomplete","rxjs","rxjs/operators","@angular/platform-browser"],t):t((e=e||self)["rulenode-core-config"]={},e.ng.core,e.ng.common,e["ngx-translate"],e.shared,e["ngrx-store"],e.ng.forms,e.publicApi$1,e.core,e.ng.cdk.keycodes,e.ng.cdk.coercion,e.ng.material.chips,e.ng.material.autocomplete,e.rxjs,e.rxjs.operators,e.ng.platformBrowser)}(this,(function(e,t,r,n,a,o,i,l,s,m,u,d,p,c,f,g){"use strict"; -/*! ***************************************************************************** - Copyright (c) Microsoft Corporation. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH - REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY - AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, - INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM - LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR - OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - PERFORMANCE OF THIS SOFTWARE. - ***************************************************************************** */var y=function(e,t){return(y=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var r in t)Object.prototype.hasOwnProperty.call(t,r)&&(e[r]=t[r])})(e,t)};function b(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Class extends value "+String(t)+" is not a constructor or null");function r(){this.constructor=e}y(e,t),e.prototype=null===t?Object.create(t):(r.prototype=t.prototype,new r)}function h(e,t,r,n){var a,o=arguments.length,i=o<3?t:null===n?n=Object.getOwnPropertyDescriptor(t,r):n;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)i=Reflect.decorate(e,t,r,n);else for(var l=e.length-1;l>=0;l--)(a=e[l])&&(i=(o<3?a(i):o>3?a(t,r,i):a(t,r))||i);return o>3&&i&&Object.defineProperty(t,r,i),i}function C(e,t){if("object"==typeof Reflect&&"function"==typeof Reflect.metadata)return Reflect.metadata(e,t)}Object.create;function v(e){var t="function"==typeof Symbol&&Symbol.iterator,r=t&&e[t],n=0;if(r)return r.call(e);if(e&&"number"==typeof e.length)return{next:function(){return e&&n>=e.length&&(e=void 0),{value:e&&e[n++],done:!e}}};throw new TypeError(t?"Object is not iterable.":"Symbol.iterator is not defined.")}Object.create;var F,x=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.emptyConfigForm},r.prototype.onConfigurationSet=function(e){this.emptyConfigForm=this.fb.group({})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-node-empty-config",template:"
"}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),T=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.attributeScopes=Object.keys(a.AttributeScope),n.telemetryTypeTranslationsMap=a.telemetryTypeTranslations,n}return b(r,e),r.prototype.configForm=function(){return this.attributesConfigForm},r.prototype.onConfigurationSet=function(e){this.attributesConfigForm=this.fb.group({scope:[e?e.scope:null,[i.Validators.required]],notifyDevice:[!e||e.scope,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-attributes-config",template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.notify-device\' | translate }}\n \n
tb.rulenode.notify-device-hint
\n
\n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),q=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.timeseriesConfigForm},r.prototype.onConfigurationSet=function(e){this.timeseriesConfigForm=this.fb.group({defaultTTL:[e?e.defaultTTL:null,[i.Validators.required,i.Validators.min(0)]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-timeseries-config",template:'
\n \n tb.rulenode.default-ttl\n \n \n {{ \'tb.rulenode.default-ttl-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-default-ttl-message\' | translate }}\n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),S=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.rpcRequestConfigForm},r.prototype.onConfigurationSet=function(e){this.rpcRequestConfigForm=this.fb.group({timeoutInSeconds:[e?e.timeoutInSeconds:null,[i.Validators.required,i.Validators.min(0)]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-rpc-request-config",template:'
\n \n tb.rulenode.timeout-sec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-message\' | translate }}\n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),I=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return b(r,e),r.prototype.configForm=function(){return this.logConfigForm},r.prototype.onConfigurationSet=function(e){this.logConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.logConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"string",this.translate.instant("tb.rulenode.to-string"),"ToString",["msg","metadata","msgType"],this.ruleNodeId,"rulenode/log_node_script_fn").subscribe((function(t){t&&e.logConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-action-node-log-config",template:'
\n \n \n \n
\n \n
\n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),k=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.assignCustomerConfigForm},r.prototype.onConfigurationSet=function(e){this.assignCustomerConfigForm=this.fb.group({customerNamePattern:[e?e.customerNamePattern:null,[i.Validators.required,i.Validators.pattern(/.*\S.*/)]],createCustomerIfNotExists:[!!e&&e.createCustomerIfNotExists,[]],customerCacheExpiration:[e?e.customerCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.prototype.prepareOutputConfig=function(e){return e.customerNamePattern=e.customerNamePattern.trim(),e},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-assign-to-customer-config",template:'
\n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.create-customer-if-not-exists\' | translate }}\n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n tb.rulenode.customer-cache-expiration-hint\n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),N=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return b(r,e),r.prototype.configForm=function(){return this.clearAlarmConfigForm},r.prototype.onConfigurationSet=function(e){this.clearAlarmConfigForm=this.fb.group({alarmDetailsBuildJs:[e?e.alarmDetailsBuildJs:null,[i.Validators.required]],alarmType:[e?e.alarmType:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.clearAlarmConfigForm.get("alarmDetailsBuildJs").value;this.nodeScriptTestService.testNodeScript(t,"json",this.translate.instant("tb.rulenode.details"),"Details",["msg","metadata","msgType"],this.ruleNodeId,"rulenode/clear_alarm_node_script_fn").subscribe((function(t){t&&e.clearAlarmConfigForm.get("alarmDetailsBuildJs").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-action-node-clear-alarm-config",template:'
\n \n \n \n
\n \n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),V=function(e){function r(t,r,n,o){var i=e.call(this,t)||this;return i.store=t,i.fb=r,i.nodeScriptTestService=n,i.translate=o,i.alarmSeverities=Object.keys(a.AlarmSeverity),i.alarmSeverityTranslationMap=a.alarmSeverityTranslations,i.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],i}return b(r,e),r.prototype.configForm=function(){return this.createAlarmConfigForm},r.prototype.onConfigurationSet=function(e){var t=this;this.createAlarmConfigForm=this.fb.group({alarmDetailsBuildJs:[e?e.alarmDetailsBuildJs:null,[i.Validators.required]],useMessageAlarmData:[!!e&&e.useMessageAlarmData,[]],alarmType:[e?e.alarmType:null,[]],severity:[e?e.severity:null,[]],propagate:[!!e&&e.propagate,[]],relationTypes:[e?e.relationTypes:null,[]],dynamicSeverity:!1}),this.createAlarmConfigForm.get("dynamicSeverity").valueChanges.subscribe((function(e){e?t.createAlarmConfigForm.get("severity").patchValue("",{emitEvent:!1}):t.createAlarmConfigForm.get("severity").patchValue(t.alarmSeverities[0],{emitEvent:!1})}))},r.prototype.validatorTriggers=function(){return["useMessageAlarmData"]},r.prototype.updateValidators=function(e){this.createAlarmConfigForm.get("useMessageAlarmData").value?(this.createAlarmConfigForm.get("alarmType").setValidators([]),this.createAlarmConfigForm.get("severity").setValidators([])):(this.createAlarmConfigForm.get("alarmType").setValidators([i.Validators.required]),this.createAlarmConfigForm.get("severity").setValidators([i.Validators.required])),this.createAlarmConfigForm.get("alarmType").updateValueAndValidity({emitEvent:e}),this.createAlarmConfigForm.get("severity").updateValueAndValidity({emitEvent:e})},r.prototype.testScript=function(){var e=this,t=this.createAlarmConfigForm.get("alarmDetailsBuildJs").value;this.nodeScriptTestService.testNodeScript(t,"json",this.translate.instant("tb.rulenode.details"),"Details",["msg","metadata","msgType"],this.ruleNodeId,"rulenode/create_alarm_node_script_fn").subscribe((function(t){t&&e.createAlarmConfigForm.get("alarmDetailsBuildJs").setValue(t)}))},r.prototype.removeKey=function(e,t){var r=this.createAlarmConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.createAlarmConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.createAlarmConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.createAlarmConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-action-node-create-alarm-config",template:'
\n \n \n \n
\n \n
\n
\n \n {{ \'tb.rulenode.use-message-alarm-data\' | translate }}\n \n \n {{ \'tb.rulenode.use-dynamically-change-the-severity-of-alar\' | translate }}\n \n
\n
\n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n \n tb.rulenode.alarm-severity\n \n \n {{ alarmSeverityTranslationMap.get(severity) | translate }}\n \n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.alarm-severity\' | translate }}\n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.propagate\' | translate }}\n \n
\n \n tb.rulenode.relation-types-list\n \n \n {{key}}\n close\n \n \n \n tb.rulenode.relation-types-list-hint\n \n
\n
\n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),E=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.entityType=a.EntityType,n}return b(r,e),r.prototype.configForm=function(){return this.createRelationConfigForm},r.prototype.onConfigurationSet=function(e){this.createRelationConfigForm=this.fb.group({direction:[e?e.direction:null,[i.Validators.required]],entityType:[e?e.entityType:null,[i.Validators.required]],entityNamePattern:[e?e.entityNamePattern:null,[]],entityTypePattern:[e?e.entityTypePattern:null,[]],relationType:[e?e.relationType:null,[i.Validators.required]],createEntityIfNotExists:[!!e&&e.createEntityIfNotExists,[]],removeCurrentRelations:[!!e&&e.removeCurrentRelations,[]],changeOriginatorToRelatedEntity:[!!e&&e.changeOriginatorToRelatedEntity,[]],entityCacheExpiration:[e?e.entityCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.prototype.validatorTriggers=function(){return["entityType"]},r.prototype.updateValidators=function(e){var t=this.createRelationConfigForm.get("entityType").value;t?this.createRelationConfigForm.get("entityNamePattern").setValidators([i.Validators.required,i.Validators.pattern(/.*\S.*/)]):this.createRelationConfigForm.get("entityNamePattern").setValidators([]),!t||t!==a.EntityType.DEVICE&&t!==a.EntityType.ASSET?this.createRelationConfigForm.get("entityTypePattern").setValidators([]):this.createRelationConfigForm.get("entityTypePattern").setValidators([i.Validators.required,i.Validators.pattern(/.*\S.*/)]),this.createRelationConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e}),this.createRelationConfigForm.get("entityTypePattern").updateValueAndValidity({emitEvent:e})},r.prototype.prepareOutputConfig=function(e){return e.entityNamePattern=e.entityNamePattern?e.entityNamePattern.trim():null,e.entityTypePattern=e.entityTypePattern?e.entityTypePattern.trim():null,e},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-create-relation-config",template:'
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-type-pattern\n \n \n {{ \'tb.rulenode.entity-type-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.create-entity-if-not-exists\' | translate }}\n \n
tb.rulenode.create-entity-if-not-exists-hint
\n
\n \n {{ \'tb.rulenode.remove-current-relations\' | translate }}\n \n
tb.rulenode.remove-current-relations-hint
\n \n {{ \'tb.rulenode.change-originator-to-related-entity\' | translate }}\n \n
tb.rulenode.change-originator-to-related-entity-hint
\n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n tb.rulenode.entity-cache-expiration-hint\n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),A=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.msgDelayConfigForm},r.prototype.onConfigurationSet=function(e){this.msgDelayConfigForm=this.fb.group({useMetadataPeriodInSecondsPatterns:[!!e&&e.useMetadataPeriodInSecondsPatterns,[]],periodInSeconds:[e?e.periodInSeconds:null,[]],periodInSecondsPattern:[e?e.periodInSecondsPattern:null,[]],maxPendingMsgs:[e?e.maxPendingMsgs:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(1e5)]]})},r.prototype.validatorTriggers=function(){return["useMetadataPeriodInSecondsPatterns"]},r.prototype.updateValidators=function(e){this.msgDelayConfigForm.get("useMetadataPeriodInSecondsPatterns").value?(this.msgDelayConfigForm.get("periodInSecondsPattern").setValidators([i.Validators.required]),this.msgDelayConfigForm.get("periodInSeconds").setValidators([])):(this.msgDelayConfigForm.get("periodInSecondsPattern").setValidators([]),this.msgDelayConfigForm.get("periodInSeconds").setValidators([i.Validators.required,i.Validators.min(0)])),this.msgDelayConfigForm.get("periodInSecondsPattern").updateValueAndValidity({emitEvent:e}),this.msgDelayConfigForm.get("periodInSeconds").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-msg-delay-config",template:'
\n \n {{ \'tb.rulenode.use-metadata-period-in-seconds-patterns\' | translate }}\n \n
tb.rulenode.use-metadata-period-in-seconds-patterns-hint
\n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-0-seconds-message\' | translate }}\n \n \n \n \n tb.rulenode.period-in-seconds-pattern\n \n \n {{ \'tb.rulenode.period-in-seconds-pattern-required\' | translate }}\n \n \n \n \n \n tb.rulenode.max-pending-messages\n \n \n {{ \'tb.rulenode.max-pending-messages-required\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),L=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.entityType=a.EntityType,n}return b(r,e),r.prototype.configForm=function(){return this.deleteRelationConfigForm},r.prototype.onConfigurationSet=function(e){this.deleteRelationConfigForm=this.fb.group({deleteForSingleEntity:[!!e&&e.deleteForSingleEntity,[]],direction:[e?e.direction:null,[i.Validators.required]],entityType:[e?e.entityType:null,[]],entityNamePattern:[e?e.entityNamePattern:null,[]],relationType:[e?e.relationType:null,[i.Validators.required]],entityCacheExpiration:[e?e.entityCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.prototype.validatorTriggers=function(){return["deleteForSingleEntity","entityType"]},r.prototype.updateValidators=function(e){var t=this.deleteRelationConfigForm.get("deleteForSingleEntity").value,r=this.deleteRelationConfigForm.get("entityType").value;t?this.deleteRelationConfigForm.get("entityType").setValidators([i.Validators.required]):this.deleteRelationConfigForm.get("entityType").setValidators([]),t&&r?this.deleteRelationConfigForm.get("entityNamePattern").setValidators([i.Validators.required,i.Validators.pattern(/.*\S.*/)]):this.deleteRelationConfigForm.get("entityNamePattern").setValidators([]),this.deleteRelationConfigForm.get("entityType").updateValueAndValidity({emitEvent:!1}),this.deleteRelationConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e})},r.prototype.prepareOutputConfig=function(e){return e.entityNamePattern=e.entityNamePattern?e.entityNamePattern.trim():null,e},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-delete-relation-config",template:'
\n \n {{ \'tb.rulenode.delete-relation-to-specific-entity\' | translate }}\n \n
tb.rulenode.delete-relation-hint
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n tb.rulenode.entity-cache-expiration-hint\n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),P=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return b(r,e),r.prototype.configForm=function(){return this.generatorConfigForm},r.prototype.onConfigurationSet=function(e){this.generatorConfigForm=this.fb.group({msgCount:[e?e.msgCount:null,[i.Validators.required,i.Validators.min(0)]],periodInSeconds:[e?e.periodInSeconds:null,[i.Validators.required,i.Validators.min(1)]],originator:[e?e.originator:null,[]],jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.prepareInputConfig=function(e){return e&&(e.originatorId&&e.originatorType?e.originator={id:e.originatorId,entityType:e.originatorType}:e.originator=null,delete e.originatorId,delete e.originatorType),e},r.prototype.prepareOutputConfig=function(e){return e.originator?(e.originatorId=e.originator.id,e.originatorType=e.originator.entityType):(e.originatorId=null,e.originatorType=null),delete e.originator,e},r.prototype.testScript=function(){var e=this,t=this.generatorConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"generate",this.translate.instant("tb.rulenode.generator"),"Generate",["prevMsg","prevMetadata","prevMsgType"],this.ruleNodeId,"rulenode/generator_node_script_fn").subscribe((function(t){t&&e.generatorConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-action-node-generator-config",template:'
\n \n tb.rulenode.message-count\n \n \n {{ \'tb.rulenode.message-count-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-message-count-message\' | translate }}\n \n \n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-seconds-message\' | translate }}\n \n \n
\n \n \n \n
\n \n \n \n
\n \n
\n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent);!function(e){e.CUSTOMER="CUSTOMER",e.TENANT="TENANT",e.RELATED="RELATED",e.ALARM_ORIGINATOR="ALARM_ORIGINATOR"}(F||(F={}));var M,w=new Map([[F.CUSTOMER,"tb.rulenode.originator-customer"],[F.TENANT,"tb.rulenode.originator-tenant"],[F.RELATED,"tb.rulenode.originator-related"],[F.ALARM_ORIGINATOR,"tb.rulenode.originator-alarm-originator"]]);!function(e){e.CIRCLE="CIRCLE",e.POLYGON="POLYGON"}(M||(M={}));var R,D=new Map([[M.CIRCLE,"tb.rulenode.perimeter-circle"],[M.POLYGON,"tb.rulenode.perimeter-polygon"]]);!function(e){e.MILLISECONDS="MILLISECONDS",e.SECONDS="SECONDS",e.MINUTES="MINUTES",e.HOURS="HOURS",e.DAYS="DAYS"}(R||(R={}));var O,K=new Map([[R.MILLISECONDS,"tb.rulenode.time-unit-milliseconds"],[R.SECONDS,"tb.rulenode.time-unit-seconds"],[R.MINUTES,"tb.rulenode.time-unit-minutes"],[R.HOURS,"tb.rulenode.time-unit-hours"],[R.DAYS,"tb.rulenode.time-unit-days"]]);!function(e){e.METER="METER",e.KILOMETER="KILOMETER",e.FOOT="FOOT",e.MILE="MILE",e.NAUTICAL_MILE="NAUTICAL_MILE"}(O||(O={}));var B,H=new Map([[O.METER,"tb.rulenode.range-unit-meter"],[O.KILOMETER,"tb.rulenode.range-unit-kilometer"],[O.FOOT,"tb.rulenode.range-unit-foot"],[O.MILE,"tb.rulenode.range-unit-mile"],[O.NAUTICAL_MILE,"tb.rulenode.range-unit-nautical-mile"]]);!function(e){e.TITLE="TITLE",e.COUNTRY="COUNTRY",e.STATE="STATE",e.ZIP="ZIP",e.ADDRESS="ADDRESS",e.ADDRESS2="ADDRESS2",e.PHONE="PHONE",e.EMAIL="EMAIL",e.ADDITIONAL_INFO="ADDITIONAL_INFO"}(B||(B={}));var G,j,U,_=new Map([[B.TITLE,"tb.rulenode.entity-details-title"],[B.COUNTRY,"tb.rulenode.entity-details-country"],[B.STATE,"tb.rulenode.entity-details-state"],[B.ZIP,"tb.rulenode.entity-details-zip"],[B.ADDRESS,"tb.rulenode.entity-details-address"],[B.ADDRESS2,"tb.rulenode.entity-details-address2"],[B.PHONE,"tb.rulenode.entity-details-phone"],[B.EMAIL,"tb.rulenode.entity-details-email"],[B.ADDITIONAL_INFO,"tb.rulenode.entity-details-additional_info"]]);!function(e){e.FIRST="FIRST",e.LAST="LAST",e.ALL="ALL"}(G||(G={})),function(e){e.ASC="ASC",e.DESC="DESC"}(j||(j={})),function(e){e.STANDARD="STANDARD",e.FIFO="FIFO"}(U||(U={}));var z,Q=new Map([[U.STANDARD,"tb.rulenode.sqs-queue-standard"],[U.FIFO,"tb.rulenode.sqs-queue-fifo"]]),$=["anonymous","basic","cert.PEM"],W=new Map([["anonymous","tb.rulenode.credentials-anonymous"],["basic","tb.rulenode.credentials-basic"],["cert.PEM","tb.rulenode.credentials-pem"]]),J=["sas","cert.PEM"],Y=new Map([["sas","tb.rulenode.credentials-sas"],["cert.PEM","tb.rulenode.credentials-pem"]]);!function(e){e.GET="GET",e.POST="POST",e.PUT="PUT",e.DELETE="DELETE"}(z||(z={}));var Z=["US-ASCII","ISO-8859-1","UTF-8","UTF-16BE","UTF-16LE","UTF-16"],X=new Map([["US-ASCII","tb.rulenode.charset-us-ascii"],["ISO-8859-1","tb.rulenode.charset-iso-8859-1"],["UTF-8","tb.rulenode.charset-utf-8"],["UTF-16BE","tb.rulenode.charset-utf-16be"],["UTF-16LE","tb.rulenode.charset-utf-16le"],["UTF-16","tb.rulenode.charset-utf-16"]]),ee=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.perimeterType=M,n.perimeterTypes=Object.keys(M),n.perimeterTypeTranslationMap=D,n.rangeUnits=Object.keys(O),n.rangeUnitTranslationMap=H,n.timeUnits=Object.keys(R),n.timeUnitsTranslationMap=K,n}return b(r,e),r.prototype.configForm=function(){return this.geoActionConfigForm},r.prototype.onConfigurationSet=function(e){this.geoActionConfigForm=this.fb.group({latitudeKeyName:[e?e.latitudeKeyName:null,[i.Validators.required]],longitudeKeyName:[e?e.longitudeKeyName:null,[i.Validators.required]],fetchPerimeterInfoFromMessageMetadata:[!!e&&e.fetchPerimeterInfoFromMessageMetadata,[]],perimeterType:[e?e.perimeterType:null,[]],centerLatitude:[e?e.centerLatitude:null,[]],centerLongitude:[e?e.centerLatitude:null,[]],range:[e?e.range:null,[]],rangeUnit:[e?e.rangeUnit:null,[]],polygonsDefinition:[e?e.polygonsDefinition:null,[]],minInsideDuration:[e?e.minInsideDuration:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]],minInsideDurationTimeUnit:[e?e.minInsideDurationTimeUnit:null,[i.Validators.required]],minOutsideDuration:[e?e.minOutsideDuration:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]],minOutsideDurationTimeUnit:[e?e.minOutsideDurationTimeUnit:null,[i.Validators.required]]})},r.prototype.validatorTriggers=function(){return["fetchPerimeterInfoFromMessageMetadata","perimeterType"]},r.prototype.updateValidators=function(e){var t=this.geoActionConfigForm.get("fetchPerimeterInfoFromMessageMetadata").value,r=this.geoActionConfigForm.get("perimeterType").value;t?this.geoActionConfigForm.get("perimeterType").setValidators([]):this.geoActionConfigForm.get("perimeterType").setValidators([i.Validators.required]),t||r!==M.CIRCLE?(this.geoActionConfigForm.get("centerLatitude").setValidators([]),this.geoActionConfigForm.get("centerLongitude").setValidators([]),this.geoActionConfigForm.get("range").setValidators([]),this.geoActionConfigForm.get("rangeUnit").setValidators([])):(this.geoActionConfigForm.get("centerLatitude").setValidators([i.Validators.required,i.Validators.min(-90),i.Validators.max(90)]),this.geoActionConfigForm.get("centerLongitude").setValidators([i.Validators.required,i.Validators.min(-180),i.Validators.max(180)]),this.geoActionConfigForm.get("range").setValidators([i.Validators.required,i.Validators.min(0)]),this.geoActionConfigForm.get("rangeUnit").setValidators([i.Validators.required])),t||r!==M.POLYGON?this.geoActionConfigForm.get("polygonsDefinition").setValidators([]):this.geoActionConfigForm.get("polygonsDefinition").setValidators([i.Validators.required]),this.geoActionConfigForm.get("perimeterType").updateValueAndValidity({emitEvent:!1}),this.geoActionConfigForm.get("centerLatitude").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("centerLongitude").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("range").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("rangeUnit").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("polygonsDefinition").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-gps-geofencing-config",template:'
\n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n
\n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.min-inside-duration\n \n \n {{ \'tb.rulenode.min-inside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-inside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n tb.rulenode.min-outside-duration\n \n \n {{ \'tb.rulenode.min-outside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-outside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),te=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.msgCountConfigForm},r.prototype.onConfigurationSet=function(e){this.msgCountConfigForm=this.fb.group({interval:[e?e.interval:null,[i.Validators.required,i.Validators.min(1)]],telemetryPrefix:[e?e.telemetryPrefix:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-msg-count-config",template:'
\n \n tb.rulenode.interval-seconds\n \n \n {{ \'tb.rulenode.interval-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-interval-seconds-message\' | translate }}\n \n \n \n tb.rulenode.output-timeseries-key-prefix\n \n \n {{ \'tb.rulenode.output-timeseries-key-prefix-required\' | translate }}\n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),re=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.rpcReplyConfigForm},r.prototype.onConfigurationSet=function(e){this.rpcReplyConfigForm=this.fb.group({requestIdMetaDataAttribute:[e?e.requestIdMetaDataAttribute:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-rpc-reply-config",template:'
\n \n tb.rulenode.request-id-metadata-attribute\n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ne=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.saveToCustomTableConfigForm},r.prototype.onConfigurationSet=function(e){this.saveToCustomTableConfigForm=this.fb.group({tableName:[e?e.tableName:null,[i.Validators.required,i.Validators.pattern(/.*\S.*/)]],fieldsMapping:[e?e.fieldsMapping:null,[i.Validators.required]]})},r.prototype.prepareOutputConfig=function(e){return e.tableName=e.tableName.trim(),e},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-custom-table-config",template:'
\n \n tb.rulenode.custom-table-name\n \n \n {{ \'tb.rulenode.custom-table-name-required\' | translate }}\n \n tb.rulenode.custom-table-hint\n \n \n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ae=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.translate=r,o.injector=n,o.fb=a,o.propagateChange=null,o.valueChangeSubscription=null,o}var a;return b(r,e),a=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){this.ngControl=this.injector.get(i.NgControl),null!=this.ngControl&&(this.ngControl.valueAccessor=this),this.kvListFormGroup=this.fb.group({}),this.kvListFormGroup.addControl("keyVals",this.fb.array([]))},r.prototype.keyValsFormArray=function(){return this.kvListFormGroup.get("keyVals")},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.kvListFormGroup.disable({emitEvent:!1}):this.kvListFormGroup.enable({emitEvent:!1})},r.prototype.writeValue=function(e){var t,r,n=this;this.valueChangeSubscription&&this.valueChangeSubscription.unsubscribe();var a=[];if(e)try{for(var o=v(Object.keys(e)),l=o.next();!l.done;l=o.next()){var s=l.value;Object.prototype.hasOwnProperty.call(e,s)&&a.push(this.fb.group({key:[s,[i.Validators.required]],value:[e[s],[i.Validators.required]]}))}}catch(e){t={error:e}}finally{try{l&&!l.done&&(r=o.return)&&r.call(o)}finally{if(t)throw t.error}}this.kvListFormGroup.setControl("keyVals",this.fb.array(a)),this.valueChangeSubscription=this.kvListFormGroup.valueChanges.subscribe((function(){n.updateModel()}))},r.prototype.removeKeyVal=function(e){this.kvListFormGroup.get("keyVals").removeAt(e)},r.prototype.addKeyVal=function(){this.kvListFormGroup.get("keyVals").push(this.fb.group({key:["",[i.Validators.required]],value:["",[i.Validators.required]]}))},r.prototype.validate=function(e){return!this.kvListFormGroup.get("keyVals").value.length&&this.required?{kvMapRequired:!0}:this.kvListFormGroup.valid?null:{kvFieldsRequired:!0}},r.prototype.updateModel=function(){var e=this.kvListFormGroup.get("keyVals").value;if(this.required&&!e.length||!this.kvListFormGroup.valid)this.propagateChange(null);else{var t={};e.forEach((function(e){t[e.key]=e.value})),this.propagateChange(t)}},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:t.Injector},{type:i.FormBuilder}]},h([t.Input(),C("design:type",Boolean)],r.prototype,"disabled",void 0),h([t.Input(),C("design:type",String)],r.prototype,"requiredText",void 0),h([t.Input(),C("design:type",String)],r.prototype,"keyText",void 0),h([t.Input(),C("design:type",String)],r.prototype,"keyRequiredText",void 0),h([t.Input(),C("design:type",String)],r.prototype,"valText",void 0),h([t.Input(),C("design:type",String)],r.prototype,"valRequiredText",void 0),h([t.Input(),C("design:type",Boolean),C("design:paramtypes",[Boolean])],r.prototype,"required",null),r=a=h([t.Component({selector:"tb-kv-map-config",template:'
\n
\n {{ keyText | translate }}\n {{ valText | translate }}\n \n
\n
\n
\n \n \n \n \n {{ keyRequiredText | translate }}\n \n \n \n \n \n \n {{ valRequiredText | translate }}\n \n \n \n
\n
\n \n
\n \n
\n
\n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return a})),multi:!0},{provide:i.NG_VALIDATORS,useExisting:t.forwardRef((function(){return a})),multi:!0}],styles:[":host .tb-kv-map-config{margin-bottom:16px}:host .tb-kv-map-config .header{padding-left:5px;padding-right:5px;padding-bottom:5px}:host .tb-kv-map-config .header .cell{padding-left:5px;padding-right:5px;color:rgba(0,0,0,.54);font-size:12px;font-weight:700;white-space:nowrap}:host .tb-kv-map-config .body{padding-left:5px;padding-right:5px;padding-bottom:20px;max-height:300px;overflow:auto}:host .tb-kv-map-config .body .row{padding-top:5px;max-height:40px}:host .tb-kv-map-config .body .cell{padding-left:5px;padding-right:5px}:host ::ng-deep .tb-kv-map-config .body mat-form-field.cell{margin:0;max-height:40px}:host ::ng-deep .tb-kv-map-config .body mat-form-field.cell .mat-form-field-infix{border-top:0}:host ::ng-deep .tb-kv-map-config .body button.mat-button{margin:0}"]}),C("design:paramtypes",[o.Store,n.TranslateService,t.Injector,i.FormBuilder])],r)}(a.PageComponent),oe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.entityType=a.EntityType,n.propagateChange=null,n}var n;return b(r,e),n=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){var e=this;this.deviceRelationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[i.Validators.required]],maxLevel:[null,[]],relationType:[null],deviceTypes:[null,[i.Validators.required]]}),this.deviceRelationsQueryFormGroup.valueChanges.subscribe((function(t){e.deviceRelationsQueryFormGroup.valid?e.propagateChange(t):e.propagateChange(null)}))},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.deviceRelationsQueryFormGroup.disable({emitEvent:!1}):this.deviceRelationsQueryFormGroup.enable({emitEvent:!1})},r.prototype.writeValue=function(e){this.deviceRelationsQueryFormGroup.reset(e,{emitEvent:!1})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},h([t.Input(),C("design:type",Boolean)],r.prototype,"disabled",void 0),h([t.Input(),C("design:type",Boolean),C("design:paramtypes",[Boolean])],r.prototype,"required",null),r=n=h([t.Component({selector:"tb-device-relations-query-config",template:'
\n \n {{ \'alias.last-level-relation\' | translate }}\n \n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n
\n
relation.relation-type
\n \n \n
device.device-types
\n \n \n
\n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return n})),multi:!0}]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.PageComponent),ie=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.propagateChange=null,n}var n;return b(r,e),n=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){var e=this;this.relationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[i.Validators.required]],maxLevel:[null,[]],filters:[null]}),this.relationsQueryFormGroup.valueChanges.subscribe((function(t){e.relationsQueryFormGroup.valid?e.propagateChange(t):e.propagateChange(null)}))},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.relationsQueryFormGroup.disable({emitEvent:!1}):this.relationsQueryFormGroup.enable({emitEvent:!1})},r.prototype.writeValue=function(e){this.relationsQueryFormGroup.reset(e||{},{emitEvent:!1})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},h([t.Input(),C("design:type",Boolean)],r.prototype,"disabled",void 0),h([t.Input(),C("design:type",Boolean),C("design:paramtypes",[Boolean])],r.prototype,"required",null),r=n=h([t.Component({selector:"tb-relations-query-config",template:'
\n \n {{ \'alias.last-level-relation\' | translate }}\n \n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n
\n
relation.relation-filters
\n \n
\n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return n})),multi:!0}]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.PageComponent),le=function(e){function r(t,r,n,o){var i,l,s=e.call(this,t)||this;s.store=t,s.translate=r,s.truncate=n,s.fb=o,s.placeholder="tb.rulenode.message-type",s.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],s.messageTypes=[],s.messageTypesList=[],s.searchText="",s.propagateChange=function(e){},s.messageTypeConfigForm=s.fb.group({messageType:[null]});try{for(var u=v(Object.keys(a.MessageType)),d=u.next();!d.done;d=u.next()){var p=d.value;s.messageTypesList.push({name:a.messageTypeNames.get(a.MessageType[p]),value:p})}}catch(e){i={error:e}}finally{try{d&&!d.done&&(l=u.return)&&l.call(u)}finally{if(i)throw i.error}}return s}var l;return b(r,e),l=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.ngOnInit=function(){var e=this;this.filteredMessageTypes=this.messageTypeConfigForm.get("messageType").valueChanges.pipe(f.startWith(""),f.map((function(e){return e||""})),f.mergeMap((function(t){return e.fetchMessageTypes(t)})),f.share())},r.prototype.ngAfterViewInit=function(){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.messageTypeConfigForm.disable({emitEvent:!1}):this.messageTypeConfigForm.enable({emitEvent:!1})},r.prototype.writeValue=function(e){var t=this;this.searchText="",this.messageTypes.length=0,e&&e.forEach((function(e){var r=t.messageTypesList.find((function(t){return t.value===e}));r?t.messageTypes.push({name:r.name,value:r.value}):t.messageTypes.push({name:e,value:e})}))},r.prototype.displayMessageTypeFn=function(e){return e?e.name:void 0},r.prototype.textIsNotEmpty=function(e){return!!(e&&null!=e&&e.length>0)},r.prototype.createMessageType=function(e,t){e.preventDefault(),this.transformMessageType(t)},r.prototype.add=function(e){this.transformMessageType(e.value)},r.prototype.fetchMessageTypes=function(e){if(this.searchText=e,this.searchText&&this.searchText.length){var t=this.searchText.toUpperCase();return c.of(this.messageTypesList.filter((function(e){return e.name.toUpperCase().includes(t)})))}return c.of(this.messageTypesList)},r.prototype.transformMessageType=function(e){if((e||"").trim()){var t=null,r=e.trim(),n=this.messageTypesList.find((function(e){return e.name===r}));(t=n?{name:n.name,value:n.value}:{name:r,value:r})&&this.addMessageType(t)}this.clear("")},r.prototype.remove=function(e){var t=this.messageTypes.indexOf(e);t>=0&&(this.messageTypes.splice(t,1),this.updateModel())},r.prototype.selected=function(e){this.addMessageType(e.option.value),this.clear("")},r.prototype.addMessageType=function(e){-1===this.messageTypes.findIndex((function(t){return t.value===e.value}))&&(this.messageTypes.push(e),this.updateModel())},r.prototype.onFocus=function(){this.messageTypeConfigForm.get("messageType").updateValueAndValidity({onlySelf:!0,emitEvent:!0})},r.prototype.clear=function(e){var t=this;void 0===e&&(e=""),this.messageTypeInput.nativeElement.value=e,this.messageTypeConfigForm.get("messageType").patchValue(null,{emitEvent:!0}),setTimeout((function(){t.messageTypeInput.nativeElement.blur(),t.messageTypeInput.nativeElement.focus()}),0)},r.prototype.updateModel=function(){var e=this.messageTypes.map((function(e){return e.value}));this.required?(this.chipList.errorState=!e.length,this.propagateChange(e.length>0?e:null)):(this.chipList.errorState=!1,this.propagateChange(e))},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:a.TruncatePipe},{type:i.FormBuilder}]},h([t.Input(),C("design:type",Boolean),C("design:paramtypes",[Boolean])],r.prototype,"required",null),h([t.Input(),C("design:type",String)],r.prototype,"label",void 0),h([t.Input(),C("design:type",Object)],r.prototype,"placeholder",void 0),h([t.Input(),C("design:type",Boolean)],r.prototype,"disabled",void 0),h([t.ViewChild("chipList",{static:!1}),C("design:type",d.MatChipList)],r.prototype,"chipList",void 0),h([t.ViewChild("messageTypeAutocomplete",{static:!1}),C("design:type",p.MatAutocomplete)],r.prototype,"matAutocomplete",void 0),h([t.ViewChild("messageTypeInput",{static:!1}),C("design:type",t.ElementRef)],r.prototype,"messageTypeInput",void 0),r=l=h([t.Component({selector:"tb-message-types-config",template:'\n {{ label }}\n \n \n {{messageType.name}}\n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-message-types-found\n
\n \n \n {{ translate.get(\'tb.rulenode.no-message-type-matching\',\n {messageType: truncate.transform(searchText, true, 6, '...')}) | async }}\n \n \n \n tb.rulenode.create-new-message-type\n \n
\n
\n
\n \n {{ \'tb.rulenode.message-types-required\' | translate }}\n \n
\n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return l})),multi:!0}]}),C("design:paramtypes",[o.Store,n.TranslateService,a.TruncatePipe,i.FormBuilder])],r)}(a.PageComponent),se=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.subscriptions=[],n.disableCertPemCredentials=!1,n.passwordFieldRquired=!0,n.allCredentialsTypes=$,n.credentialsTypeTranslationsMap=W,n.propagateChange=null,n}var n;return b(r,e),n=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){var e=this;this.credentialsConfigFormGroup=this.fb.group({type:[null,[i.Validators.required]],username:[null,[]],password:[null,[]],caCert:[null,[]],caCertFileName:[null,[]],privateKey:[null,[]],privateKeyFileName:[null,[]],cert:[null,[]],certFileName:[null,[]]}),this.subscriptions.push(this.credentialsConfigFormGroup.valueChanges.pipe(f.distinctUntilChanged()).subscribe((function(){e.updateView()}))),this.subscriptions.push(this.credentialsConfigFormGroup.get("type").valueChanges.subscribe((function(){e.credentialsTypeChanged()})))},r.prototype.ngOnChanges=function(e){var t,r,n=this;try{for(var a=v(Object.keys(e)),o=a.next();!o.done;o=a.next()){var i=o.value,l=e[i];if(!l.firstChange&&l.currentValue!==l.previousValue)if(l.currentValue&&"disableCertPemCredentials"===i)"cert.PEM"===this.credentialsConfigFormGroup.get("type").value&&setTimeout((function(){n.credentialsConfigFormGroup.get("type").patchValue("anonymous",{emitEvent:!0})}))}}catch(e){t={error:e}}finally{try{o&&!o.done&&(r=a.return)&&r.call(a)}finally{if(t)throw t.error}}},r.prototype.ngOnDestroy=function(){this.subscriptions.forEach((function(e){return e.unsubscribe()}))},r.prototype.writeValue=function(e){s.isDefinedAndNotNull(e)&&(this.credentialsConfigFormGroup.reset(e,{emitEvent:!1}),this.updateValidators(!1))},r.prototype.setDisabledState=function(e){e?this.credentialsConfigFormGroup.disable():(this.credentialsConfigFormGroup.enable(),this.updateValidators())},r.prototype.updateView=function(){var e=this.credentialsConfigFormGroup.value,t=e.type;switch(t){case"anonymous":e={type:t};break;case"basic":e={type:t,username:e.username,password:e.password};break;case"cert.PEM":delete e.username}this.propagateChange(e)},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.validate=function(e){return this.credentialsConfigFormGroup.valid?null:{credentialsConfig:{valid:!1}}},r.prototype.credentialsTypeChanged=function(){this.credentialsConfigFormGroup.patchValue({username:null,password:null,caCert:null,caCertFileName:null,privateKey:null,privateKeyFileName:null,cert:null,certFileName:null}),this.updateValidators()},r.prototype.updateValidators=function(e){void 0===e&&(e=!1);var t=this.credentialsConfigFormGroup.get("type").value;switch(e&&this.credentialsConfigFormGroup.reset({type:t},{emitEvent:!1}),this.credentialsConfigFormGroup.setValidators([]),this.credentialsConfigFormGroup.get("username").setValidators([]),this.credentialsConfigFormGroup.get("password").setValidators([]),t){case"anonymous":break;case"basic":this.credentialsConfigFormGroup.get("username").setValidators([i.Validators.required]),this.credentialsConfigFormGroup.get("password").setValidators(this.passwordFieldRquired?[i.Validators.required]:[]);break;case"cert.PEM":this.credentialsConfigFormGroup.setValidators([this.requiredFilesSelected(i.Validators.required,[["caCert","caCertFileName"],["privateKey","privateKeyFileName","cert","certFileName"]])])}this.credentialsConfigFormGroup.get("username").updateValueAndValidity({emitEvent:e}),this.credentialsConfigFormGroup.get("password").updateValueAndValidity({emitEvent:e}),this.credentialsConfigFormGroup.updateValueAndValidity({emitEvent:e})},r.prototype.requiredFilesSelected=function(e,t){return void 0===t&&(t=null),function(r){return t||(t=[Object.keys(r.controls)]),(null==r?void 0:r.controls)&&t.some((function(t){return t.every((function(t){return!e(r.controls[t])}))}))?null:{notAllRequiredFilesSelected:!0}}},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},h([t.Input(),C("design:type",Boolean),C("design:paramtypes",[Boolean])],r.prototype,"required",null),h([t.Input(),C("design:type",Object)],r.prototype,"disableCertPemCredentials",void 0),h([t.Input(),C("design:type",Object)],r.prototype,"passwordFieldRquired",void 0),r=n=h([t.Component({selector:"tb-credentials-config",template:'
\n \n \n tb.rulenode.credentials\n \n {{ credentialsTypeTranslationsMap.get(credentialsConfigFormGroup.get(\'type\').value) | translate }}\n \n \n \n \n tb.rulenode.credentials-type\n \n \n {{ credentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
\n \n \n \n \n tb.rulenode.username\n \n \n {{ \'tb.rulenode.username-required\' | translate }}\n \n \n \n tb.rulenode.password\n \n \n \n {{ \'tb.rulenode.password-required\' | translate }}\n \n \n \n \n
{{ \'tb.rulenode.credentials-pem-hint\' | translate }}
\n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n
\n
\n
\n
\n
\n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return n})),multi:!0},{provide:i.NG_VALIDATORS,useExisting:t.forwardRef((function(){return n})),multi:!0}]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.PageComponent),me=function(){function e(e){this.sanitizer=e}return e.prototype.transform=function(e){return this.sanitizer.bypassSecurityTrustHtml(e)},e.ctorParameters=function(){return[{type:g.DomSanitizer}]},e=h([t.Pipe({name:"safeHtml"}),C("design:paramtypes",[g.DomSanitizer])],e)}(),ue=function(){function e(){}return e=h([t.NgModule({declarations:[ae,oe,ie,le,se,me],imports:[r.CommonModule,a.SharedModule,l.HomeComponentsModule],exports:[ae,oe,ie,le,se,me]})],e)}(),de=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.unassignCustomerConfigForm},r.prototype.onConfigurationSet=function(e){this.unassignCustomerConfigForm=this.fb.group({customerNamePattern:[e?e.customerNamePattern:null,[i.Validators.required,i.Validators.pattern(/.*\S.*/)]],customerCacheExpiration:[e?e.customerCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.prototype.prepareOutputConfig=function(e){return e.customerNamePattern=e.customerNamePattern.trim(),e},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-un-assign-to-customer-config",template:'
\n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n tb.rulenode.customer-cache-expiration-hint\n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),pe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.snsConfigForm},r.prototype.onConfigurationSet=function(e){this.snsConfigForm=this.fb.group({topicArnPattern:[e?e.topicArnPattern:null,[i.Validators.required]],accessKeyId:[e?e.accessKeyId:null,[i.Validators.required]],secretAccessKey:[e?e.secretAccessKey:null,[i.Validators.required]],region:[e?e.region:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-sns-config",template:'
\n \n tb.rulenode.topic-arn-pattern\n \n \n {{ \'tb.rulenode.topic-arn-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ce=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.sqsQueueType=U,n.sqsQueueTypes=Object.keys(U),n.sqsQueueTypeTranslationsMap=Q,n}return b(r,e),r.prototype.configForm=function(){return this.sqsConfigForm},r.prototype.onConfigurationSet=function(e){this.sqsConfigForm=this.fb.group({queueType:[e?e.queueType:null,[i.Validators.required]],queueUrlPattern:[e?e.queueUrlPattern:null,[i.Validators.required]],delaySeconds:[e?e.delaySeconds:null,[i.Validators.min(0),i.Validators.max(900)]],messageAttributes:[e?e.messageAttributes:null,[]],accessKeyId:[e?e.accessKeyId:null,[i.Validators.required]],secretAccessKey:[e?e.secretAccessKey:null,[i.Validators.required]],region:[e?e.region:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-sqs-config",template:'
\n \n tb.rulenode.queue-type\n \n \n {{ sqsQueueTypeTranslationsMap.get(type) | translate }}\n \n \n \n \n tb.rulenode.queue-url-pattern\n \n \n {{ \'tb.rulenode.queue-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.delay-seconds\n \n \n {{ \'tb.rulenode.min-delay-seconds-message\' | translate }}\n \n \n {{ \'tb.rulenode.max-delay-seconds-message\' | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),fe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.pubSubConfigForm},r.prototype.onConfigurationSet=function(e){this.pubSubConfigForm=this.fb.group({projectId:[e?e.projectId:null,[i.Validators.required]],topicName:[e?e.topicName:null,[i.Validators.required]],serviceAccountKey:[e?e.serviceAccountKey:null,[i.Validators.required]],serviceAccountKeyFileName:[e?e.serviceAccountKeyFileName:null,[i.Validators.required]],messageAttributes:[e?e.messageAttributes:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-pub-sub-config",template:'
\n \n tb.rulenode.gcp-project-id\n \n \n {{ \'tb.rulenode.gcp-project-id-required\' | translate }}\n \n \n \n tb.rulenode.pubsub-topic-name\n \n \n {{ \'tb.rulenode.pubsub-topic-name-required\' | translate }}\n \n \n \n \n \n
\n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ge=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.ackValues=["all","-1","0","1"],n.ToByteStandartCharsetTypesValues=Z,n.ToByteStandartCharsetTypeTranslationMap=X,n}return b(r,e),r.prototype.configForm=function(){return this.kafkaConfigForm},r.prototype.onConfigurationSet=function(e){this.kafkaConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[i.Validators.required]],bootstrapServers:[e?e.bootstrapServers:null,[i.Validators.required]],retries:[e?e.retries:null,[i.Validators.min(0)]],batchSize:[e?e.batchSize:null,[i.Validators.min(0)]],linger:[e?e.linger:null,[i.Validators.min(0)]],bufferMemory:[e?e.bufferMemory:null,[i.Validators.min(0)]],acks:[e?e.acks:null,[i.Validators.required]],keySerializer:[e?e.keySerializer:null,[i.Validators.required]],valueSerializer:[e?e.valueSerializer:null,[i.Validators.required]],otherProperties:[e?e.otherProperties:null,[]],addMetadataKeyValuesAsKafkaHeaders:[!!e&&e.addMetadataKeyValuesAsKafkaHeaders,[]],kafkaHeadersCharset:[e?e.kafkaHeadersCharset:null,[]]})},r.prototype.validatorTriggers=function(){return["addMetadataKeyValuesAsKafkaHeaders"]},r.prototype.updateValidators=function(e){this.kafkaConfigForm.get("addMetadataKeyValuesAsKafkaHeaders").value?this.kafkaConfigForm.get("kafkaHeadersCharset").setValidators([i.Validators.required]):this.kafkaConfigForm.get("kafkaHeadersCharset").setValidators([]),this.kafkaConfigForm.get("kafkaHeadersCharset").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-kafka-config",template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.bootstrap-servers\n \n \n {{ \'tb.rulenode.bootstrap-servers-required\' | translate }}\n \n \n \n tb.rulenode.retries\n \n \n {{ \'tb.rulenode.min-retries-message\' | translate }}\n \n \n \n tb.rulenode.batch-size-bytes\n \n \n {{ \'tb.rulenode.min-batch-size-bytes-message\' | translate }}\n \n \n \n tb.rulenode.linger-ms\n \n \n {{ \'tb.rulenode.min-linger-ms-message\' | translate }}\n \n \n \n tb.rulenode.buffer-memory-bytes\n \n \n {{ \'tb.rulenode.min-buffer-memory-bytes-message\' | translate }}\n \n \n \n tb.rulenode.acks\n \n \n {{ ackValue }}\n \n \n \n \n tb.rulenode.key-serializer\n \n \n {{ \'tb.rulenode.key-serializer-required\' | translate }}\n \n \n \n tb.rulenode.value-serializer\n \n \n {{ \'tb.rulenode.value-serializer-required\' | translate }}\n \n \n \n \n \n \n {{ \'tb.rulenode.add-metadata-key-values-as-kafka-headers\' | translate }}\n \n
tb.rulenode.add-metadata-key-values-as-kafka-headers-hint
\n \n tb.rulenode.charset-encoding\n \n \n {{ ToByteStandartCharsetTypeTranslationMap.get(charset) | translate }}\n \n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ye=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.mqttConfigForm},r.prototype.onConfigurationSet=function(e){this.mqttConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[i.Validators.required]],host:[e?e.host:null,[i.Validators.required]],port:[e?e.port:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]],connectTimeoutSec:[e?e.connectTimeoutSec:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(200)]],clientId:[e?e.clientId:null,[]],cleanSession:[!!e&&e.cleanSession,[]],ssl:[!!e&&e.ssl,[]],credentials:[e?e.credentials:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-mqtt-config",template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n \n tb.rulenode.connect-timeout\n \n \n {{ \'tb.rulenode.connect-timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n
\n \n tb.rulenode.client-id\n \n \n
tb.rulenode.client-id-hint
\n \n {{ \'tb.rulenode.clean-session\' | translate }}\n \n \n {{ \'tb.rulenode.enable-ssl\' | translate }}\n \n \n
\n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}:host .tb-hint.client-id{margin-top:-1.25em;max-width:-webkit-fit-content;max-width:-moz-fit-content;max-width:fit-content}"]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),be=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.messageProperties=[null,"BASIC","TEXT_PLAIN","MINIMAL_BASIC","MINIMAL_PERSISTENT_BASIC","PERSISTENT_BASIC","PERSISTENT_TEXT_PLAIN"],n}return b(r,e),r.prototype.configForm=function(){return this.rabbitMqConfigForm},r.prototype.onConfigurationSet=function(e){this.rabbitMqConfigForm=this.fb.group({exchangeNamePattern:[e?e.exchangeNamePattern:null,[]],routingKeyPattern:[e?e.routingKeyPattern:null,[]],messageProperties:[e?e.messageProperties:null,[]],host:[e?e.host:null,[i.Validators.required]],port:[e?e.port:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]],virtualHost:[e?e.virtualHost:null,[]],username:[e?e.username:null,[]],password:[e?e.password:null,[]],automaticRecoveryEnabled:[!!e&&e.automaticRecoveryEnabled,[]],connectionTimeout:[e?e.connectionTimeout:null,[i.Validators.min(0)]],handshakeTimeout:[e?e.handshakeTimeout:null,[i.Validators.min(0)]],clientProperties:[e?e.clientProperties:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-rabbit-mq-config",template:'
\n \n tb.rulenode.exchange-name-pattern\n \n \n \n tb.rulenode.routing-key-pattern\n \n \n \n tb.rulenode.message-properties\n \n \n {{ property }}\n \n \n \n
\n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n
\n \n tb.rulenode.virtual-host\n \n \n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n \n {{ \'tb.rulenode.automatic-recovery\' | translate }}\n \n \n tb.rulenode.connection-timeout-ms\n \n \n {{ \'tb.rulenode.min-connection-timeout-ms-message\' | translate }}\n \n \n \n tb.rulenode.handshake-timeout-ms\n \n \n {{ \'tb.rulenode.min-handshake-timeout-ms-message\' | translate }}\n \n \n \n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),he=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.proxySchemes=["http","https"],n.httpRequestTypes=Object.keys(z),n}return b(r,e),r.prototype.configForm=function(){return this.restApiCallConfigForm},r.prototype.onConfigurationSet=function(e){this.restApiCallConfigForm=this.fb.group({restEndpointUrlPattern:[e?e.restEndpointUrlPattern:null,[i.Validators.required]],requestMethod:[e?e.requestMethod:null,[i.Validators.required]],useSimpleClientHttpFactory:[!!e&&e.useSimpleClientHttpFactory,[]],ignoreRequestBody:[!!e&&e.ignoreRequestBody,[]],enableProxy:[!!e&&e.enableProxy,[]],useSystemProxyProperties:[!!e&&e.enableProxy,[]],proxyScheme:[e?e.proxyHost:null,[]],proxyHost:[e?e.proxyHost:null,[]],proxyPort:[e?e.proxyPort:null,[]],proxyUser:[e?e.proxyUser:null,[]],proxyPassword:[e?e.proxyPassword:null,[]],readTimeoutMs:[e?e.readTimeoutMs:null,[]],maxParallelRequestsCount:[e?e.maxParallelRequestsCount:null,[i.Validators.min(0)]],headers:[e?e.headers:null,[]],useRedisQueueForMsgPersistence:[!!e&&e.useRedisQueueForMsgPersistence,[]],trimQueue:[!!e&&e.trimQueue,[]],maxQueueSize:[e?e.maxQueueSize:null,[]],credentials:[e?e.credentials:null,[]]})},r.prototype.validatorTriggers=function(){return["useSimpleClientHttpFactory","useRedisQueueForMsgPersistence","enableProxy","useSystemProxyProperties"]},r.prototype.updateValidators=function(e){var t=this.restApiCallConfigForm.get("useSimpleClientHttpFactory").value,r=this.restApiCallConfigForm.get("useRedisQueueForMsgPersistence").value,n=this.restApiCallConfigForm.get("enableProxy").value,a=this.restApiCallConfigForm.get("useSystemProxyProperties").value;n&&!a?(this.restApiCallConfigForm.get("proxyHost").setValidators(n?[i.Validators.required]:[]),this.restApiCallConfigForm.get("proxyPort").setValidators(n?[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]:[])):(this.restApiCallConfigForm.get("proxyHost").setValidators([]),this.restApiCallConfigForm.get("proxyPort").setValidators([]),t?this.restApiCallConfigForm.get("readTimeoutMs").setValidators([]):this.restApiCallConfigForm.get("readTimeoutMs").setValidators([i.Validators.min(0)])),r?this.restApiCallConfigForm.get("maxQueueSize").setValidators([i.Validators.min(0)]):this.restApiCallConfigForm.get("maxQueueSize").setValidators([]),this.restApiCallConfigForm.get("readTimeoutMs").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("maxQueueSize").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("proxyHost").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("proxyPort").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("credentials").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-rest-api-call-config",template:'
\n \n tb.rulenode.endpoint-url-pattern\n \n \n {{ \'tb.rulenode.endpoint-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.request-method\n \n \n {{ requestType }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n \n {{ \'tb.rulenode.use-simple-client-http-factory\' | translate }}\n \n \n {{ \'tb.rulenode.ignore-request-body\' | translate }}\n \n
\n \n {{ \'tb.rulenode.use-system-proxy-properties\' | translate }}\n \n
\n
\n \n tb.rulenode.proxy-scheme\n \n \n {{ proxyScheme }}\n \n \n \n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
\n
\n \n tb.rulenode.read-timeout\n \n tb.rulenode.read-timeout-hint\n \n \n tb.rulenode.max-parallel-requests-count\n \n tb.rulenode.max-parallel-requests-count-hint\n \n \n
\n \n \n \n {{ \'tb.rulenode.use-redis-queue\' | translate }}\n \n
\n \n {{ \'tb.rulenode.trim-redis-queue\' | translate }}\n \n \n tb.rulenode.redis-queue-max-size\n \n \n
\n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ce=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.smtpProtocols=["smtp","smtps"],n.tlsVersions=["TLSv1","TLSv1.1","TLSv1.2","TLSv1.3"],n}return b(r,e),r.prototype.configForm=function(){return this.sendEmailConfigForm},r.prototype.onConfigurationSet=function(e){this.sendEmailConfigForm=this.fb.group({useSystemSmtpSettings:[!!e&&e.useSystemSmtpSettings,[]],smtpProtocol:[e?e.smtpProtocol:null,[]],smtpHost:[e?e.smtpHost:null,[]],smtpPort:[e?e.smtpPort:null,[]],timeout:[e?e.timeout:null,[]],enableTls:[!!e&&e.enableTls,[]],tlsVersion:[e?e.tlsVersion:null,[]],enableProxy:[!!e&&e.enableProxy,[]],proxyHost:[e?e.proxyHost:null,[]],proxyPort:[e?e.proxyPort:null,[]],proxyUser:[e?e.proxyUser:null,[]],proxyPassword:[e?e.proxyPassword:null,[]],username:[e?e.username:null,[]],password:[e?e.password:null,[]]})},r.prototype.validatorTriggers=function(){return["useSystemSmtpSettings","enableProxy"]},r.prototype.updateValidators=function(e){var t=this.sendEmailConfigForm.get("useSystemSmtpSettings").value,r=this.sendEmailConfigForm.get("enableProxy").value;t?(this.sendEmailConfigForm.get("smtpProtocol").setValidators([]),this.sendEmailConfigForm.get("smtpHost").setValidators([]),this.sendEmailConfigForm.get("smtpPort").setValidators([]),this.sendEmailConfigForm.get("timeout").setValidators([]),this.sendEmailConfigForm.get("proxyHost").setValidators([]),this.sendEmailConfigForm.get("proxyPort").setValidators([])):(this.sendEmailConfigForm.get("smtpProtocol").setValidators([i.Validators.required]),this.sendEmailConfigForm.get("smtpHost").setValidators([i.Validators.required]),this.sendEmailConfigForm.get("smtpPort").setValidators([i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]),this.sendEmailConfigForm.get("timeout").setValidators([i.Validators.required,i.Validators.min(0)]),this.sendEmailConfigForm.get("proxyHost").setValidators(r?[i.Validators.required]:[]),this.sendEmailConfigForm.get("proxyPort").setValidators(r?[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]:[])),this.sendEmailConfigForm.get("smtpProtocol").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("smtpHost").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("smtpPort").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("timeout").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("proxyHost").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("proxyPort").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-send-email-config",template:'
\n \n {{ \'tb.rulenode.use-system-smtp-settings\' | translate }}\n \n
\n \n tb.rulenode.smtp-protocol\n \n \n {{ smtpProtocol.toUpperCase() }}\n \n \n \n
\n \n tb.rulenode.smtp-host\n \n \n {{ \'tb.rulenode.smtp-host-required\' | translate }}\n \n \n \n tb.rulenode.smtp-port\n \n \n {{ \'tb.rulenode.smtp-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.timeout-msec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-msec-message\' | translate }}\n \n \n \n {{ \'tb.rulenode.enable-tls\' | translate }}\n \n \n tb.rulenode.tls-version\n \n \n {{ tlsVersion }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n
\n
\n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
\n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n
\n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ve=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.serviceType=a.ServiceType.TB_RULE_ENGINE,n}return b(r,e),r.prototype.configForm=function(){return this.checkPointConfigForm},r.prototype.onConfigurationSet=function(e){this.checkPointConfigForm=this.fb.group({queueName:[e?e.queueName:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-check-point-config",template:'
\n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Fe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.allAzureIotHubCredentialsTypes=J,n.azureIotHubCredentialsTypeTranslationsMap=Y,n}return b(r,e),r.prototype.configForm=function(){return this.azureIotHubConfigForm},r.prototype.onConfigurationSet=function(e){this.azureIotHubConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[i.Validators.required]],host:[e?e.host:null,[i.Validators.required]],port:[e?e.port:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]],connectTimeoutSec:[e?e.connectTimeoutSec:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(200)]],clientId:[e?e.clientId:null,[i.Validators.required]],cleanSession:[!!e&&e.cleanSession,[]],ssl:[!!e&&e.ssl,[]],credentials:this.fb.group({type:[e&&e.credentials?e.credentials.type:null,[i.Validators.required]],sasKey:[e&&e.credentials?e.credentials.sasKey:null,[]],caCert:[e&&e.credentials?e.credentials.caCert:null,[]],caCertFileName:[e&&e.credentials?e.credentials.caCertFileName:null,[]],privateKey:[e&&e.credentials?e.credentials.privateKey:null,[]],privateKeyFileName:[e&&e.credentials?e.credentials.privateKeyFileName:null,[]],cert:[e&&e.credentials?e.credentials.cert:null,[]],certFileName:[e&&e.credentials?e.credentials.certFileName:null,[]],password:[e&&e.credentials?e.credentials.password:null,[]]})})},r.prototype.prepareOutputConfig=function(e){var t=e.credentials.type;return"sas"===t&&(e.credentials={type:t,sasKey:e.credentials.sasKey,caCert:e.credentials.caCert,caCertFileName:e.credentials.caCertFileName}),e},r.prototype.validatorTriggers=function(){return["credentials.type"]},r.prototype.updateValidators=function(e){var t=this.azureIotHubConfigForm.get("credentials"),r=t.get("type").value;switch(e&&t.reset({type:r},{emitEvent:!1}),t.get("sasKey").setValidators([]),t.get("privateKey").setValidators([]),t.get("privateKeyFileName").setValidators([]),t.get("cert").setValidators([]),t.get("certFileName").setValidators([]),r){case"sas":t.get("sasKey").setValidators([i.Validators.required]);break;case"cert.PEM":t.get("privateKey").setValidators([i.Validators.required]),t.get("privateKeyFileName").setValidators([i.Validators.required]),t.get("cert").setValidators([i.Validators.required]),t.get("certFileName").setValidators([i.Validators.required])}t.get("sasKey").updateValueAndValidity({emitEvent:e}),t.get("privateKey").updateValueAndValidity({emitEvent:e}),t.get("privateKeyFileName").updateValueAndValidity({emitEvent:e}),t.get("cert").updateValueAndValidity({emitEvent:e}),t.get("certFileName").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-azure-iot-hub-config",template:'
\n \n tb.rulenode.topic\n \n \n {{ \'tb.rulenode.topic-required\' | translate }}\n \n \n \n \n tb.rulenode.hostname\n \n \n {{ \'tb.rulenode.hostname-required\' | translate }}\n \n \n \n tb.rulenode.device-id\n \n \n {{ \'tb.rulenode.device-id-required\' | translate }}\n \n \n \n \n \n tb.rulenode.credentials\n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(azureIotHubConfigForm.get(\'credentials.type\').value) | translate }}\n \n \n
\n \n tb.rulenode.credentials-type\n \n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
\n \n \n \n \n tb.rulenode.sas-key\n \n \n \n {{ \'tb.rulenode.sas-key-required\' | translate }}\n \n \n \n \n \n \n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n \n
\n
\n
\n
\n
\n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}:host .tb-hint.client-id{margin-top:-1.25em;max-width:-webkit-fit-content;max-width:-moz-fit-content;max-width:fit-content}"]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),xe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.deviceProfile},r.prototype.onConfigurationSet=function(e){this.deviceProfile=this.fb.group({persistAlarmRulesState:[!!e&&e.persistAlarmRulesState,i.Validators.required],fetchAlarmRulesStateOnStart:[!!e&&e.fetchAlarmRulesStateOnStart,i.Validators.required]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-device-profile-config",template:'
\n \n {{ \'tb.rulenode.persist-alarm-rules\' | translate }}\n \n \n {{ \'tb.rulenode.fetch-alarm-rules\' | translate }}\n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Te=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.sendSmsConfigForm},r.prototype.onConfigurationSet=function(e){this.sendSmsConfigForm=this.fb.group({numbersToTemplate:[e?e.numbersToTemplate:null,[i.Validators.required]],smsMessageTemplate:[e?e.smsMessageTemplate:null,[i.Validators.required]],useSystemSmsSettings:[!!e&&e.useSystemSmsSettings,[]],smsProviderConfiguration:[e?e.smsProviderConfiguration:null,[]]})},r.prototype.validatorTriggers=function(){return["useSystemSmsSettings"]},r.prototype.updateValidators=function(e){this.sendSmsConfigForm.get("useSystemSmsSettings").value?this.sendSmsConfigForm.get("smsProviderConfiguration").setValidators([]):this.sendSmsConfigForm.get("smsProviderConfiguration").setValidators([i.Validators.required]),this.sendSmsConfigForm.get("smsProviderConfiguration").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-send-sms-config",template:'
\n \n tb.rulenode.numbers-to-template\n \n \n {{ \'tb.rulenode.numbers-to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.sms-message-template\n \n \n {{ \'tb.rulenode.sms-message-template-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-system-sms-settings\' | translate }}\n \n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),qe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.attributeScopes=Object.keys(a.AttributeScope),n.telemetryTypeTranslationsMap=a.telemetryTypeTranslations,n}return b(r,e),r.prototype.configForm=function(){return this.pushToEdgeConfigForm},r.prototype.onConfigurationSet=function(e){this.pushToEdgeConfigForm=this.fb.group({scope:[e?e.scope:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-push-to-edge-config",template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Se=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.attributeScopes=Object.keys(a.AttributeScope),n.telemetryTypeTranslationsMap=a.telemetryTypeTranslations,n}return b(r,e),r.prototype.configForm=function(){return this.pushToCloudConfigForm},r.prototype.onConfigurationSet=function(e){this.pushToCloudConfigForm=this.fb.group({scope:[e?e.scope:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-action-node-push-to-cloud-config",template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ie=function(){function e(){}return e=h([t.NgModule({declarations:[T,q,S,I,k,N,V,E,A,L,P,ee,te,re,ne,de,pe,ce,fe,ge,ye,be,he,Ce,ve,Fe,xe,Te,qe,Se],imports:[r.CommonModule,a.SharedModule,l.HomeComponentsModule,ue],exports:[T,q,S,I,k,N,V,E,A,L,P,ee,te,re,ne,de,pe,ce,fe,ge,ye,be,he,Ce,ve,Fe,xe,Te,qe,Se]})],e)}(),ke=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n}return b(r,e),r.prototype.configForm=function(){return this.checkMessageConfigForm},r.prototype.onConfigurationSet=function(e){this.checkMessageConfigForm=this.fb.group({messageNames:[e?e.messageNames:null,[]],metadataNames:[e?e.metadataNames:null,[]],checkAllKeys:[!!e&&e.checkAllKeys,[]]})},r.prototype.validateConfig=function(){var e=this.checkMessageConfigForm.get("messageNames").value,t=this.checkMessageConfigForm.get("metadataNames").value;return e.length>0||t.length>0},r.prototype.removeMessageName=function(e){var t=this.checkMessageConfigForm.get("messageNames").value,r=t.indexOf(e);r>=0&&(t.splice(r,1),this.checkMessageConfigForm.get("messageNames").setValue(t,{emitEvent:!0}))},r.prototype.removeMetadataName=function(e){var t=this.checkMessageConfigForm.get("metadataNames").value,r=t.indexOf(e);r>=0&&(t.splice(r,1),this.checkMessageConfigForm.get("metadataNames").setValue(t,{emitEvent:!0}))},r.prototype.addMessageName=function(e){var t=e.input,r=e.value;if((r||"").trim()){r=r.trim();var n=this.checkMessageConfigForm.get("messageNames").value;n&&-1!==n.indexOf(r)||(n||(n=[]),n.push(r),this.checkMessageConfigForm.get("messageNames").setValue(n,{emitEvent:!0}))}t&&(t.value="")},r.prototype.addMetadataName=function(e){var t=e.input,r=e.value;if((r||"").trim()){r=r.trim();var n=this.checkMessageConfigForm.get("metadataNames").value;n&&-1!==n.indexOf(r)||(n||(n=[]),n.push(r),this.checkMessageConfigForm.get("metadataNames").setValue(n,{emitEvent:!0}))}t&&(t.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-filter-node-check-message-config",template:'
\n \n \n \n \n \n {{messageName}}\n close\n \n \n \n \n
tb.rulenode.separator-hint
\n \n \n \n \n \n {{metadataName}}\n close\n \n \n \n \n
tb.rulenode.separator-hint
\n \n {{ \'tb.rulenode.check-all-keys\' | translate }}\n \n
tb.rulenode.check-all-keys-hint
\n
\n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ne=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.entitySearchDirection=Object.keys(a.EntitySearchDirection),n.entitySearchDirectionTranslationsMap=a.entitySearchDirectionTranslations,n}return b(r,e),r.prototype.configForm=function(){return this.checkRelationConfigForm},r.prototype.onConfigurationSet=function(e){this.checkRelationConfigForm=this.fb.group({checkForSingleEntity:[!!e&&e.checkForSingleEntity,[]],direction:[e?e.direction:null,[]],entityType:[e?e.entityType:null,e&&e.checkForSingleEntity?[i.Validators.required]:[]],entityId:[e?e.entityId:null,e&&e.checkForSingleEntity?[i.Validators.required]:[]],relationType:[e?e.relationType:null,[i.Validators.required]]})},r.prototype.validatorTriggers=function(){return["checkForSingleEntity"]},r.prototype.updateValidators=function(e){var t=this.checkRelationConfigForm.get("checkForSingleEntity").value;this.checkRelationConfigForm.get("entityType").setValidators(t?[i.Validators.required]:[]),this.checkRelationConfigForm.get("entityType").updateValueAndValidity({emitEvent:e}),this.checkRelationConfigForm.get("entityId").setValidators(t?[i.Validators.required]:[]),this.checkRelationConfigForm.get("entityId").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-filter-node-check-relation-config",template:'
\n \n {{ \'tb.rulenode.check-relation-to-specific-entity\' | translate }}\n \n
tb.rulenode.check-relation-hint
\n \n relation.direction\n \n \n {{ entitySearchDirectionTranslationsMap.get(direction) | translate }}\n \n \n \n
\n \n \n \n \n
\n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ve=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.perimeterType=M,n.perimeterTypes=Object.keys(M),n.perimeterTypeTranslationMap=D,n.rangeUnits=Object.keys(O),n.rangeUnitTranslationMap=H,n}return b(r,e),r.prototype.configForm=function(){return this.geoFilterConfigForm},r.prototype.onConfigurationSet=function(e){this.geoFilterConfigForm=this.fb.group({latitudeKeyName:[e?e.latitudeKeyName:null,[i.Validators.required]],longitudeKeyName:[e?e.longitudeKeyName:null,[i.Validators.required]],fetchPerimeterInfoFromMessageMetadata:[!!e&&e.fetchPerimeterInfoFromMessageMetadata,[]],perimeterType:[e?e.perimeterType:null,[]],centerLatitude:[e?e.centerLatitude:null,[]],centerLongitude:[e?e.centerLatitude:null,[]],range:[e?e.range:null,[]],rangeUnit:[e?e.rangeUnit:null,[]],polygonsDefinition:[e?e.polygonsDefinition:null,[]]})},r.prototype.validatorTriggers=function(){return["fetchPerimeterInfoFromMessageMetadata","perimeterType"]},r.prototype.updateValidators=function(e){var t=this.geoFilterConfigForm.get("fetchPerimeterInfoFromMessageMetadata").value,r=this.geoFilterConfigForm.get("perimeterType").value;t?this.geoFilterConfigForm.get("perimeterType").setValidators([]):this.geoFilterConfigForm.get("perimeterType").setValidators([i.Validators.required]),t||r!==M.CIRCLE?(this.geoFilterConfigForm.get("centerLatitude").setValidators([]),this.geoFilterConfigForm.get("centerLongitude").setValidators([]),this.geoFilterConfigForm.get("range").setValidators([]),this.geoFilterConfigForm.get("rangeUnit").setValidators([])):(this.geoFilterConfigForm.get("centerLatitude").setValidators([i.Validators.required,i.Validators.min(-90),i.Validators.max(90)]),this.geoFilterConfigForm.get("centerLongitude").setValidators([i.Validators.required,i.Validators.min(-180),i.Validators.max(180)]),this.geoFilterConfigForm.get("range").setValidators([i.Validators.required,i.Validators.min(0)]),this.geoFilterConfigForm.get("rangeUnit").setValidators([i.Validators.required])),t||r!==M.POLYGON?this.geoFilterConfigForm.get("polygonsDefinition").setValidators([]):this.geoFilterConfigForm.get("polygonsDefinition").setValidators([i.Validators.required]),this.geoFilterConfigForm.get("perimeterType").updateValueAndValidity({emitEvent:!1}),this.geoFilterConfigForm.get("centerLatitude").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("centerLongitude").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("range").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("rangeUnit").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("polygonsDefinition").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-filter-node-gps-geofencing-config",template:'
\n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n
\n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n
\n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
\n
\n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ee=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.messageTypeConfigForm},r.prototype.onConfigurationSet=function(e){this.messageTypeConfigForm=this.fb.group({messageTypes:[e?e.messageTypes:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-filter-node-message-type-config",template:'
\n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ae=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.allowedEntityTypes=[a.EntityType.DEVICE,a.EntityType.ASSET,a.EntityType.ENTITY_VIEW,a.EntityType.TENANT,a.EntityType.CUSTOMER,a.EntityType.USER,a.EntityType.DASHBOARD,a.EntityType.RULE_CHAIN,a.EntityType.RULE_NODE],n}return b(r,e),r.prototype.configForm=function(){return this.originatorTypeConfigForm},r.prototype.onConfigurationSet=function(e){this.originatorTypeConfigForm=this.fb.group({originatorTypes:[e?e.originatorTypes:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-filter-node-originator-type-config",template:'
\n \n \n \n
\n',styles:[":host ::ng-deep tb-entity-type-list .mat-form-field-flex{padding-top:0}:host ::ng-deep tb-entity-type-list .mat-form-field-infix{border-top:0}"]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Le=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return b(r,e),r.prototype.configForm=function(){return this.scriptConfigForm},r.prototype.onConfigurationSet=function(e){this.scriptConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.scriptConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"filter",this.translate.instant("tb.rulenode.filter"),"Filter",["msg","metadata","msgType"],this.ruleNodeId,"rulenode/filter_node_script_fn").subscribe((function(t){t&&e.scriptConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-filter-node-script-config",template:'
\n \n \n \n
\n \n
\n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),Pe=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return b(r,e),r.prototype.configForm=function(){return this.switchConfigForm},r.prototype.onConfigurationSet=function(e){this.switchConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.switchConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"switch",this.translate.instant("tb.rulenode.switch"),"Switch",["msg","metadata","msgType"],this.ruleNodeId,"rulenode/switch_node_script_fn").subscribe((function(t){t&&e.switchConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-filter-node-switch-config",template:'
\n \n \n \n
\n \n
\n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),Me=function(e){function r(t,r,n){var o,l,s=e.call(this,t)||this;s.store=t,s.translate=r,s.fb=n,s.alarmStatusTranslationsMap=a.alarmStatusTranslations,s.alarmStatusList=[],s.searchText="",s.displayStatusFn=s.displayStatus.bind(s);try{for(var m=v(Object.keys(a.AlarmStatus)),u=m.next();!u.done;u=m.next()){var d=u.value;s.alarmStatusList.push(a.AlarmStatus[d])}}catch(e){o={error:e}}finally{try{u&&!u.done&&(l=m.return)&&l.call(m)}finally{if(o)throw o.error}}return s.statusFormControl=new i.FormControl(""),s.filteredAlarmStatus=s.statusFormControl.valueChanges.pipe(f.startWith(""),f.map((function(e){return e||""})),f.mergeMap((function(e){return s.fetchAlarmStatus(e)})),f.share()),s}return b(r,e),r.prototype.ngOnInit=function(){e.prototype.ngOnInit.call(this)},r.prototype.configForm=function(){return this.alarmStatusConfigForm},r.prototype.prepareInputConfig=function(e){return this.searchText="",this.statusFormControl.patchValue("",{emitEvent:!0}),e},r.prototype.onConfigurationSet=function(e){this.alarmStatusConfigForm=this.fb.group({alarmStatusList:[e?e.alarmStatusList:null,[i.Validators.required]]})},r.prototype.displayStatus=function(e){return e?this.translate.instant(a.alarmStatusTranslations.get(e)):void 0},r.prototype.fetchAlarmStatus=function(e){var t=this,r=this.getAlarmStatusList();if(this.searchText=e,this.searchText&&this.searchText.length){var n=this.searchText.toUpperCase();return c.of(r.filter((function(e){return t.translate.instant(a.alarmStatusTranslations.get(a.AlarmStatus[e])).toUpperCase().includes(n)})))}return c.of(r)},r.prototype.alarmStatusSelected=function(e){this.addAlarmStatus(e.option.value),this.clear("")},r.prototype.removeAlarmStatus=function(e){var t=this.alarmStatusConfigForm.get("alarmStatusList").value;if(t){var r=t.indexOf(e);r>=0&&(t.splice(r,1),this.alarmStatusConfigForm.get("alarmStatusList").setValue(t))}},r.prototype.addAlarmStatus=function(e){var t=this.alarmStatusConfigForm.get("alarmStatusList").value;t||(t=[]),-1===t.indexOf(e)&&(t.push(e),this.alarmStatusConfigForm.get("alarmStatusList").setValue(t))},r.prototype.getAlarmStatusList=function(){var e=this;return this.alarmStatusList.filter((function(t){return-1===e.alarmStatusConfigForm.get("alarmStatusList").value.indexOf(t)}))},r.prototype.onAlarmStatusInputFocus=function(){this.statusFormControl.updateValueAndValidity({onlySelf:!0,emitEvent:!0})},r.prototype.clear=function(e){var t=this;void 0===e&&(e=""),this.alarmStatusInput.nativeElement.value=e,this.statusFormControl.patchValue(null,{emitEvent:!0}),setTimeout((function(){t.alarmStatusInput.nativeElement.blur(),t.alarmStatusInput.nativeElement.focus()}),0)},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:i.FormBuilder}]},h([t.ViewChild("alarmStatusInput",{static:!1}),C("design:type",t.ElementRef)],r.prototype,"alarmStatusInput",void 0),r=h([t.Component({selector:"tb-filter-node-check-alarm-status-config",template:'
\n \n tb.rulenode.alarm-status-filter\n \n \n \n {{alarmStatusTranslationsMap.get(alarmStatus) | translate}}\n \n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-alarm-status-matching\n
\n
\n
\n
\n
\n \n
\n\n\n\n'}),C("design:paramtypes",[o.Store,n.TranslateService,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),we=function(){function e(){}return e=h([t.NgModule({declarations:[ke,Ne,Ve,Ee,Ae,Le,Pe,Me],imports:[r.CommonModule,a.SharedModule,ue],exports:[ke,Ne,Ve,Ee,Ae,Le,Pe,Me]})],e)}(),Re=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.customerAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.customerAttributesConfigForm=this.fb.group({telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-customer-attributes-config",template:'
\n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),De=function(e){function r(t,r,n){var a,o,l=e.call(this,t)||this;l.store=t,l.translate=r,l.fb=n,l.entityDetailsTranslationsMap=_,l.entityDetailsList=[],l.searchText="",l.displayDetailsFn=l.displayDetails.bind(l);try{for(var s=v(Object.keys(B)),m=s.next();!m.done;m=s.next()){var u=m.value;l.entityDetailsList.push(B[u])}}catch(e){a={error:e}}finally{try{m&&!m.done&&(o=s.return)&&o.call(s)}finally{if(a)throw a.error}}return l.detailsFormControl=new i.FormControl(""),l.filteredEntityDetails=l.detailsFormControl.valueChanges.pipe(f.startWith(""),f.map((function(e){return e||""})),f.mergeMap((function(e){return l.fetchEntityDetails(e)})),f.share()),l}return b(r,e),r.prototype.ngOnInit=function(){e.prototype.ngOnInit.call(this)},r.prototype.configForm=function(){return this.entityDetailsConfigForm},r.prototype.prepareInputConfig=function(e){return this.searchText="",this.detailsFormControl.patchValue("",{emitEvent:!0}),e},r.prototype.onConfigurationSet=function(e){this.entityDetailsConfigForm=this.fb.group({detailsList:[e?e.detailsList:null,[i.Validators.required]],addToMetadata:[!!e&&e.addToMetadata,[]]})},r.prototype.displayDetails=function(e){return e?this.translate.instant(_.get(e)):void 0},r.prototype.fetchEntityDetails=function(e){var t=this;if(this.searchText=e,this.searchText&&this.searchText.length){var r=this.searchText.toUpperCase();return c.of(this.entityDetailsList.filter((function(e){return t.translate.instant(_.get(B[e])).toUpperCase().includes(r)})))}return c.of(this.entityDetailsList)},r.prototype.detailsFieldSelected=function(e){this.addDetailsField(e.option.value),this.clear("")},r.prototype.removeDetailsField=function(e){var t=this.entityDetailsConfigForm.get("detailsList").value;if(t){var r=t.indexOf(e);r>=0&&(t.splice(r,1),this.entityDetailsConfigForm.get("detailsList").setValue(t))}},r.prototype.addDetailsField=function(e){var t=this.entityDetailsConfigForm.get("detailsList").value;t||(t=[]),-1===t.indexOf(e)&&(t.push(e),this.entityDetailsConfigForm.get("detailsList").setValue(t))},r.prototype.onEntityDetailsInputFocus=function(){this.detailsFormControl.updateValueAndValidity({onlySelf:!0,emitEvent:!0})},r.prototype.clear=function(e){var t=this;void 0===e&&(e=""),this.detailsInput.nativeElement.value=e,this.detailsFormControl.patchValue(null,{emitEvent:!0}),setTimeout((function(){t.detailsInput.nativeElement.blur(),t.detailsInput.nativeElement.focus()}),0)},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:i.FormBuilder}]},h([t.ViewChild("detailsInput",{static:!1}),C("design:type",t.ElementRef)],r.prototype,"detailsInput",void 0),r=h([t.Component({selector:"tb-enrichment-node-entity-details-config",template:'
\n \n tb.rulenode.entity-details\n \n \n \n {{entityDetailsTranslationsMap.get(details) | translate}}\n \n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-entity-details-matching\n
\n
\n
\n
\n
\n \n \n {{ \'tb.rulenode.add-to-metadata\' | translate }}\n \n
tb.rulenode.add-to-metadata-hint
\n
\n',styles:[":host ::ng-deep mat-form-field.entity-fields-list .mat-form-field-wrapper{margin-bottom:-1.25em}"]}),C("design:paramtypes",[o.Store,n.TranslateService,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Oe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n}return b(r,e),r.prototype.configForm=function(){return this.deviceAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.deviceAttributesConfigForm=this.fb.group({deviceRelationsQuery:[e?e.deviceRelationsQuery:null,[i.Validators.required]],tellFailureIfAbsent:[!!e&&e.tellFailureIfAbsent,[]],clientAttributeNames:[e?e.clientAttributeNames:null,[]],sharedAttributeNames:[e?e.sharedAttributeNames:null,[]],serverAttributeNames:[e?e.serverAttributeNames:null,[]],latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],getLatestValueWithTs:[!!e&&e.getLatestValueWithTs,[]]})},r.prototype.removeKey=function(e,t){var r=this.deviceAttributesConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.deviceAttributesConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.deviceAttributesConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.deviceAttributesConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-device-attributes-config",template:'
\n \n \n \n \n {{ \'tb.rulenode.tell-failure-if-absent\' | translate }}\n \n
tb.rulenode.tell-failure-if-absent-hint
\n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n {{ \'tb.rulenode.get-latest-value-with-ts\' | translate }}\n \n
\n
\n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ke=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n}return b(r,e),r.prototype.configForm=function(){return this.originatorAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.originatorAttributesConfigForm=this.fb.group({tellFailureIfAbsent:[!!e&&e.tellFailureIfAbsent,[]],clientAttributeNames:[e?e.clientAttributeNames:null,[]],sharedAttributeNames:[e?e.sharedAttributeNames:null,[]],serverAttributeNames:[e?e.serverAttributeNames:null,[]],latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],getLatestValueWithTs:[!!e&&e.getLatestValueWithTs,[]]})},r.prototype.removeKey=function(e,t){var r=this.originatorAttributesConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.originatorAttributesConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.originatorAttributesConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.originatorAttributesConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-originator-attributes-config",template:'
\n \n {{ \'tb.rulenode.tell-failure-if-absent\' | translate }}\n \n
tb.rulenode.tell-failure-if-absent-hint
\n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n {{ \'tb.rulenode.get-latest-value-with-ts\' | translate }}\n \n
\n
\n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Be=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.originatorFieldsConfigForm},r.prototype.onConfigurationSet=function(e){this.originatorFieldsConfigForm=this.fb.group({fieldsMapping:[e?e.fieldsMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-originator-fields-config",template:'
\n \n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),He=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n.aggregationTypes=a.AggregationType,n.aggregations=Object.keys(a.AggregationType),n.aggregationTypesTranslations=a.aggregationTranslations,n.fetchMode=G,n.fetchModes=Object.keys(G),n.samplingOrders=Object.keys(j),n.timeUnits=Object.values(R),n.timeUnitsTranslationMap=K,n}return b(r,e),r.prototype.configForm=function(){return this.getTelemetryFromDatabaseConfigForm},r.prototype.onConfigurationSet=function(e){this.getTelemetryFromDatabaseConfigForm=this.fb.group({latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],aggregation:[e?e.aggregation:null,[i.Validators.required]],fetchMode:[e?e.fetchMode:null,[i.Validators.required]],orderBy:[e?e.orderBy:null,[]],limit:[e?e.limit:null,[]],useMetadataIntervalPatterns:[!!e&&e.useMetadataIntervalPatterns,[]],startInterval:[e?e.startInterval:null,[]],startIntervalTimeUnit:[e?e.startIntervalTimeUnit:null,[]],endInterval:[e?e.endInterval:null,[]],endIntervalTimeUnit:[e?e.endIntervalTimeUnit:null,[]],startIntervalPattern:[e?e.startIntervalPattern:null,[]],endIntervalPattern:[e?e.endIntervalPattern:null,[]]})},r.prototype.validatorTriggers=function(){return["fetchMode","useMetadataIntervalPatterns"]},r.prototype.updateValidators=function(e){var t=this.getTelemetryFromDatabaseConfigForm.get("fetchMode").value,r=this.getTelemetryFromDatabaseConfigForm.get("useMetadataIntervalPatterns").value;t&&t===G.ALL?(this.getTelemetryFromDatabaseConfigForm.get("aggregation").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("orderBy").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("limit").setValidators([i.Validators.required,i.Validators.min(2),i.Validators.max(1e3)])):(this.getTelemetryFromDatabaseConfigForm.get("aggregation").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("orderBy").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("limit").setValidators([])),r?(this.getTelemetryFromDatabaseConfigForm.get("startInterval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endInterval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").setValidators([i.Validators.required])):(this.getTelemetryFromDatabaseConfigForm.get("startInterval").setValidators([i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("endInterval").setValidators([i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").setValidators([])),this.getTelemetryFromDatabaseConfigForm.get("aggregation").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("orderBy").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("limit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startInterval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endInterval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").updateValueAndValidity({emitEvent:e})},r.prototype.removeKey=function(e,t){var r=this.getTelemetryFromDatabaseConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.getTelemetryFromDatabaseConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.getTelemetryFromDatabaseConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.getTelemetryFromDatabaseConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-get-telemetry-from-database",template:'
\n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.fetch-mode\n \n \n {{ mode }}\n \n \n tb.rulenode.fetch-mode-hint\n \n
\n \n aggregation.function\n \n \n {{ aggregationTypesTranslations.get(aggregationTypes[aggregation]) | translate }}\n \n \n \n \n tb.rulenode.order-by\n \n \n {{ order }}\n \n \n tb.rulenode.order-by-hint\n \n \n tb.rulenode.limit\n \n tb.rulenode.limit-hint\n \n
\n \n {{ \'tb.rulenode.use-metadata-interval-patterns\' | translate }}\n \n
tb.rulenode.use-metadata-interval-patterns-hint
\n
\n
\n \n tb.rulenode.start-interval\n \n \n {{ \'tb.rulenode.start-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.start-interval-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n tb.rulenode.end-interval\n \n \n {{ \'tb.rulenode.end-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.end-interval-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n \n tb.rulenode.start-interval-pattern\n \n \n {{ \'tb.rulenode.start-interval-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.end-interval-pattern\n \n \n {{ \'tb.rulenode.end-interval-pattern-required\' | translate }}\n \n \n \n \n
\n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ge=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.relatedAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.relatedAttributesConfigForm=this.fb.group({relationsQuery:[e?e.relationsQuery:null,[i.Validators.required]],telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-related-attributes-config",template:'
\n \n \n \n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),je=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return b(r,e),r.prototype.configForm=function(){return this.tenantAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.tenantAttributesConfigForm=this.fb.group({telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-tenant-attributes-config",template:'
\n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ue=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[m.ENTER,m.COMMA,m.SEMICOLON],n}return b(r,e),r.prototype.configForm=function(){return this.calculateDeltaConfigForm},r.prototype.onConfigurationSet=function(e){this.calculateDeltaConfigForm=this.fb.group({inputValueKey:[e?e.inputValueKey:null,[i.Validators.required]],outputValueKey:[e?e.outputValueKey:null,[i.Validators.required]],useCache:[e?e.useCache:null,[]],addPeriodBetweenMsgs:[!!e&&e.addPeriodBetweenMsgs,[]],periodValueKey:[e?e.periodValueKey:null,[]],round:[e?e.round:null,[i.Validators.min(0),i.Validators.max(15)]],tellFailureIfDeltaIsNegative:[e?e.tellFailureIfDeltaIsNegative:null,[]]})},r.prototype.updateValidators=function(e){this.calculateDeltaConfigForm.get("addPeriodBetweenMsgs").value?this.calculateDeltaConfigForm.get("periodValueKey").setValidators([i.Validators.required]):this.calculateDeltaConfigForm.get("periodValueKey").setValidators([]),this.calculateDeltaConfigForm.get("periodValueKey").updateValueAndValidity({emitEvent:e})},r.prototype.validatorTriggers=function(){return["addPeriodBetweenMsgs"]},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-enrichment-node-calculate-delta-config",template:'
\n
\n \n tb.rulenode.input-value-key\n \n \n {{ \'tb.rulenode.input-value-key-required\' | translate }}\n \n \n \n tb.rulenode.output-value-key\n \n \n {{ \'tb.rulenode.output-value-key-required\' | translate }}\n \n \n \n tb.rulenode.round\n \n \n {{ \'tb.rulenode.round-range\' | translate }}\n \n \n {{ \'tb.rulenode.round-range\' | translate }}\n \n \n
\n \n {{ \'tb.rulenode.use-cache\' | translate }}\n \n \n {{ \'tb.rulenode.tell-failure-if-delta-is-negative\' | translate }}\n \n \n {{ \'tb.rulenode.add-period-between-msgs\' | translate }}\n \n \n tb.rulenode.period-value-key\n \n \n {{ \'tb.rulenode.period-value-key-required\' | translate }}\n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),_e=function(){function e(){}return e=h([t.NgModule({declarations:[Re,De,Oe,Ke,Be,He,Ge,je,Ue],imports:[r.CommonModule,a.SharedModule,ue],exports:[Re,De,Oe,Ke,Be,He,Ge,je,Ue]})],e)}(),ze=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.originatorSource=F,n.originatorSources=Object.keys(F),n.originatorSourceTranslationMap=w,n}return b(r,e),r.prototype.configForm=function(){return this.changeOriginatorConfigForm},r.prototype.onConfigurationSet=function(e){this.changeOriginatorConfigForm=this.fb.group({originatorSource:[e?e.originatorSource:null,[i.Validators.required]],relationsQuery:[e?e.relationsQuery:null,[]]})},r.prototype.validatorTriggers=function(){return["originatorSource"]},r.prototype.updateValidators=function(e){var t=this.changeOriginatorConfigForm.get("originatorSource").value;t&&t===F.RELATED?this.changeOriginatorConfigForm.get("relationsQuery").setValidators([i.Validators.required]):this.changeOriginatorConfigForm.get("relationsQuery").setValidators([]),this.changeOriginatorConfigForm.get("relationsQuery").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-transformation-node-change-originator-config",template:'
\n \n tb.rulenode.originator-source\n \n \n {{ originatorSourceTranslationMap.get(source) | translate }}\n \n \n \n
\n \n \n \n
\n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Qe=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return b(r,e),r.prototype.configForm=function(){return this.scriptConfigForm},r.prototype.onConfigurationSet=function(e){this.scriptConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.scriptConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"update",this.translate.instant("tb.rulenode.transformer"),"Transform",["msg","metadata","msgType"],this.ruleNodeId,"rulenode/transformation_node_script_fn").subscribe((function(t){t&&e.scriptConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:s.NodeScriptTestService},{type:n.TranslateService}]},h([t.ViewChild("jsFuncComponent",{static:!0}),C("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=h([t.Component({selector:"tb-transformation-node-script-config",template:'
\n \n \n \n
\n \n
\n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder,s.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),$e=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.mailBodyTypes=[{name:"tb.mail-body-type.plain-text",value:"false"},{name:"tb.mail-body-type.html",value:"true"},{name:"tb.mail-body-type.dynamic",value:"dynamic"}],n}return b(r,e),r.prototype.configForm=function(){return this.toEmailConfigForm},r.prototype.onConfigurationSet=function(e){var t=this;this.toEmailConfigForm=this.fb.group({fromTemplate:[e?e.fromTemplate:null,[i.Validators.required]],toTemplate:[e?e.toTemplate:null,[i.Validators.required]],ccTemplate:[e?e.ccTemplate:null,[]],bccTemplate:[e?e.bccTemplate:null,[]],subjectTemplate:[e?e.subjectTemplate:null,[i.Validators.required]],mailBodyType:[e?e.mailBodyType:null],isHtmlTemplate:[e?e.isHtmlTemplate:null],bodyTemplate:[e?e.bodyTemplate:null,[i.Validators.required]]}),this.toEmailConfigForm.get("mailBodyType").valueChanges.pipe(f.startWith([null==e?void 0:e.subjectTemplate])).subscribe((function(e){"dynamic"===e?(t.toEmailConfigForm.get("isHtmlTemplate").patchValue("",{emitEvent:!1}),t.toEmailConfigForm.get("isHtmlTemplate").setValidators(i.Validators.required)):t.toEmailConfigForm.get("isHtmlTemplate").clearValidators(),t.toEmailConfigForm.get("isHtmlTemplate").updateValueAndValidity()}))},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=h([t.Component({selector:"tb-transformation-node-to-email-config",template:'
\n \n tb.rulenode.from-template\n \n \n {{ \'tb.rulenode.from-template-required\' | translate }}\n \n \n \n \n tb.rulenode.to-template\n \n \n {{ \'tb.rulenode.to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.cc-template\n \n \n \n \n tb.rulenode.bcc-template\n \n \n \n \n tb.rulenode.subject-template\n \n \n {{ \'tb.rulenode.subject-template-required\' | translate }}\n \n \n \n \n tb.rulenode.mail-body-type\n \n \n {{ type.name | translate }}\n \n \n \n \n tb.rulenode.dynamic-mail-body-type\n \n \n \n \n tb.rulenode.body-template\n \n \n {{ \'tb.rulenode.body-template-required\' | translate }}\n \n \n \n
\n'}),C("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),We=function(){function e(){}return e=h([t.NgModule({declarations:[ze,Qe,$e],imports:[r.CommonModule,a.SharedModule,ue],exports:[ze,Qe,$e]})],e)}(),Je=function(){function e(e){!function(e){e.setTranslation("en_US",{tb:{rulenode:{"create-entity-if-not-exists":"Create new entity if not exists","create-entity-if-not-exists-hint":"Create a new entity set above if it does not exist.","entity-name-pattern":"Name pattern","entity-name-pattern-required":"Name pattern is required","entity-type-pattern":"Type pattern","entity-type-pattern-required":"Type pattern is required","entity-cache-expiration":"Entities cache expiration time (sec)","entity-cache-expiration-hint":"Specifies maximum time interval allowed to store found entity records. 0 value means that records will never expire.","entity-cache-expiration-required":"Entities cache expiration time is required.","entity-cache-expiration-range":"Entities cache expiration time should be greater than or equal to 0.","customer-name-pattern":"Customer name pattern","customer-name-pattern-required":"Customer name pattern is required","create-customer-if-not-exists":"Create new customer if not exists","customer-cache-expiration":"Customers cache expiration time (sec)","customer-cache-expiration-hint":"Specifies maximum time interval allowed to store found customer records. 0 value means that records will never expire.","customer-cache-expiration-required":"Customers cache expiration time is required.","customer-cache-expiration-range":"Customers cache expiration time should be greater than or equal to 0.","start-interval":"Start Interval","end-interval":"End Interval","start-interval-time-unit":"Start Interval Time Unit","end-interval-time-unit":"End Interval Time Unit","fetch-mode":"Fetch mode","fetch-mode-hint":"If selected fetch mode 'ALL' you able to choose telemetry sampling order.","order-by":"Order by","order-by-hint":"Select to choose telemetry sampling order.",limit:"Limit","limit-hint":"Min limit value is 2, max - 1000. In case you want to fetch a single entry, select fetch mode 'FIRST' or 'LAST'.","time-unit-milliseconds":"Milliseconds","time-unit-seconds":"Seconds","time-unit-minutes":"Minutes","time-unit-hours":"Hours","time-unit-days":"Days","time-value-range":"Time value should be in a range from 1 to 2147483647.","start-interval-value-required":"Start interval value is required.","end-interval-value-required":"End interval value is required.",filter:"Filter",switch:"Switch","message-type":"Message type","message-type-required":"Message type is required.","message-types-filter":"Message types filter","no-message-types-found":"No message types found","no-message-type-matching":"'{{messageType}}' not found.","create-new-message-type":"Create a new one!","message-types-required":"Message types are required.","client-attributes":"Client attributes","shared-attributes":"Shared attributes","server-attributes":"Server attributes","notify-device":"Notify Device","notify-device-hint":"If the message arrives from the device, we will push it back to the device by default.","latest-timeseries":"Latest timeseries","timeseries-key":"Timeseries key","data-keys":"Message data","metadata-keys":"Message metadata","relations-query":"Relations query","device-relations-query":"Device relations query","max-relation-level":"Max relation level","relation-type-pattern":"Relation type pattern","relation-type-pattern-required":"Relation type pattern is required","relation-types-list":"Relation types to propagate","relation-types-list-hint":"If Propagate relation types are not selected, alarms will be propagated without filtering by relation type.","unlimited-level":"Unlimited level","latest-telemetry":"Latest telemetry","attr-mapping":"Attributes mapping","source-attribute":"Source attribute","source-attribute-required":"Source attribute is required.","source-telemetry":"Source telemetry","source-telemetry-required":"Source telemetry is required.","target-attribute":"Target attribute","target-attribute-required":"Target attribute is required.","attr-mapping-required":"At least one attribute mapping should be specified.","fields-mapping":"Fields mapping","fields-mapping-required":"At least one field mapping should be specified.","source-field":"Source field","source-field-required":"Source field is required.","originator-source":"Originator source","originator-customer":"Customer","originator-tenant":"Tenant","originator-related":"Related","originator-alarm-originator":"Alarm Originator","clone-message":"Clone message",transform:"Transform","default-ttl":"Default TTL in seconds","default-ttl-required":"Default TTL is required.","min-default-ttl-message":"Only 0 minimum TTL is allowed.","message-count":"Message count (0 - unlimited)","message-count-required":"Message count is required.","min-message-count-message":"Only 0 minimum message count is allowed.","period-seconds":"Period in seconds","period-seconds-required":"Period is required.","use-metadata-period-in-seconds-patterns":"Use period in seconds pattern","use-metadata-period-in-seconds-patterns-hint":"If selected, rule node use period in seconds interval pattern from message metadata or data assuming that intervals are in the seconds.","period-in-seconds-pattern":"Period in seconds pattern","period-in-seconds-pattern-required":"Period in seconds pattern is required","min-period-seconds-message":"Only 1 second minimum period is allowed.",originator:"Originator","message-body":"Message body","message-metadata":"Message metadata",generate:"Generate","test-generator-function":"Test generator function",generator:"Generator","test-filter-function":"Test filter function","test-switch-function":"Test switch function","test-transformer-function":"Test transformer function",transformer:"Transformer","alarm-create-condition":"Alarm create condition","test-condition-function":"Test condition function","alarm-clear-condition":"Alarm clear condition","alarm-details-builder":"Alarm details builder","test-details-function":"Test details function","alarm-type":"Alarm type","alarm-type-required":"Alarm type is required.","alarm-severity":"Alarm severity","alarm-severity-required":"Alarm severity is required","alarm-status-filter":"Alarm status filter","alarm-status-list-empty":"Alarm status list is empty","no-alarm-status-matching":"No alarm status matching were found.",propagate:"Propagate",condition:"Condition",details:"Details","to-string":"To string","test-to-string-function":"Test to string function","from-template":"From Template","from-template-required":"From Template is required","to-template":"To Template","to-template-required":"To Template is required","mail-address-list-template-hint":'Comma separated address list, use ${metadataKey} for value from metadata, $[messageKey] for value from message body',"cc-template":"Cc Template","bcc-template":"Bcc Template","subject-template":"Subject Template","subject-template-required":"Subject Template is required","body-template":"Body Template","body-template-required":"Body Template is required","dynamic-mail-body-type":"Dynamic mail body type","mail-body-type":"Mail body type","request-id-metadata-attribute":"Request Id Metadata attribute name","timeout-sec":"Timeout in seconds","timeout-required":"Timeout is required","min-timeout-message":"Only 0 minimum timeout value is allowed.","endpoint-url-pattern":"Endpoint URL pattern","endpoint-url-pattern-required":"Endpoint URL pattern is required","request-method":"Request method","use-simple-client-http-factory":"Use simple client HTTP factory","ignore-request-body":"Without request body","read-timeout":"Read timeout in millis","read-timeout-hint":"The value of 0 means an infinite timeout","max-parallel-requests-count":"Max number of parallel requests","max-parallel-requests-count-hint":"The value of 0 specifies no limit in parallel processing",headers:"Headers","headers-hint":'Use ${metadataKey} for value from metadata, $[messageKey] for value from message body in header/value fields',header:"Header","header-required":"Header is required",value:"Value","value-required":"Value is required","topic-pattern":"Topic pattern","topic-pattern-required":"Topic pattern is required",topic:"Topic","topic-required":"Topic is required","bootstrap-servers":"Bootstrap servers","bootstrap-servers-required":"Bootstrap servers value is required","other-properties":"Other properties",key:"Key","key-required":"Key is required",retries:"Automatically retry times if fails","min-retries-message":"Only 0 minimum retries is allowed.","batch-size-bytes":"Produces batch size in bytes","min-batch-size-bytes-message":"Only 0 minimum batch size is allowed.","linger-ms":"Time to buffer locally (ms)","min-linger-ms-message":"Only 0 ms minimum value is allowed.","buffer-memory-bytes":"Client buffer max size in bytes","min-buffer-memory-message":"Only 0 minimum buffer size is allowed.",acks:"Number of acknowledgments","key-serializer":"Key serializer","key-serializer-required":"Key serializer is required","value-serializer":"Value serializer","value-serializer-required":"Value serializer is required","topic-arn-pattern":"Topic ARN pattern","topic-arn-pattern-required":"Topic ARN pattern is required","aws-access-key-id":"AWS Access Key ID","aws-access-key-id-required":"AWS Access Key ID is required","aws-secret-access-key":"AWS Secret Access Key","aws-secret-access-key-required":"AWS Secret Access Key is required","aws-region":"AWS Region","aws-region-required":"AWS Region is required","exchange-name-pattern":"Exchange name pattern","routing-key-pattern":"Routing key pattern","message-properties":"Message properties",host:"Host","host-required":"Host is required",port:"Port","port-required":"Port is required","port-range":"Port should be in a range from 1 to 65535.","virtual-host":"Virtual host",username:"Username",password:"Password","automatic-recovery":"Automatic recovery","connection-timeout-ms":"Connection timeout (ms)","min-connection-timeout-ms-message":"Only 0 ms minimum value is allowed.","handshake-timeout-ms":"Handshake timeout (ms)","min-handshake-timeout-ms-message":"Only 0 ms minimum value is allowed.","client-properties":"Client properties","queue-url-pattern":"Queue URL pattern","queue-url-pattern-required":"Queue URL pattern is required","delay-seconds":"Delay (seconds)","min-delay-seconds-message":"Only 0 seconds minimum value is allowed.","max-delay-seconds-message":"Only 900 seconds maximum value is allowed.",name:"Name","name-required":"Name is required","queue-type":"Queue type","sqs-queue-standard":"Standard","sqs-queue-fifo":"FIFO","gcp-project-id":"GCP project ID","gcp-project-id-required":"GCP project ID is required","gcp-service-account-key":"GCP service account key file","gcp-service-account-key-required":"GCP service account key file is required","pubsub-topic-name":"Topic name","pubsub-topic-name-required":"Topic name is required","message-attributes":"Message attributes","message-attributes-hint":'Use ${metadataKey} for value from metadata, $[messageKey] for value from message body in name/value fields',"connect-timeout":"Connection timeout (sec)","connect-timeout-required":"Connection timeout is required.","connect-timeout-range":"Connection timeout should be in a range from 1 to 200.","client-id":"Client ID","client-id-hint":"Hint: Optional. Leave empty for auto-generated client id. Be careful when specifying the Client ID.Majority of the MQTT brokers will not allow multiple connections with the same client id. To connect to such brokers, your mqtt client id must be unique. When platform is running in a micro-services mode, the copy of rule nodeis launched in each micro-service. This will automatically lead to multiple mqtt clients with the same id and may cause failures of the rule node.","device-id":"Device ID","device-id-required":"Device ID is required.","clean-session":"Clean session","enable-ssl":"Enable SSL",credentials:"Credentials","credentials-type":"Credentials type","credentials-type-required":"Credentials type is required.","credentials-anonymous":"Anonymous","credentials-basic":"Basic","credentials-pem":"PEM","credentials-pem-hint":"At least Server CA certificate file or a pair of Client certificate and Client private key files are required","credentials-sas":"Shared Access Signature","sas-key":"SAS Key","sas-key-required":"SAS Key is required.",hostname:"Hostname","hostname-required":"Hostname is required.","azure-ca-cert":"CA certificate file","username-required":"Username is required.","password-required":"Password is required.","ca-cert":"Server CA certificate file *","private-key":"Client private key file *",cert:"Client certificate file *","no-file":"No file selected.","drop-file":"Drop a file or click to select a file to upload.","private-key-password":"Private key password","use-system-smtp-settings":"Use system SMTP settings","use-metadata-interval-patterns":"Use interval patterns","use-metadata-interval-patterns-hint":"If selected, rule node use start and end interval patterns from message metadata or data assuming that intervals are in the milliseconds.","use-message-alarm-data":"Use message alarm data","use-dynamically-change-the-severity-of-alar":"Use dynamically change the severity of alarm","check-all-keys":"Check that all selected keys are present","check-all-keys-hint":"If selected, checks that all specified keys are present in the message data and metadata.","check-relation-to-specific-entity":"Check relation to specific entity","check-relation-hint":"Checks existence of relation to specific entity or to any entity based on direction and relation type.","delete-relation-to-specific-entity":"Delete relation to specific entity","delete-relation-hint":"Deletes relation from the originator of the incoming message to the specified entity or list of entities based on direction and type.","remove-current-relations":"Remove current relations","remove-current-relations-hint":"Removes current relations from the originator of the incoming message based on direction and type.","change-originator-to-related-entity":"Change originator to related entity","change-originator-to-related-entity-hint":"Used to process submitted message as a message from another entity.","start-interval-pattern":"Start interval pattern","end-interval-pattern":"End interval pattern","start-interval-pattern-required":"Start interval pattern is required","end-interval-pattern-required":"End interval pattern is required","smtp-protocol":"Protocol","smtp-host":"SMTP host","smtp-host-required":"SMTP host is required.","smtp-port":"SMTP port","smtp-port-required":"You must supply a smtp port.","smtp-port-range":"SMTP port should be in a range from 1 to 65535.","timeout-msec":"Timeout ms","min-timeout-msec-message":"Only 0 ms minimum value is allowed.","enter-username":"Enter username","enter-password":"Enter password","enable-tls":"Enable TLS","tls-version":"TLS version","enable-proxy":"Enable proxy","use-system-proxy-properties":"Use system proxy properties","proxy-host":"Proxy host","proxy-host-required":"Proxy host is required.","proxy-port":"Proxy port","proxy-port-required":"Proxy port is required.","proxy-port-range":"Proxy port should be in a range from 1 to 65535.","proxy-user":"Proxy user","proxy-password":"Proxy password","proxy-scheme":"Proxy scheme","numbers-to-template":"Phone Numbers To Template","numbers-to-template-required":"Phone Numbers To Template is required","numbers-to-template-hint":'Comma separated Phone Numbers, use ${metadataKey} for value from metadata, $[messageKey] for value from message body',"sms-message-template":"SMS message Template","sms-message-template-required":"SMS message Template is required","use-system-sms-settings":"Use system SMS provider settings","min-period-0-seconds-message":"Only 0 second minimum period is allowed.","max-pending-messages":"Maximum pending messages","max-pending-messages-required":"Maximum pending messages is required.","max-pending-messages-range":"Maximum pending messages should be in a range from 1 to 100000.","originator-types-filter":"Originator types filter","interval-seconds":"Interval in seconds","interval-seconds-required":"Interval is required.","min-interval-seconds-message":"Only 1 second minimum interval is allowed.","output-timeseries-key-prefix":"Output timeseries key prefix","output-timeseries-key-prefix-required":"Output timeseries key prefix required.","separator-hint":'You should press "enter" to complete field input.',"entity-details":"Select entity details:","entity-details-title":"Title","entity-details-country":"Country","entity-details-state":"State","entity-details-zip":"Zip","entity-details-address":"Address","entity-details-address2":"Address2","entity-details-additional_info":"Additional Info","entity-details-phone":"Phone","entity-details-email":"Email","add-to-metadata":"Add selected details to message metadata","add-to-metadata-hint":"If selected, adds the selected details keys to the message metadata instead of message data.","entity-details-list-empty":"No entity details selected.","no-entity-details-matching":"No entity details matching were found.","custom-table-name":"Custom table name","custom-table-name-required":"Table Name is required","custom-table-hint":"You should enter the table name without prefix 'cs_tb_'.","message-field":"Message field","message-field-required":"Message field is required.","table-col":"Table column","table-col-required":"Table column is required.","latitude-key-name":"Latitude key name","longitude-key-name":"Longitude key name","latitude-key-name-required":"Latitude key name is required.","longitude-key-name-required":"Longitude key name is required.","fetch-perimeter-info-from-message-metadata":"Fetch perimeter information from message metadata","perimeter-circle":"Circle","perimeter-polygon":"Polygon","perimeter-type":"Perimeter type","circle-center-latitude":"Center latitude","circle-center-latitude-required":"Center latitude is required.","circle-center-longitude":"Center longitude","circle-center-longitude-required":"Center longitude is required.","range-unit-meter":"Meter","range-unit-kilometer":"Kilometer","range-unit-foot":"Foot","range-unit-mile":"Mile","range-unit-nautical-mile":"Nautical mile","range-units":"Range units",range:"Range","range-required":"Range is required.","polygon-definition":"Polygon definition","polygon-definition-required":"Polygon definition is required.","polygon-definition-hint":"Please, use the following format for manual definition of polygon: [[lat1,lon1],[lat2,lon2], ... ,[latN,lonN]].","min-inside-duration":"Minimal inside duration","min-inside-duration-value-required":"Minimal inside duration is required","min-inside-duration-time-unit":"Minimal inside duration time unit","min-outside-duration":"Minimal outside duration","min-outside-duration-value-required":"Minimal outside duration is required","min-outside-duration-time-unit":"Minimal outside duration time unit","tell-failure-if-absent":"Tell Failure","tell-failure-if-absent-hint":'If at least one selected key doesn\'t exist the outbound message will report "Failure".',"get-latest-value-with-ts":"Fetch Latest telemetry with Timestamp","get-latest-value-with-ts-hint":'If selected, latest telemetry values will be added to the outbound message metadata with timestamp, e.g: "temp": "{"ts":1574329385897, "value":42}"',"use-redis-queue":"Use redis queue for message persistence","trim-redis-queue":"Trim redis queue","redis-queue-max-size":"Redis queue max size","add-metadata-key-values-as-kafka-headers":"Add Message metadata key-value pairs to Kafka record headers","add-metadata-key-values-as-kafka-headers-hint":"If selected, key-value pairs from message metadata will be added to the outgoing records headers as byte arrays with predefined charset encoding.","charset-encoding":"Charset encoding","charset-encoding-required":"Charset encoding is required.","charset-us-ascii":"US-ASCII","charset-iso-8859-1":"ISO-8859-1","charset-utf-8":"UTF-8","charset-utf-16be":"UTF-16BE","charset-utf-16le":"UTF-16LE","charset-utf-16":"UTF-16","select-queue-hint":"The queue name can be selected from a drop-down list or add a custom name.","persist-alarm-rules":"Persist state of alarm rules","fetch-alarm-rules":"Fetch state of alarm rules","input-value-key":"Input value key","input-value-key-required":"Input value key is required.","output-value-key":"Output value key","output-value-key-required":"Output value key is required.",round:"Decimals","round-range":"Decimals should be in a range from 0 to 15.","use-cache":"Use cache for latest value","tell-failure-if-delta-is-negative":"Tell Failure if delta is negative","add-period-between-msgs":"Add period between messages","period-value-key":"Period value key","period-key-required":"Period value key is required.","general-pattern-hint":'Hint: use ${metadataKey} for value from metadata, $[messageKey] for value from message body',"alarm-severity-pattern-hint":'Hint: use ${metadataKey} for value from metadata, $[messageKey] for value from message body. Alarm severity should be system (CRITICAL, MAJOR etc.)'},"key-val":{key:"Key",value:"Value","remove-entry":"Remove entry","add-entry":"Add entry"},"mail-body-type":{"plain-text":"Plain Text",html:"HTML",dynamic:"Dynamic"}}},!0)}(e)}return e.ctorParameters=function(){return[{type:n.TranslateService}]},e=h([t.NgModule({declarations:[x],imports:[r.CommonModule,a.SharedModule],exports:[Ie,we,_e,We,x]}),C("design:paramtypes",[n.TranslateService])],e)}();e.RuleNodeCoreConfigModule=Je,e.ɵa=x,e.ɵb=Ie,e.ɵba=ve,e.ɵbb=Fe,e.ɵbc=xe,e.ɵbd=Te,e.ɵbe=qe,e.ɵbf=Se,e.ɵbg=ue,e.ɵbh=ae,e.ɵbi=oe,e.ɵbj=ie,e.ɵbk=le,e.ɵbl=se,e.ɵbm=me,e.ɵbn=we,e.ɵbo=ke,e.ɵbp=Ne,e.ɵbq=Ve,e.ɵbr=Ee,e.ɵbs=Ae,e.ɵbt=Le,e.ɵbu=Pe,e.ɵbv=Me,e.ɵbw=_e,e.ɵbx=Re,e.ɵby=De,e.ɵbz=Oe,e.ɵc=T,e.ɵca=Ke,e.ɵcb=Be,e.ɵcc=He,e.ɵcd=Ge,e.ɵce=je,e.ɵcf=Ue,e.ɵcg=We,e.ɵch=ze,e.ɵci=Qe,e.ɵcj=$e,e.ɵd=q,e.ɵe=S,e.ɵf=I,e.ɵg=k,e.ɵh=N,e.ɵi=V,e.ɵj=E,e.ɵk=A,e.ɵl=L,e.ɵm=P,e.ɵn=ee,e.ɵo=te,e.ɵp=re,e.ɵq=ne,e.ɵr=de,e.ɵs=pe,e.ɵt=ce,e.ɵu=fe,e.ɵv=ge,e.ɵw=ye,e.ɵx=be,e.ɵy=he,e.ɵz=Ce,Object.defineProperty(e,"__esModule",{value:!0})})); -//# sourceMappingURL=rulenode-core-config.umd.min.js.map \ No newline at end of file +import * as i0 from '@angular/core'; +import { Component, Pipe, ViewChild, forwardRef, Input, NgModule } from '@angular/core'; +import * as i3$4 from '@shared/public-api'; +import { RuleNodeConfigurationComponent, AttributeScope, telemetryTypeTranslations, ServiceType, AlarmSeverity, alarmSeverityTranslations, EntitySearchDirection, entitySearchDirectionTranslations, EntityType, PageComponent, MessageType, messageTypeNames, SharedModule, AggregationType, aggregationTranslations, alarmStatusTranslations, AlarmStatus } from '@shared/public-api'; +import * as i1 from '@ngrx/store'; +import * as i2 from '@angular/forms'; +import { Validators, NgControl, NG_VALUE_ACCESSOR, NG_VALIDATORS, FormControl } from '@angular/forms'; +import * as i3 from '@angular/material/form-field'; +import * as i3$1 from '@angular/material/checkbox'; +import * as i8 from '@angular/flex-layout/flex'; +import * as i4 from '@ngx-translate/core'; +import * as i11 from '@angular/material/input'; +import * as i10 from '@angular/common'; +import { CommonModule } from '@angular/common'; +import * as i1$1 from '@angular/platform-browser'; +import * as i4$1 from '@angular/material/select'; +import * as i5 from '@angular/material/core'; +import * as i4$2 from '@angular/material/expansion'; +import * as i7 from '@shared/components/button/toggle-password.component'; +import * as i8$1 from '@shared/components/file-input.component'; +import * as i3$2 from '@shared/components/queue/queue-type-list.component'; +import * as i3$3 from '@core/public-api'; +import { isDefinedAndNotNull } from '@core/public-api'; +import * as i5$1 from '@shared/components/js-func.component'; +import * as i6 from '@angular/material/button'; +import { ENTER, COMMA, SEMICOLON } from '@angular/cdk/keycodes'; +import * as i5$2 from '@angular/material/chips'; +import * as i6$1 from '@angular/material/icon'; +import * as i7$1 from '@shared/components/entity/entity-type-select.component'; +import * as i6$2 from '@shared/components/entity/entity-select.component'; +import { coerceBooleanProperty } from '@angular/cdk/coercion'; +import * as i9 from '@shared/components/tb-error.component'; +import * as i9$1 from '@angular/flex-layout/extended'; +import * as i12 from '@angular/material/tooltip'; +import { distinctUntilChanged, startWith, map, mergeMap, share } from 'rxjs/operators'; +import * as i7$2 from '@shared/components/tb-checkbox.component'; +import * as i5$3 from '@home/components/sms/sms-provider-configuration.component'; +import { HomeComponentsModule } from '@home/components/public-api'; +import * as i7$3 from '@shared/components/relation/relation-type-autocomplete.component'; +import * as i8$2 from '@shared/components/entity/entity-subtype-list.component'; +import * as i7$4 from '@home/components/relation/relation-filters.component'; +import { of } from 'rxjs'; +import * as i7$5 from '@angular/material/autocomplete'; +import * as i12$1 from '@shared/pipe/highlight.pipe'; +import * as i8$3 from '@shared/components/entity/entity-autocomplete.component'; +import * as i3$5 from '@shared/components/entity/entity-type-list.component'; + +class EmptyConfigComponent extends RuleNodeConfigurationComponent { + constructor(store, fb) { + super(store); + this.store = store; + this.fb = fb; + } + configForm() { + return this.emptyConfigForm; + } + onConfigurationSet(configuration) { + this.emptyConfigForm = this.fb.group({}); + } +} +EmptyConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: EmptyConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); +EmptyConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: EmptyConfigComponent, selector: "tb-node-empty-config", usesInheritance: true, ngImport: i0, template: '
', isInline: true }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: EmptyConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-node-empty-config', + template: '
', + styleUrls: [] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); + +class SafeHtmlPipe { + constructor(sanitizer) { + this.sanitizer = sanitizer; + } + transform(html) { + return this.sanitizer.bypassSecurityTrustHtml(html); + } +} +SafeHtmlPipe.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: SafeHtmlPipe, deps: [{ token: i1$1.DomSanitizer }], target: i0.ɵɵFactoryTarget.Pipe }); +SafeHtmlPipe.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: SafeHtmlPipe, name: "safeHtml" }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: SafeHtmlPipe, decorators: [{ + type: Pipe, + args: [{ + name: 'safeHtml', + }] + }], ctorParameters: function () { return [{ type: i1$1.DomSanitizer }]; } }); + +class AssignCustomerConfigComponent extends RuleNodeConfigurationComponent { + constructor(store, fb) { + super(store); + this.store = store; + this.fb = fb; + } + configForm() { + return this.assignCustomerConfigForm; + } + onConfigurationSet(configuration) { + this.assignCustomerConfigForm = this.fb.group({ + customerNamePattern: [configuration ? configuration.customerNamePattern : null, [Validators.required, Validators.pattern(/.*\S.*/)]], + createCustomerIfNotExists: [configuration ? configuration.createCustomerIfNotExists : false, []], + customerCacheExpiration: [configuration ? configuration.customerCacheExpiration : null, [Validators.required, Validators.min(0)]] + }); + } + prepareOutputConfig(configuration) { + configuration.customerNamePattern = configuration.customerNamePattern.trim(); + return configuration; + } +} +AssignCustomerConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: AssignCustomerConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); +AssignCustomerConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: AssignCustomerConfigComponent, selector: "tb-action-node-assign-to-customer-config", usesInheritance: true, ngImport: i0, template: "
\n \n tb.rulenode.customer-name-pattern\n \n \n {{ 'tb.rulenode.customer-name-pattern-required' | translate }}\n \n \n \n \n {{ 'tb.rulenode.create-customer-if-not-exists' | translate }}\n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ 'tb.rulenode.customer-cache-expiration-required' | translate }}\n \n \n {{ 'tb.rulenode.customer-cache-expiration-range' | translate }}\n \n tb.rulenode.customer-cache-expiration-hint\n \n
\n", components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }, { type: i3$1.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex", "aria-label", "aria-labelledby", "id", "labelPosition", "name", "required", "checked", "disabled", "indeterminate", "aria-describedby", "value"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.MatError, selector: "mat-error", inputs: ["id"] }, { type: i3.MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }, { type: i2.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { type: i2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }], pipes: { "translate": i4.TranslatePipe, "safeHtml": SafeHtmlPipe } }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: AssignCustomerConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-action-node-assign-to-customer-config', + templateUrl: './assign-customer-config.component.html', + styleUrls: [] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); + +class AttributesConfigComponent extends RuleNodeConfigurationComponent { + constructor(store, fb) { + super(store); + this.store = store; + this.fb = fb; + this.attributeScopes = Object.keys(AttributeScope); + this.telemetryTypeTranslationsMap = telemetryTypeTranslations; + } + configForm() { + return this.attributesConfigForm; + } + onConfigurationSet(configuration) { + this.attributesConfigForm = this.fb.group({ + scope: [configuration ? configuration.scope : null, [Validators.required]], + notifyDevice: [configuration ? configuration.scope : true, []] + }); + } +} +AttributesConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: AttributesConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); +AttributesConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: AttributesConfigComponent, selector: "tb-action-node-attributes-config", usesInheritance: true, ngImport: i0, template: "
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n \n {{ 'tb.rulenode.notify-device' | translate }}\n \n
tb.rulenode.notify-device-hint
\n
\n
\n", components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }, { type: i4$1.MatSelect, selector: "mat-select", inputs: ["disabled", "disableRipple", "tabIndex"], exportAs: ["matSelect"] }, { type: i5.MatOption, selector: "mat-option", exportAs: ["matOption"] }, { type: i3$1.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex", "aria-label", "aria-labelledby", "id", "labelPosition", "name", "required", "checked", "disabled", "indeterminate", "aria-describedby", "value"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i10.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], pipes: { "translate": i4.TranslatePipe } }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: AttributesConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-action-node-attributes-config', + templateUrl: './attributes-config.component.html', + styleUrls: [] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); + +var OriginatorSource; +(function (OriginatorSource) { + OriginatorSource["CUSTOMER"] = "CUSTOMER"; + OriginatorSource["TENANT"] = "TENANT"; + OriginatorSource["RELATED"] = "RELATED"; + OriginatorSource["ALARM_ORIGINATOR"] = "ALARM_ORIGINATOR"; +})(OriginatorSource || (OriginatorSource = {})); +const originatorSourceTranslations = new Map([ + [OriginatorSource.CUSTOMER, 'tb.rulenode.originator-customer'], + [OriginatorSource.TENANT, 'tb.rulenode.originator-tenant'], + [OriginatorSource.RELATED, 'tb.rulenode.originator-related'], + [OriginatorSource.ALARM_ORIGINATOR, 'tb.rulenode.originator-alarm-originator'], +]); +var PerimeterType; +(function (PerimeterType) { + PerimeterType["CIRCLE"] = "CIRCLE"; + PerimeterType["POLYGON"] = "POLYGON"; +})(PerimeterType || (PerimeterType = {})); +const perimeterTypeTranslations = new Map([ + [PerimeterType.CIRCLE, 'tb.rulenode.perimeter-circle'], + [PerimeterType.POLYGON, 'tb.rulenode.perimeter-polygon'], +]); +var TimeUnit; +(function (TimeUnit) { + TimeUnit["MILLISECONDS"] = "MILLISECONDS"; + TimeUnit["SECONDS"] = "SECONDS"; + TimeUnit["MINUTES"] = "MINUTES"; + TimeUnit["HOURS"] = "HOURS"; + TimeUnit["DAYS"] = "DAYS"; +})(TimeUnit || (TimeUnit = {})); +const timeUnitTranslations = new Map([ + [TimeUnit.MILLISECONDS, 'tb.rulenode.time-unit-milliseconds'], + [TimeUnit.SECONDS, 'tb.rulenode.time-unit-seconds'], + [TimeUnit.MINUTES, 'tb.rulenode.time-unit-minutes'], + [TimeUnit.HOURS, 'tb.rulenode.time-unit-hours'], + [TimeUnit.DAYS, 'tb.rulenode.time-unit-days'] +]); +var RangeUnit; +(function (RangeUnit) { + RangeUnit["METER"] = "METER"; + RangeUnit["KILOMETER"] = "KILOMETER"; + RangeUnit["FOOT"] = "FOOT"; + RangeUnit["MILE"] = "MILE"; + RangeUnit["NAUTICAL_MILE"] = "NAUTICAL_MILE"; +})(RangeUnit || (RangeUnit = {})); +const rangeUnitTranslations = new Map([ + [RangeUnit.METER, 'tb.rulenode.range-unit-meter'], + [RangeUnit.KILOMETER, 'tb.rulenode.range-unit-kilometer'], + [RangeUnit.FOOT, 'tb.rulenode.range-unit-foot'], + [RangeUnit.MILE, 'tb.rulenode.range-unit-mile'], + [RangeUnit.NAUTICAL_MILE, 'tb.rulenode.range-unit-nautical-mile'] +]); +var EntityDetailsField; +(function (EntityDetailsField) { + EntityDetailsField["TITLE"] = "TITLE"; + EntityDetailsField["COUNTRY"] = "COUNTRY"; + EntityDetailsField["STATE"] = "STATE"; + EntityDetailsField["ZIP"] = "ZIP"; + EntityDetailsField["ADDRESS"] = "ADDRESS"; + EntityDetailsField["ADDRESS2"] = "ADDRESS2"; + EntityDetailsField["PHONE"] = "PHONE"; + EntityDetailsField["EMAIL"] = "EMAIL"; + EntityDetailsField["ADDITIONAL_INFO"] = "ADDITIONAL_INFO"; +})(EntityDetailsField || (EntityDetailsField = {})); +const entityDetailsTranslations = new Map([ + [EntityDetailsField.TITLE, 'tb.rulenode.entity-details-title'], + [EntityDetailsField.COUNTRY, 'tb.rulenode.entity-details-country'], + [EntityDetailsField.STATE, 'tb.rulenode.entity-details-state'], + [EntityDetailsField.ZIP, 'tb.rulenode.entity-details-zip'], + [EntityDetailsField.ADDRESS, 'tb.rulenode.entity-details-address'], + [EntityDetailsField.ADDRESS2, 'tb.rulenode.entity-details-address2'], + [EntityDetailsField.PHONE, 'tb.rulenode.entity-details-phone'], + [EntityDetailsField.EMAIL, 'tb.rulenode.entity-details-email'], + [EntityDetailsField.ADDITIONAL_INFO, 'tb.rulenode.entity-details-additional_info'] +]); +var FetchMode; +(function (FetchMode) { + FetchMode["FIRST"] = "FIRST"; + FetchMode["LAST"] = "LAST"; + FetchMode["ALL"] = "ALL"; +})(FetchMode || (FetchMode = {})); +var SamplingOrder; +(function (SamplingOrder) { + SamplingOrder["ASC"] = "ASC"; + SamplingOrder["DESC"] = "DESC"; +})(SamplingOrder || (SamplingOrder = {})); +var SqsQueueType; +(function (SqsQueueType) { + SqsQueueType["STANDARD"] = "STANDARD"; + SqsQueueType["FIFO"] = "FIFO"; +})(SqsQueueType || (SqsQueueType = {})); +const sqsQueueTypeTranslations = new Map([ + [SqsQueueType.STANDARD, 'tb.rulenode.sqs-queue-standard'], + [SqsQueueType.FIFO, 'tb.rulenode.sqs-queue-fifo'], +]); +const credentialsTypes = ['anonymous', 'basic', 'cert.PEM']; +const credentialsTypeTranslations = new Map([ + ['anonymous', 'tb.rulenode.credentials-anonymous'], + ['basic', 'tb.rulenode.credentials-basic'], + ['cert.PEM', 'tb.rulenode.credentials-pem'] +]); +const azureIotHubCredentialsTypes = ['sas', 'cert.PEM']; +const azureIotHubCredentialsTypeTranslations = new Map([ + ['sas', 'tb.rulenode.credentials-sas'], + ['cert.PEM', 'tb.rulenode.credentials-pem'] +]); +var HttpRequestType; +(function (HttpRequestType) { + HttpRequestType["GET"] = "GET"; + HttpRequestType["POST"] = "POST"; + HttpRequestType["PUT"] = "PUT"; + HttpRequestType["DELETE"] = "DELETE"; +})(HttpRequestType || (HttpRequestType = {})); +const ToByteStandartCharsetTypes = [ + 'US-ASCII', + 'ISO-8859-1', + 'UTF-8', + 'UTF-16BE', + 'UTF-16LE', + 'UTF-16' +]; +const ToByteStandartCharsetTypeTranslations = new Map([ + ['US-ASCII', 'tb.rulenode.charset-us-ascii'], + ['ISO-8859-1', 'tb.rulenode.charset-iso-8859-1'], + ['UTF-8', 'tb.rulenode.charset-utf-8'], + ['UTF-16BE', 'tb.rulenode.charset-utf-16be'], + ['UTF-16LE', 'tb.rulenode.charset-utf-16le'], + ['UTF-16', 'tb.rulenode.charset-utf-16'], +]); + +class AzureIotHubConfigComponent extends RuleNodeConfigurationComponent { + constructor(store, fb) { + super(store); + this.store = store; + this.fb = fb; + this.allAzureIotHubCredentialsTypes = azureIotHubCredentialsTypes; + this.azureIotHubCredentialsTypeTranslationsMap = azureIotHubCredentialsTypeTranslations; + } + configForm() { + return this.azureIotHubConfigForm; + } + onConfigurationSet(configuration) { + this.azureIotHubConfigForm = this.fb.group({ + topicPattern: [configuration ? configuration.topicPattern : null, [Validators.required]], + host: [configuration ? configuration.host : null, [Validators.required]], + port: [configuration ? configuration.port : null, [Validators.required, Validators.min(1), Validators.max(65535)]], + connectTimeoutSec: [configuration ? configuration.connectTimeoutSec : null, + [Validators.required, Validators.min(1), Validators.max(200)]], + clientId: [configuration ? configuration.clientId : null, [Validators.required]], + cleanSession: [configuration ? configuration.cleanSession : false, []], + ssl: [configuration ? configuration.ssl : false, []], + credentials: this.fb.group({ + type: [configuration && configuration.credentials ? configuration.credentials.type : null, [Validators.required]], + sasKey: [configuration && configuration.credentials ? configuration.credentials.sasKey : null, []], + caCert: [configuration && configuration.credentials ? configuration.credentials.caCert : null, []], + caCertFileName: [configuration && configuration.credentials ? configuration.credentials.caCertFileName : null, []], + privateKey: [configuration && configuration.credentials ? configuration.credentials.privateKey : null, []], + privateKeyFileName: [configuration && configuration.credentials ? configuration.credentials.privateKeyFileName : null, []], + cert: [configuration && configuration.credentials ? configuration.credentials.cert : null, []], + certFileName: [configuration && configuration.credentials ? configuration.credentials.certFileName : null, []], + password: [configuration && configuration.credentials ? configuration.credentials.password : null, []], + }) + }); + } + prepareOutputConfig(configuration) { + const credentialsType = configuration.credentials.type; + if (credentialsType === 'sas') { + configuration.credentials = { + type: credentialsType, + sasKey: configuration.credentials.sasKey, + caCert: configuration.credentials.caCert, + caCertFileName: configuration.credentials.caCertFileName + }; + } + return configuration; + } + validatorTriggers() { + return ['credentials.type']; + } + updateValidators(emitEvent) { + const credentialsControl = this.azureIotHubConfigForm.get('credentials'); + const credentialsType = credentialsControl.get('type').value; + if (emitEvent) { + credentialsControl.reset({ type: credentialsType }, { emitEvent: false }); + } + credentialsControl.get('sasKey').setValidators([]); + credentialsControl.get('privateKey').setValidators([]); + credentialsControl.get('privateKeyFileName').setValidators([]); + credentialsControl.get('cert').setValidators([]); + credentialsControl.get('certFileName').setValidators([]); + switch (credentialsType) { + case 'sas': + credentialsControl.get('sasKey').setValidators([Validators.required]); + break; + case 'cert.PEM': + credentialsControl.get('privateKey').setValidators([Validators.required]); + credentialsControl.get('privateKeyFileName').setValidators([Validators.required]); + credentialsControl.get('cert').setValidators([Validators.required]); + credentialsControl.get('certFileName').setValidators([Validators.required]); + break; + } + credentialsControl.get('sasKey').updateValueAndValidity({ emitEvent }); + credentialsControl.get('privateKey').updateValueAndValidity({ emitEvent }); + credentialsControl.get('privateKeyFileName').updateValueAndValidity({ emitEvent }); + credentialsControl.get('cert').updateValueAndValidity({ emitEvent }); + credentialsControl.get('certFileName').updateValueAndValidity({ emitEvent }); + } +} +AzureIotHubConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: AzureIotHubConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); +AzureIotHubConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: AzureIotHubConfigComponent, selector: "tb-action-node-azure-iot-hub-config", usesInheritance: true, ngImport: i0, template: "
\n \n tb.rulenode.topic\n \n \n {{ 'tb.rulenode.topic-required' | translate }}\n \n \n \n \n tb.rulenode.hostname\n \n \n {{ 'tb.rulenode.hostname-required' | translate }}\n \n \n \n tb.rulenode.device-id\n \n \n {{ 'tb.rulenode.device-id-required' | translate }}\n \n \n \n \n \n tb.rulenode.credentials\n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(azureIotHubConfigForm.get('credentials.type').value) | translate }}\n \n \n
\n \n tb.rulenode.credentials-type\n \n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ 'tb.rulenode.credentials-type-required' | translate }}\n \n \n
\n \n \n \n \n tb.rulenode.sas-key\n \n \n \n {{ 'tb.rulenode.sas-key-required' | translate }}\n \n \n \n \n \n \n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n \n
\n
\n
\n
\n
\n", styles: [":host .tb-mqtt-credentials-panel-group{margin:0 6px}:host .tb-hint.client-id{margin-top:-1.25em;max-width:-moz-fit-content;max-width:fit-content}\n"], components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }, { type: i4$2.MatExpansionPanel, selector: "mat-expansion-panel", inputs: ["disabled", "expanded", "hideToggle", "togglePosition"], outputs: ["opened", "closed", "expandedChange", "afterExpand", "afterCollapse"], exportAs: ["matExpansionPanel"] }, { type: i4$2.MatExpansionPanelHeader, selector: "mat-expansion-panel-header", inputs: ["tabIndex", "expandedHeight", "collapsedHeight"] }, { type: i4$1.MatSelect, selector: "mat-select", inputs: ["disabled", "disableRipple", "tabIndex"], exportAs: ["matSelect"] }, { type: i5.MatOption, selector: "mat-option", exportAs: ["matOption"] }, { type: i7.TogglePasswordComponent, selector: "tb-toggle-password" }, { type: i8$1.FileInputComponent, selector: "tb-file-input", inputs: ["label", "accept", "noFileText", "inputId", "allowedExtensions", "dropLabel", "contentConvertFunction", "required", "requiredAsError", "disabled", "existingFileName", "readAsBinary", "workFromFileObj", "multipleFile"], outputs: ["fileNameChanged"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.MatError, selector: "mat-error", inputs: ["id"] }, { type: i3.MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { type: i4$2.MatAccordion, selector: "mat-accordion", inputs: ["multi", "displayMode", "togglePosition", "hideToggle"], exportAs: ["matAccordion"] }, { type: i4$2.MatExpansionPanelTitle, selector: "mat-panel-title" }, { type: i4$2.MatExpansionPanelDescription, selector: "mat-panel-description" }, { type: i2.FormGroupName, selector: "[formGroupName]", inputs: ["formGroupName"] }, { type: i10.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i10.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { type: i10.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { type: i3.MatSuffix, selector: "[matSuffix]" }], pipes: { "translate": i4.TranslatePipe, "safeHtml": SafeHtmlPipe } }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: AzureIotHubConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-action-node-azure-iot-hub-config', + templateUrl: './azure-iot-hub-config.component.html', + styleUrls: ['./mqtt-config.component.scss'] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); + +class CheckPointConfigComponent extends RuleNodeConfigurationComponent { + constructor(store, fb) { + super(store); + this.store = store; + this.fb = fb; + this.serviceType = ServiceType.TB_RULE_ENGINE; + } + configForm() { + return this.checkPointConfigForm; + } + onConfigurationSet(configuration) { + this.checkPointConfigForm = this.fb.group({ + queueName: [configuration ? configuration.queueName : null, [Validators.required]] + }); + } +} +CheckPointConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: CheckPointConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); +CheckPointConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: CheckPointConfigComponent, selector: "tb-action-node-check-point-config", usesInheritance: true, ngImport: i0, template: "
\n \n \n
\n", components: [{ type: i3$2.QueueTypeListComponent, selector: "tb-queue-type-list", inputs: ["required", "disabled", "queueType"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }] }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: CheckPointConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-action-node-check-point-config', + templateUrl: './check-point-config.component.html', + styleUrls: [] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); + +class ClearAlarmConfigComponent extends RuleNodeConfigurationComponent { + constructor(store, fb, nodeScriptTestService, translate) { + super(store); + this.store = store; + this.fb = fb; + this.nodeScriptTestService = nodeScriptTestService; + this.translate = translate; + } + configForm() { + return this.clearAlarmConfigForm; + } + onConfigurationSet(configuration) { + this.clearAlarmConfigForm = this.fb.group({ + alarmDetailsBuildJs: [configuration ? configuration.alarmDetailsBuildJs : null, [Validators.required]], + alarmType: [configuration ? configuration.alarmType : null, [Validators.required]] + }); + } + testScript() { + const script = this.clearAlarmConfigForm.get('alarmDetailsBuildJs').value; + this.nodeScriptTestService.testNodeScript(script, 'json', this.translate.instant('tb.rulenode.details'), 'Details', ['msg', 'metadata', 'msgType'], this.ruleNodeId, 'rulenode/clear_alarm_node_script_fn').subscribe((theScript) => { + if (theScript) { + this.clearAlarmConfigForm.get('alarmDetailsBuildJs').setValue(theScript); + } + }); + } + onValidate() { + this.jsFuncComponent.validateOnSubmit(); + } +} +ClearAlarmConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: ClearAlarmConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }, { token: i3$3.NodeScriptTestService }, { token: i4.TranslateService }], target: i0.ɵɵFactoryTarget.Component }); +ClearAlarmConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: ClearAlarmConfigComponent, selector: "tb-action-node-clear-alarm-config", viewQueries: [{ propertyName: "jsFuncComponent", first: true, predicate: ["jsFuncComponent"], descendants: true, static: true }], usesInheritance: true, ngImport: i0, template: "
\n \n \n \n
\n \n
\n \n tb.rulenode.alarm-type\n \n \n {{ 'tb.rulenode.alarm-type-required' | translate }}\n \n \n \n
\n", components: [{ type: i5$1.JsFuncComponent, selector: "tb-js-func", inputs: ["functionName", "functionArgs", "validationArgs", "resultType", "disabled", "fillHeight", "editorCompleter", "globalVariables", "disableUndefinedCheck", "helpId", "noValidate", "required"] }, { type: i6.MatButton, selector: "button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }, { type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.MatError, selector: "mat-error", inputs: ["id"] }, { type: i3.MatHint, selector: "mat-hint", inputs: ["align", "id"] }], pipes: { "translate": i4.TranslatePipe, "safeHtml": SafeHtmlPipe } }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: ClearAlarmConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-action-node-clear-alarm-config', + templateUrl: './clear-alarm-config.component.html', + styleUrls: [] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }, { type: i3$3.NodeScriptTestService }, { type: i4.TranslateService }]; }, propDecorators: { jsFuncComponent: [{ + type: ViewChild, + args: ['jsFuncComponent', { static: true }] + }] } }); + +class CreateAlarmConfigComponent extends RuleNodeConfigurationComponent { + constructor(store, fb, nodeScriptTestService, translate) { + super(store); + this.store = store; + this.fb = fb; + this.nodeScriptTestService = nodeScriptTestService; + this.translate = translate; + this.alarmSeverities = Object.keys(AlarmSeverity); + this.alarmSeverityTranslationMap = alarmSeverityTranslations; + this.separatorKeysCodes = [ENTER, COMMA, SEMICOLON]; + } + configForm() { + return this.createAlarmConfigForm; + } + onConfigurationSet(configuration) { + this.createAlarmConfigForm = this.fb.group({ + alarmDetailsBuildJs: [configuration ? configuration.alarmDetailsBuildJs : null, [Validators.required]], + useMessageAlarmData: [configuration ? configuration.useMessageAlarmData : false, []], + alarmType: [configuration ? configuration.alarmType : null, []], + severity: [configuration ? configuration.severity : null, []], + propagate: [configuration ? configuration.propagate : false, []], + relationTypes: [configuration ? configuration.relationTypes : null, []], + dynamicSeverity: false + }); + this.createAlarmConfigForm.get('dynamicSeverity').valueChanges.subscribe((dynamicSeverity) => { + if (dynamicSeverity) { + this.createAlarmConfigForm.get('severity').patchValue('', { emitEvent: false }); + } + else { + this.createAlarmConfigForm.get('severity').patchValue(this.alarmSeverities[0], { emitEvent: false }); + } + }); + } + validatorTriggers() { + return ['useMessageAlarmData']; + } + updateValidators(emitEvent) { + const useMessageAlarmData = this.createAlarmConfigForm.get('useMessageAlarmData').value; + if (useMessageAlarmData) { + this.createAlarmConfigForm.get('alarmType').setValidators([]); + this.createAlarmConfigForm.get('severity').setValidators([]); + } + else { + this.createAlarmConfigForm.get('alarmType').setValidators([Validators.required]); + this.createAlarmConfigForm.get('severity').setValidators([Validators.required]); + } + this.createAlarmConfigForm.get('alarmType').updateValueAndValidity({ emitEvent }); + this.createAlarmConfigForm.get('severity').updateValueAndValidity({ emitEvent }); + } + testScript() { + const script = this.createAlarmConfigForm.get('alarmDetailsBuildJs').value; + this.nodeScriptTestService.testNodeScript(script, 'json', this.translate.instant('tb.rulenode.details'), 'Details', ['msg', 'metadata', 'msgType'], this.ruleNodeId, 'rulenode/create_alarm_node_script_fn').subscribe((theScript) => { + if (theScript) { + this.createAlarmConfigForm.get('alarmDetailsBuildJs').setValue(theScript); + } + }); + } + removeKey(key, keysField) { + const keys = this.createAlarmConfigForm.get(keysField).value; + const index = keys.indexOf(key); + if (index >= 0) { + keys.splice(index, 1); + this.createAlarmConfigForm.get(keysField).setValue(keys, { emitEvent: true }); + } + } + addKey(event, keysField) { + const input = event.input; + let value = event.value; + if ((value || '').trim()) { + value = value.trim(); + let keys = this.createAlarmConfigForm.get(keysField).value; + if (!keys || keys.indexOf(value) === -1) { + if (!keys) { + keys = []; + } + keys.push(value); + this.createAlarmConfigForm.get(keysField).setValue(keys, { emitEvent: true }); + } + } + if (input) { + input.value = ''; + } + } + onValidate() { + this.jsFuncComponent.validateOnSubmit(); + } +} +CreateAlarmConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: CreateAlarmConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }, { token: i3$3.NodeScriptTestService }, { token: i4.TranslateService }], target: i0.ɵɵFactoryTarget.Component }); +CreateAlarmConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: CreateAlarmConfigComponent, selector: "tb-action-node-create-alarm-config", viewQueries: [{ propertyName: "jsFuncComponent", first: true, predicate: ["jsFuncComponent"], descendants: true, static: true }], usesInheritance: true, ngImport: i0, template: "
\n \n \n \n
\n \n
\n
\n \n {{ 'tb.rulenode.use-message-alarm-data' | translate }}\n \n \n {{ 'tb.rulenode.use-dynamically-change-the-severity-of-alar' | translate }}\n \n
\n
\n
\n \n tb.rulenode.alarm-type\n \n \n {{ 'tb.rulenode.alarm-type-required' | translate }}\n \n \n \n \n tb.rulenode.alarm-severity\n \n \n {{ alarmSeverityTranslationMap.get(severity) | translate }}\n \n \n \n {{ 'tb.rulenode.alarm-severity-required' | translate }}\n \n \n \n {{ 'tb.rulenode.alarm-severity' | translate }}\n \n \n {{ 'tb.rulenode.alarm-severity-required' | translate }}\n \n \n \n
\n \n {{ 'tb.rulenode.propagate' | translate }}\n \n
\n \n tb.rulenode.relation-types-list\n \n \n {{key}}\n close\n \n \n \n tb.rulenode.relation-types-list-hint\n \n
\n
\n
\n", components: [{ type: i5$1.JsFuncComponent, selector: "tb-js-func", inputs: ["functionName", "functionArgs", "validationArgs", "resultType", "disabled", "fillHeight", "editorCompleter", "globalVariables", "disableUndefinedCheck", "helpId", "noValidate", "required"] }, { type: i6.MatButton, selector: "button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }, { type: i3$1.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex", "aria-label", "aria-labelledby", "id", "labelPosition", "name", "required", "checked", "disabled", "indeterminate", "aria-describedby", "value"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }, { type: i4$1.MatSelect, selector: "mat-select", inputs: ["disabled", "disableRipple", "tabIndex"], exportAs: ["matSelect"] }, { type: i5.MatOption, selector: "mat-option", exportAs: ["matOption"] }, { type: i5$2.MatChipList, selector: "mat-chip-list", inputs: ["aria-orientation", "multiple", "compareWith", "value", "required", "placeholder", "disabled", "selectable", "tabIndex", "errorStateMatcher"], outputs: ["change", "valueChange"], exportAs: ["matChipList"] }, { type: i6$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i8.DefaultLayoutGapDirective, selector: " [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]", inputs: ["fxLayoutGap", "fxLayoutGap.xs", "fxLayoutGap.sm", "fxLayoutGap.md", "fxLayoutGap.lg", "fxLayoutGap.xl", "fxLayoutGap.lt-sm", "fxLayoutGap.lt-md", "fxLayoutGap.lt-lg", "fxLayoutGap.lt-xl", "fxLayoutGap.gt-xs", "fxLayoutGap.gt-sm", "fxLayoutGap.gt-md", "fxLayoutGap.gt-lg"] }, { type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i3.MatError, selector: "mat-error", inputs: ["id"] }, { type: i3.MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { type: i10.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i5$2.MatChip, selector: "mat-basic-chip, [mat-basic-chip], mat-chip, [mat-chip]", inputs: ["color", "disableRipple", "tabIndex", "selected", "value", "selectable", "disabled", "removable"], outputs: ["selectionChange", "destroyed", "removed"], exportAs: ["matChip"] }, { type: i5$2.MatChipRemove, selector: "[matChipRemove]" }, { type: i5$2.MatChipInput, selector: "input[matChipInputFor]", inputs: ["matChipInputSeparatorKeyCodes", "placeholder", "id", "matChipInputFor", "matChipInputAddOnBlur", "disabled"], outputs: ["matChipInputTokenEnd"], exportAs: ["matChipInput", "matChipInputFor"] }], pipes: { "translate": i4.TranslatePipe, "safeHtml": SafeHtmlPipe } }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: CreateAlarmConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-action-node-create-alarm-config', + templateUrl: './create-alarm-config.component.html', + styleUrls: [] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }, { type: i3$3.NodeScriptTestService }, { type: i4.TranslateService }]; }, propDecorators: { jsFuncComponent: [{ + type: ViewChild, + args: ['jsFuncComponent', { static: true }] + }] } }); + +class CreateRelationConfigComponent extends RuleNodeConfigurationComponent { + constructor(store, fb) { + super(store); + this.store = store; + this.fb = fb; + this.directionTypes = Object.keys(EntitySearchDirection); + this.directionTypeTranslations = entitySearchDirectionTranslations; + this.entityType = EntityType; + } + configForm() { + return this.createRelationConfigForm; + } + onConfigurationSet(configuration) { + this.createRelationConfigForm = this.fb.group({ + direction: [configuration ? configuration.direction : null, [Validators.required]], + entityType: [configuration ? configuration.entityType : null, [Validators.required]], + entityNamePattern: [configuration ? configuration.entityNamePattern : null, []], + entityTypePattern: [configuration ? configuration.entityTypePattern : null, []], + relationType: [configuration ? configuration.relationType : null, [Validators.required]], + createEntityIfNotExists: [configuration ? configuration.createEntityIfNotExists : false, []], + removeCurrentRelations: [configuration ? configuration.removeCurrentRelations : false, []], + changeOriginatorToRelatedEntity: [configuration ? configuration.changeOriginatorToRelatedEntity : false, []], + entityCacheExpiration: [configuration ? configuration.entityCacheExpiration : null, [Validators.required, Validators.min(0)]], + }); + } + validatorTriggers() { + return ['entityType']; + } + updateValidators(emitEvent) { + const entityType = this.createRelationConfigForm.get('entityType').value; + if (entityType) { + this.createRelationConfigForm.get('entityNamePattern').setValidators([Validators.required, Validators.pattern(/.*\S.*/)]); + } + else { + this.createRelationConfigForm.get('entityNamePattern').setValidators([]); + } + if (entityType && (entityType === EntityType.DEVICE || entityType === EntityType.ASSET)) { + this.createRelationConfigForm.get('entityTypePattern').setValidators([Validators.required, Validators.pattern(/.*\S.*/)]); + } + else { + this.createRelationConfigForm.get('entityTypePattern').setValidators([]); + } + this.createRelationConfigForm.get('entityNamePattern').updateValueAndValidity({ emitEvent }); + this.createRelationConfigForm.get('entityTypePattern').updateValueAndValidity({ emitEvent }); + } + prepareOutputConfig(configuration) { + configuration.entityNamePattern = configuration.entityNamePattern ? configuration.entityNamePattern.trim() : null; + configuration.entityTypePattern = configuration.entityTypePattern ? configuration.entityTypePattern.trim() : null; + return configuration; + } +} +CreateRelationConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: CreateRelationConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); +CreateRelationConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: CreateRelationConfigComponent, selector: "tb-action-node-create-relation-config", usesInheritance: true, ngImport: i0, template: "
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ 'tb.rulenode.entity-name-pattern-required' | translate }}\n \n \n \n \n tb.rulenode.entity-type-pattern\n \n \n {{ 'tb.rulenode.entity-type-pattern-required' | translate }}\n \n \n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ 'tb.rulenode.relation-type-pattern-required' | translate }}\n \n \n \n
\n \n {{ 'tb.rulenode.create-entity-if-not-exists' | translate }}\n \n
tb.rulenode.create-entity-if-not-exists-hint
\n
\n \n {{ 'tb.rulenode.remove-current-relations' | translate }}\n \n
tb.rulenode.remove-current-relations-hint
\n \n {{ 'tb.rulenode.change-originator-to-related-entity' | translate }}\n \n
tb.rulenode.change-originator-to-related-entity-hint
\n \n tb.rulenode.entity-cache-expiration\n \n \n {{ 'tb.rulenode.entity-cache-expiration-required' | translate }}\n \n \n {{ 'tb.rulenode.entity-cache-expiration-range' | translate }}\n \n tb.rulenode.entity-cache-expiration-hint\n \n
\n", components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }, { type: i4$1.MatSelect, selector: "mat-select", inputs: ["disabled", "disableRipple", "tabIndex"], exportAs: ["matSelect"] }, { type: i5.MatOption, selector: "mat-option", exportAs: ["matOption"] }, { type: i7$1.EntityTypeSelectComponent, selector: "tb-entity-type-select", inputs: ["allowedEntityTypes", "useAliasEntityTypes", "showLabel", "required", "disabled"] }, { type: i3$1.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex", "aria-label", "aria-labelledby", "id", "labelPosition", "name", "required", "checked", "disabled", "indeterminate", "aria-describedby", "value"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i10.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i8.DefaultLayoutGapDirective, selector: " [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]", inputs: ["fxLayoutGap", "fxLayoutGap.xs", "fxLayoutGap.sm", "fxLayoutGap.md", "fxLayoutGap.lg", "fxLayoutGap.xl", "fxLayoutGap.lt-sm", "fxLayoutGap.lt-md", "fxLayoutGap.lt-lg", "fxLayoutGap.lt-xl", "fxLayoutGap.gt-xs", "fxLayoutGap.gt-sm", "fxLayoutGap.gt-md", "fxLayoutGap.gt-lg"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i3.MatError, selector: "mat-error", inputs: ["id"] }, { type: i3.MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { type: i2.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { type: i2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }], pipes: { "translate": i4.TranslatePipe, "safeHtml": SafeHtmlPipe } }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: CreateRelationConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-action-node-create-relation-config', + templateUrl: './create-relation-config.component.html', + styleUrls: [] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); + +class DeleteRelationConfigComponent extends RuleNodeConfigurationComponent { + constructor(store, fb) { + super(store); + this.store = store; + this.fb = fb; + this.directionTypes = Object.keys(EntitySearchDirection); + this.directionTypeTranslations = entitySearchDirectionTranslations; + this.entityType = EntityType; + } + configForm() { + return this.deleteRelationConfigForm; + } + onConfigurationSet(configuration) { + this.deleteRelationConfigForm = this.fb.group({ + deleteForSingleEntity: [configuration ? configuration.deleteForSingleEntity : false, []], + direction: [configuration ? configuration.direction : null, [Validators.required]], + entityType: [configuration ? configuration.entityType : null, []], + entityNamePattern: [configuration ? configuration.entityNamePattern : null, []], + relationType: [configuration ? configuration.relationType : null, [Validators.required]], + entityCacheExpiration: [configuration ? configuration.entityCacheExpiration : null, [Validators.required, Validators.min(0)]], + }); + } + validatorTriggers() { + return ['deleteForSingleEntity', 'entityType']; + } + updateValidators(emitEvent) { + const deleteForSingleEntity = this.deleteRelationConfigForm.get('deleteForSingleEntity').value; + const entityType = this.deleteRelationConfigForm.get('entityType').value; + if (deleteForSingleEntity) { + this.deleteRelationConfigForm.get('entityType').setValidators([Validators.required]); + } + else { + this.deleteRelationConfigForm.get('entityType').setValidators([]); + } + if (deleteForSingleEntity && entityType) { + this.deleteRelationConfigForm.get('entityNamePattern').setValidators([Validators.required, Validators.pattern(/.*\S.*/)]); + } + else { + this.deleteRelationConfigForm.get('entityNamePattern').setValidators([]); + } + this.deleteRelationConfigForm.get('entityType').updateValueAndValidity({ emitEvent: false }); + this.deleteRelationConfigForm.get('entityNamePattern').updateValueAndValidity({ emitEvent }); + } + prepareOutputConfig(configuration) { + configuration.entityNamePattern = configuration.entityNamePattern ? configuration.entityNamePattern.trim() : null; + return configuration; + } +} +DeleteRelationConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: DeleteRelationConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); +DeleteRelationConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: DeleteRelationConfigComponent, selector: "tb-action-node-delete-relation-config", usesInheritance: true, ngImport: i0, template: "
\n \n {{ 'tb.rulenode.delete-relation-to-specific-entity' | translate }}\n \n
tb.rulenode.delete-relation-hint
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ 'tb.rulenode.entity-name-pattern-required' | translate }}\n \n \n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ 'tb.rulenode.relation-type-pattern-required' | translate }}\n \n \n \n \n tb.rulenode.entity-cache-expiration\n \n \n {{ 'tb.rulenode.entity-cache-expiration-required' | translate }}\n \n \n {{ 'tb.rulenode.entity-cache-expiration-range' | translate }}\n \n tb.rulenode.entity-cache-expiration-hint\n \n
\n", components: [{ type: i3$1.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex", "aria-label", "aria-labelledby", "id", "labelPosition", "name", "required", "checked", "disabled", "indeterminate", "aria-describedby", "value"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }, { type: i4$1.MatSelect, selector: "mat-select", inputs: ["disabled", "disableRipple", "tabIndex"], exportAs: ["matSelect"] }, { type: i5.MatOption, selector: "mat-option", exportAs: ["matOption"] }, { type: i7$1.EntityTypeSelectComponent, selector: "tb-entity-type-select", inputs: ["allowedEntityTypes", "useAliasEntityTypes", "showLabel", "required", "disabled"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i10.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i8.DefaultLayoutGapDirective, selector: " [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]", inputs: ["fxLayoutGap", "fxLayoutGap.xs", "fxLayoutGap.sm", "fxLayoutGap.md", "fxLayoutGap.lg", "fxLayoutGap.xl", "fxLayoutGap.lt-sm", "fxLayoutGap.lt-md", "fxLayoutGap.lt-lg", "fxLayoutGap.lt-xl", "fxLayoutGap.gt-xs", "fxLayoutGap.gt-sm", "fxLayoutGap.gt-md", "fxLayoutGap.gt-lg"] }, { type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i3.MatError, selector: "mat-error", inputs: ["id"] }, { type: i3.MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { type: i2.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { type: i2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }], pipes: { "translate": i4.TranslatePipe, "safeHtml": SafeHtmlPipe } }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: DeleteRelationConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-action-node-delete-relation-config', + templateUrl: './delete-relation-config.component.html', + styleUrls: [] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); + +class DeviceProfileConfigComponent extends RuleNodeConfigurationComponent { + constructor(store, fb) { + super(store); + this.store = store; + this.fb = fb; + } + configForm() { + return this.deviceProfile; + } + onConfigurationSet(configuration) { + this.deviceProfile = this.fb.group({ + persistAlarmRulesState: [configuration ? configuration.persistAlarmRulesState : false, Validators.required], + fetchAlarmRulesStateOnStart: [configuration ? configuration.fetchAlarmRulesStateOnStart : false, Validators.required] + }); + } +} +DeviceProfileConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: DeviceProfileConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); +DeviceProfileConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: DeviceProfileConfigComponent, selector: "tb-device-profile-config", usesInheritance: true, ngImport: i0, template: "
\n \n {{ 'tb.rulenode.persist-alarm-rules' | translate }}\n \n \n {{ 'tb.rulenode.fetch-alarm-rules' | translate }}\n \n
\n", components: [{ type: i3$1.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex", "aria-label", "aria-labelledby", "id", "labelPosition", "name", "required", "checked", "disabled", "indeterminate", "aria-describedby", "value"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }], pipes: { "translate": i4.TranslatePipe } }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: DeviceProfileConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-device-profile-config', + templateUrl: './device-profile-config.component.html', + styleUrls: [] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); + +class GeneratorConfigComponent extends RuleNodeConfigurationComponent { + constructor(store, fb, nodeScriptTestService, translate) { + super(store); + this.store = store; + this.fb = fb; + this.nodeScriptTestService = nodeScriptTestService; + this.translate = translate; + } + configForm() { + return this.generatorConfigForm; + } + onConfigurationSet(configuration) { + this.generatorConfigForm = this.fb.group({ + msgCount: [configuration ? configuration.msgCount : null, [Validators.required, Validators.min(0)]], + periodInSeconds: [configuration ? configuration.periodInSeconds : null, [Validators.required, Validators.min(1)]], + originator: [configuration ? configuration.originator : null, []], + jsScript: [configuration ? configuration.jsScript : null, [Validators.required]] + }); + } + prepareInputConfig(configuration) { + if (configuration) { + if (configuration.originatorId && configuration.originatorType) { + configuration.originator = { + id: configuration.originatorId, entityType: configuration.originatorType + }; + } + else { + configuration.originator = null; + } + delete configuration.originatorId; + delete configuration.originatorType; + } + return configuration; + } + prepareOutputConfig(configuration) { + if (configuration.originator) { + configuration.originatorId = configuration.originator.id; + configuration.originatorType = configuration.originator.entityType; + } + else { + configuration.originatorId = null; + configuration.originatorType = null; + } + delete configuration.originator; + return configuration; + } + testScript() { + const script = this.generatorConfigForm.get('jsScript').value; + this.nodeScriptTestService.testNodeScript(script, 'generate', this.translate.instant('tb.rulenode.generator'), 'Generate', ['prevMsg', 'prevMetadata', 'prevMsgType'], this.ruleNodeId, 'rulenode/generator_node_script_fn').subscribe((theScript) => { + if (theScript) { + this.generatorConfigForm.get('jsScript').setValue(theScript); + } + }); + } + onValidate() { + this.jsFuncComponent.validateOnSubmit(); + } +} +GeneratorConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: GeneratorConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }, { token: i3$3.NodeScriptTestService }, { token: i4.TranslateService }], target: i0.ɵɵFactoryTarget.Component }); +GeneratorConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: GeneratorConfigComponent, selector: "tb-action-node-generator-config", viewQueries: [{ propertyName: "jsFuncComponent", first: true, predicate: ["jsFuncComponent"], descendants: true, static: true }], usesInheritance: true, ngImport: i0, template: "
\n \n tb.rulenode.message-count\n \n \n {{ 'tb.rulenode.message-count-required' | translate }}\n \n \n {{ 'tb.rulenode.min-message-count-message' | translate }}\n \n \n \n tb.rulenode.period-seconds\n \n \n {{ 'tb.rulenode.period-seconds-required' | translate }}\n \n \n {{ 'tb.rulenode.min-period-seconds-message' | translate }}\n \n \n
\n \n \n \n
\n \n \n \n
\n \n
\n
\n", components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }, { type: i6$2.EntitySelectComponent, selector: "tb-entity-select", inputs: ["allowedEntityTypes", "useAliasEntityTypes", "required", "disabled"] }, { type: i5$1.JsFuncComponent, selector: "tb-js-func", inputs: ["functionName", "functionArgs", "validationArgs", "resultType", "disabled", "fillHeight", "editorCompleter", "globalVariables", "disableUndefinedCheck", "helpId", "noValidate", "required"] }, { type: i6.MatButton, selector: "button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i2.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { type: i2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.MatError, selector: "mat-error", inputs: ["id"] }], pipes: { "translate": i4.TranslatePipe } }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: GeneratorConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-action-node-generator-config', + templateUrl: './generator-config.component.html', + styleUrls: [] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }, { type: i3$3.NodeScriptTestService }, { type: i4.TranslateService }]; }, propDecorators: { jsFuncComponent: [{ + type: ViewChild, + args: ['jsFuncComponent', { static: true }] + }] } }); + +class GpsGeoActionConfigComponent extends RuleNodeConfigurationComponent { + constructor(store, fb) { + super(store); + this.store = store; + this.fb = fb; + this.perimeterType = PerimeterType; + this.perimeterTypes = Object.keys(PerimeterType); + this.perimeterTypeTranslationMap = perimeterTypeTranslations; + this.rangeUnits = Object.keys(RangeUnit); + this.rangeUnitTranslationMap = rangeUnitTranslations; + this.timeUnits = Object.keys(TimeUnit); + this.timeUnitsTranslationMap = timeUnitTranslations; + } + configForm() { + return this.geoActionConfigForm; + } + onConfigurationSet(configuration) { + this.geoActionConfigForm = this.fb.group({ + latitudeKeyName: [configuration ? configuration.latitudeKeyName : null, [Validators.required]], + longitudeKeyName: [configuration ? configuration.longitudeKeyName : null, [Validators.required]], + fetchPerimeterInfoFromMessageMetadata: [configuration ? configuration.fetchPerimeterInfoFromMessageMetadata : false, []], + perimeterType: [configuration ? configuration.perimeterType : null, []], + centerLatitude: [configuration ? configuration.centerLatitude : null, []], + centerLongitude: [configuration ? configuration.centerLatitude : null, []], + range: [configuration ? configuration.range : null, []], + rangeUnit: [configuration ? configuration.rangeUnit : null, []], + polygonsDefinition: [configuration ? configuration.polygonsDefinition : null, []], + minInsideDuration: [configuration ? configuration.minInsideDuration : null, + [Validators.required, Validators.min(1), Validators.max(2147483647)]], + minInsideDurationTimeUnit: [configuration ? configuration.minInsideDurationTimeUnit : null, [Validators.required]], + minOutsideDuration: [configuration ? configuration.minOutsideDuration : null, + [Validators.required, Validators.min(1), Validators.max(2147483647)]], + minOutsideDurationTimeUnit: [configuration ? configuration.minOutsideDurationTimeUnit : null, [Validators.required]], + }); + } + validatorTriggers() { + return ['fetchPerimeterInfoFromMessageMetadata', 'perimeterType']; + } + updateValidators(emitEvent) { + const fetchPerimeterInfoFromMessageMetadata = this.geoActionConfigForm.get('fetchPerimeterInfoFromMessageMetadata').value; + const perimeterType = this.geoActionConfigForm.get('perimeterType').value; + if (fetchPerimeterInfoFromMessageMetadata) { + this.geoActionConfigForm.get('perimeterType').setValidators([]); + } + else { + this.geoActionConfigForm.get('perimeterType').setValidators([Validators.required]); + } + if (!fetchPerimeterInfoFromMessageMetadata && perimeterType === PerimeterType.CIRCLE) { + this.geoActionConfigForm.get('centerLatitude').setValidators([Validators.required, + Validators.min(-90), Validators.max(90)]); + this.geoActionConfigForm.get('centerLongitude').setValidators([Validators.required, + Validators.min(-180), Validators.max(180)]); + this.geoActionConfigForm.get('range').setValidators([Validators.required, Validators.min(0)]); + this.geoActionConfigForm.get('rangeUnit').setValidators([Validators.required]); + } + else { + this.geoActionConfigForm.get('centerLatitude').setValidators([]); + this.geoActionConfigForm.get('centerLongitude').setValidators([]); + this.geoActionConfigForm.get('range').setValidators([]); + this.geoActionConfigForm.get('rangeUnit').setValidators([]); + } + if (!fetchPerimeterInfoFromMessageMetadata && perimeterType === PerimeterType.POLYGON) { + this.geoActionConfigForm.get('polygonsDefinition').setValidators([Validators.required]); + } + else { + this.geoActionConfigForm.get('polygonsDefinition').setValidators([]); + } + this.geoActionConfigForm.get('perimeterType').updateValueAndValidity({ emitEvent: false }); + this.geoActionConfigForm.get('centerLatitude').updateValueAndValidity({ emitEvent }); + this.geoActionConfigForm.get('centerLongitude').updateValueAndValidity({ emitEvent }); + this.geoActionConfigForm.get('range').updateValueAndValidity({ emitEvent }); + this.geoActionConfigForm.get('rangeUnit').updateValueAndValidity({ emitEvent }); + this.geoActionConfigForm.get('polygonsDefinition').updateValueAndValidity({ emitEvent }); + } +} +GpsGeoActionConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: GpsGeoActionConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); +GpsGeoActionConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: GpsGeoActionConfigComponent, selector: "tb-action-node-gps-geofencing-config", usesInheritance: true, ngImport: i0, template: "
\n \n tb.rulenode.latitude-key-name\n \n \n {{ 'tb.rulenode.latitude-key-name-required' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ 'tb.rulenode.longitude-key-name-required' | translate }}\n \n \n \n {{ 'tb.rulenode.fetch-perimeter-info-from-message-metadata' | translate }}\n \n
\n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n \n tb.rulenode.circle-center-latitude\n \n \n {{ 'tb.rulenode.circle-center-latitude-required' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ 'tb.rulenode.circle-center-longitude-required' | translate }}\n \n \n
\n
\n \n tb.rulenode.range\n \n \n {{ 'tb.rulenode.range-required' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n \n tb.rulenode.polygon-definition\n \n \n {{ 'tb.rulenode.polygon-definition-required' | translate }}\n \n \n
\n
\n \n tb.rulenode.min-inside-duration\n \n \n {{ 'tb.rulenode.min-inside-duration-value-required' | translate }}\n \n \n {{ 'tb.rulenode.time-value-range' | translate }}\n \n \n {{ 'tb.rulenode.time-value-range' | translate }}\n \n \n \n tb.rulenode.min-inside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n tb.rulenode.min-outside-duration\n \n \n {{ 'tb.rulenode.min-outside-duration-value-required' | translate }}\n \n \n {{ 'tb.rulenode.time-value-range' | translate }}\n \n \n {{ 'tb.rulenode.time-value-range' | translate }}\n \n \n \n tb.rulenode.min-outside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n", components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }, { type: i3$1.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex", "aria-label", "aria-labelledby", "id", "labelPosition", "name", "required", "checked", "disabled", "indeterminate", "aria-describedby", "value"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { type: i4$1.MatSelect, selector: "mat-select", inputs: ["disabled", "disableRipple", "tabIndex"], exportAs: ["matSelect"] }, { type: i5.MatOption, selector: "mat-option", exportAs: ["matOption"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.MatError, selector: "mat-error", inputs: ["id"] }, { type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }, { type: i10.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i8.DefaultLayoutGapDirective, selector: " [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]", inputs: ["fxLayoutGap", "fxLayoutGap.xs", "fxLayoutGap.sm", "fxLayoutGap.md", "fxLayoutGap.lg", "fxLayoutGap.xl", "fxLayoutGap.lt-sm", "fxLayoutGap.lt-md", "fxLayoutGap.lt-lg", "fxLayoutGap.lt-xl", "fxLayoutGap.gt-xs", "fxLayoutGap.gt-sm", "fxLayoutGap.gt-md", "fxLayoutGap.gt-lg"] }, { type: i2.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { type: i2.MaxValidator, selector: "input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]", inputs: ["max"] }, { type: i2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }], pipes: { "translate": i4.TranslatePipe } }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: GpsGeoActionConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-action-node-gps-geofencing-config', + templateUrl: './gps-geo-action-config.component.html', + styleUrls: [] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); + +class KvMapConfigComponent extends PageComponent { + constructor(store, translate, injector, fb) { + super(store); + this.store = store; + this.translate = translate; + this.injector = injector; + this.fb = fb; + this.propagateChange = null; + this.valueChangeSubscription = null; + } + get required() { + return this.requiredValue; + } + set required(value) { + this.requiredValue = coerceBooleanProperty(value); + } + ngOnInit() { + this.ngControl = this.injector.get(NgControl); + if (this.ngControl != null) { + this.ngControl.valueAccessor = this; + } + this.kvListFormGroup = this.fb.group({}); + this.kvListFormGroup.addControl('keyVals', this.fb.array([])); + } + keyValsFormArray() { + return this.kvListFormGroup.get('keyVals'); + } + registerOnChange(fn) { + this.propagateChange = fn; + } + registerOnTouched(fn) { + } + setDisabledState(isDisabled) { + this.disabled = isDisabled; + if (this.disabled) { + this.kvListFormGroup.disable({ emitEvent: false }); + } + else { + this.kvListFormGroup.enable({ emitEvent: false }); + } + } + writeValue(keyValMap) { + if (this.valueChangeSubscription) { + this.valueChangeSubscription.unsubscribe(); + } + const keyValsControls = []; + if (keyValMap) { + for (const property of Object.keys(keyValMap)) { + if (Object.prototype.hasOwnProperty.call(keyValMap, property)) { + keyValsControls.push(this.fb.group({ + key: [property, [Validators.required]], + value: [keyValMap[property], [Validators.required]] + })); + } + } + } + this.kvListFormGroup.setControl('keyVals', this.fb.array(keyValsControls)); + this.valueChangeSubscription = this.kvListFormGroup.valueChanges.subscribe(() => { + this.updateModel(); + }); + } + removeKeyVal(index) { + this.kvListFormGroup.get('keyVals').removeAt(index); + } + addKeyVal() { + const keyValsFormArray = this.kvListFormGroup.get('keyVals'); + keyValsFormArray.push(this.fb.group({ + key: ['', [Validators.required]], + value: ['', [Validators.required]] + })); + } + validate(c) { + const kvList = this.kvListFormGroup.get('keyVals').value; + if (!kvList.length && this.required) { + return { + kvMapRequired: true + }; + } + if (!this.kvListFormGroup.valid) { + return { + kvFieldsRequired: true + }; + } + return null; + } + updateModel() { + const kvList = this.kvListFormGroup.get('keyVals').value; + if (this.required && !kvList.length || !this.kvListFormGroup.valid) { + this.propagateChange(null); + } + else { + const keyValMap = {}; + kvList.forEach((entry) => { + keyValMap[entry.key] = entry.value; + }); + this.propagateChange(keyValMap); + } + } +} +KvMapConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: KvMapConfigComponent, deps: [{ token: i1.Store }, { token: i4.TranslateService }, { token: i0.Injector }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); +KvMapConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: KvMapConfigComponent, selector: "tb-kv-map-config", inputs: { disabled: "disabled", requiredText: "requiredText", keyText: "keyText", keyRequiredText: "keyRequiredText", valText: "valText", valRequiredText: "valRequiredText", required: "required" }, providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => KvMapConfigComponent), + multi: true + }, + { + provide: NG_VALIDATORS, + useExisting: forwardRef(() => KvMapConfigComponent), + multi: true, + } + ], usesInheritance: true, ngImport: i0, template: "
\n
\n {{ keyText | translate }}\n {{ valText | translate }}\n \n
\n
\n
\n \n \n \n \n {{ keyRequiredText | translate }}\n \n \n \n \n \n \n {{ valRequiredText | translate }}\n \n \n \n
\n
\n \n
\n \n
\n
\n", styles: [":host .tb-kv-map-config{margin-bottom:16px}:host .tb-kv-map-config .header{padding-left:5px;padding-right:5px;padding-bottom:5px}:host .tb-kv-map-config .header .cell{padding-left:5px;padding-right:5px;color:#0000008a;font-size:12px;font-weight:700;white-space:nowrap}:host .tb-kv-map-config .body{padding-left:5px;padding-right:5px;padding-bottom:20px;max-height:300px;overflow:auto}:host .tb-kv-map-config .body .row{padding-top:5px;max-height:40px}:host .tb-kv-map-config .body .cell{padding-left:5px;padding-right:5px}:host ::ng-deep .tb-kv-map-config .body mat-form-field.cell{margin:0;max-height:40px}:host ::ng-deep .tb-kv-map-config .body mat-form-field.cell .mat-form-field-infix{border-top:0}:host ::ng-deep .tb-kv-map-config .body button.mat-button{margin:0}\n"], components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }, { type: i6.MatButton, selector: "button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }, { type: i6$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { type: i9.TbErrorComponent, selector: "tb-error", inputs: ["error"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }, { type: i8.DefaultLayoutGapDirective, selector: " [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]", inputs: ["fxLayoutGap", "fxLayoutGap.xs", "fxLayoutGap.sm", "fxLayoutGap.md", "fxLayoutGap.lg", "fxLayoutGap.xl", "fxLayoutGap.lt-sm", "fxLayoutGap.lt-md", "fxLayoutGap.lt-lg", "fxLayoutGap.lt-xl", "fxLayoutGap.gt-xs", "fxLayoutGap.gt-sm", "fxLayoutGap.gt-md", "fxLayoutGap.gt-lg"] }, { type: i9$1.DefaultShowHideDirective, selector: " [fxShow], [fxShow.print], [fxShow.xs], [fxShow.sm], [fxShow.md], [fxShow.lg], [fxShow.xl], [fxShow.lt-sm], [fxShow.lt-md], [fxShow.lt-lg], [fxShow.lt-xl], [fxShow.gt-xs], [fxShow.gt-sm], [fxShow.gt-md], [fxShow.gt-lg], [fxHide], [fxHide.print], [fxHide.xs], [fxHide.sm], [fxHide.md], [fxHide.lg], [fxHide.xl], [fxHide.lt-sm], [fxHide.lt-md], [fxHide.lt-lg], [fxHide.lt-xl], [fxHide.gt-xs], [fxHide.gt-sm], [fxHide.gt-md], [fxHide.gt-lg]", inputs: ["fxShow", "fxShow.print", "fxShow.xs", "fxShow.sm", "fxShow.md", "fxShow.lg", "fxShow.xl", "fxShow.lt-sm", "fxShow.lt-md", "fxShow.lt-lg", "fxShow.lt-xl", "fxShow.gt-xs", "fxShow.gt-sm", "fxShow.gt-md", "fxShow.gt-lg", "fxHide", "fxHide.print", "fxHide.xs", "fxHide.sm", "fxHide.md", "fxHide.lg", "fxHide.xl", "fxHide.lt-sm", "fxHide.lt-md", "fxHide.lt-lg", "fxHide.lt-xl", "fxHide.gt-xs", "fxHide.gt-sm", "fxHide.gt-md", "fxHide.gt-lg"] }, { type: i10.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i8.DefaultLayoutAlignDirective, selector: " [fxLayoutAlign], [fxLayoutAlign.xs], [fxLayoutAlign.sm], [fxLayoutAlign.md], [fxLayoutAlign.lg], [fxLayoutAlign.xl], [fxLayoutAlign.lt-sm], [fxLayoutAlign.lt-md], [fxLayoutAlign.lt-lg], [fxLayoutAlign.lt-xl], [fxLayoutAlign.gt-xs], [fxLayoutAlign.gt-sm], [fxLayoutAlign.gt-md], [fxLayoutAlign.gt-lg]", inputs: ["fxLayoutAlign", "fxLayoutAlign.xs", "fxLayoutAlign.sm", "fxLayoutAlign.md", "fxLayoutAlign.lg", "fxLayoutAlign.xl", "fxLayoutAlign.lt-sm", "fxLayoutAlign.lt-md", "fxLayoutAlign.lt-lg", "fxLayoutAlign.lt-xl", "fxLayoutAlign.gt-xs", "fxLayoutAlign.gt-sm", "fxLayoutAlign.gt-md", "fxLayoutAlign.gt-lg"] }, { type: i2.FormArrayName, selector: "[formArrayName]", inputs: ["formArrayName"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlDirective, selector: "[formControl]", inputs: ["disabled", "formControl", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.MatError, selector: "mat-error", inputs: ["id"] }, { type: i12.MatTooltip, selector: "[matTooltip]", exportAs: ["matTooltip"] }], pipes: { "translate": i4.TranslatePipe, "async": i10.AsyncPipe } }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: KvMapConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-kv-map-config', + templateUrl: './kv-map-config.component.html', + styleUrls: ['./kv-map-config.component.scss'], + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => KvMapConfigComponent), + multi: true + }, + { + provide: NG_VALIDATORS, + useExisting: forwardRef(() => KvMapConfigComponent), + multi: true, + } + ] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i4.TranslateService }, { type: i0.Injector }, { type: i2.FormBuilder }]; }, propDecorators: { disabled: [{ + type: Input + }], requiredText: [{ + type: Input + }], keyText: [{ + type: Input + }], keyRequiredText: [{ + type: Input + }], valText: [{ + type: Input + }], valRequiredText: [{ + type: Input + }], required: [{ + type: Input + }] } }); + +class KafkaConfigComponent extends RuleNodeConfigurationComponent { + constructor(store, fb) { + super(store); + this.store = store; + this.fb = fb; + this.ackValues = ['all', '-1', '0', '1']; + this.ToByteStandartCharsetTypesValues = ToByteStandartCharsetTypes; + this.ToByteStandartCharsetTypeTranslationMap = ToByteStandartCharsetTypeTranslations; + } + configForm() { + return this.kafkaConfigForm; + } + onConfigurationSet(configuration) { + this.kafkaConfigForm = this.fb.group({ + topicPattern: [configuration ? configuration.topicPattern : null, [Validators.required]], + bootstrapServers: [configuration ? configuration.bootstrapServers : null, [Validators.required]], + retries: [configuration ? configuration.retries : null, [Validators.min(0)]], + batchSize: [configuration ? configuration.batchSize : null, [Validators.min(0)]], + linger: [configuration ? configuration.linger : null, [Validators.min(0)]], + bufferMemory: [configuration ? configuration.bufferMemory : null, [Validators.min(0)]], + acks: [configuration ? configuration.acks : null, [Validators.required]], + keySerializer: [configuration ? configuration.keySerializer : null, [Validators.required]], + valueSerializer: [configuration ? configuration.valueSerializer : null, [Validators.required]], + otherProperties: [configuration ? configuration.otherProperties : null, []], + addMetadataKeyValuesAsKafkaHeaders: [configuration ? configuration.addMetadataKeyValuesAsKafkaHeaders : false, []], + kafkaHeadersCharset: [configuration ? configuration.kafkaHeadersCharset : null, []] + }); + } + validatorTriggers() { + return ['addMetadataKeyValuesAsKafkaHeaders']; + } + updateValidators(emitEvent) { + const addMetadataKeyValuesAsKafkaHeaders = this.kafkaConfigForm.get('addMetadataKeyValuesAsKafkaHeaders').value; + if (addMetadataKeyValuesAsKafkaHeaders) { + this.kafkaConfigForm.get('kafkaHeadersCharset').setValidators([Validators.required]); + } + else { + this.kafkaConfigForm.get('kafkaHeadersCharset').setValidators([]); + } + this.kafkaConfigForm.get('kafkaHeadersCharset').updateValueAndValidity({ emitEvent }); + } +} +KafkaConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: KafkaConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); +KafkaConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: KafkaConfigComponent, selector: "tb-action-node-kafka-config", usesInheritance: true, ngImport: i0, template: "
\n \n tb.rulenode.topic-pattern\n \n \n {{ 'tb.rulenode.topic-pattern-required' | translate }}\n \n \n \n \n tb.rulenode.bootstrap-servers\n \n \n {{ 'tb.rulenode.bootstrap-servers-required' | translate }}\n \n \n \n tb.rulenode.retries\n \n \n {{ 'tb.rulenode.min-retries-message' | translate }}\n \n \n \n tb.rulenode.batch-size-bytes\n \n \n {{ 'tb.rulenode.min-batch-size-bytes-message' | translate }}\n \n \n \n tb.rulenode.linger-ms\n \n \n {{ 'tb.rulenode.min-linger-ms-message' | translate }}\n \n \n \n tb.rulenode.buffer-memory-bytes\n \n \n {{ 'tb.rulenode.min-buffer-memory-bytes-message' | translate }}\n \n \n \n tb.rulenode.acks\n \n \n {{ ackValue }}\n \n \n \n \n tb.rulenode.key-serializer\n \n \n {{ 'tb.rulenode.key-serializer-required' | translate }}\n \n \n \n tb.rulenode.value-serializer\n \n \n {{ 'tb.rulenode.value-serializer-required' | translate }}\n \n \n \n \n \n \n {{ 'tb.rulenode.add-metadata-key-values-as-kafka-headers' | translate }}\n \n
tb.rulenode.add-metadata-key-values-as-kafka-headers-hint
\n \n tb.rulenode.charset-encoding\n \n \n {{ ToByteStandartCharsetTypeTranslationMap.get(charset) | translate }}\n \n \n \n
\n", components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }, { type: i4$1.MatSelect, selector: "mat-select", inputs: ["disabled", "disableRipple", "tabIndex"], exportAs: ["matSelect"] }, { type: i5.MatOption, selector: "mat-option", exportAs: ["matOption"] }, { type: KvMapConfigComponent, selector: "tb-kv-map-config", inputs: ["disabled", "requiredText", "keyText", "keyRequiredText", "valText", "valRequiredText", "required"] }, { type: i3$1.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex", "aria-label", "aria-labelledby", "id", "labelPosition", "name", "required", "checked", "disabled", "indeterminate", "aria-describedby", "value"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.MatError, selector: "mat-error", inputs: ["id"] }, { type: i3.MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { type: i2.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { type: i2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { type: i10.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }], pipes: { "translate": i4.TranslatePipe, "safeHtml": SafeHtmlPipe } }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: KafkaConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-action-node-kafka-config', + templateUrl: './kafka-config.component.html', + styleUrls: [] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); + +class LogConfigComponent extends RuleNodeConfigurationComponent { + constructor(store, fb, nodeScriptTestService, translate) { + super(store); + this.store = store; + this.fb = fb; + this.nodeScriptTestService = nodeScriptTestService; + this.translate = translate; + } + configForm() { + return this.logConfigForm; + } + onConfigurationSet(configuration) { + this.logConfigForm = this.fb.group({ + jsScript: [configuration ? configuration.jsScript : null, [Validators.required]] + }); + } + testScript() { + const script = this.logConfigForm.get('jsScript').value; + this.nodeScriptTestService.testNodeScript(script, 'string', this.translate.instant('tb.rulenode.to-string'), 'ToString', ['msg', 'metadata', 'msgType'], this.ruleNodeId, 'rulenode/log_node_script_fn').subscribe((theScript) => { + if (theScript) { + this.logConfigForm.get('jsScript').setValue(theScript); + } + }); + } + onValidate() { + this.jsFuncComponent.validateOnSubmit(); + } +} +LogConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: LogConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }, { token: i3$3.NodeScriptTestService }, { token: i4.TranslateService }], target: i0.ɵɵFactoryTarget.Component }); +LogConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: LogConfigComponent, selector: "tb-action-node-log-config", viewQueries: [{ propertyName: "jsFuncComponent", first: true, predicate: ["jsFuncComponent"], descendants: true, static: true }], usesInheritance: true, ngImport: i0, template: "
\n \n \n \n
\n \n
\n
\n", components: [{ type: i5$1.JsFuncComponent, selector: "tb-js-func", inputs: ["functionName", "functionArgs", "validationArgs", "resultType", "disabled", "fillHeight", "editorCompleter", "globalVariables", "disableUndefinedCheck", "helpId", "noValidate", "required"] }, { type: i6.MatButton, selector: "button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }], pipes: { "translate": i4.TranslatePipe } }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: LogConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-action-node-log-config', + templateUrl: './log-config.component.html', + styleUrls: [] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }, { type: i3$3.NodeScriptTestService }, { type: i4.TranslateService }]; }, propDecorators: { jsFuncComponent: [{ + type: ViewChild, + args: ['jsFuncComponent', { static: true }] + }] } }); + +class CredentialsConfigComponent extends PageComponent { + constructor(store, fb) { + super(store); + this.store = store; + this.fb = fb; + this.subscriptions = []; + this.disableCertPemCredentials = false; + this.passwordFieldRquired = true; + this.allCredentialsTypes = credentialsTypes; + this.credentialsTypeTranslationsMap = credentialsTypeTranslations; + this.propagateChange = null; + } + get required() { + return this.requiredValue; + } + set required(value) { + this.requiredValue = coerceBooleanProperty(value); + } + ngOnInit() { + this.credentialsConfigFormGroup = this.fb.group({ + type: [null, [Validators.required]], + username: [null, []], + password: [null, []], + caCert: [null, []], + caCertFileName: [null, []], + privateKey: [null, []], + privateKeyFileName: [null, []], + cert: [null, []], + certFileName: [null, []] + }); + this.subscriptions.push(this.credentialsConfigFormGroup.valueChanges.pipe(distinctUntilChanged()).subscribe(() => { + this.updateView(); + })); + this.subscriptions.push(this.credentialsConfigFormGroup.get('type').valueChanges.subscribe(() => { + this.credentialsTypeChanged(); + })); + } + ngOnChanges(changes) { + for (const propName of Object.keys(changes)) { + const change = changes[propName]; + if (!change.firstChange && change.currentValue !== change.previousValue) { + if (change.currentValue && propName === 'disableCertPemCredentials') { + const credentialsTypeValue = this.credentialsConfigFormGroup.get('type').value; + if (credentialsTypeValue === 'cert.PEM') { + setTimeout(() => { + this.credentialsConfigFormGroup.get('type').patchValue('anonymous', { emitEvent: true }); + }); + } + } + } + } + } + ngOnDestroy() { + this.subscriptions.forEach(s => s.unsubscribe()); + } + writeValue(credentials) { + if (isDefinedAndNotNull(credentials)) { + this.credentialsConfigFormGroup.reset(credentials, { emitEvent: false }); + this.updateValidators(false); + } + } + setDisabledState(isDisabled) { + if (isDisabled) { + this.credentialsConfigFormGroup.disable(); + } + else { + this.credentialsConfigFormGroup.enable(); + this.updateValidators(); + } + } + updateView() { + let credentialsConfigValue = this.credentialsConfigFormGroup.value; + const credentialsTypeValue = credentialsConfigValue.type; + switch (credentialsTypeValue) { + case 'anonymous': + credentialsConfigValue = { + type: credentialsTypeValue + }; + break; + case 'basic': + credentialsConfigValue = { + type: credentialsTypeValue, + username: credentialsConfigValue.username, + password: credentialsConfigValue.password, + }; + break; + case 'cert.PEM': + delete credentialsConfigValue.username; + break; + } + this.propagateChange(credentialsConfigValue); + } + registerOnChange(fn) { + this.propagateChange = fn; + } + registerOnTouched(fn) { + } + validate(c) { + return this.credentialsConfigFormGroup.valid ? null : { + credentialsConfig: { + valid: false, + }, + }; + } + credentialsTypeChanged() { + this.credentialsConfigFormGroup.patchValue({ + username: null, + password: null, + caCert: null, + caCertFileName: null, + privateKey: null, + privateKeyFileName: null, + cert: null, + certFileName: null, + }); + this.updateValidators(); + } + updateValidators(emitEvent = false) { + const credentialsTypeValue = this.credentialsConfigFormGroup.get('type').value; + if (emitEvent) { + this.credentialsConfigFormGroup.reset({ type: credentialsTypeValue }, { emitEvent: false }); + } + this.credentialsConfigFormGroup.setValidators([]); + this.credentialsConfigFormGroup.get('username').setValidators([]); + this.credentialsConfigFormGroup.get('password').setValidators([]); + switch (credentialsTypeValue) { + case 'anonymous': + break; + case 'basic': + this.credentialsConfigFormGroup.get('username').setValidators([Validators.required]); + this.credentialsConfigFormGroup.get('password').setValidators(this.passwordFieldRquired ? [Validators.required] : []); + break; + case 'cert.PEM': + this.credentialsConfigFormGroup.setValidators([this.requiredFilesSelected(Validators.required, [['caCert', 'caCertFileName'], ['privateKey', 'privateKeyFileName', 'cert', 'certFileName']])]); + break; + } + this.credentialsConfigFormGroup.get('username').updateValueAndValidity({ emitEvent }); + this.credentialsConfigFormGroup.get('password').updateValueAndValidity({ emitEvent }); + this.credentialsConfigFormGroup.updateValueAndValidity({ emitEvent }); + } + requiredFilesSelected(validator, requiredFieldsSet = null) { + return (group) => { + if (!requiredFieldsSet) { + requiredFieldsSet = [Object.keys(group.controls)]; + } + const allRequiredFilesSelected = (group === null || group === void 0 ? void 0 : group.controls) && + requiredFieldsSet.some(arrFields => arrFields.every(k => !validator(group.controls[k]))); + return allRequiredFilesSelected ? null : { notAllRequiredFilesSelected: true }; + }; + } +} +CredentialsConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: CredentialsConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); +CredentialsConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: CredentialsConfigComponent, selector: "tb-credentials-config", inputs: { required: "required", disableCertPemCredentials: "disableCertPemCredentials", passwordFieldRquired: "passwordFieldRquired" }, providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => CredentialsConfigComponent), + multi: true + }, + { + provide: NG_VALIDATORS, + useExisting: forwardRef(() => CredentialsConfigComponent), + multi: true, + } + ], usesInheritance: true, usesOnChanges: true, ngImport: i0, template: "
\n \n \n tb.rulenode.credentials\n \n {{ credentialsTypeTranslationsMap.get(credentialsConfigFormGroup.get('type').value) | translate }}\n \n \n \n \n tb.rulenode.credentials-type\n \n \n {{ credentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ 'tb.rulenode.credentials-type-required' | translate }}\n \n \n
\n \n \n \n \n tb.rulenode.username\n \n \n {{ 'tb.rulenode.username-required' | translate }}\n \n \n \n tb.rulenode.password\n \n \n \n {{ 'tb.rulenode.password-required' | translate }}\n \n \n \n \n
{{ 'tb.rulenode.credentials-pem-hint' | translate }}
\n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n
\n
\n
\n
\n
\n", components: [{ type: i4$2.MatExpansionPanel, selector: "mat-expansion-panel", inputs: ["disabled", "expanded", "hideToggle", "togglePosition"], outputs: ["opened", "closed", "expandedChange", "afterExpand", "afterCollapse"], exportAs: ["matExpansionPanel"] }, { type: i4$2.MatExpansionPanelHeader, selector: "mat-expansion-panel-header", inputs: ["tabIndex", "expandedHeight", "collapsedHeight"] }, { type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }, { type: i4$1.MatSelect, selector: "mat-select", inputs: ["disabled", "disableRipple", "tabIndex"], exportAs: ["matSelect"] }, { type: i5.MatOption, selector: "mat-option", exportAs: ["matOption"] }, { type: i7.TogglePasswordComponent, selector: "tb-toggle-password" }, { type: i8$1.FileInputComponent, selector: "tb-file-input", inputs: ["label", "accept", "noFileText", "inputId", "allowedExtensions", "dropLabel", "contentConvertFunction", "required", "requiredAsError", "disabled", "existingFileName", "readAsBinary", "workFromFileObj", "multipleFile"], outputs: ["fileNameChanged"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i4$2.MatExpansionPanelTitle, selector: "mat-panel-title" }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i4$2.MatExpansionPanelDescription, selector: "mat-panel-description" }, { type: i4$2.MatExpansionPanelContent, selector: "ng-template[matExpansionPanelContent]" }, { type: i3.MatLabel, selector: "mat-label" }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i10.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.MatError, selector: "mat-error", inputs: ["id"] }, { type: i10.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { type: i10.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i3.MatSuffix, selector: "[matSuffix]" }], pipes: { "translate": i4.TranslatePipe } }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: CredentialsConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-credentials-config', + templateUrl: './credentials-config.component.html', + styleUrls: [], + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => CredentialsConfigComponent), + multi: true + }, + { + provide: NG_VALIDATORS, + useExisting: forwardRef(() => CredentialsConfigComponent), + multi: true, + } + ] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; }, propDecorators: { required: [{ + type: Input + }], disableCertPemCredentials: [{ + type: Input + }], passwordFieldRquired: [{ + type: Input + }] } }); + +class MqttConfigComponent extends RuleNodeConfigurationComponent { + constructor(store, fb) { + super(store); + this.store = store; + this.fb = fb; + } + configForm() { + return this.mqttConfigForm; + } + onConfigurationSet(configuration) { + this.mqttConfigForm = this.fb.group({ + topicPattern: [configuration ? configuration.topicPattern : null, [Validators.required]], + host: [configuration ? configuration.host : null, [Validators.required]], + port: [configuration ? configuration.port : null, [Validators.required, Validators.min(1), Validators.max(65535)]], + connectTimeoutSec: [configuration ? configuration.connectTimeoutSec : null, + [Validators.required, Validators.min(1), Validators.max(200)]], + clientId: [configuration ? configuration.clientId : null, []], + cleanSession: [configuration ? configuration.cleanSession : false, []], + ssl: [configuration ? configuration.ssl : false, []], + credentials: [configuration ? configuration.credentials : null, []] + }); + } +} +MqttConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: MqttConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); +MqttConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: MqttConfigComponent, selector: "tb-action-node-mqtt-config", usesInheritance: true, ngImport: i0, template: "
\n \n tb.rulenode.topic-pattern\n \n \n {{ 'tb.rulenode.topic-pattern-required' | translate }}\n \n \n \n
\n \n tb.rulenode.host\n \n \n {{ 'tb.rulenode.host-required' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ 'tb.rulenode.port-required' | translate }}\n \n \n {{ 'tb.rulenode.port-range' | translate }}\n \n \n {{ 'tb.rulenode.port-range' | translate }}\n \n \n \n tb.rulenode.connect-timeout\n \n \n {{ 'tb.rulenode.connect-timeout-required' | translate }}\n \n \n {{ 'tb.rulenode.connect-timeout-range' | translate }}\n \n \n {{ 'tb.rulenode.connect-timeout-range' | translate }}\n \n \n
\n \n tb.rulenode.client-id\n \n \n
tb.rulenode.client-id-hint
\n \n {{ 'tb.rulenode.clean-session' | translate }}\n \n \n {{ 'tb.rulenode.enable-ssl' | translate }}\n \n \n
\n", styles: [":host .tb-mqtt-credentials-panel-group{margin:0 6px}:host .tb-hint.client-id{margin-top:-1.25em;max-width:-moz-fit-content;max-width:fit-content}\n"], components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }, { type: i3$1.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex", "aria-label", "aria-labelledby", "id", "labelPosition", "name", "required", "checked", "disabled", "indeterminate", "aria-describedby", "value"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { type: CredentialsConfigComponent, selector: "tb-credentials-config", inputs: ["required", "disableCertPemCredentials", "passwordFieldRquired"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.MatError, selector: "mat-error", inputs: ["id"] }, { type: i3.MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }, { type: i8.DefaultLayoutGapDirective, selector: " [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]", inputs: ["fxLayoutGap", "fxLayoutGap.xs", "fxLayoutGap.sm", "fxLayoutGap.md", "fxLayoutGap.lg", "fxLayoutGap.xl", "fxLayoutGap.lt-sm", "fxLayoutGap.lt-md", "fxLayoutGap.lt-lg", "fxLayoutGap.lt-xl", "fxLayoutGap.gt-xs", "fxLayoutGap.gt-sm", "fxLayoutGap.gt-md", "fxLayoutGap.gt-lg"] }, { type: i2.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { type: i2.MaxValidator, selector: "input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]", inputs: ["max"] }, { type: i2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }], pipes: { "translate": i4.TranslatePipe, "safeHtml": SafeHtmlPipe } }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: MqttConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-action-node-mqtt-config', + templateUrl: './mqtt-config.component.html', + styleUrls: ['./mqtt-config.component.scss'] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); + +class MsgCountConfigComponent extends RuleNodeConfigurationComponent { + constructor(store, fb) { + super(store); + this.store = store; + this.fb = fb; + } + configForm() { + return this.msgCountConfigForm; + } + onConfigurationSet(configuration) { + this.msgCountConfigForm = this.fb.group({ + interval: [configuration ? configuration.interval : null, [Validators.required, Validators.min(1)]], + telemetryPrefix: [configuration ? configuration.telemetryPrefix : null, [Validators.required]] + }); + } +} +MsgCountConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: MsgCountConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); +MsgCountConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: MsgCountConfigComponent, selector: "tb-action-node-msg-count-config", usesInheritance: true, ngImport: i0, template: "
\n \n tb.rulenode.interval-seconds\n \n \n {{ 'tb.rulenode.interval-seconds-required' | translate }}\n \n \n {{ 'tb.rulenode.min-interval-seconds-message' | translate }}\n \n \n \n tb.rulenode.output-timeseries-key-prefix\n \n \n {{ 'tb.rulenode.output-timeseries-key-prefix-required' | translate }}\n \n \n
\n", components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i2.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { type: i2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.MatError, selector: "mat-error", inputs: ["id"] }], pipes: { "translate": i4.TranslatePipe } }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: MsgCountConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-action-node-msg-count-config', + templateUrl: './msg-count-config.component.html', + styleUrls: [] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); + +class MsgDelayConfigComponent extends RuleNodeConfigurationComponent { + constructor(store, fb) { + super(store); + this.store = store; + this.fb = fb; + } + configForm() { + return this.msgDelayConfigForm; + } + onConfigurationSet(configuration) { + this.msgDelayConfigForm = this.fb.group({ + useMetadataPeriodInSecondsPatterns: [configuration ? configuration.useMetadataPeriodInSecondsPatterns : false, []], + periodInSeconds: [configuration ? configuration.periodInSeconds : null, []], + periodInSecondsPattern: [configuration ? configuration.periodInSecondsPattern : null, []], + maxPendingMsgs: [configuration ? configuration.maxPendingMsgs : null, + [Validators.required, Validators.min(1), Validators.max(100000)]], + }); + } + validatorTriggers() { + return ['useMetadataPeriodInSecondsPatterns']; + } + updateValidators(emitEvent) { + const useMetadataPeriodInSecondsPatterns = this.msgDelayConfigForm.get('useMetadataPeriodInSecondsPatterns').value; + if (useMetadataPeriodInSecondsPatterns) { + this.msgDelayConfigForm.get('periodInSecondsPattern').setValidators([Validators.required]); + this.msgDelayConfigForm.get('periodInSeconds').setValidators([]); + } + else { + this.msgDelayConfigForm.get('periodInSecondsPattern').setValidators([]); + this.msgDelayConfigForm.get('periodInSeconds').setValidators([Validators.required, Validators.min(0)]); + } + this.msgDelayConfigForm.get('periodInSecondsPattern').updateValueAndValidity({ emitEvent }); + this.msgDelayConfigForm.get('periodInSeconds').updateValueAndValidity({ emitEvent }); + } +} +MsgDelayConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: MsgDelayConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); +MsgDelayConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: MsgDelayConfigComponent, selector: "tb-action-node-msg-delay-config", usesInheritance: true, ngImport: i0, template: "
\n \n {{ 'tb.rulenode.use-metadata-period-in-seconds-patterns' | translate }}\n \n
tb.rulenode.use-metadata-period-in-seconds-patterns-hint
\n \n tb.rulenode.period-seconds\n \n \n {{ 'tb.rulenode.period-seconds-required' | translate }}\n \n \n {{ 'tb.rulenode.min-period-0-seconds-message' | translate }}\n \n \n \n \n tb.rulenode.period-in-seconds-pattern\n \n \n {{ 'tb.rulenode.period-in-seconds-pattern-required' | translate }}\n \n \n \n \n \n tb.rulenode.max-pending-messages\n \n \n {{ 'tb.rulenode.max-pending-messages-required' | translate }}\n \n \n {{ 'tb.rulenode.max-pending-messages-range' | translate }}\n \n \n {{ 'tb.rulenode.max-pending-messages-range' | translate }}\n \n \n
\n", components: [{ type: i3$1.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex", "aria-label", "aria-labelledby", "id", "labelPosition", "name", "required", "checked", "disabled", "indeterminate", "aria-describedby", "value"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i2.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { type: i2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i3.MatError, selector: "mat-error", inputs: ["id"] }, { type: i3.MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { type: i2.MaxValidator, selector: "input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]", inputs: ["max"] }], pipes: { "translate": i4.TranslatePipe, "safeHtml": SafeHtmlPipe } }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: MsgDelayConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-action-node-msg-delay-config', + templateUrl: './msg-delay-config.component.html', + styleUrls: [] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); + +class PubSubConfigComponent extends RuleNodeConfigurationComponent { + constructor(store, fb) { + super(store); + this.store = store; + this.fb = fb; + } + configForm() { + return this.pubSubConfigForm; + } + onConfigurationSet(configuration) { + this.pubSubConfigForm = this.fb.group({ + projectId: [configuration ? configuration.projectId : null, [Validators.required]], + topicName: [configuration ? configuration.topicName : null, [Validators.required]], + serviceAccountKey: [configuration ? configuration.serviceAccountKey : null, [Validators.required]], + serviceAccountKeyFileName: [configuration ? configuration.serviceAccountKeyFileName : null, [Validators.required]], + messageAttributes: [configuration ? configuration.messageAttributes : null, []] + }); + } +} +PubSubConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: PubSubConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); +PubSubConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: PubSubConfigComponent, selector: "tb-action-node-pub-sub-config", usesInheritance: true, ngImport: i0, template: "
\n \n tb.rulenode.gcp-project-id\n \n \n {{ 'tb.rulenode.gcp-project-id-required' | translate }}\n \n \n \n tb.rulenode.pubsub-topic-name\n \n \n {{ 'tb.rulenode.pubsub-topic-name-required' | translate }}\n \n \n \n \n \n
\n \n \n
\n", components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }, { type: i8$1.FileInputComponent, selector: "tb-file-input", inputs: ["label", "accept", "noFileText", "inputId", "allowedExtensions", "dropLabel", "contentConvertFunction", "required", "requiredAsError", "disabled", "existingFileName", "readAsBinary", "workFromFileObj", "multipleFile"], outputs: ["fileNameChanged"] }, { type: KvMapConfigComponent, selector: "tb-kv-map-config", inputs: ["disabled", "requiredText", "keyText", "keyRequiredText", "valText", "valRequiredText", "required"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.MatError, selector: "mat-error", inputs: ["id"] }], pipes: { "translate": i4.TranslatePipe, "safeHtml": SafeHtmlPipe } }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: PubSubConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-action-node-pub-sub-config', + templateUrl: './pubsub-config.component.html', + styleUrls: [] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); + +class PushToCloudConfigComponent extends RuleNodeConfigurationComponent { + constructor(store, fb) { + super(store); + this.store = store; + this.fb = fb; + this.attributeScopes = Object.keys(AttributeScope); + this.telemetryTypeTranslationsMap = telemetryTypeTranslations; + } + configForm() { + return this.pushToCloudConfigForm; + } + onConfigurationSet(configuration) { + this.pushToCloudConfigForm = this.fb.group({ + scope: [configuration ? configuration.scope : null, [Validators.required]] + }); + } +} +PushToCloudConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: PushToCloudConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); +PushToCloudConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: PushToCloudConfigComponent, selector: "tb-action-node-push-to-cloud-config", usesInheritance: true, ngImport: i0, template: "
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n", components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }, { type: i4$1.MatSelect, selector: "mat-select", inputs: ["disabled", "disableRipple", "tabIndex"], exportAs: ["matSelect"] }, { type: i5.MatOption, selector: "mat-option", exportAs: ["matOption"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i10.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }], pipes: { "translate": i4.TranslatePipe } }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: PushToCloudConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-action-node-push-to-cloud-config', + templateUrl: './push-to-cloud-config.component.html', + styleUrls: [] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); + +class PushToEdgeConfigComponent extends RuleNodeConfigurationComponent { + constructor(store, fb) { + super(store); + this.store = store; + this.fb = fb; + this.attributeScopes = Object.keys(AttributeScope); + this.telemetryTypeTranslationsMap = telemetryTypeTranslations; + } + configForm() { + return this.pushToEdgeConfigForm; + } + onConfigurationSet(configuration) { + this.pushToEdgeConfigForm = this.fb.group({ + scope: [configuration ? configuration.scope : null, [Validators.required]] + }); + } +} +PushToEdgeConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: PushToEdgeConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); +PushToEdgeConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: PushToEdgeConfigComponent, selector: "tb-action-node-push-to-edge-config", usesInheritance: true, ngImport: i0, template: "
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n", components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }, { type: i4$1.MatSelect, selector: "mat-select", inputs: ["disabled", "disableRipple", "tabIndex"], exportAs: ["matSelect"] }, { type: i5.MatOption, selector: "mat-option", exportAs: ["matOption"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i10.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }], pipes: { "translate": i4.TranslatePipe } }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: PushToEdgeConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-action-node-push-to-edge-config', + templateUrl: './push-to-edge-config.component.html', + styleUrls: [] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); + +class RabbitMqConfigComponent extends RuleNodeConfigurationComponent { + constructor(store, fb) { + super(store); + this.store = store; + this.fb = fb; + this.messageProperties = [ + null, + 'BASIC', + 'TEXT_PLAIN', + 'MINIMAL_BASIC', + 'MINIMAL_PERSISTENT_BASIC', + 'PERSISTENT_BASIC', + 'PERSISTENT_TEXT_PLAIN' + ]; + } + configForm() { + return this.rabbitMqConfigForm; + } + onConfigurationSet(configuration) { + this.rabbitMqConfigForm = this.fb.group({ + exchangeNamePattern: [configuration ? configuration.exchangeNamePattern : null, []], + routingKeyPattern: [configuration ? configuration.routingKeyPattern : null, []], + messageProperties: [configuration ? configuration.messageProperties : null, []], + host: [configuration ? configuration.host : null, [Validators.required]], + port: [configuration ? configuration.port : null, [Validators.required, Validators.min(1), Validators.max(65535)]], + virtualHost: [configuration ? configuration.virtualHost : null, []], + username: [configuration ? configuration.username : null, []], + password: [configuration ? configuration.password : null, []], + automaticRecoveryEnabled: [configuration ? configuration.automaticRecoveryEnabled : false, []], + connectionTimeout: [configuration ? configuration.connectionTimeout : null, [Validators.min(0)]], + handshakeTimeout: [configuration ? configuration.handshakeTimeout : null, [Validators.min(0)]], + clientProperties: [configuration ? configuration.clientProperties : null, []] + }); + } +} +RabbitMqConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RabbitMqConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); +RabbitMqConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: RabbitMqConfigComponent, selector: "tb-action-node-rabbit-mq-config", usesInheritance: true, ngImport: i0, template: "
\n \n tb.rulenode.exchange-name-pattern\n \n \n \n tb.rulenode.routing-key-pattern\n \n \n \n tb.rulenode.message-properties\n \n \n {{ property }}\n \n \n \n
\n \n tb.rulenode.host\n \n \n {{ 'tb.rulenode.host-required' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ 'tb.rulenode.port-required' | translate }}\n \n \n {{ 'tb.rulenode.port-range' | translate }}\n \n \n {{ 'tb.rulenode.port-range' | translate }}\n \n \n
\n \n tb.rulenode.virtual-host\n \n \n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n \n {{ 'tb.rulenode.automatic-recovery' | translate }}\n \n \n tb.rulenode.connection-timeout-ms\n \n \n {{ 'tb.rulenode.min-connection-timeout-ms-message' | translate }}\n \n \n \n tb.rulenode.handshake-timeout-ms\n \n \n {{ 'tb.rulenode.min-handshake-timeout-ms-message' | translate }}\n \n \n \n \n \n
\n", components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }, { type: i4$1.MatSelect, selector: "mat-select", inputs: ["disabled", "disableRipple", "tabIndex"], exportAs: ["matSelect"] }, { type: i5.MatOption, selector: "mat-option", exportAs: ["matOption"] }, { type: i7.TogglePasswordComponent, selector: "tb-toggle-password" }, { type: i3$1.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex", "aria-label", "aria-labelledby", "id", "labelPosition", "name", "required", "checked", "disabled", "indeterminate", "aria-describedby", "value"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { type: KvMapConfigComponent, selector: "tb-kv-map-config", inputs: ["disabled", "requiredText", "keyText", "keyRequiredText", "valText", "valRequiredText", "required"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i10.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i8.DefaultLayoutGapDirective, selector: " [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]", inputs: ["fxLayoutGap", "fxLayoutGap.xs", "fxLayoutGap.sm", "fxLayoutGap.md", "fxLayoutGap.lg", "fxLayoutGap.xl", "fxLayoutGap.lt-sm", "fxLayoutGap.lt-md", "fxLayoutGap.lt-lg", "fxLayoutGap.lt-xl", "fxLayoutGap.gt-xs", "fxLayoutGap.gt-sm", "fxLayoutGap.gt-md", "fxLayoutGap.gt-lg"] }, { type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.MatError, selector: "mat-error", inputs: ["id"] }, { type: i2.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { type: i2.MaxValidator, selector: "input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]", inputs: ["max"] }, { type: i2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { type: i3.MatSuffix, selector: "[matSuffix]" }], pipes: { "translate": i4.TranslatePipe } }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RabbitMqConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-action-node-rabbit-mq-config', + templateUrl: './rabbit-mq-config.component.html', + styleUrls: [] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); + +class RestApiCallConfigComponent extends RuleNodeConfigurationComponent { + constructor(store, fb) { + super(store); + this.store = store; + this.fb = fb; + this.proxySchemes = ['http', 'https']; + this.httpRequestTypes = Object.keys(HttpRequestType); + } + configForm() { + return this.restApiCallConfigForm; + } + onConfigurationSet(configuration) { + this.restApiCallConfigForm = this.fb.group({ + restEndpointUrlPattern: [configuration ? configuration.restEndpointUrlPattern : null, [Validators.required]], + requestMethod: [configuration ? configuration.requestMethod : null, [Validators.required]], + useSimpleClientHttpFactory: [configuration ? configuration.useSimpleClientHttpFactory : false, []], + ignoreRequestBody: [configuration ? configuration.ignoreRequestBody : false, []], + enableProxy: [configuration ? configuration.enableProxy : false, []], + useSystemProxyProperties: [configuration ? configuration.enableProxy : false, []], + proxyScheme: [configuration ? configuration.proxyHost : null, []], + proxyHost: [configuration ? configuration.proxyHost : null, []], + proxyPort: [configuration ? configuration.proxyPort : null, []], + proxyUser: [configuration ? configuration.proxyUser : null, []], + proxyPassword: [configuration ? configuration.proxyPassword : null, []], + readTimeoutMs: [configuration ? configuration.readTimeoutMs : null, []], + maxParallelRequestsCount: [configuration ? configuration.maxParallelRequestsCount : null, [Validators.min(0)]], + headers: [configuration ? configuration.headers : null, []], + useRedisQueueForMsgPersistence: [configuration ? configuration.useRedisQueueForMsgPersistence : false, []], + trimQueue: [configuration ? configuration.trimQueue : false, []], + maxQueueSize: [configuration ? configuration.maxQueueSize : null, []], + credentials: [configuration ? configuration.credentials : null, []] + }); + } + validatorTriggers() { + return ['useSimpleClientHttpFactory', 'useRedisQueueForMsgPersistence', 'enableProxy', 'useSystemProxyProperties']; + } + updateValidators(emitEvent) { + const useSimpleClientHttpFactory = this.restApiCallConfigForm.get('useSimpleClientHttpFactory').value; + const useRedisQueueForMsgPersistence = this.restApiCallConfigForm.get('useRedisQueueForMsgPersistence').value; + const enableProxy = this.restApiCallConfigForm.get('enableProxy').value; + const useSystemProxyProperties = this.restApiCallConfigForm.get('useSystemProxyProperties').value; + if (enableProxy && !useSystemProxyProperties) { + this.restApiCallConfigForm.get('proxyHost').setValidators(enableProxy ? [Validators.required] : []); + this.restApiCallConfigForm.get('proxyPort').setValidators(enableProxy ? + [Validators.required, Validators.min(1), Validators.max(65535)] : []); + } + else { + this.restApiCallConfigForm.get('proxyHost').setValidators([]); + this.restApiCallConfigForm.get('proxyPort').setValidators([]); + if (useSimpleClientHttpFactory) { + this.restApiCallConfigForm.get('readTimeoutMs').setValidators([]); + } + else { + this.restApiCallConfigForm.get('readTimeoutMs').setValidators([Validators.min(0)]); + } + } + if (useRedisQueueForMsgPersistence) { + this.restApiCallConfigForm.get('maxQueueSize').setValidators([Validators.min(0)]); + } + else { + this.restApiCallConfigForm.get('maxQueueSize').setValidators([]); + } + this.restApiCallConfigForm.get('readTimeoutMs').updateValueAndValidity({ emitEvent }); + this.restApiCallConfigForm.get('maxQueueSize').updateValueAndValidity({ emitEvent }); + this.restApiCallConfigForm.get('proxyHost').updateValueAndValidity({ emitEvent }); + this.restApiCallConfigForm.get('proxyPort').updateValueAndValidity({ emitEvent }); + this.restApiCallConfigForm.get('credentials').updateValueAndValidity({ emitEvent }); + } +} +RestApiCallConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RestApiCallConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); +RestApiCallConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: RestApiCallConfigComponent, selector: "tb-action-node-rest-api-call-config", usesInheritance: true, ngImport: i0, template: "
\n \n tb.rulenode.endpoint-url-pattern\n \n \n {{ 'tb.rulenode.endpoint-url-pattern-required' | translate }}\n \n \n \n \n tb.rulenode.request-method\n \n \n {{ requestType }}\n \n \n \n \n {{ 'tb.rulenode.enable-proxy' | translate }}\n \n \n {{ 'tb.rulenode.use-simple-client-http-factory' | translate }}\n \n \n {{ 'tb.rulenode.ignore-request-body' | translate }}\n \n
\n \n {{ 'tb.rulenode.use-system-proxy-properties' | translate }}\n \n
\n
\n \n tb.rulenode.proxy-scheme\n \n \n {{ proxyScheme }}\n \n \n \n \n tb.rulenode.proxy-host\n \n \n {{ 'tb.rulenode.proxy-host-required' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ 'tb.rulenode.proxy-port-required' | translate }}\n \n \n {{ 'tb.rulenode.proxy-port-range' | translate }}\n \n \n
\n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
\n
\n \n tb.rulenode.read-timeout\n \n tb.rulenode.read-timeout-hint\n \n \n tb.rulenode.max-parallel-requests-count\n \n tb.rulenode.max-parallel-requests-count-hint\n \n \n
\n \n \n \n {{ 'tb.rulenode.use-redis-queue' | translate }}\n \n
\n \n {{ 'tb.rulenode.trim-redis-queue' | translate }}\n \n \n tb.rulenode.redis-queue-max-size\n \n \n
\n \n
\n", components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }, { type: i4$1.MatSelect, selector: "mat-select", inputs: ["disabled", "disableRipple", "tabIndex"], exportAs: ["matSelect"] }, { type: i5.MatOption, selector: "mat-option", exportAs: ["matOption"] }, { type: i3$1.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex", "aria-label", "aria-labelledby", "id", "labelPosition", "name", "required", "checked", "disabled", "indeterminate", "aria-describedby", "value"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { type: KvMapConfigComponent, selector: "tb-kv-map-config", inputs: ["disabled", "requiredText", "keyText", "keyRequiredText", "valText", "valRequiredText", "required"] }, { type: CredentialsConfigComponent, selector: "tb-credentials-config", inputs: ["required", "disableCertPemCredentials", "passwordFieldRquired"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.MatError, selector: "mat-error", inputs: ["id"] }, { type: i3.MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { type: i10.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i8.DefaultLayoutGapDirective, selector: " [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]", inputs: ["fxLayoutGap", "fxLayoutGap.xs", "fxLayoutGap.sm", "fxLayoutGap.md", "fxLayoutGap.lg", "fxLayoutGap.xl", "fxLayoutGap.lt-sm", "fxLayoutGap.lt-md", "fxLayoutGap.lt-lg", "fxLayoutGap.lt-xl", "fxLayoutGap.gt-xs", "fxLayoutGap.gt-sm", "fxLayoutGap.gt-md", "fxLayoutGap.gt-lg"] }, { type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }, { type: i2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { type: i2.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }], pipes: { "translate": i4.TranslatePipe, "safeHtml": SafeHtmlPipe } }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RestApiCallConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-action-node-rest-api-call-config', + templateUrl: './rest-api-call-config.component.html', + styleUrls: [] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); + +class RpcReplyConfigComponent extends RuleNodeConfigurationComponent { + constructor(store, fb) { + super(store); + this.store = store; + this.fb = fb; + } + configForm() { + return this.rpcReplyConfigForm; + } + onConfigurationSet(configuration) { + this.rpcReplyConfigForm = this.fb.group({ + requestIdMetaDataAttribute: [configuration ? configuration.requestIdMetaDataAttribute : null, []] + }); + } +} +RpcReplyConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RpcReplyConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); +RpcReplyConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: RpcReplyConfigComponent, selector: "tb-action-node-rpc-reply-config", usesInheritance: true, ngImport: i0, template: "
\n \n tb.rulenode.request-id-metadata-attribute\n \n \n
\n", components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }] }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RpcReplyConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-action-node-rpc-reply-config', + templateUrl: './rpc-reply-config.component.html', + styleUrls: [] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); + +class RpcRequestConfigComponent extends RuleNodeConfigurationComponent { + constructor(store, fb) { + super(store); + this.store = store; + this.fb = fb; + } + configForm() { + return this.rpcRequestConfigForm; + } + onConfigurationSet(configuration) { + this.rpcRequestConfigForm = this.fb.group({ + timeoutInSeconds: [configuration ? configuration.timeoutInSeconds : null, [Validators.required, Validators.min(0)]] + }); + } +} +RpcRequestConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RpcRequestConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); +RpcRequestConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: RpcRequestConfigComponent, selector: "tb-action-node-rpc-request-config", usesInheritance: true, ngImport: i0, template: "
\n \n tb.rulenode.timeout-sec\n \n \n {{ 'tb.rulenode.timeout-required' | translate }}\n \n \n {{ 'tb.rulenode.min-timeout-message' | translate }}\n \n \n
\n", components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i2.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { type: i2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.MatError, selector: "mat-error", inputs: ["id"] }], pipes: { "translate": i4.TranslatePipe } }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RpcRequestConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-action-node-rpc-request-config', + templateUrl: './rpc-request-config.component.html', + styleUrls: [] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); + +class SaveToCustomTableConfigComponent extends RuleNodeConfigurationComponent { + constructor(store, fb) { + super(store); + this.store = store; + this.fb = fb; + } + configForm() { + return this.saveToCustomTableConfigForm; + } + onConfigurationSet(configuration) { + this.saveToCustomTableConfigForm = this.fb.group({ + tableName: [configuration ? configuration.tableName : null, [Validators.required, Validators.pattern(/.*\S.*/)]], + fieldsMapping: [configuration ? configuration.fieldsMapping : null, [Validators.required]] + }); + } + prepareOutputConfig(configuration) { + configuration.tableName = configuration.tableName.trim(); + return configuration; + } +} +SaveToCustomTableConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: SaveToCustomTableConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); +SaveToCustomTableConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: SaveToCustomTableConfigComponent, selector: "tb-action-node-custom-table-config", usesInheritance: true, ngImport: i0, template: "
\n \n tb.rulenode.custom-table-name\n \n \n {{ 'tb.rulenode.custom-table-name-required' | translate }}\n \n tb.rulenode.custom-table-hint\n \n \n \n \n
\n", components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }, { type: KvMapConfigComponent, selector: "tb-kv-map-config", inputs: ["disabled", "requiredText", "keyText", "keyRequiredText", "valText", "valRequiredText", "required"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.MatError, selector: "mat-error", inputs: ["id"] }, { type: i3.MatHint, selector: "mat-hint", inputs: ["align", "id"] }], pipes: { "translate": i4.TranslatePipe } }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: SaveToCustomTableConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-action-node-custom-table-config', + templateUrl: './save-to-custom-table-config.component.html', + styleUrls: [] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); + +class SendEmailConfigComponent extends RuleNodeConfigurationComponent { + constructor(store, fb) { + super(store); + this.store = store; + this.fb = fb; + this.smtpProtocols = [ + 'smtp', + 'smtps' + ]; + this.tlsVersions = ['TLSv1', 'TLSv1.1', 'TLSv1.2', 'TLSv1.3']; + } + configForm() { + return this.sendEmailConfigForm; + } + onConfigurationSet(configuration) { + this.sendEmailConfigForm = this.fb.group({ + useSystemSmtpSettings: [configuration ? configuration.useSystemSmtpSettings : false, []], + smtpProtocol: [configuration ? configuration.smtpProtocol : null, []], + smtpHost: [configuration ? configuration.smtpHost : null, []], + smtpPort: [configuration ? configuration.smtpPort : null, []], + timeout: [configuration ? configuration.timeout : null, []], + enableTls: [configuration ? configuration.enableTls : false, []], + tlsVersion: [configuration ? configuration.tlsVersion : null, []], + enableProxy: [configuration ? configuration.enableProxy : false, []], + proxyHost: [configuration ? configuration.proxyHost : null, []], + proxyPort: [configuration ? configuration.proxyPort : null, []], + proxyUser: [configuration ? configuration.proxyUser : null, []], + proxyPassword: [configuration ? configuration.proxyPassword : null, []], + username: [configuration ? configuration.username : null, []], + password: [configuration ? configuration.password : null, []] + }); + } + validatorTriggers() { + return ['useSystemSmtpSettings', 'enableProxy']; + } + updateValidators(emitEvent) { + const useSystemSmtpSettings = this.sendEmailConfigForm.get('useSystemSmtpSettings').value; + const enableProxy = this.sendEmailConfigForm.get('enableProxy').value; + if (useSystemSmtpSettings) { + this.sendEmailConfigForm.get('smtpProtocol').setValidators([]); + this.sendEmailConfigForm.get('smtpHost').setValidators([]); + this.sendEmailConfigForm.get('smtpPort').setValidators([]); + this.sendEmailConfigForm.get('timeout').setValidators([]); + this.sendEmailConfigForm.get('proxyHost').setValidators([]); + this.sendEmailConfigForm.get('proxyPort').setValidators([]); + } + else { + this.sendEmailConfigForm.get('smtpProtocol').setValidators([Validators.required]); + this.sendEmailConfigForm.get('smtpHost').setValidators([Validators.required]); + this.sendEmailConfigForm.get('smtpPort').setValidators([Validators.required, Validators.min(1), Validators.max(65535)]); + this.sendEmailConfigForm.get('timeout').setValidators([Validators.required, Validators.min(0)]); + this.sendEmailConfigForm.get('proxyHost').setValidators(enableProxy ? [Validators.required] : []); + this.sendEmailConfigForm.get('proxyPort').setValidators(enableProxy ? + [Validators.required, Validators.min(1), Validators.max(65535)] : []); + } + this.sendEmailConfigForm.get('smtpProtocol').updateValueAndValidity({ emitEvent }); + this.sendEmailConfigForm.get('smtpHost').updateValueAndValidity({ emitEvent }); + this.sendEmailConfigForm.get('smtpPort').updateValueAndValidity({ emitEvent }); + this.sendEmailConfigForm.get('timeout').updateValueAndValidity({ emitEvent }); + this.sendEmailConfigForm.get('proxyHost').updateValueAndValidity({ emitEvent }); + this.sendEmailConfigForm.get('proxyPort').updateValueAndValidity({ emitEvent }); + } +} +SendEmailConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: SendEmailConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); +SendEmailConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: SendEmailConfigComponent, selector: "tb-action-node-send-email-config", usesInheritance: true, ngImport: i0, template: "
\n \n {{ 'tb.rulenode.use-system-smtp-settings' | translate }}\n \n
\n \n tb.rulenode.smtp-protocol\n \n \n {{ smtpProtocol.toUpperCase() }}\n \n \n \n
\n \n tb.rulenode.smtp-host\n \n \n {{ 'tb.rulenode.smtp-host-required' | translate }}\n \n \n \n tb.rulenode.smtp-port\n \n \n {{ 'tb.rulenode.smtp-port-required' | translate }}\n \n \n {{ 'tb.rulenode.smtp-port-range' | translate }}\n \n \n {{ 'tb.rulenode.smtp-port-range' | translate }}\n \n \n
\n \n tb.rulenode.timeout-msec\n \n \n {{ 'tb.rulenode.timeout-required' | translate }}\n \n \n {{ 'tb.rulenode.min-timeout-msec-message' | translate }}\n \n \n \n {{ 'tb.rulenode.enable-tls' | translate }}\n \n \n tb.rulenode.tls-version\n \n \n {{ tlsVersion }}\n \n \n \n \n {{ 'tb.rulenode.enable-proxy' | translate }}\n \n
\n
\n \n tb.rulenode.proxy-host\n \n \n {{ 'tb.rulenode.proxy-host-required' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ 'tb.rulenode.proxy-port-required' | translate }}\n \n \n {{ 'tb.rulenode.proxy-port-range' | translate }}\n \n \n
\n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
\n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n
\n
\n", components: [{ type: i3$1.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex", "aria-label", "aria-labelledby", "id", "labelPosition", "name", "required", "checked", "disabled", "indeterminate", "aria-describedby", "value"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }, { type: i4$1.MatSelect, selector: "mat-select", inputs: ["disabled", "disableRipple", "tabIndex"], exportAs: ["matSelect"] }, { type: i5.MatOption, selector: "mat-option", exportAs: ["matOption"] }, { type: i7$2.TbCheckboxComponent, selector: "tb-checkbox", inputs: ["disabled", "trueValue", "falseValue"], outputs: ["valueChange"] }, { type: i7.TogglePasswordComponent, selector: "tb-toggle-password" }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i10.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i8.DefaultLayoutGapDirective, selector: " [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]", inputs: ["fxLayoutGap", "fxLayoutGap.xs", "fxLayoutGap.sm", "fxLayoutGap.md", "fxLayoutGap.lg", "fxLayoutGap.xl", "fxLayoutGap.lt-sm", "fxLayoutGap.lt-md", "fxLayoutGap.lt-lg", "fxLayoutGap.lt-xl", "fxLayoutGap.gt-xs", "fxLayoutGap.gt-sm", "fxLayoutGap.gt-md", "fxLayoutGap.gt-lg"] }, { type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i3.MatError, selector: "mat-error", inputs: ["id"] }, { type: i2.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { type: i2.MaxValidator, selector: "input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]", inputs: ["max"] }, { type: i2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { type: i3.MatSuffix, selector: "[matSuffix]" }], pipes: { "translate": i4.TranslatePipe } }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: SendEmailConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-action-node-send-email-config', + templateUrl: './send-email-config.component.html', + styleUrls: [] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); + +class SendSmsConfigComponent extends RuleNodeConfigurationComponent { + constructor(store, fb) { + super(store); + this.store = store; + this.fb = fb; + } + configForm() { + return this.sendSmsConfigForm; + } + onConfigurationSet(configuration) { + this.sendSmsConfigForm = this.fb.group({ + numbersToTemplate: [configuration ? configuration.numbersToTemplate : null, [Validators.required]], + smsMessageTemplate: [configuration ? configuration.smsMessageTemplate : null, [Validators.required]], + useSystemSmsSettings: [configuration ? configuration.useSystemSmsSettings : false, []], + smsProviderConfiguration: [configuration ? configuration.smsProviderConfiguration : null, []], + }); + } + validatorTriggers() { + return ['useSystemSmsSettings']; + } + updateValidators(emitEvent) { + const useSystemSmsSettings = this.sendSmsConfigForm.get('useSystemSmsSettings').value; + if (useSystemSmsSettings) { + this.sendSmsConfigForm.get('smsProviderConfiguration').setValidators([]); + } + else { + this.sendSmsConfigForm.get('smsProviderConfiguration').setValidators([Validators.required]); + } + this.sendSmsConfigForm.get('smsProviderConfiguration').updateValueAndValidity({ emitEvent }); + } +} +SendSmsConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: SendSmsConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); +SendSmsConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: SendSmsConfigComponent, selector: "tb-action-node-send-sms-config", usesInheritance: true, ngImport: i0, template: "
\n \n tb.rulenode.numbers-to-template\n \n \n {{ 'tb.rulenode.numbers-to-template-required' | translate }}\n \n \n \n \n tb.rulenode.sms-message-template\n \n \n {{ 'tb.rulenode.sms-message-template-required' | translate }}\n \n \n \n \n {{ 'tb.rulenode.use-system-sms-settings' | translate }}\n \n \n \n
\n", components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }, { type: i3$1.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex", "aria-label", "aria-labelledby", "id", "labelPosition", "name", "required", "checked", "disabled", "indeterminate", "aria-describedby", "value"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { type: i5$3.SmsProviderConfigurationComponent, selector: "tb-sms-provider-configuration", inputs: ["required", "disabled"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.MatError, selector: "mat-error", inputs: ["id"] }, { type: i3.MatHint, selector: "mat-hint", inputs: ["align", "id"] }], pipes: { "translate": i4.TranslatePipe, "safeHtml": SafeHtmlPipe } }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: SendSmsConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-action-node-send-sms-config', + templateUrl: './send-sms-config.component.html', + styleUrls: [] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); + +class SnsConfigComponent extends RuleNodeConfigurationComponent { + constructor(store, fb) { + super(store); + this.store = store; + this.fb = fb; + } + configForm() { + return this.snsConfigForm; + } + onConfigurationSet(configuration) { + this.snsConfigForm = this.fb.group({ + topicArnPattern: [configuration ? configuration.topicArnPattern : null, [Validators.required]], + accessKeyId: [configuration ? configuration.accessKeyId : null, [Validators.required]], + secretAccessKey: [configuration ? configuration.secretAccessKey : null, [Validators.required]], + region: [configuration ? configuration.region : null, [Validators.required]] + }); + } +} +SnsConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: SnsConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); +SnsConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: SnsConfigComponent, selector: "tb-action-node-sns-config", usesInheritance: true, ngImport: i0, template: "
\n \n tb.rulenode.topic-arn-pattern\n \n \n {{ 'tb.rulenode.topic-arn-pattern-required' | translate }}\n \n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ 'tb.rulenode.aws-access-key-id-required' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ 'tb.rulenode.aws-secret-access-key-required' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ 'tb.rulenode.aws-region-required' | translate }}\n \n \n
\n", components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.MatError, selector: "mat-error", inputs: ["id"] }, { type: i3.MatHint, selector: "mat-hint", inputs: ["align", "id"] }], pipes: { "translate": i4.TranslatePipe, "safeHtml": SafeHtmlPipe } }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: SnsConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-action-node-sns-config', + templateUrl: './sns-config.component.html', + styleUrls: [] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); + +class SqsConfigComponent extends RuleNodeConfigurationComponent { + constructor(store, fb) { + super(store); + this.store = store; + this.fb = fb; + this.sqsQueueType = SqsQueueType; + this.sqsQueueTypes = Object.keys(SqsQueueType); + this.sqsQueueTypeTranslationsMap = sqsQueueTypeTranslations; + } + configForm() { + return this.sqsConfigForm; + } + onConfigurationSet(configuration) { + this.sqsConfigForm = this.fb.group({ + queueType: [configuration ? configuration.queueType : null, [Validators.required]], + queueUrlPattern: [configuration ? configuration.queueUrlPattern : null, [Validators.required]], + delaySeconds: [configuration ? configuration.delaySeconds : null, [Validators.min(0), Validators.max(900)]], + messageAttributes: [configuration ? configuration.messageAttributes : null, []], + accessKeyId: [configuration ? configuration.accessKeyId : null, [Validators.required]], + secretAccessKey: [configuration ? configuration.secretAccessKey : null, [Validators.required]], + region: [configuration ? configuration.region : null, [Validators.required]] + }); + } +} +SqsConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: SqsConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); +SqsConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: SqsConfigComponent, selector: "tb-action-node-sqs-config", usesInheritance: true, ngImport: i0, template: "
\n \n tb.rulenode.queue-type\n \n \n {{ sqsQueueTypeTranslationsMap.get(type) | translate }}\n \n \n \n \n tb.rulenode.queue-url-pattern\n \n \n {{ 'tb.rulenode.queue-url-pattern-required' | translate }}\n \n \n \n \n tb.rulenode.delay-seconds\n \n \n {{ 'tb.rulenode.min-delay-seconds-message' | translate }}\n \n \n {{ 'tb.rulenode.max-delay-seconds-message' | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ 'tb.rulenode.aws-access-key-id-required' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ 'tb.rulenode.aws-secret-access-key-required' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ 'tb.rulenode.aws-region-required' | translate }}\n \n \n
\n", components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }, { type: i4$1.MatSelect, selector: "mat-select", inputs: ["disabled", "disableRipple", "tabIndex"], exportAs: ["matSelect"] }, { type: i5.MatOption, selector: "mat-option", exportAs: ["matOption"] }, { type: KvMapConfigComponent, selector: "tb-kv-map-config", inputs: ["disabled", "requiredText", "keyText", "keyRequiredText", "valText", "valRequiredText", "required"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i10.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.MatError, selector: "mat-error", inputs: ["id"] }, { type: i3.MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { type: i2.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { type: i2.MaxValidator, selector: "input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]", inputs: ["max"] }, { type: i2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }], pipes: { "translate": i4.TranslatePipe, "safeHtml": SafeHtmlPipe } }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: SqsConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-action-node-sqs-config', + templateUrl: './sqs-config.component.html', + styleUrls: [] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); + +class TimeseriesConfigComponent extends RuleNodeConfigurationComponent { + constructor(store, fb) { + super(store); + this.store = store; + this.fb = fb; + } + configForm() { + return this.timeseriesConfigForm; + } + onConfigurationSet(configuration) { + this.timeseriesConfigForm = this.fb.group({ + defaultTTL: [configuration ? configuration.defaultTTL : null, [Validators.required, Validators.min(0)]] + }); + } +} +TimeseriesConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: TimeseriesConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); +TimeseriesConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: TimeseriesConfigComponent, selector: "tb-action-node-timeseries-config", usesInheritance: true, ngImport: i0, template: "
\n \n tb.rulenode.default-ttl\n \n \n {{ 'tb.rulenode.default-ttl-required' | translate }}\n \n \n {{ 'tb.rulenode.min-default-ttl-message' | translate }}\n \n \n
\n", components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i2.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { type: i2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.MatError, selector: "mat-error", inputs: ["id"] }], pipes: { "translate": i4.TranslatePipe } }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: TimeseriesConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-action-node-timeseries-config', + templateUrl: './timeseries-config.component.html', + styleUrls: [] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); + +class UnassignCustomerConfigComponent extends RuleNodeConfigurationComponent { + constructor(store, fb) { + super(store); + this.store = store; + this.fb = fb; + } + configForm() { + return this.unassignCustomerConfigForm; + } + onConfigurationSet(configuration) { + this.unassignCustomerConfigForm = this.fb.group({ + customerNamePattern: [configuration ? configuration.customerNamePattern : null, [Validators.required, Validators.pattern(/.*\S.*/)]], + customerCacheExpiration: [configuration ? configuration.customerCacheExpiration : null, [Validators.required, Validators.min(0)]] + }); + } + prepareOutputConfig(configuration) { + configuration.customerNamePattern = configuration.customerNamePattern.trim(); + return configuration; + } +} +UnassignCustomerConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: UnassignCustomerConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); +UnassignCustomerConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: UnassignCustomerConfigComponent, selector: "tb-action-node-un-assign-to-customer-config", usesInheritance: true, ngImport: i0, template: "
\n \n tb.rulenode.customer-name-pattern\n \n \n {{ 'tb.rulenode.customer-name-pattern-required' | translate }}\n \n \n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ 'tb.rulenode.customer-cache-expiration-required' | translate }}\n \n \n {{ 'tb.rulenode.customer-cache-expiration-range' | translate }}\n \n tb.rulenode.customer-cache-expiration-hint\n \n
\n", components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.MatError, selector: "mat-error", inputs: ["id"] }, { type: i3.MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { type: i2.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { type: i2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }], pipes: { "translate": i4.TranslatePipe, "safeHtml": SafeHtmlPipe } }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: UnassignCustomerConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-action-node-un-assign-to-customer-config', + templateUrl: './unassign-customer-config.component.html', + styleUrls: [] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); + +class DeviceRelationsQueryConfigComponent extends PageComponent { + constructor(store, fb) { + super(store); + this.store = store; + this.fb = fb; + this.directionTypes = Object.keys(EntitySearchDirection); + this.directionTypeTranslations = entitySearchDirectionTranslations; + this.entityType = EntityType; + this.propagateChange = null; + } + get required() { + return this.requiredValue; + } + set required(value) { + this.requiredValue = coerceBooleanProperty(value); + } + ngOnInit() { + this.deviceRelationsQueryFormGroup = this.fb.group({ + fetchLastLevelOnly: [false, []], + direction: [null, [Validators.required]], + maxLevel: [null, []], + relationType: [null], + deviceTypes: [null, [Validators.required]] + }); + this.deviceRelationsQueryFormGroup.valueChanges.subscribe((query) => { + if (this.deviceRelationsQueryFormGroup.valid) { + this.propagateChange(query); + } + else { + this.propagateChange(null); + } + }); + } + registerOnChange(fn) { + this.propagateChange = fn; + } + registerOnTouched(fn) { + } + setDisabledState(isDisabled) { + this.disabled = isDisabled; + if (this.disabled) { + this.deviceRelationsQueryFormGroup.disable({ emitEvent: false }); + } + else { + this.deviceRelationsQueryFormGroup.enable({ emitEvent: false }); + } + } + writeValue(query) { + this.deviceRelationsQueryFormGroup.reset(query, { emitEvent: false }); + } +} +DeviceRelationsQueryConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: DeviceRelationsQueryConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); +DeviceRelationsQueryConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: DeviceRelationsQueryConfigComponent, selector: "tb-device-relations-query-config", inputs: { disabled: "disabled", required: "required" }, providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => DeviceRelationsQueryConfigComponent), + multi: true + } + ], usesInheritance: true, ngImport: i0, template: "
\n \n {{ 'alias.last-level-relation' | translate }}\n \n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n
\n
relation.relation-type
\n \n \n
device.device-types
\n \n \n
\n", components: [{ type: i3$1.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex", "aria-label", "aria-labelledby", "id", "labelPosition", "name", "required", "checked", "disabled", "indeterminate", "aria-describedby", "value"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }, { type: i4$1.MatSelect, selector: "mat-select", inputs: ["disabled", "disableRipple", "tabIndex"], exportAs: ["matSelect"] }, { type: i5.MatOption, selector: "mat-option", exportAs: ["matOption"] }, { type: i7$3.RelationTypeAutocompleteComponent, selector: "tb-relation-type-autocomplete", inputs: ["required", "disabled"] }, { type: i8$2.EntitySubTypeListComponent, selector: "tb-entity-subtype-list", inputs: ["required", "disabled", "entityType"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i8.DefaultLayoutGapDirective, selector: " [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]", inputs: ["fxLayoutGap", "fxLayoutGap.xs", "fxLayoutGap.sm", "fxLayoutGap.md", "fxLayoutGap.lg", "fxLayoutGap.xl", "fxLayoutGap.lt-sm", "fxLayoutGap.lt-md", "fxLayoutGap.lt-lg", "fxLayoutGap.lt-xl", "fxLayoutGap.gt-xs", "fxLayoutGap.gt-sm", "fxLayoutGap.gt-md", "fxLayoutGap.gt-lg"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i10.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i2.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { type: i2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }], pipes: { "translate": i4.TranslatePipe } }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: DeviceRelationsQueryConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-device-relations-query-config', + templateUrl: './device-relations-query-config.component.html', + styleUrls: [], + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => DeviceRelationsQueryConfigComponent), + multi: true + } + ] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; }, propDecorators: { disabled: [{ + type: Input + }], required: [{ + type: Input + }] } }); + +class RelationsQueryConfigComponent extends PageComponent { + constructor(store, fb) { + super(store); + this.store = store; + this.fb = fb; + this.directionTypes = Object.keys(EntitySearchDirection); + this.directionTypeTranslations = entitySearchDirectionTranslations; + this.propagateChange = null; + } + get required() { + return this.requiredValue; + } + set required(value) { + this.requiredValue = coerceBooleanProperty(value); + } + ngOnInit() { + this.relationsQueryFormGroup = this.fb.group({ + fetchLastLevelOnly: [false, []], + direction: [null, [Validators.required]], + maxLevel: [null, []], + filters: [null] + }); + this.relationsQueryFormGroup.valueChanges.subscribe((query) => { + if (this.relationsQueryFormGroup.valid) { + this.propagateChange(query); + } + else { + this.propagateChange(null); + } + }); + } + registerOnChange(fn) { + this.propagateChange = fn; + } + registerOnTouched(fn) { + } + setDisabledState(isDisabled) { + this.disabled = isDisabled; + if (this.disabled) { + this.relationsQueryFormGroup.disable({ emitEvent: false }); + } + else { + this.relationsQueryFormGroup.enable({ emitEvent: false }); + } + } + writeValue(query) { + this.relationsQueryFormGroup.reset(query || {}, { emitEvent: false }); + } +} +RelationsQueryConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RelationsQueryConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); +RelationsQueryConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: RelationsQueryConfigComponent, selector: "tb-relations-query-config", inputs: { disabled: "disabled", required: "required" }, providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => RelationsQueryConfigComponent), + multi: true + } + ], usesInheritance: true, ngImport: i0, template: "
\n \n {{ 'alias.last-level-relation' | translate }}\n \n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n
\n
relation.relation-filters
\n \n
\n", components: [{ type: i3$1.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex", "aria-label", "aria-labelledby", "id", "labelPosition", "name", "required", "checked", "disabled", "indeterminate", "aria-describedby", "value"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }, { type: i4$1.MatSelect, selector: "mat-select", inputs: ["disabled", "disableRipple", "tabIndex"], exportAs: ["matSelect"] }, { type: i5.MatOption, selector: "mat-option", exportAs: ["matOption"] }, { type: i7$4.RelationFiltersComponent, selector: "tb-relation-filters", inputs: ["disabled", "allowedEntityTypes"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i8.DefaultLayoutGapDirective, selector: " [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]", inputs: ["fxLayoutGap", "fxLayoutGap.xs", "fxLayoutGap.sm", "fxLayoutGap.md", "fxLayoutGap.lg", "fxLayoutGap.xl", "fxLayoutGap.lt-sm", "fxLayoutGap.lt-md", "fxLayoutGap.lt-lg", "fxLayoutGap.lt-xl", "fxLayoutGap.gt-xs", "fxLayoutGap.gt-sm", "fxLayoutGap.gt-md", "fxLayoutGap.gt-lg"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i10.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i2.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { type: i2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }], pipes: { "translate": i4.TranslatePipe } }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RelationsQueryConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-relations-query-config', + templateUrl: './relations-query-config.component.html', + styleUrls: [], + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => RelationsQueryConfigComponent), + multi: true + } + ] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; }, propDecorators: { disabled: [{ + type: Input + }], required: [{ + type: Input + }] } }); + +class MessageTypesConfigComponent extends PageComponent { + constructor(store, translate, truncate, fb) { + super(store); + this.store = store; + this.translate = translate; + this.truncate = truncate; + this.fb = fb; + this.placeholder = 'tb.rulenode.message-type'; + this.separatorKeysCodes = [ENTER, COMMA, SEMICOLON]; + this.messageTypes = []; + this.messageTypesList = []; + this.searchText = ''; + this.propagateChange = (v) => { }; + this.messageTypeConfigForm = this.fb.group({ + messageType: [null] + }); + for (const type of Object.keys(MessageType)) { + this.messageTypesList.push({ + name: messageTypeNames.get(MessageType[type]), + value: type + }); + } + } + get required() { + return this.requiredValue; + } + set required(value) { + this.requiredValue = coerceBooleanProperty(value); + } + registerOnChange(fn) { + this.propagateChange = fn; + } + registerOnTouched(fn) { + } + ngOnInit() { + this.filteredMessageTypes = this.messageTypeConfigForm.get('messageType').valueChanges + .pipe(startWith(''), map((value) => value ? value : ''), mergeMap(name => this.fetchMessageTypes(name)), share()); + } + ngAfterViewInit() { } + setDisabledState(isDisabled) { + this.disabled = isDisabled; + if (this.disabled) { + this.messageTypeConfigForm.disable({ emitEvent: false }); + } + else { + this.messageTypeConfigForm.enable({ emitEvent: false }); + } + } + writeValue(value) { + this.searchText = ''; + this.messageTypes.length = 0; + if (value) { + value.forEach((type) => { + const found = this.messageTypesList.find((messageType => messageType.value === type)); + if (found) { + this.messageTypes.push({ + name: found.name, + value: found.value + }); + } + else { + this.messageTypes.push({ + name: type, + value: type + }); + } + }); + } + } + displayMessageTypeFn(messageType) { + return messageType ? messageType.name : undefined; + } + textIsNotEmpty(text) { + return (text && text != null && text.length > 0) ? true : false; + } + createMessageType($event, value) { + $event.preventDefault(); + this.transformMessageType(value); + } + add(event) { + this.transformMessageType(event.value); + } + fetchMessageTypes(searchText) { + this.searchText = searchText; + if (this.searchText && this.searchText.length) { + const search = this.searchText.toUpperCase(); + return of(this.messageTypesList.filter(messageType => messageType.name.toUpperCase().includes(search))); + } + else { + return of(this.messageTypesList); + } + } + transformMessageType(value) { + if ((value || '').trim()) { + let newMessageType = null; + const messageTypeName = value.trim(); + const existingMessageType = this.messageTypesList.find(messageType => messageType.name === messageTypeName); + if (existingMessageType) { + newMessageType = { + name: existingMessageType.name, + value: existingMessageType.value + }; + } + else { + newMessageType = { + name: messageTypeName, + value: messageTypeName + }; + } + if (newMessageType) { + this.addMessageType(newMessageType); + } + } + this.clear(''); + } + remove(messageType) { + const index = this.messageTypes.indexOf(messageType); + if (index >= 0) { + this.messageTypes.splice(index, 1); + this.updateModel(); + } + } + selected(event) { + this.addMessageType(event.option.value); + this.clear(''); + } + addMessageType(messageType) { + const index = this.messageTypes.findIndex(existingMessageType => existingMessageType.value === messageType.value); + if (index === -1) { + this.messageTypes.push(messageType); + this.updateModel(); + } + } + onFocus() { + this.messageTypeConfigForm.get('messageType').updateValueAndValidity({ onlySelf: true, emitEvent: true }); + } + clear(value = '') { + this.messageTypeInput.nativeElement.value = value; + this.messageTypeConfigForm.get('messageType').patchValue(null, { emitEvent: true }); + setTimeout(() => { + this.messageTypeInput.nativeElement.blur(); + this.messageTypeInput.nativeElement.focus(); + }, 0); + } + updateModel() { + const value = this.messageTypes.map((messageType => messageType.value)); + if (this.required) { + this.chipList.errorState = !value.length; + this.propagateChange(value.length > 0 ? value : null); + } + else { + this.chipList.errorState = false; + this.propagateChange(value); + } + } +} +MessageTypesConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: MessageTypesConfigComponent, deps: [{ token: i1.Store }, { token: i4.TranslateService }, { token: i3$4.TruncatePipe }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); +MessageTypesConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: MessageTypesConfigComponent, selector: "tb-message-types-config", inputs: { required: "required", label: "label", placeholder: "placeholder", disabled: "disabled" }, providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => MessageTypesConfigComponent), + multi: true + } + ], viewQueries: [{ propertyName: "chipList", first: true, predicate: ["chipList"], descendants: true }, { propertyName: "matAutocomplete", first: true, predicate: ["messageTypeAutocomplete"], descendants: true }, { propertyName: "messageTypeInput", first: true, predicate: ["messageTypeInput"], descendants: true }], usesInheritance: true, ngImport: i0, template: "\n {{ label }}\n \n \n {{messageType.name}}\n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-message-types-found\n
\n \n \n {{ translate.get('tb.rulenode.no-message-type-matching',\n {messageType: truncate.transform(searchText, true, 6, '...')}) | async }}\n \n \n \n tb.rulenode.create-new-message-type\n \n
\n
\n
\n \n {{ 'tb.rulenode.message-types-required' | translate }}\n \n
\n", components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }, { type: i5$2.MatChipList, selector: "mat-chip-list", inputs: ["aria-orientation", "multiple", "compareWith", "value", "required", "placeholder", "disabled", "selectable", "tabIndex", "errorStateMatcher"], outputs: ["change", "valueChange"], exportAs: ["matChipList"] }, { type: i6$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { type: i7$5.MatAutocomplete, selector: "mat-autocomplete", inputs: ["disableRipple"], exportAs: ["matAutocomplete"] }, { type: i5.MatOption, selector: "mat-option", exportAs: ["matOption"] }], directives: [{ type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i10.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i5$2.MatChip, selector: "mat-basic-chip, [mat-basic-chip], mat-chip, [mat-chip]", inputs: ["color", "disableRipple", "tabIndex", "selected", "value", "selectable", "disabled", "removable"], outputs: ["selectionChange", "destroyed", "removed"], exportAs: ["matChip"] }, { type: i5$2.MatChipRemove, selector: "[matChipRemove]" }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i7$5.MatAutocompleteTrigger, selector: "input[matAutocomplete], textarea[matAutocomplete]", exportAs: ["matAutocompleteTrigger"] }, { type: i5$2.MatChipInput, selector: "input[matChipInputFor]", inputs: ["matChipInputSeparatorKeyCodes", "placeholder", "id", "matChipInputFor", "matChipInputAddOnBlur", "disabled"], outputs: ["matChipInputTokenEnd"], exportAs: ["matChipInput", "matChipInputFor"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i7$5.MatAutocompleteOrigin, selector: "[matAutocompleteOrigin]", exportAs: ["matAutocompleteOrigin"] }, { type: i3.MatError, selector: "mat-error", inputs: ["id"] }], pipes: { "translate": i4.TranslatePipe, "async": i10.AsyncPipe, "highlight": i12$1.HighlightPipe } }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: MessageTypesConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-message-types-config', + templateUrl: './message-types-config.component.html', + styleUrls: [], + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => MessageTypesConfigComponent), + multi: true + } + ] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i4.TranslateService }, { type: i3$4.TruncatePipe }, { type: i2.FormBuilder }]; }, propDecorators: { required: [{ + type: Input + }], label: [{ + type: Input + }], placeholder: [{ + type: Input + }], disabled: [{ + type: Input + }], chipList: [{ + type: ViewChild, + args: ['chipList', { static: false }] + }], matAutocomplete: [{ + type: ViewChild, + args: ['messageTypeAutocomplete', { static: false }] + }], messageTypeInput: [{ + type: ViewChild, + args: ['messageTypeInput', { static: false }] + }] } }); + +class RulenodeCoreConfigCommonModule { +} +RulenodeCoreConfigCommonModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RulenodeCoreConfigCommonModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); +RulenodeCoreConfigCommonModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RulenodeCoreConfigCommonModule, declarations: [KvMapConfigComponent, + DeviceRelationsQueryConfigComponent, + RelationsQueryConfigComponent, + MessageTypesConfigComponent, + CredentialsConfigComponent, + SafeHtmlPipe], imports: [CommonModule, + SharedModule, + HomeComponentsModule], exports: [KvMapConfigComponent, + DeviceRelationsQueryConfigComponent, + RelationsQueryConfigComponent, + MessageTypesConfigComponent, + CredentialsConfigComponent, + SafeHtmlPipe] }); +RulenodeCoreConfigCommonModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RulenodeCoreConfigCommonModule, imports: [[ + CommonModule, + SharedModule, + HomeComponentsModule + ]] }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RulenodeCoreConfigCommonModule, decorators: [{ + type: NgModule, + args: [{ + declarations: [ + KvMapConfigComponent, + DeviceRelationsQueryConfigComponent, + RelationsQueryConfigComponent, + MessageTypesConfigComponent, + CredentialsConfigComponent, + SafeHtmlPipe + ], + imports: [ + CommonModule, + SharedModule, + HomeComponentsModule + ], + exports: [ + KvMapConfigComponent, + DeviceRelationsQueryConfigComponent, + RelationsQueryConfigComponent, + MessageTypesConfigComponent, + CredentialsConfigComponent, + SafeHtmlPipe + ] + }] + }] }); + +class RuleNodeCoreConfigActionModule { +} +RuleNodeCoreConfigActionModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RuleNodeCoreConfigActionModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); +RuleNodeCoreConfigActionModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RuleNodeCoreConfigActionModule, declarations: [AttributesConfigComponent, + TimeseriesConfigComponent, + RpcRequestConfigComponent, + LogConfigComponent, + AssignCustomerConfigComponent, + ClearAlarmConfigComponent, + CreateAlarmConfigComponent, + CreateRelationConfigComponent, + MsgDelayConfigComponent, + DeleteRelationConfigComponent, + GeneratorConfigComponent, + GpsGeoActionConfigComponent, + MsgCountConfigComponent, + RpcReplyConfigComponent, + SaveToCustomTableConfigComponent, + UnassignCustomerConfigComponent, + SnsConfigComponent, + SqsConfigComponent, + PubSubConfigComponent, + KafkaConfigComponent, + MqttConfigComponent, + RabbitMqConfigComponent, + RestApiCallConfigComponent, + SendEmailConfigComponent, + CheckPointConfigComponent, + AzureIotHubConfigComponent, + DeviceProfileConfigComponent, + SendSmsConfigComponent, + PushToEdgeConfigComponent, + PushToCloudConfigComponent], imports: [CommonModule, + SharedModule, + HomeComponentsModule, + RulenodeCoreConfigCommonModule], exports: [AttributesConfigComponent, + TimeseriesConfigComponent, + RpcRequestConfigComponent, + LogConfigComponent, + AssignCustomerConfigComponent, + ClearAlarmConfigComponent, + CreateAlarmConfigComponent, + CreateRelationConfigComponent, + MsgDelayConfigComponent, + DeleteRelationConfigComponent, + GeneratorConfigComponent, + GpsGeoActionConfigComponent, + MsgCountConfigComponent, + RpcReplyConfigComponent, + SaveToCustomTableConfigComponent, + UnassignCustomerConfigComponent, + SnsConfigComponent, + SqsConfigComponent, + PubSubConfigComponent, + KafkaConfigComponent, + MqttConfigComponent, + RabbitMqConfigComponent, + RestApiCallConfigComponent, + SendEmailConfigComponent, + CheckPointConfigComponent, + AzureIotHubConfigComponent, + DeviceProfileConfigComponent, + SendSmsConfigComponent, + PushToEdgeConfigComponent, + PushToCloudConfigComponent] }); +RuleNodeCoreConfigActionModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RuleNodeCoreConfigActionModule, imports: [[ + CommonModule, + SharedModule, + HomeComponentsModule, + RulenodeCoreConfigCommonModule + ]] }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RuleNodeCoreConfigActionModule, decorators: [{ + type: NgModule, + args: [{ + declarations: [ + AttributesConfigComponent, + TimeseriesConfigComponent, + RpcRequestConfigComponent, + LogConfigComponent, + AssignCustomerConfigComponent, + ClearAlarmConfigComponent, + CreateAlarmConfigComponent, + CreateRelationConfigComponent, + MsgDelayConfigComponent, + DeleteRelationConfigComponent, + GeneratorConfigComponent, + GpsGeoActionConfigComponent, + MsgCountConfigComponent, + RpcReplyConfigComponent, + SaveToCustomTableConfigComponent, + UnassignCustomerConfigComponent, + SnsConfigComponent, + SqsConfigComponent, + PubSubConfigComponent, + KafkaConfigComponent, + MqttConfigComponent, + RabbitMqConfigComponent, + RestApiCallConfigComponent, + SendEmailConfigComponent, + CheckPointConfigComponent, + AzureIotHubConfigComponent, + DeviceProfileConfigComponent, + SendSmsConfigComponent, + PushToEdgeConfigComponent, + PushToCloudConfigComponent + ], + imports: [ + CommonModule, + SharedModule, + HomeComponentsModule, + RulenodeCoreConfigCommonModule + ], + exports: [ + AttributesConfigComponent, + TimeseriesConfigComponent, + RpcRequestConfigComponent, + LogConfigComponent, + AssignCustomerConfigComponent, + ClearAlarmConfigComponent, + CreateAlarmConfigComponent, + CreateRelationConfigComponent, + MsgDelayConfigComponent, + DeleteRelationConfigComponent, + GeneratorConfigComponent, + GpsGeoActionConfigComponent, + MsgCountConfigComponent, + RpcReplyConfigComponent, + SaveToCustomTableConfigComponent, + UnassignCustomerConfigComponent, + SnsConfigComponent, + SqsConfigComponent, + PubSubConfigComponent, + KafkaConfigComponent, + MqttConfigComponent, + RabbitMqConfigComponent, + RestApiCallConfigComponent, + SendEmailConfigComponent, + CheckPointConfigComponent, + AzureIotHubConfigComponent, + DeviceProfileConfigComponent, + SendSmsConfigComponent, + PushToEdgeConfigComponent, + PushToCloudConfigComponent + ] + }] + }] }); + +class CalculateDeltaConfigComponent extends RuleNodeConfigurationComponent { + constructor(store, fb) { + super(store); + this.store = store; + this.fb = fb; + this.separatorKeysCodes = [ENTER, COMMA, SEMICOLON]; + } + configForm() { + return this.calculateDeltaConfigForm; + } + onConfigurationSet(configuration) { + this.calculateDeltaConfigForm = this.fb.group({ + inputValueKey: [configuration ? configuration.inputValueKey : null, [Validators.required]], + outputValueKey: [configuration ? configuration.outputValueKey : null, [Validators.required]], + useCache: [configuration ? configuration.useCache : null, []], + addPeriodBetweenMsgs: [configuration ? configuration.addPeriodBetweenMsgs : false, []], + periodValueKey: [configuration ? configuration.periodValueKey : null, []], + round: [configuration ? configuration.round : null, [Validators.min(0), Validators.max(15)]], + tellFailureIfDeltaIsNegative: [configuration ? configuration.tellFailureIfDeltaIsNegative : null, []] + }); + } + updateValidators(emitEvent) { + const addPeriodBetweenMsgs = this.calculateDeltaConfigForm.get('addPeriodBetweenMsgs').value; + if (addPeriodBetweenMsgs) { + this.calculateDeltaConfigForm.get('periodValueKey').setValidators([Validators.required]); + } + else { + this.calculateDeltaConfigForm.get('periodValueKey').setValidators([]); + } + this.calculateDeltaConfigForm.get('periodValueKey').updateValueAndValidity({ emitEvent }); + } + validatorTriggers() { + return ['addPeriodBetweenMsgs']; + } +} +CalculateDeltaConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: CalculateDeltaConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); +CalculateDeltaConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: CalculateDeltaConfigComponent, selector: "tb-enrichment-node-calculate-delta-config", usesInheritance: true, ngImport: i0, template: "
\n
\n \n tb.rulenode.input-value-key\n \n \n {{ 'tb.rulenode.input-value-key-required' | translate }}\n \n \n \n tb.rulenode.output-value-key\n \n \n {{ 'tb.rulenode.output-value-key-required' | translate }}\n \n \n \n tb.rulenode.round\n \n \n {{ 'tb.rulenode.round-range' | translate }}\n \n \n {{ 'tb.rulenode.round-range' | translate }}\n \n \n
\n \n {{ 'tb.rulenode.use-cache' | translate }}\n \n \n {{ 'tb.rulenode.tell-failure-if-delta-is-negative' | translate }}\n \n \n {{ 'tb.rulenode.add-period-between-msgs' | translate }}\n \n \n tb.rulenode.period-value-key\n \n \n {{ 'tb.rulenode.period-value-key-required' | translate }}\n \n \n
\n", components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }, { type: i3$1.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex", "aria-label", "aria-labelledby", "id", "labelPosition", "name", "required", "checked", "disabled", "indeterminate", "aria-describedby", "value"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i8.DefaultLayoutGapDirective, selector: " [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]", inputs: ["fxLayoutGap", "fxLayoutGap.xs", "fxLayoutGap.sm", "fxLayoutGap.md", "fxLayoutGap.lg", "fxLayoutGap.xl", "fxLayoutGap.lt-sm", "fxLayoutGap.lt-md", "fxLayoutGap.lt-lg", "fxLayoutGap.lt-xl", "fxLayoutGap.gt-xs", "fxLayoutGap.gt-sm", "fxLayoutGap.gt-md", "fxLayoutGap.gt-lg"] }, { type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.MatError, selector: "mat-error", inputs: ["id"] }, { type: i2.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { type: i2.MaxValidator, selector: "input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]", inputs: ["max"] }, { type: i2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }], pipes: { "translate": i4.TranslatePipe } }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: CalculateDeltaConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-enrichment-node-calculate-delta-config', + templateUrl: './calculate-delta-config.component.html', + styleUrls: [] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); + +class CustomerAttributesConfigComponent extends RuleNodeConfigurationComponent { + constructor(store, fb) { + super(store); + this.store = store; + this.fb = fb; + } + configForm() { + return this.customerAttributesConfigForm; + } + onConfigurationSet(configuration) { + this.customerAttributesConfigForm = this.fb.group({ + telemetry: [configuration ? configuration.telemetry : false, []], + attrMapping: [configuration ? configuration.attrMapping : null, [Validators.required]] + }); + } +} +CustomerAttributesConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: CustomerAttributesConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); +CustomerAttributesConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: CustomerAttributesConfigComponent, selector: "tb-enrichment-node-customer-attributes-config", usesInheritance: true, ngImport: i0, template: "
\n \n \n {{ 'tb.rulenode.latest-telemetry' | translate }}\n \n \n \n
\n", components: [{ type: i3$1.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex", "aria-label", "aria-labelledby", "id", "labelPosition", "name", "required", "checked", "disabled", "indeterminate", "aria-describedby", "value"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { type: KvMapConfigComponent, selector: "tb-kv-map-config", inputs: ["disabled", "requiredText", "keyText", "keyRequiredText", "valText", "valRequiredText", "required"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }], pipes: { "translate": i4.TranslatePipe } }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: CustomerAttributesConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-enrichment-node-customer-attributes-config', + templateUrl: './customer-attributes-config.component.html', + styleUrls: [] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); + +class DeviceAttributesConfigComponent extends RuleNodeConfigurationComponent { + constructor(store, fb) { + super(store); + this.store = store; + this.fb = fb; + this.separatorKeysCodes = [ENTER, COMMA, SEMICOLON]; + } + configForm() { + return this.deviceAttributesConfigForm; + } + onConfigurationSet(configuration) { + this.deviceAttributesConfigForm = this.fb.group({ + deviceRelationsQuery: [configuration ? configuration.deviceRelationsQuery : null, [Validators.required]], + tellFailureIfAbsent: [configuration ? configuration.tellFailureIfAbsent : false, []], + clientAttributeNames: [configuration ? configuration.clientAttributeNames : null, []], + sharedAttributeNames: [configuration ? configuration.sharedAttributeNames : null, []], + serverAttributeNames: [configuration ? configuration.serverAttributeNames : null, []], + latestTsKeyNames: [configuration ? configuration.latestTsKeyNames : null, []], + getLatestValueWithTs: [configuration ? configuration.getLatestValueWithTs : false, []] + }); + } + removeKey(key, keysField) { + const keys = this.deviceAttributesConfigForm.get(keysField).value; + const index = keys.indexOf(key); + if (index >= 0) { + keys.splice(index, 1); + this.deviceAttributesConfigForm.get(keysField).setValue(keys, { emitEvent: true }); + } + } + addKey(event, keysField) { + const input = event.input; + let value = event.value; + if ((value || '').trim()) { + value = value.trim(); + let keys = this.deviceAttributesConfigForm.get(keysField).value; + if (!keys || keys.indexOf(value) === -1) { + if (!keys) { + keys = []; + } + keys.push(value); + this.deviceAttributesConfigForm.get(keysField).setValue(keys, { emitEvent: true }); + } + } + if (input) { + input.value = ''; + } + } +} +DeviceAttributesConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: DeviceAttributesConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); +DeviceAttributesConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: DeviceAttributesConfigComponent, selector: "tb-enrichment-node-device-attributes-config", usesInheritance: true, ngImport: i0, template: "
\n \n \n \n \n {{ 'tb.rulenode.tell-failure-if-absent' | translate }}\n \n
tb.rulenode.tell-failure-if-absent-hint
\n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n {{ 'tb.rulenode.get-latest-value-with-ts' | translate }}\n \n
\n
\n", styles: [":host label.tb-title{margin-bottom:-10px}\n"], components: [{ type: DeviceRelationsQueryConfigComponent, selector: "tb-device-relations-query-config", inputs: ["disabled", "required"] }, { type: i3$1.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex", "aria-label", "aria-labelledby", "id", "labelPosition", "name", "required", "checked", "disabled", "indeterminate", "aria-describedby", "value"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }, { type: i5$2.MatChipList, selector: "mat-chip-list", inputs: ["aria-orientation", "multiple", "compareWith", "value", "required", "placeholder", "disabled", "selectable", "tabIndex", "errorStateMatcher"], outputs: ["change", "valueChange"], exportAs: ["matChipList"] }, { type: i6$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i10.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i5$2.MatChip, selector: "mat-basic-chip, [mat-basic-chip], mat-chip, [mat-chip]", inputs: ["color", "disableRipple", "tabIndex", "selected", "value", "selectable", "disabled", "removable"], outputs: ["selectionChange", "destroyed", "removed"], exportAs: ["matChip"] }, { type: i5$2.MatChipRemove, selector: "[matChipRemove]" }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i5$2.MatChipInput, selector: "input[matChipInputFor]", inputs: ["matChipInputSeparatorKeyCodes", "placeholder", "id", "matChipInputFor", "matChipInputAddOnBlur", "disabled"], outputs: ["matChipInputTokenEnd"], exportAs: ["matChipInput", "matChipInputFor"] }], pipes: { "translate": i4.TranslatePipe, "safeHtml": SafeHtmlPipe } }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: DeviceAttributesConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-enrichment-node-device-attributes-config', + templateUrl: './device-attributes-config.component.html', + styleUrls: ['./device-attributes-config.component.scss'] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); + +class EntityDetailsConfigComponent extends RuleNodeConfigurationComponent { + constructor(store, translate, fb) { + super(store); + this.store = store; + this.translate = translate; + this.fb = fb; + this.entityDetailsTranslationsMap = entityDetailsTranslations; + this.entityDetailsList = []; + this.searchText = ''; + this.displayDetailsFn = this.displayDetails.bind(this); + for (const field of Object.keys(EntityDetailsField)) { + this.entityDetailsList.push(EntityDetailsField[field]); + } + this.detailsFormControl = new FormControl(''); + this.filteredEntityDetails = this.detailsFormControl.valueChanges + .pipe(startWith(''), map((value) => value ? value : ''), mergeMap(name => this.fetchEntityDetails(name)), share()); + } + ngOnInit() { + super.ngOnInit(); + } + configForm() { + return this.entityDetailsConfigForm; + } + prepareInputConfig(configuration) { + this.searchText = ''; + this.detailsFormControl.patchValue('', { emitEvent: true }); + return configuration; + } + onConfigurationSet(configuration) { + this.entityDetailsConfigForm = this.fb.group({ + detailsList: [configuration ? configuration.detailsList : null, [Validators.required]], + addToMetadata: [configuration ? configuration.addToMetadata : false, []] + }); + } + displayDetails(details) { + return details ? this.translate.instant(entityDetailsTranslations.get(details)) : undefined; + } + fetchEntityDetails(searchText) { + this.searchText = searchText; + if (this.searchText && this.searchText.length) { + const search = this.searchText.toUpperCase(); + return of(this.entityDetailsList.filter(field => this.translate.instant(entityDetailsTranslations.get(EntityDetailsField[field])).toUpperCase().includes(search))); + } + else { + return of(this.entityDetailsList); + } + } + detailsFieldSelected(event) { + this.addDetailsField(event.option.value); + this.clear(''); + } + removeDetailsField(details) { + const detailsList = this.entityDetailsConfigForm.get('detailsList').value; + if (detailsList) { + const index = detailsList.indexOf(details); + if (index >= 0) { + detailsList.splice(index, 1); + this.entityDetailsConfigForm.get('detailsList').setValue(detailsList); + } + } + } + addDetailsField(details) { + let detailsList = this.entityDetailsConfigForm.get('detailsList').value; + if (!detailsList) { + detailsList = []; + } + const index = detailsList.indexOf(details); + if (index === -1) { + detailsList.push(details); + this.entityDetailsConfigForm.get('detailsList').setValue(detailsList); + } + } + onEntityDetailsInputFocus() { + this.detailsFormControl.updateValueAndValidity({ onlySelf: true, emitEvent: true }); + } + clear(value = '') { + this.detailsInput.nativeElement.value = value; + this.detailsFormControl.patchValue(null, { emitEvent: true }); + setTimeout(() => { + this.detailsInput.nativeElement.blur(); + this.detailsInput.nativeElement.focus(); + }, 0); + } +} +EntityDetailsConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: EntityDetailsConfigComponent, deps: [{ token: i1.Store }, { token: i4.TranslateService }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); +EntityDetailsConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: EntityDetailsConfigComponent, selector: "tb-enrichment-node-entity-details-config", viewQueries: [{ propertyName: "detailsInput", first: true, predicate: ["detailsInput"], descendants: true }], usesInheritance: true, ngImport: i0, template: "
\n \n tb.rulenode.entity-details\n \n \n \n {{entityDetailsTranslationsMap.get(details) | translate}}\n \n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-entity-details-matching\n
\n
\n
\n
\n
\n \n \n {{ 'tb.rulenode.add-to-metadata' | translate }}\n \n
tb.rulenode.add-to-metadata-hint
\n
\n", styles: [":host ::ng-deep mat-form-field.entity-fields-list .mat-form-field-wrapper{margin-bottom:-1.25em}\n"], components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }, { type: i5$2.MatChipList, selector: "mat-chip-list", inputs: ["aria-orientation", "multiple", "compareWith", "value", "required", "placeholder", "disabled", "selectable", "tabIndex", "errorStateMatcher"], outputs: ["change", "valueChange"], exportAs: ["matChipList"] }, { type: i6$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { type: i7$5.MatAutocomplete, selector: "mat-autocomplete", inputs: ["disableRipple"], exportAs: ["matAutocomplete"] }, { type: i5.MatOption, selector: "mat-option", exportAs: ["matOption"] }, { type: i9.TbErrorComponent, selector: "tb-error", inputs: ["error"] }, { type: i3$1.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex", "aria-label", "aria-labelledby", "id", "labelPosition", "name", "required", "checked", "disabled", "indeterminate", "aria-describedby", "value"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i10.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i5$2.MatChip, selector: "mat-basic-chip, [mat-basic-chip], mat-chip, [mat-chip]", inputs: ["color", "disableRipple", "tabIndex", "selected", "value", "selectable", "disabled", "removable"], outputs: ["selectionChange", "destroyed", "removed"], exportAs: ["matChip"] }, { type: i5$2.MatChipRemove, selector: "[matChipRemove]" }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i7$5.MatAutocompleteTrigger, selector: "input[matAutocomplete], textarea[matAutocomplete]", exportAs: ["matAutocompleteTrigger"] }, { type: i5$2.MatChipInput, selector: "input[matChipInputFor]", inputs: ["matChipInputSeparatorKeyCodes", "placeholder", "id", "matChipInputFor", "matChipInputAddOnBlur", "disabled"], outputs: ["matChipInputTokenEnd"], exportAs: ["matChipInput", "matChipInputFor"] }, { type: i7$5.MatAutocompleteOrigin, selector: "[matAutocompleteOrigin]", exportAs: ["matAutocompleteOrigin"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlDirective, selector: "[formControl]", inputs: ["disabled", "formControl", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }], pipes: { "translate": i4.TranslatePipe, "async": i10.AsyncPipe, "highlight": i12$1.HighlightPipe } }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: EntityDetailsConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-enrichment-node-entity-details-config', + templateUrl: './entity-details-config.component.html', + styleUrls: ['./entity-details-config.component.scss'] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i4.TranslateService }, { type: i2.FormBuilder }]; }, propDecorators: { detailsInput: [{ + type: ViewChild, + args: ['detailsInput', { static: false }] + }] } }); + +class GetTelemetryFromDatabaseConfigComponent extends RuleNodeConfigurationComponent { + constructor(store, fb) { + super(store); + this.store = store; + this.fb = fb; + this.separatorKeysCodes = [ENTER, COMMA, SEMICOLON]; + this.aggregationTypes = AggregationType; + this.aggregations = Object.keys(AggregationType); + this.aggregationTypesTranslations = aggregationTranslations; + this.fetchMode = FetchMode; + this.fetchModes = Object.keys(FetchMode); + this.samplingOrders = Object.keys(SamplingOrder); + this.timeUnits = Object.values(TimeUnit); + this.timeUnitsTranslationMap = timeUnitTranslations; + } + configForm() { + return this.getTelemetryFromDatabaseConfigForm; + } + onConfigurationSet(configuration) { + this.getTelemetryFromDatabaseConfigForm = this.fb.group({ + latestTsKeyNames: [configuration ? configuration.latestTsKeyNames : null, []], + aggregation: [configuration ? configuration.aggregation : null, [Validators.required]], + fetchMode: [configuration ? configuration.fetchMode : null, [Validators.required]], + orderBy: [configuration ? configuration.orderBy : null, []], + limit: [configuration ? configuration.limit : null, []], + useMetadataIntervalPatterns: [configuration ? configuration.useMetadataIntervalPatterns : false, []], + startInterval: [configuration ? configuration.startInterval : null, []], + startIntervalTimeUnit: [configuration ? configuration.startIntervalTimeUnit : null, []], + endInterval: [configuration ? configuration.endInterval : null, []], + endIntervalTimeUnit: [configuration ? configuration.endIntervalTimeUnit : null, []], + startIntervalPattern: [configuration ? configuration.startIntervalPattern : null, []], + endIntervalPattern: [configuration ? configuration.endIntervalPattern : null, []], + }); + } + validatorTriggers() { + return ['fetchMode', 'useMetadataIntervalPatterns']; + } + updateValidators(emitEvent) { + const fetchMode = this.getTelemetryFromDatabaseConfigForm.get('fetchMode').value; + const useMetadataIntervalPatterns = this.getTelemetryFromDatabaseConfigForm.get('useMetadataIntervalPatterns').value; + if (fetchMode && fetchMode === FetchMode.ALL) { + this.getTelemetryFromDatabaseConfigForm.get('aggregation').setValidators([Validators.required]); + this.getTelemetryFromDatabaseConfigForm.get('orderBy').setValidators([Validators.required]); + this.getTelemetryFromDatabaseConfigForm.get('limit').setValidators([Validators.required, Validators.min(2), Validators.max(1000)]); + } + else { + this.getTelemetryFromDatabaseConfigForm.get('aggregation').setValidators([]); + this.getTelemetryFromDatabaseConfigForm.get('orderBy').setValidators([]); + this.getTelemetryFromDatabaseConfigForm.get('limit').setValidators([]); + } + if (useMetadataIntervalPatterns) { + this.getTelemetryFromDatabaseConfigForm.get('startInterval').setValidators([]); + this.getTelemetryFromDatabaseConfigForm.get('startIntervalTimeUnit').setValidators([]); + this.getTelemetryFromDatabaseConfigForm.get('endInterval').setValidators([]); + this.getTelemetryFromDatabaseConfigForm.get('endIntervalTimeUnit').setValidators([]); + this.getTelemetryFromDatabaseConfigForm.get('startIntervalPattern').setValidators([Validators.required]); + this.getTelemetryFromDatabaseConfigForm.get('endIntervalPattern').setValidators([Validators.required]); + } + else { + this.getTelemetryFromDatabaseConfigForm.get('startInterval').setValidators([Validators.required, + Validators.min(1), Validators.max(2147483647)]); + this.getTelemetryFromDatabaseConfigForm.get('startIntervalTimeUnit').setValidators([Validators.required]); + this.getTelemetryFromDatabaseConfigForm.get('endInterval').setValidators([Validators.required, + Validators.min(1), Validators.max(2147483647)]); + this.getTelemetryFromDatabaseConfigForm.get('endIntervalTimeUnit').setValidators([Validators.required]); + this.getTelemetryFromDatabaseConfigForm.get('startIntervalPattern').setValidators([]); + this.getTelemetryFromDatabaseConfigForm.get('endIntervalPattern').setValidators([]); + } + this.getTelemetryFromDatabaseConfigForm.get('aggregation').updateValueAndValidity({ emitEvent }); + this.getTelemetryFromDatabaseConfigForm.get('orderBy').updateValueAndValidity({ emitEvent }); + this.getTelemetryFromDatabaseConfigForm.get('limit').updateValueAndValidity({ emitEvent }); + this.getTelemetryFromDatabaseConfigForm.get('startInterval').updateValueAndValidity({ emitEvent }); + this.getTelemetryFromDatabaseConfigForm.get('startIntervalTimeUnit').updateValueAndValidity({ emitEvent }); + this.getTelemetryFromDatabaseConfigForm.get('endInterval').updateValueAndValidity({ emitEvent }); + this.getTelemetryFromDatabaseConfigForm.get('endIntervalTimeUnit').updateValueAndValidity({ emitEvent }); + this.getTelemetryFromDatabaseConfigForm.get('startIntervalPattern').updateValueAndValidity({ emitEvent }); + this.getTelemetryFromDatabaseConfigForm.get('endIntervalPattern').updateValueAndValidity({ emitEvent }); + } + removeKey(key, keysField) { + const keys = this.getTelemetryFromDatabaseConfigForm.get(keysField).value; + const index = keys.indexOf(key); + if (index >= 0) { + keys.splice(index, 1); + this.getTelemetryFromDatabaseConfigForm.get(keysField).setValue(keys, { emitEvent: true }); + } + } + addKey(event, keysField) { + const input = event.input; + let value = event.value; + if ((value || '').trim()) { + value = value.trim(); + let keys = this.getTelemetryFromDatabaseConfigForm.get(keysField).value; + if (!keys || keys.indexOf(value) === -1) { + if (!keys) { + keys = []; + } + keys.push(value); + this.getTelemetryFromDatabaseConfigForm.get(keysField).setValue(keys, { emitEvent: true }); + } + } + if (input) { + input.value = ''; + } + } +} +GetTelemetryFromDatabaseConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: GetTelemetryFromDatabaseConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); +GetTelemetryFromDatabaseConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: GetTelemetryFromDatabaseConfigComponent, selector: "tb-enrichment-node-get-telemetry-from-database", usesInheritance: true, ngImport: i0, template: "
\n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.fetch-mode\n \n \n {{ mode }}\n \n \n tb.rulenode.fetch-mode-hint\n \n
\n \n aggregation.function\n \n \n {{ aggregationTypesTranslations.get(aggregationTypes[aggregation]) | translate }}\n \n \n \n \n tb.rulenode.order-by\n \n \n {{ order }}\n \n \n tb.rulenode.order-by-hint\n \n \n tb.rulenode.limit\n \n tb.rulenode.limit-hint\n \n
\n \n {{ 'tb.rulenode.use-metadata-interval-patterns' | translate }}\n \n
tb.rulenode.use-metadata-interval-patterns-hint
\n
\n
\n \n tb.rulenode.start-interval\n \n \n {{ 'tb.rulenode.start-interval-value-required' | translate }}\n \n \n {{ 'tb.rulenode.time-value-range' | translate }}\n \n \n {{ 'tb.rulenode.time-value-range' | translate }}\n \n \n \n tb.rulenode.start-interval-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n tb.rulenode.end-interval\n \n \n {{ 'tb.rulenode.end-interval-value-required' | translate }}\n \n \n {{ 'tb.rulenode.time-value-range' | translate }}\n \n \n {{ 'tb.rulenode.time-value-range' | translate }}\n \n \n \n tb.rulenode.end-interval-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n \n tb.rulenode.start-interval-pattern\n \n \n {{ 'tb.rulenode.start-interval-pattern-required' | translate }}\n \n \n \n \n tb.rulenode.end-interval-pattern\n \n \n {{ 'tb.rulenode.end-interval-pattern-required' | translate }}\n \n \n \n \n
\n", styles: [":host label.tb-title{margin-bottom:-10px}\n"], components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }, { type: i5$2.MatChipList, selector: "mat-chip-list", inputs: ["aria-orientation", "multiple", "compareWith", "value", "required", "placeholder", "disabled", "selectable", "tabIndex", "errorStateMatcher"], outputs: ["change", "valueChange"], exportAs: ["matChipList"] }, { type: i6$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { type: i4$1.MatSelect, selector: "mat-select", inputs: ["disabled", "disableRipple", "tabIndex"], exportAs: ["matSelect"] }, { type: i5.MatOption, selector: "mat-option", exportAs: ["matOption"] }, { type: i3$1.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex", "aria-label", "aria-labelledby", "id", "labelPosition", "name", "required", "checked", "disabled", "indeterminate", "aria-describedby", "value"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i10.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i5$2.MatChip, selector: "mat-basic-chip, [mat-basic-chip], mat-chip, [mat-chip]", inputs: ["color", "disableRipple", "tabIndex", "selected", "value", "selectable", "disabled", "removable"], outputs: ["selectionChange", "destroyed", "removed"], exportAs: ["matChip"] }, { type: i5$2.MatChipRemove, selector: "[matChipRemove]" }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i5$2.MatChipInput, selector: "input[matChipInputFor]", inputs: ["matChipInputSeparatorKeyCodes", "placeholder", "id", "matChipInputFor", "matChipInputAddOnBlur", "disabled"], outputs: ["matChipInputTokenEnd"], exportAs: ["matChipInput", "matChipInputFor"] }, { type: i3.MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i2.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { type: i2.MaxValidator, selector: "input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]", inputs: ["max"] }, { type: i2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i8.DefaultLayoutGapDirective, selector: " [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]", inputs: ["fxLayoutGap", "fxLayoutGap.xs", "fxLayoutGap.sm", "fxLayoutGap.md", "fxLayoutGap.lg", "fxLayoutGap.xl", "fxLayoutGap.lt-sm", "fxLayoutGap.lt-md", "fxLayoutGap.lt-lg", "fxLayoutGap.lt-xl", "fxLayoutGap.gt-xs", "fxLayoutGap.gt-sm", "fxLayoutGap.gt-md", "fxLayoutGap.gt-lg"] }, { type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }, { type: i3.MatError, selector: "mat-error", inputs: ["id"] }], pipes: { "translate": i4.TranslatePipe, "safeHtml": SafeHtmlPipe } }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: GetTelemetryFromDatabaseConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-enrichment-node-get-telemetry-from-database', + templateUrl: './get-telemetry-from-database-config.component.html', + styleUrls: ['./get-telemetry-from-database-config.component.scss'] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); + +class OriginatorAttributesConfigComponent extends RuleNodeConfigurationComponent { + constructor(store, fb) { + super(store); + this.store = store; + this.fb = fb; + this.separatorKeysCodes = [ENTER, COMMA, SEMICOLON]; + } + configForm() { + return this.originatorAttributesConfigForm; + } + onConfigurationSet(configuration) { + this.originatorAttributesConfigForm = this.fb.group({ + tellFailureIfAbsent: [configuration ? configuration.tellFailureIfAbsent : false, []], + clientAttributeNames: [configuration ? configuration.clientAttributeNames : null, []], + sharedAttributeNames: [configuration ? configuration.sharedAttributeNames : null, []], + serverAttributeNames: [configuration ? configuration.serverAttributeNames : null, []], + latestTsKeyNames: [configuration ? configuration.latestTsKeyNames : null, []], + getLatestValueWithTs: [configuration ? configuration.getLatestValueWithTs : false, []] + }); + } + removeKey(key, keysField) { + const keys = this.originatorAttributesConfigForm.get(keysField).value; + const index = keys.indexOf(key); + if (index >= 0) { + keys.splice(index, 1); + this.originatorAttributesConfigForm.get(keysField).setValue(keys, { emitEvent: true }); + } + } + addKey(event, keysField) { + const input = event.input; + let value = event.value; + if ((value || '').trim()) { + value = value.trim(); + let keys = this.originatorAttributesConfigForm.get(keysField).value; + if (!keys || keys.indexOf(value) === -1) { + if (!keys) { + keys = []; + } + keys.push(value); + this.originatorAttributesConfigForm.get(keysField).setValue(keys, { emitEvent: true }); + } + } + if (input) { + input.value = ''; + } + } +} +OriginatorAttributesConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: OriginatorAttributesConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); +OriginatorAttributesConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: OriginatorAttributesConfigComponent, selector: "tb-enrichment-node-originator-attributes-config", usesInheritance: true, ngImport: i0, template: "
\n \n {{ 'tb.rulenode.tell-failure-if-absent' | translate }}\n \n
tb.rulenode.tell-failure-if-absent-hint
\n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n {{ 'tb.rulenode.get-latest-value-with-ts' | translate }}\n \n
\n
\n", styles: [":host label.tb-title{margin-bottom:-10px}\n"], components: [{ type: i3$1.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex", "aria-label", "aria-labelledby", "id", "labelPosition", "name", "required", "checked", "disabled", "indeterminate", "aria-describedby", "value"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }, { type: i5$2.MatChipList, selector: "mat-chip-list", inputs: ["aria-orientation", "multiple", "compareWith", "value", "required", "placeholder", "disabled", "selectable", "tabIndex", "errorStateMatcher"], outputs: ["change", "valueChange"], exportAs: ["matChipList"] }, { type: i6$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i10.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i5$2.MatChip, selector: "mat-basic-chip, [mat-basic-chip], mat-chip, [mat-chip]", inputs: ["color", "disableRipple", "tabIndex", "selected", "value", "selectable", "disabled", "removable"], outputs: ["selectionChange", "destroyed", "removed"], exportAs: ["matChip"] }, { type: i5$2.MatChipRemove, selector: "[matChipRemove]" }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i5$2.MatChipInput, selector: "input[matChipInputFor]", inputs: ["matChipInputSeparatorKeyCodes", "placeholder", "id", "matChipInputFor", "matChipInputAddOnBlur", "disabled"], outputs: ["matChipInputTokenEnd"], exportAs: ["matChipInput", "matChipInputFor"] }, { type: i3.MatHint, selector: "mat-hint", inputs: ["align", "id"] }], pipes: { "translate": i4.TranslatePipe, "safeHtml": SafeHtmlPipe } }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: OriginatorAttributesConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-enrichment-node-originator-attributes-config', + templateUrl: './originator-attributes-config.component.html', + styleUrls: ['./originator-attributes-config.component.scss'] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); + +class OriginatorFieldsConfigComponent extends RuleNodeConfigurationComponent { + constructor(store, fb) { + super(store); + this.store = store; + this.fb = fb; + } + configForm() { + return this.originatorFieldsConfigForm; + } + onConfigurationSet(configuration) { + this.originatorFieldsConfigForm = this.fb.group({ + fieldsMapping: [configuration ? configuration.fieldsMapping : null, [Validators.required]] + }); + } +} +OriginatorFieldsConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: OriginatorFieldsConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); +OriginatorFieldsConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: OriginatorFieldsConfigComponent, selector: "tb-enrichment-node-originator-fields-config", usesInheritance: true, ngImport: i0, template: "
\n \n \n \n
\n", components: [{ type: KvMapConfigComponent, selector: "tb-kv-map-config", inputs: ["disabled", "requiredText", "keyText", "keyRequiredText", "valText", "valRequiredText", "required"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }] }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: OriginatorFieldsConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-enrichment-node-originator-fields-config', + templateUrl: './originator-fields-config.component.html', + styleUrls: [] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); + +class RelatedAttributesConfigComponent extends RuleNodeConfigurationComponent { + constructor(store, fb) { + super(store); + this.store = store; + this.fb = fb; + } + configForm() { + return this.relatedAttributesConfigForm; + } + onConfigurationSet(configuration) { + this.relatedAttributesConfigForm = this.fb.group({ + relationsQuery: [configuration ? configuration.relationsQuery : null, [Validators.required]], + telemetry: [configuration ? configuration.telemetry : false, []], + attrMapping: [configuration ? configuration.attrMapping : null, [Validators.required]] + }); + } +} +RelatedAttributesConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RelatedAttributesConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); +RelatedAttributesConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: RelatedAttributesConfigComponent, selector: "tb-enrichment-node-related-attributes-config", usesInheritance: true, ngImport: i0, template: "
\n \n \n \n \n \n {{ 'tb.rulenode.latest-telemetry' | translate }}\n \n \n \n
\n", components: [{ type: RelationsQueryConfigComponent, selector: "tb-relations-query-config", inputs: ["disabled", "required"] }, { type: i3$1.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex", "aria-label", "aria-labelledby", "id", "labelPosition", "name", "required", "checked", "disabled", "indeterminate", "aria-describedby", "value"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { type: KvMapConfigComponent, selector: "tb-kv-map-config", inputs: ["disabled", "requiredText", "keyText", "keyRequiredText", "valText", "valRequiredText", "required"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }], pipes: { "translate": i4.TranslatePipe } }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RelatedAttributesConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-enrichment-node-related-attributes-config', + templateUrl: './related-attributes-config.component.html', + styleUrls: [] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); + +class TenantAttributesConfigComponent extends RuleNodeConfigurationComponent { + constructor(store, fb) { + super(store); + this.store = store; + this.fb = fb; + } + configForm() { + return this.tenantAttributesConfigForm; + } + onConfigurationSet(configuration) { + this.tenantAttributesConfigForm = this.fb.group({ + telemetry: [configuration ? configuration.telemetry : false, []], + attrMapping: [configuration ? configuration.attrMapping : null, [Validators.required]] + }); + } +} +TenantAttributesConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: TenantAttributesConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); +TenantAttributesConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: TenantAttributesConfigComponent, selector: "tb-enrichment-node-tenant-attributes-config", usesInheritance: true, ngImport: i0, template: "
\n \n \n {{ 'tb.rulenode.latest-telemetry' | translate }}\n \n \n \n
\n", components: [{ type: i3$1.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex", "aria-label", "aria-labelledby", "id", "labelPosition", "name", "required", "checked", "disabled", "indeterminate", "aria-describedby", "value"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { type: KvMapConfigComponent, selector: "tb-kv-map-config", inputs: ["disabled", "requiredText", "keyText", "keyRequiredText", "valText", "valRequiredText", "required"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }], pipes: { "translate": i4.TranslatePipe } }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: TenantAttributesConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-enrichment-node-tenant-attributes-config', + templateUrl: './tenant-attributes-config.component.html', + styleUrls: [] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); + +class RulenodeCoreConfigEnrichmentModule { +} +RulenodeCoreConfigEnrichmentModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RulenodeCoreConfigEnrichmentModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); +RulenodeCoreConfigEnrichmentModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RulenodeCoreConfigEnrichmentModule, declarations: [CustomerAttributesConfigComponent, + EntityDetailsConfigComponent, + DeviceAttributesConfigComponent, + OriginatorAttributesConfigComponent, + OriginatorFieldsConfigComponent, + GetTelemetryFromDatabaseConfigComponent, + RelatedAttributesConfigComponent, + TenantAttributesConfigComponent, + CalculateDeltaConfigComponent], imports: [CommonModule, + SharedModule, + RulenodeCoreConfigCommonModule], exports: [CustomerAttributesConfigComponent, + EntityDetailsConfigComponent, + DeviceAttributesConfigComponent, + OriginatorAttributesConfigComponent, + OriginatorFieldsConfigComponent, + GetTelemetryFromDatabaseConfigComponent, + RelatedAttributesConfigComponent, + TenantAttributesConfigComponent, + CalculateDeltaConfigComponent] }); +RulenodeCoreConfigEnrichmentModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RulenodeCoreConfigEnrichmentModule, imports: [[ + CommonModule, + SharedModule, + RulenodeCoreConfigCommonModule + ]] }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RulenodeCoreConfigEnrichmentModule, decorators: [{ + type: NgModule, + args: [{ + declarations: [ + CustomerAttributesConfigComponent, + EntityDetailsConfigComponent, + DeviceAttributesConfigComponent, + OriginatorAttributesConfigComponent, + OriginatorFieldsConfigComponent, + GetTelemetryFromDatabaseConfigComponent, + RelatedAttributesConfigComponent, + TenantAttributesConfigComponent, + CalculateDeltaConfigComponent + ], + imports: [ + CommonModule, + SharedModule, + RulenodeCoreConfigCommonModule + ], + exports: [ + CustomerAttributesConfigComponent, + EntityDetailsConfigComponent, + DeviceAttributesConfigComponent, + OriginatorAttributesConfigComponent, + OriginatorFieldsConfigComponent, + GetTelemetryFromDatabaseConfigComponent, + RelatedAttributesConfigComponent, + TenantAttributesConfigComponent, + CalculateDeltaConfigComponent + ] + }] + }] }); + +class CheckAlarmStatusComponent extends RuleNodeConfigurationComponent { + constructor(store, translate, fb) { + super(store); + this.store = store; + this.translate = translate; + this.fb = fb; + this.alarmStatusTranslationsMap = alarmStatusTranslations; + this.alarmStatusList = []; + this.searchText = ''; + this.displayStatusFn = this.displayStatus.bind(this); + for (const field of Object.keys(AlarmStatus)) { + this.alarmStatusList.push(AlarmStatus[field]); + } + this.statusFormControl = new FormControl(''); + this.filteredAlarmStatus = this.statusFormControl.valueChanges + .pipe(startWith(''), map((value) => value ? value : ''), mergeMap(name => this.fetchAlarmStatus(name)), share()); + } + ngOnInit() { + super.ngOnInit(); + } + configForm() { + return this.alarmStatusConfigForm; + } + prepareInputConfig(configuration) { + this.searchText = ''; + this.statusFormControl.patchValue('', { emitEvent: true }); + return configuration; + } + onConfigurationSet(configuration) { + this.alarmStatusConfigForm = this.fb.group({ + alarmStatusList: [configuration ? configuration.alarmStatusList : null, [Validators.required]], + }); + } + displayStatus(status) { + return status ? this.translate.instant(alarmStatusTranslations.get(status)) : undefined; + } + fetchAlarmStatus(searchText) { + const alarmStatusList = this.getAlarmStatusList(); + this.searchText = searchText; + if (this.searchText && this.searchText.length) { + const search = this.searchText.toUpperCase(); + return of(alarmStatusList.filter(field => this.translate.instant(alarmStatusTranslations.get(AlarmStatus[field])).toUpperCase().includes(search))); + } + else { + return of(alarmStatusList); + } + } + alarmStatusSelected(event) { + this.addAlarmStatus(event.option.value); + this.clear(''); + } + removeAlarmStatus(status) { + const alarmStatusList = this.alarmStatusConfigForm.get('alarmStatusList').value; + if (alarmStatusList) { + const index = alarmStatusList.indexOf(status); + if (index >= 0) { + alarmStatusList.splice(index, 1); + this.alarmStatusConfigForm.get('alarmStatusList').setValue(alarmStatusList); + } + } + } + addAlarmStatus(status) { + let alarmStatusList = this.alarmStatusConfigForm.get('alarmStatusList').value; + if (!alarmStatusList) { + alarmStatusList = []; + } + const index = alarmStatusList.indexOf(status); + if (index === -1) { + alarmStatusList.push(status); + this.alarmStatusConfigForm.get('alarmStatusList').setValue(alarmStatusList); + } + } + getAlarmStatusList() { + return this.alarmStatusList.filter((listItem) => { + return this.alarmStatusConfigForm.get('alarmStatusList').value.indexOf(listItem) === -1; + }); + } + onAlarmStatusInputFocus() { + this.statusFormControl.updateValueAndValidity({ onlySelf: true, emitEvent: true }); + } + clear(value = '') { + this.alarmStatusInput.nativeElement.value = value; + this.statusFormControl.patchValue(null, { emitEvent: true }); + setTimeout(() => { + this.alarmStatusInput.nativeElement.blur(); + this.alarmStatusInput.nativeElement.focus(); + }, 0); + } +} +CheckAlarmStatusComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: CheckAlarmStatusComponent, deps: [{ token: i1.Store }, { token: i4.TranslateService }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); +CheckAlarmStatusComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: CheckAlarmStatusComponent, selector: "tb-filter-node-check-alarm-status-config", viewQueries: [{ propertyName: "alarmStatusInput", first: true, predicate: ["alarmStatusInput"], descendants: true }], usesInheritance: true, ngImport: i0, template: "
\n \n tb.rulenode.alarm-status-filter\n \n \n \n {{alarmStatusTranslationsMap.get(alarmStatus) | translate}}\n \n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-alarm-status-matching\n
\n
\n
\n
\n
\n \n
\n\n\n\n", components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }, { type: i5$2.MatChipList, selector: "mat-chip-list", inputs: ["aria-orientation", "multiple", "compareWith", "value", "required", "placeholder", "disabled", "selectable", "tabIndex", "errorStateMatcher"], outputs: ["change", "valueChange"], exportAs: ["matChipList"] }, { type: i6$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { type: i7$5.MatAutocomplete, selector: "mat-autocomplete", inputs: ["disableRipple"], exportAs: ["matAutocomplete"] }, { type: i5.MatOption, selector: "mat-option", exportAs: ["matOption"] }, { type: i9.TbErrorComponent, selector: "tb-error", inputs: ["error"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i10.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i5$2.MatChip, selector: "mat-basic-chip, [mat-basic-chip], mat-chip, [mat-chip]", inputs: ["color", "disableRipple", "tabIndex", "selected", "value", "selectable", "disabled", "removable"], outputs: ["selectionChange", "destroyed", "removed"], exportAs: ["matChip"] }, { type: i5$2.MatChipRemove, selector: "[matChipRemove]" }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i7$5.MatAutocompleteTrigger, selector: "input[matAutocomplete], textarea[matAutocomplete]", exportAs: ["matAutocompleteTrigger"] }, { type: i5$2.MatChipInput, selector: "input[matChipInputFor]", inputs: ["matChipInputSeparatorKeyCodes", "placeholder", "id", "matChipInputFor", "matChipInputAddOnBlur", "disabled"], outputs: ["matChipInputTokenEnd"], exportAs: ["matChipInput", "matChipInputFor"] }, { type: i7$5.MatAutocompleteOrigin, selector: "[matAutocompleteOrigin]", exportAs: ["matAutocompleteOrigin"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlDirective, selector: "[formControl]", inputs: ["disabled", "formControl", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], pipes: { "translate": i4.TranslatePipe, "async": i10.AsyncPipe, "highlight": i12$1.HighlightPipe } }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: CheckAlarmStatusComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-filter-node-check-alarm-status-config', + templateUrl: './check-alarm-status.component.html', + styleUrls: [] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i4.TranslateService }, { type: i2.FormBuilder }]; }, propDecorators: { alarmStatusInput: [{ + type: ViewChild, + args: ['alarmStatusInput', { static: false }] + }] } }); + +class CheckMessageConfigComponent extends RuleNodeConfigurationComponent { + constructor(store, fb) { + super(store); + this.store = store; + this.fb = fb; + this.separatorKeysCodes = [ENTER, COMMA, SEMICOLON]; + } + configForm() { + return this.checkMessageConfigForm; + } + onConfigurationSet(configuration) { + this.checkMessageConfigForm = this.fb.group({ + messageNames: [configuration ? configuration.messageNames : null, []], + metadataNames: [configuration ? configuration.metadataNames : null, []], + checkAllKeys: [configuration ? configuration.checkAllKeys : false, []], + }); + } + validateConfig() { + const messageNames = this.checkMessageConfigForm.get('messageNames').value; + const metadataNames = this.checkMessageConfigForm.get('metadataNames').value; + return messageNames.length > 0 || metadataNames.length > 0; + } + removeMessageName(messageName) { + const messageNames = this.checkMessageConfigForm.get('messageNames').value; + const index = messageNames.indexOf(messageName); + if (index >= 0) { + messageNames.splice(index, 1); + this.checkMessageConfigForm.get('messageNames').setValue(messageNames, { emitEvent: true }); + } + } + removeMetadataName(metadataName) { + const metadataNames = this.checkMessageConfigForm.get('metadataNames').value; + const index = metadataNames.indexOf(metadataName); + if (index >= 0) { + metadataNames.splice(index, 1); + this.checkMessageConfigForm.get('metadataNames').setValue(metadataNames, { emitEvent: true }); + } + } + addMessageName(event) { + const input = event.input; + let value = event.value; + if ((value || '').trim()) { + value = value.trim(); + let messageNames = this.checkMessageConfigForm.get('messageNames').value; + if (!messageNames || messageNames.indexOf(value) === -1) { + if (!messageNames) { + messageNames = []; + } + messageNames.push(value); + this.checkMessageConfigForm.get('messageNames').setValue(messageNames, { emitEvent: true }); + } + } + if (input) { + input.value = ''; + } + } + addMetadataName(event) { + const input = event.input; + let value = event.value; + if ((value || '').trim()) { + value = value.trim(); + let metadataNames = this.checkMessageConfigForm.get('metadataNames').value; + if (!metadataNames || metadataNames.indexOf(value) === -1) { + if (!metadataNames) { + metadataNames = []; + } + metadataNames.push(value); + this.checkMessageConfigForm.get('metadataNames').setValue(metadataNames, { emitEvent: true }); + } + } + if (input) { + input.value = ''; + } + } +} +CheckMessageConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: CheckMessageConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); +CheckMessageConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: CheckMessageConfigComponent, selector: "tb-filter-node-check-message-config", usesInheritance: true, ngImport: i0, template: "
\n \n \n \n \n \n {{messageName}}\n close\n \n \n \n \n
tb.rulenode.separator-hint
\n \n \n \n \n \n {{metadataName}}\n close\n \n \n \n \n
tb.rulenode.separator-hint
\n \n {{ 'tb.rulenode.check-all-keys' | translate }}\n \n
tb.rulenode.check-all-keys-hint
\n
\n", styles: [":host label.tb-title{margin-bottom:-10px}\n"], components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }, { type: i5$2.MatChipList, selector: "mat-chip-list", inputs: ["aria-orientation", "multiple", "compareWith", "value", "required", "placeholder", "disabled", "selectable", "tabIndex", "errorStateMatcher"], outputs: ["change", "valueChange"], exportAs: ["matChipList"] }, { type: i6$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { type: i3$1.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex", "aria-label", "aria-labelledby", "id", "labelPosition", "name", "required", "checked", "disabled", "indeterminate", "aria-describedby", "value"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i10.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i5$2.MatChip, selector: "mat-basic-chip, [mat-basic-chip], mat-chip, [mat-chip]", inputs: ["color", "disableRipple", "tabIndex", "selected", "value", "selectable", "disabled", "removable"], outputs: ["selectionChange", "destroyed", "removed"], exportAs: ["matChip"] }, { type: i5$2.MatChipRemove, selector: "[matChipRemove]" }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i5$2.MatChipInput, selector: "input[matChipInputFor]", inputs: ["matChipInputSeparatorKeyCodes", "placeholder", "id", "matChipInputFor", "matChipInputAddOnBlur", "disabled"], outputs: ["matChipInputTokenEnd"], exportAs: ["matChipInput", "matChipInputFor"] }, { type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }], pipes: { "translate": i4.TranslatePipe } }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: CheckMessageConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-filter-node-check-message-config', + templateUrl: './check-message-config.component.html', + styleUrls: ['./check-message-config.component.scss'] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); + +class CheckRelationConfigComponent extends RuleNodeConfigurationComponent { + constructor(store, fb) { + super(store); + this.store = store; + this.fb = fb; + this.entitySearchDirection = Object.keys(EntitySearchDirection); + this.entitySearchDirectionTranslationsMap = entitySearchDirectionTranslations; + } + configForm() { + return this.checkRelationConfigForm; + } + onConfigurationSet(configuration) { + this.checkRelationConfigForm = this.fb.group({ + checkForSingleEntity: [configuration ? configuration.checkForSingleEntity : false, []], + direction: [configuration ? configuration.direction : null, []], + entityType: [configuration ? configuration.entityType : null, + configuration && configuration.checkForSingleEntity ? [Validators.required] : []], + entityId: [configuration ? configuration.entityId : null, + configuration && configuration.checkForSingleEntity ? [Validators.required] : []], + relationType: [configuration ? configuration.relationType : null, [Validators.required]] + }); + } + validatorTriggers() { + return ['checkForSingleEntity']; + } + updateValidators(emitEvent) { + const checkForSingleEntity = this.checkRelationConfigForm.get('checkForSingleEntity').value; + this.checkRelationConfigForm.get('entityType').setValidators(checkForSingleEntity ? [Validators.required] : []); + this.checkRelationConfigForm.get('entityType').updateValueAndValidity({ emitEvent }); + this.checkRelationConfigForm.get('entityId').setValidators(checkForSingleEntity ? [Validators.required] : []); + this.checkRelationConfigForm.get('entityId').updateValueAndValidity({ emitEvent }); + } +} +CheckRelationConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: CheckRelationConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); +CheckRelationConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: CheckRelationConfigComponent, selector: "tb-filter-node-check-relation-config", usesInheritance: true, ngImport: i0, template: "
\n \n {{ 'tb.rulenode.check-relation-to-specific-entity' | translate }}\n \n
tb.rulenode.check-relation-hint
\n \n relation.direction\n \n \n {{ entitySearchDirectionTranslationsMap.get(direction) | translate }}\n \n \n \n
\n \n \n \n \n
\n \n \n
\n", components: [{ type: i3$1.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex", "aria-label", "aria-labelledby", "id", "labelPosition", "name", "required", "checked", "disabled", "indeterminate", "aria-describedby", "value"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }, { type: i4$1.MatSelect, selector: "mat-select", inputs: ["disabled", "disableRipple", "tabIndex"], exportAs: ["matSelect"] }, { type: i5.MatOption, selector: "mat-option", exportAs: ["matOption"] }, { type: i7$1.EntityTypeSelectComponent, selector: "tb-entity-type-select", inputs: ["allowedEntityTypes", "useAliasEntityTypes", "showLabel", "required", "disabled"] }, { type: i8$3.EntityAutocompleteComponent, selector: "tb-entity-autocomplete", inputs: ["entityType", "entitySubtype", "excludeEntityIds", "labelText", "requiredText", "required", "disabled"], outputs: ["entityChanged"] }, { type: i7$3.RelationTypeAutocompleteComponent, selector: "tb-relation-type-autocomplete", inputs: ["required", "disabled"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i10.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], pipes: { "translate": i4.TranslatePipe } }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: CheckRelationConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-filter-node-check-relation-config', + templateUrl: './check-relation-config.component.html', + styleUrls: [] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); + +class GpsGeoFilterConfigComponent extends RuleNodeConfigurationComponent { + constructor(store, fb) { + super(store); + this.store = store; + this.fb = fb; + this.perimeterType = PerimeterType; + this.perimeterTypes = Object.keys(PerimeterType); + this.perimeterTypeTranslationMap = perimeterTypeTranslations; + this.rangeUnits = Object.keys(RangeUnit); + this.rangeUnitTranslationMap = rangeUnitTranslations; + } + configForm() { + return this.geoFilterConfigForm; + } + onConfigurationSet(configuration) { + this.geoFilterConfigForm = this.fb.group({ + latitudeKeyName: [configuration ? configuration.latitudeKeyName : null, [Validators.required]], + longitudeKeyName: [configuration ? configuration.longitudeKeyName : null, [Validators.required]], + fetchPerimeterInfoFromMessageMetadata: [configuration ? configuration.fetchPerimeterInfoFromMessageMetadata : false, []], + perimeterType: [configuration ? configuration.perimeterType : null, []], + centerLatitude: [configuration ? configuration.centerLatitude : null, []], + centerLongitude: [configuration ? configuration.centerLatitude : null, []], + range: [configuration ? configuration.range : null, []], + rangeUnit: [configuration ? configuration.rangeUnit : null, []], + polygonsDefinition: [configuration ? configuration.polygonsDefinition : null, []] + }); + } + validatorTriggers() { + return ['fetchPerimeterInfoFromMessageMetadata', 'perimeterType']; + } + updateValidators(emitEvent) { + const fetchPerimeterInfoFromMessageMetadata = this.geoFilterConfigForm.get('fetchPerimeterInfoFromMessageMetadata').value; + const perimeterType = this.geoFilterConfigForm.get('perimeterType').value; + if (fetchPerimeterInfoFromMessageMetadata) { + this.geoFilterConfigForm.get('perimeterType').setValidators([]); + } + else { + this.geoFilterConfigForm.get('perimeterType').setValidators([Validators.required]); + } + if (!fetchPerimeterInfoFromMessageMetadata && perimeterType === PerimeterType.CIRCLE) { + this.geoFilterConfigForm.get('centerLatitude').setValidators([Validators.required, + Validators.min(-90), Validators.max(90)]); + this.geoFilterConfigForm.get('centerLongitude').setValidators([Validators.required, + Validators.min(-180), Validators.max(180)]); + this.geoFilterConfigForm.get('range').setValidators([Validators.required, Validators.min(0)]); + this.geoFilterConfigForm.get('rangeUnit').setValidators([Validators.required]); + } + else { + this.geoFilterConfigForm.get('centerLatitude').setValidators([]); + this.geoFilterConfigForm.get('centerLongitude').setValidators([]); + this.geoFilterConfigForm.get('range').setValidators([]); + this.geoFilterConfigForm.get('rangeUnit').setValidators([]); + } + if (!fetchPerimeterInfoFromMessageMetadata && perimeterType === PerimeterType.POLYGON) { + this.geoFilterConfigForm.get('polygonsDefinition').setValidators([Validators.required]); + } + else { + this.geoFilterConfigForm.get('polygonsDefinition').setValidators([]); + } + this.geoFilterConfigForm.get('perimeterType').updateValueAndValidity({ emitEvent: false }); + this.geoFilterConfigForm.get('centerLatitude').updateValueAndValidity({ emitEvent }); + this.geoFilterConfigForm.get('centerLongitude').updateValueAndValidity({ emitEvent }); + this.geoFilterConfigForm.get('range').updateValueAndValidity({ emitEvent }); + this.geoFilterConfigForm.get('rangeUnit').updateValueAndValidity({ emitEvent }); + this.geoFilterConfigForm.get('polygonsDefinition').updateValueAndValidity({ emitEvent }); + } +} +GpsGeoFilterConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: GpsGeoFilterConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); +GpsGeoFilterConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: GpsGeoFilterConfigComponent, selector: "tb-filter-node-gps-geofencing-config", usesInheritance: true, ngImport: i0, template: "
\n \n tb.rulenode.latitude-key-name\n \n \n {{ 'tb.rulenode.latitude-key-name-required' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ 'tb.rulenode.longitude-key-name-required' | translate }}\n \n \n \n {{ 'tb.rulenode.fetch-perimeter-info-from-message-metadata' | translate }}\n \n
\n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n \n tb.rulenode.circle-center-latitude\n \n \n {{ 'tb.rulenode.circle-center-latitude-required' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ 'tb.rulenode.circle-center-longitude-required' | translate }}\n \n \n
\n
\n \n tb.rulenode.range\n \n \n {{ 'tb.rulenode.range-required' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n
\n \n tb.rulenode.polygon-definition\n \n \n {{ 'tb.rulenode.polygon-definition-required' | translate }}\n \n \n
\n
\n
\n", components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }, { type: i3$1.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex", "aria-label", "aria-labelledby", "id", "labelPosition", "name", "required", "checked", "disabled", "indeterminate", "aria-describedby", "value"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { type: i4$1.MatSelect, selector: "mat-select", inputs: ["disabled", "disableRipple", "tabIndex"], exportAs: ["matSelect"] }, { type: i5.MatOption, selector: "mat-option", exportAs: ["matOption"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.MatError, selector: "mat-error", inputs: ["id"] }, { type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }, { type: i10.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i8.DefaultLayoutGapDirective, selector: " [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]", inputs: ["fxLayoutGap", "fxLayoutGap.xs", "fxLayoutGap.sm", "fxLayoutGap.md", "fxLayoutGap.lg", "fxLayoutGap.xl", "fxLayoutGap.lt-sm", "fxLayoutGap.lt-md", "fxLayoutGap.lt-lg", "fxLayoutGap.lt-xl", "fxLayoutGap.gt-xs", "fxLayoutGap.gt-sm", "fxLayoutGap.gt-md", "fxLayoutGap.gt-lg"] }, { type: i2.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { type: i2.MaxValidator, selector: "input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]", inputs: ["max"] }, { type: i2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }], pipes: { "translate": i4.TranslatePipe } }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: GpsGeoFilterConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-filter-node-gps-geofencing-config', + templateUrl: './gps-geo-filter-config.component.html', + styleUrls: [] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); + +class MessageTypeConfigComponent extends RuleNodeConfigurationComponent { + constructor(store, fb) { + super(store); + this.store = store; + this.fb = fb; + } + configForm() { + return this.messageTypeConfigForm; + } + onConfigurationSet(configuration) { + this.messageTypeConfigForm = this.fb.group({ + messageTypes: [configuration ? configuration.messageTypes : null, [Validators.required]] + }); + } +} +MessageTypeConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: MessageTypeConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); +MessageTypeConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: MessageTypeConfigComponent, selector: "tb-filter-node-message-type-config", usesInheritance: true, ngImport: i0, template: "
\n \n
\n", components: [{ type: MessageTypesConfigComponent, selector: "tb-message-types-config", inputs: ["required", "label", "placeholder", "disabled"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }] }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: MessageTypeConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-filter-node-message-type-config', + templateUrl: './message-type-config.component.html', + styleUrls: [] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); + +class OriginatorTypeConfigComponent extends RuleNodeConfigurationComponent { + constructor(store, fb) { + super(store); + this.store = store; + this.fb = fb; + this.allowedEntityTypes = [ + EntityType.DEVICE, + EntityType.ASSET, + EntityType.ENTITY_VIEW, + EntityType.TENANT, + EntityType.CUSTOMER, + EntityType.USER, + EntityType.DASHBOARD, + EntityType.RULE_CHAIN, + EntityType.RULE_NODE + ]; + } + configForm() { + return this.originatorTypeConfigForm; + } + onConfigurationSet(configuration) { + this.originatorTypeConfigForm = this.fb.group({ + originatorTypes: [configuration ? configuration.originatorTypes : null, [Validators.required]] + }); + } +} +OriginatorTypeConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: OriginatorTypeConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); +OriginatorTypeConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: OriginatorTypeConfigComponent, selector: "tb-filter-node-originator-type-config", usesInheritance: true, ngImport: i0, template: "
\n \n \n \n
\n", styles: [":host ::ng-deep tb-entity-type-list .mat-form-field-flex{padding-top:0}:host ::ng-deep tb-entity-type-list .mat-form-field-infix{border-top:0}\n"], components: [{ type: i3$5.EntityTypeListComponent, selector: "tb-entity-type-list", inputs: ["required", "disabled", "allowedEntityTypes", "ignoreAuthorityFilter"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }] }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: OriginatorTypeConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-filter-node-originator-type-config', + templateUrl: './originator-type-config.component.html', + styleUrls: ['./originator-type-config.component.scss'] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); + +class ScriptConfigComponent extends RuleNodeConfigurationComponent { + constructor(store, fb, nodeScriptTestService, translate) { + super(store); + this.store = store; + this.fb = fb; + this.nodeScriptTestService = nodeScriptTestService; + this.translate = translate; + } + configForm() { + return this.scriptConfigForm; + } + onConfigurationSet(configuration) { + this.scriptConfigForm = this.fb.group({ + jsScript: [configuration ? configuration.jsScript : null, [Validators.required]] + }); + } + testScript() { + const script = this.scriptConfigForm.get('jsScript').value; + this.nodeScriptTestService.testNodeScript(script, 'filter', this.translate.instant('tb.rulenode.filter'), 'Filter', ['msg', 'metadata', 'msgType'], this.ruleNodeId, 'rulenode/filter_node_script_fn').subscribe((theScript) => { + if (theScript) { + this.scriptConfigForm.get('jsScript').setValue(theScript); + } + }); + } + onValidate() { + this.jsFuncComponent.validateOnSubmit(); + } +} +ScriptConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: ScriptConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }, { token: i3$3.NodeScriptTestService }, { token: i4.TranslateService }], target: i0.ɵɵFactoryTarget.Component }); +ScriptConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: ScriptConfigComponent, selector: "tb-filter-node-script-config", viewQueries: [{ propertyName: "jsFuncComponent", first: true, predicate: ["jsFuncComponent"], descendants: true, static: true }], usesInheritance: true, ngImport: i0, template: "
\n \n \n \n
\n \n
\n
\n", components: [{ type: i5$1.JsFuncComponent, selector: "tb-js-func", inputs: ["functionName", "functionArgs", "validationArgs", "resultType", "disabled", "fillHeight", "editorCompleter", "globalVariables", "disableUndefinedCheck", "helpId", "noValidate", "required"] }, { type: i6.MatButton, selector: "button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }], pipes: { "translate": i4.TranslatePipe } }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: ScriptConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-filter-node-script-config', + templateUrl: './script-config.component.html', + styleUrls: [] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }, { type: i3$3.NodeScriptTestService }, { type: i4.TranslateService }]; }, propDecorators: { jsFuncComponent: [{ + type: ViewChild, + args: ['jsFuncComponent', { static: true }] + }] } }); + +class SwitchConfigComponent extends RuleNodeConfigurationComponent { + constructor(store, fb, nodeScriptTestService, translate) { + super(store); + this.store = store; + this.fb = fb; + this.nodeScriptTestService = nodeScriptTestService; + this.translate = translate; + } + configForm() { + return this.switchConfigForm; + } + onConfigurationSet(configuration) { + this.switchConfigForm = this.fb.group({ + jsScript: [configuration ? configuration.jsScript : null, [Validators.required]] + }); + } + testScript() { + const script = this.switchConfigForm.get('jsScript').value; + this.nodeScriptTestService.testNodeScript(script, 'switch', this.translate.instant('tb.rulenode.switch'), 'Switch', ['msg', 'metadata', 'msgType'], this.ruleNodeId, 'rulenode/switch_node_script_fn').subscribe((theScript) => { + if (theScript) { + this.switchConfigForm.get('jsScript').setValue(theScript); + } + }); + } + onValidate() { + this.jsFuncComponent.validateOnSubmit(); + } +} +SwitchConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: SwitchConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }, { token: i3$3.NodeScriptTestService }, { token: i4.TranslateService }], target: i0.ɵɵFactoryTarget.Component }); +SwitchConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: SwitchConfigComponent, selector: "tb-filter-node-switch-config", viewQueries: [{ propertyName: "jsFuncComponent", first: true, predicate: ["jsFuncComponent"], descendants: true, static: true }], usesInheritance: true, ngImport: i0, template: "
\n \n \n \n
\n \n
\n
\n", components: [{ type: i5$1.JsFuncComponent, selector: "tb-js-func", inputs: ["functionName", "functionArgs", "validationArgs", "resultType", "disabled", "fillHeight", "editorCompleter", "globalVariables", "disableUndefinedCheck", "helpId", "noValidate", "required"] }, { type: i6.MatButton, selector: "button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }], pipes: { "translate": i4.TranslatePipe } }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: SwitchConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-filter-node-switch-config', + templateUrl: './switch-config.component.html', + styleUrls: [] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }, { type: i3$3.NodeScriptTestService }, { type: i4.TranslateService }]; }, propDecorators: { jsFuncComponent: [{ + type: ViewChild, + args: ['jsFuncComponent', { static: true }] + }] } }); + +class RuleNodeCoreConfigFilterModule { +} +RuleNodeCoreConfigFilterModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RuleNodeCoreConfigFilterModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); +RuleNodeCoreConfigFilterModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RuleNodeCoreConfigFilterModule, declarations: [CheckMessageConfigComponent, + CheckRelationConfigComponent, + GpsGeoFilterConfigComponent, + MessageTypeConfigComponent, + OriginatorTypeConfigComponent, + ScriptConfigComponent, + SwitchConfigComponent, + CheckAlarmStatusComponent], imports: [CommonModule, + SharedModule, + RulenodeCoreConfigCommonModule], exports: [CheckMessageConfigComponent, + CheckRelationConfigComponent, + GpsGeoFilterConfigComponent, + MessageTypeConfigComponent, + OriginatorTypeConfigComponent, + ScriptConfigComponent, + SwitchConfigComponent, + CheckAlarmStatusComponent] }); +RuleNodeCoreConfigFilterModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RuleNodeCoreConfigFilterModule, imports: [[ + CommonModule, + SharedModule, + RulenodeCoreConfigCommonModule + ]] }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RuleNodeCoreConfigFilterModule, decorators: [{ + type: NgModule, + args: [{ + declarations: [ + CheckMessageConfigComponent, + CheckRelationConfigComponent, + GpsGeoFilterConfigComponent, + MessageTypeConfigComponent, + OriginatorTypeConfigComponent, + ScriptConfigComponent, + SwitchConfigComponent, + CheckAlarmStatusComponent + ], + imports: [ + CommonModule, + SharedModule, + RulenodeCoreConfigCommonModule + ], + exports: [ + CheckMessageConfigComponent, + CheckRelationConfigComponent, + GpsGeoFilterConfigComponent, + MessageTypeConfigComponent, + OriginatorTypeConfigComponent, + ScriptConfigComponent, + SwitchConfigComponent, + CheckAlarmStatusComponent + ] + }] + }] }); + +class ChangeOriginatorConfigComponent extends RuleNodeConfigurationComponent { + constructor(store, fb) { + super(store); + this.store = store; + this.fb = fb; + this.originatorSource = OriginatorSource; + this.originatorSources = Object.keys(OriginatorSource); + this.originatorSourceTranslationMap = originatorSourceTranslations; + } + configForm() { + return this.changeOriginatorConfigForm; + } + onConfigurationSet(configuration) { + this.changeOriginatorConfigForm = this.fb.group({ + originatorSource: [configuration ? configuration.originatorSource : null, [Validators.required]], + relationsQuery: [configuration ? configuration.relationsQuery : null, []] + }); + } + validatorTriggers() { + return ['originatorSource']; + } + updateValidators(emitEvent) { + const originatorSource = this.changeOriginatorConfigForm.get('originatorSource').value; + if (originatorSource && originatorSource === OriginatorSource.RELATED) { + this.changeOriginatorConfigForm.get('relationsQuery').setValidators([Validators.required]); + } + else { + this.changeOriginatorConfigForm.get('relationsQuery').setValidators([]); + } + this.changeOriginatorConfigForm.get('relationsQuery').updateValueAndValidity({ emitEvent }); + } +} +ChangeOriginatorConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: ChangeOriginatorConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); +ChangeOriginatorConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: ChangeOriginatorConfigComponent, selector: "tb-transformation-node-change-originator-config", usesInheritance: true, ngImport: i0, template: "
\n \n tb.rulenode.originator-source\n \n \n {{ originatorSourceTranslationMap.get(source) | translate }}\n \n \n \n
\n \n \n \n
\n
\n", components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }, { type: i4$1.MatSelect, selector: "mat-select", inputs: ["disabled", "disableRipple", "tabIndex"], exportAs: ["matSelect"] }, { type: i5.MatOption, selector: "mat-option", exportAs: ["matOption"] }, { type: RelationsQueryConfigComponent, selector: "tb-relations-query-config", inputs: ["disabled", "required"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i10.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], pipes: { "translate": i4.TranslatePipe } }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: ChangeOriginatorConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-transformation-node-change-originator-config', + templateUrl: './change-originator-config.component.html', + styleUrls: [] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); + +class TransformScriptConfigComponent extends RuleNodeConfigurationComponent { + constructor(store, fb, nodeScriptTestService, translate) { + super(store); + this.store = store; + this.fb = fb; + this.nodeScriptTestService = nodeScriptTestService; + this.translate = translate; + } + configForm() { + return this.scriptConfigForm; + } + onConfigurationSet(configuration) { + this.scriptConfigForm = this.fb.group({ + jsScript: [configuration ? configuration.jsScript : null, [Validators.required]] + }); + } + testScript() { + const script = this.scriptConfigForm.get('jsScript').value; + this.nodeScriptTestService.testNodeScript(script, 'update', this.translate.instant('tb.rulenode.transformer'), 'Transform', ['msg', 'metadata', 'msgType'], this.ruleNodeId, 'rulenode/transformation_node_script_fn').subscribe((theScript) => { + if (theScript) { + this.scriptConfigForm.get('jsScript').setValue(theScript); + } + }); + } + onValidate() { + this.jsFuncComponent.validateOnSubmit(); + } +} +TransformScriptConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: TransformScriptConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }, { token: i3$3.NodeScriptTestService }, { token: i4.TranslateService }], target: i0.ɵɵFactoryTarget.Component }); +TransformScriptConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: TransformScriptConfigComponent, selector: "tb-transformation-node-script-config", viewQueries: [{ propertyName: "jsFuncComponent", first: true, predicate: ["jsFuncComponent"], descendants: true, static: true }], usesInheritance: true, ngImport: i0, template: "
\n \n \n \n
\n \n
\n
\n", components: [{ type: i5$1.JsFuncComponent, selector: "tb-js-func", inputs: ["functionName", "functionArgs", "validationArgs", "resultType", "disabled", "fillHeight", "editorCompleter", "globalVariables", "disableUndefinedCheck", "helpId", "noValidate", "required"] }, { type: i6.MatButton, selector: "button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }], pipes: { "translate": i4.TranslatePipe } }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: TransformScriptConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-transformation-node-script-config', + templateUrl: './script-config.component.html', + styleUrls: [] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }, { type: i3$3.NodeScriptTestService }, { type: i4.TranslateService }]; }, propDecorators: { jsFuncComponent: [{ + type: ViewChild, + args: ['jsFuncComponent', { static: true }] + }] } }); + +class ToEmailConfigComponent extends RuleNodeConfigurationComponent { + constructor(store, fb) { + super(store); + this.store = store; + this.fb = fb; + this.mailBodyTypes = [ + { name: 'tb.mail-body-type.plain-text', value: 'false' }, + { name: 'tb.mail-body-type.html', value: 'true' }, + { name: 'tb.mail-body-type.dynamic', value: 'dynamic' } + ]; + } + configForm() { + return this.toEmailConfigForm; + } + onConfigurationSet(configuration) { + this.toEmailConfigForm = this.fb.group({ + fromTemplate: [configuration ? configuration.fromTemplate : null, [Validators.required]], + toTemplate: [configuration ? configuration.toTemplate : null, [Validators.required]], + ccTemplate: [configuration ? configuration.ccTemplate : null, []], + bccTemplate: [configuration ? configuration.bccTemplate : null, []], + subjectTemplate: [configuration ? configuration.subjectTemplate : null, [Validators.required]], + mailBodyType: [configuration ? configuration.mailBodyType : null], + isHtmlTemplate: [configuration ? configuration.isHtmlTemplate : null], + bodyTemplate: [configuration ? configuration.bodyTemplate : null, [Validators.required]], + }); + this.toEmailConfigForm.get('mailBodyType').valueChanges.pipe(startWith([configuration === null || configuration === void 0 ? void 0 : configuration.subjectTemplate])).subscribe((mailBodyType) => { + if (mailBodyType === 'dynamic') { + this.toEmailConfigForm.get('isHtmlTemplate').patchValue('', { emitEvent: false }); + this.toEmailConfigForm.get('isHtmlTemplate').setValidators(Validators.required); + } + else { + this.toEmailConfigForm.get('isHtmlTemplate').clearValidators(); + } + this.toEmailConfigForm.get('isHtmlTemplate').updateValueAndValidity(); + }); + } +} +ToEmailConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: ToEmailConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); +ToEmailConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: ToEmailConfigComponent, selector: "tb-transformation-node-to-email-config", usesInheritance: true, ngImport: i0, template: "
\n \n tb.rulenode.from-template\n \n \n {{ 'tb.rulenode.from-template-required' | translate }}\n \n \n \n \n tb.rulenode.to-template\n \n \n {{ 'tb.rulenode.to-template-required' | translate }}\n \n \n \n \n tb.rulenode.cc-template\n \n \n \n \n tb.rulenode.bcc-template\n \n \n \n \n tb.rulenode.subject-template\n \n \n {{ 'tb.rulenode.subject-template-required' | translate }}\n \n \n \n \n tb.rulenode.mail-body-type\n \n \n {{ type.name | translate }}\n \n \n \n \n tb.rulenode.dynamic-mail-body-type\n \n \n \n \n tb.rulenode.body-template\n \n \n {{ 'tb.rulenode.body-template-required' | translate }}\n \n \n \n
\n", components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }, { type: i4$1.MatSelect, selector: "mat-select", inputs: ["disabled", "disableRipple", "tabIndex"], exportAs: ["matSelect"] }, { type: i5.MatOption, selector: "mat-option", exportAs: ["matOption"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.MatError, selector: "mat-error", inputs: ["id"] }, { type: i3.MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { type: i10.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }], pipes: { "translate": i4.TranslatePipe, "safeHtml": SafeHtmlPipe } }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: ToEmailConfigComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-transformation-node-to-email-config', + templateUrl: './to-email-config.component.html', + styleUrls: [] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); + +class RulenodeCoreConfigTransformModule { +} +RulenodeCoreConfigTransformModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RulenodeCoreConfigTransformModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); +RulenodeCoreConfigTransformModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RulenodeCoreConfigTransformModule, declarations: [ChangeOriginatorConfigComponent, + TransformScriptConfigComponent, + ToEmailConfigComponent], imports: [CommonModule, + SharedModule, + RulenodeCoreConfigCommonModule], exports: [ChangeOriginatorConfigComponent, + TransformScriptConfigComponent, + ToEmailConfigComponent] }); +RulenodeCoreConfigTransformModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RulenodeCoreConfigTransformModule, imports: [[ + CommonModule, + SharedModule, + RulenodeCoreConfigCommonModule + ]] }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RulenodeCoreConfigTransformModule, decorators: [{ + type: NgModule, + args: [{ + declarations: [ + ChangeOriginatorConfigComponent, + TransformScriptConfigComponent, + ToEmailConfigComponent + ], + imports: [ + CommonModule, + SharedModule, + RulenodeCoreConfigCommonModule + ], + exports: [ + ChangeOriginatorConfigComponent, + TransformScriptConfigComponent, + ToEmailConfigComponent + ] + }] + }] }); + +function addRuleNodeCoreLocaleEnglish(translate) { + const enUS = { + tb: { + rulenode: { + 'create-entity-if-not-exists': 'Create new entity if not exists', + 'create-entity-if-not-exists-hint': 'Create a new entity set above if it does not exist.', + 'entity-name-pattern': 'Name pattern', + 'entity-name-pattern-required': 'Name pattern is required', + 'entity-type-pattern': 'Type pattern', + 'entity-type-pattern-required': 'Type pattern is required', + 'entity-cache-expiration': 'Entities cache expiration time (sec)', + 'entity-cache-expiration-hint': 'Specifies maximum time interval allowed to store found entity records. 0 value means that records will never expire.', + 'entity-cache-expiration-required': 'Entities cache expiration time is required.', + 'entity-cache-expiration-range': 'Entities cache expiration time should be greater than or equal to 0.', + 'customer-name-pattern': 'Customer name pattern', + 'customer-name-pattern-required': 'Customer name pattern is required', + 'create-customer-if-not-exists': 'Create new customer if not exists', + 'customer-cache-expiration': 'Customers cache expiration time (sec)', + 'customer-cache-expiration-hint': 'Specifies maximum time interval allowed to store found customer records. 0 value means that records will never expire.', + 'customer-cache-expiration-required': 'Customers cache expiration time is required.', + 'customer-cache-expiration-range': 'Customers cache expiration time should be greater than or equal to 0.', + 'start-interval': 'Start Interval', + 'end-interval': 'End Interval', + 'start-interval-time-unit': 'Start Interval Time Unit', + 'end-interval-time-unit': 'End Interval Time Unit', + 'fetch-mode': 'Fetch mode', + 'fetch-mode-hint': 'If selected fetch mode \'ALL\' you able to choose telemetry sampling order.', + 'order-by': 'Order by', + 'order-by-hint': 'Select to choose telemetry sampling order.', + limit: 'Limit', + 'limit-hint': 'Min limit value is 2, max - 1000. In case you want to fetch a single entry, ' + + 'select fetch mode \'FIRST\' or \'LAST\'.', + 'time-unit-milliseconds': 'Milliseconds', + 'time-unit-seconds': 'Seconds', + 'time-unit-minutes': 'Minutes', + 'time-unit-hours': 'Hours', + 'time-unit-days': 'Days', + 'time-value-range': 'Time value should be in a range from 1 to 2147483647.', + 'start-interval-value-required': 'Start interval value is required.', + 'end-interval-value-required': 'End interval value is required.', + filter: 'Filter', + switch: 'Switch', + 'message-type': 'Message type', + 'message-type-required': 'Message type is required.', + 'message-types-filter': 'Message types filter', + 'no-message-types-found': 'No message types found', + 'no-message-type-matching': '\'{{messageType}}\' not found.', + 'create-new-message-type': 'Create a new one!', + 'message-types-required': 'Message types are required.', + 'client-attributes': 'Client attributes', + 'shared-attributes': 'Shared attributes', + 'server-attributes': 'Server attributes', + 'notify-device': 'Notify Device', + 'notify-device-hint': 'If the message arrives from the device, we will push it back to the device by default.', + 'latest-timeseries': 'Latest timeseries', + 'timeseries-key': 'Timeseries key', + 'data-keys': 'Message data', + 'metadata-keys': 'Message metadata', + 'relations-query': 'Relations query', + 'device-relations-query': 'Device relations query', + 'max-relation-level': 'Max relation level', + 'relation-type-pattern': 'Relation type pattern', + 'relation-type-pattern-required': 'Relation type pattern is required', + 'relation-types-list': 'Relation types to propagate', + 'relation-types-list-hint': 'If Propagate relation types are not selected, ' + + 'alarms will be propagated without filtering by relation type.', + 'unlimited-level': 'Unlimited level', + 'latest-telemetry': 'Latest telemetry', + 'attr-mapping': 'Attributes mapping', + 'source-attribute': 'Source attribute', + 'source-attribute-required': 'Source attribute is required.', + 'source-telemetry': 'Source telemetry', + 'source-telemetry-required': 'Source telemetry is required.', + 'target-attribute': 'Target attribute', + 'target-attribute-required': 'Target attribute is required.', + 'attr-mapping-required': 'At least one attribute mapping should be specified.', + 'fields-mapping': 'Fields mapping', + 'fields-mapping-required': 'At least one field mapping should be specified.', + 'source-field': 'Source field', + 'source-field-required': 'Source field is required.', + 'originator-source': 'Originator source', + 'originator-customer': 'Customer', + 'originator-tenant': 'Tenant', + 'originator-related': 'Related', + 'originator-alarm-originator': 'Alarm Originator', + 'clone-message': 'Clone message', + transform: 'Transform', + 'default-ttl': 'Default TTL in seconds', + 'default-ttl-required': 'Default TTL is required.', + 'min-default-ttl-message': 'Only 0 minimum TTL is allowed.', + 'message-count': 'Message count (0 - unlimited)', + 'message-count-required': 'Message count is required.', + 'min-message-count-message': 'Only 0 minimum message count is allowed.', + 'period-seconds': 'Period in seconds', + 'period-seconds-required': 'Period is required.', + 'use-metadata-period-in-seconds-patterns': 'Use period in seconds pattern', + 'use-metadata-period-in-seconds-patterns-hint': 'If selected, rule node use period in seconds interval pattern from message metadata or data ' + + 'assuming that intervals are in the seconds.', + 'period-in-seconds-pattern': 'Period in seconds pattern', + 'period-in-seconds-pattern-required': 'Period in seconds pattern is required', + 'min-period-seconds-message': 'Only 1 second minimum period is allowed.', + originator: 'Originator', + 'message-body': 'Message body', + 'message-metadata': 'Message metadata', + generate: 'Generate', + 'test-generator-function': 'Test generator function', + generator: 'Generator', + 'test-filter-function': 'Test filter function', + 'test-switch-function': 'Test switch function', + 'test-transformer-function': 'Test transformer function', + transformer: 'Transformer', + 'alarm-create-condition': 'Alarm create condition', + 'test-condition-function': 'Test condition function', + 'alarm-clear-condition': 'Alarm clear condition', + 'alarm-details-builder': 'Alarm details builder', + 'test-details-function': 'Test details function', + 'alarm-type': 'Alarm type', + 'alarm-type-required': 'Alarm type is required.', + 'alarm-severity': 'Alarm severity', + 'alarm-severity-required': 'Alarm severity is required', + 'alarm-status-filter': 'Alarm status filter', + 'alarm-status-list-empty': 'Alarm status list is empty', + 'no-alarm-status-matching': 'No alarm status matching were found.', + propagate: 'Propagate', + condition: 'Condition', + details: 'Details', + 'to-string': 'To string', + 'test-to-string-function': 'Test to string function', + 'from-template': 'From Template', + 'from-template-required': 'From Template is required', + 'to-template': 'To Template', + 'to-template-required': 'To Template is required', + 'mail-address-list-template-hint': 'Comma separated address list, use ${metadataKey' + + '} for value from metadata, $[messageKey' + + '] for value from message body', + 'cc-template': 'Cc Template', + 'bcc-template': 'Bcc Template', + 'subject-template': 'Subject Template', + 'subject-template-required': 'Subject Template is required', + 'body-template': 'Body Template', + 'body-template-required': 'Body Template is required', + 'dynamic-mail-body-type': 'Dynamic mail body type', + 'mail-body-type': 'Mail body type', + 'request-id-metadata-attribute': 'Request Id Metadata attribute name', + 'timeout-sec': 'Timeout in seconds', + 'timeout-required': 'Timeout is required', + 'min-timeout-message': 'Only 0 minimum timeout value is allowed.', + 'endpoint-url-pattern': 'Endpoint URL pattern', + 'endpoint-url-pattern-required': 'Endpoint URL pattern is required', + 'request-method': 'Request method', + 'use-simple-client-http-factory': 'Use simple client HTTP factory', + 'ignore-request-body': 'Without request body', + 'read-timeout': 'Read timeout in millis', + 'read-timeout-hint': 'The value of 0 means an infinite timeout', + 'max-parallel-requests-count': 'Max number of parallel requests', + 'max-parallel-requests-count-hint': 'The value of 0 specifies no limit in parallel processing', + headers: 'Headers', + 'headers-hint': 'Use ${metadataKey} ' + + 'for value from metadata, $[messageKey] ' + + 'for value from message body in header/value fields', + header: 'Header', + 'header-required': 'Header is required', + value: 'Value', + 'value-required': 'Value is required', + 'topic-pattern': 'Topic pattern', + 'topic-pattern-required': 'Topic pattern is required', + topic: 'Topic', + 'topic-required': 'Topic is required', + 'bootstrap-servers': 'Bootstrap servers', + 'bootstrap-servers-required': 'Bootstrap servers value is required', + 'other-properties': 'Other properties', + key: 'Key', + 'key-required': 'Key is required', + retries: 'Automatically retry times if fails', + 'min-retries-message': 'Only 0 minimum retries is allowed.', + 'batch-size-bytes': 'Produces batch size in bytes', + 'min-batch-size-bytes-message': 'Only 0 minimum batch size is allowed.', + 'linger-ms': 'Time to buffer locally (ms)', + 'min-linger-ms-message': 'Only 0 ms minimum value is allowed.', + 'buffer-memory-bytes': 'Client buffer max size in bytes', + 'min-buffer-memory-message': 'Only 0 minimum buffer size is allowed.', + acks: 'Number of acknowledgments', + 'key-serializer': 'Key serializer', + 'key-serializer-required': 'Key serializer is required', + 'value-serializer': 'Value serializer', + 'value-serializer-required': 'Value serializer is required', + 'topic-arn-pattern': 'Topic ARN pattern', + 'topic-arn-pattern-required': 'Topic ARN pattern is required', + 'aws-access-key-id': 'AWS Access Key ID', + 'aws-access-key-id-required': 'AWS Access Key ID is required', + 'aws-secret-access-key': 'AWS Secret Access Key', + 'aws-secret-access-key-required': 'AWS Secret Access Key is required', + 'aws-region': 'AWS Region', + 'aws-region-required': 'AWS Region is required', + 'exchange-name-pattern': 'Exchange name pattern', + 'routing-key-pattern': 'Routing key pattern', + 'message-properties': 'Message properties', + host: 'Host', + 'host-required': 'Host is required', + port: 'Port', + 'port-required': 'Port is required', + 'port-range': 'Port should be in a range from 1 to 65535.', + 'virtual-host': 'Virtual host', + username: 'Username', + password: 'Password', + 'automatic-recovery': 'Automatic recovery', + 'connection-timeout-ms': 'Connection timeout (ms)', + 'min-connection-timeout-ms-message': 'Only 0 ms minimum value is allowed.', + 'handshake-timeout-ms': 'Handshake timeout (ms)', + 'min-handshake-timeout-ms-message': 'Only 0 ms minimum value is allowed.', + 'client-properties': 'Client properties', + 'queue-url-pattern': 'Queue URL pattern', + 'queue-url-pattern-required': 'Queue URL pattern is required', + 'delay-seconds': 'Delay (seconds)', + 'min-delay-seconds-message': 'Only 0 seconds minimum value is allowed.', + 'max-delay-seconds-message': 'Only 900 seconds maximum value is allowed.', + name: 'Name', + 'name-required': 'Name is required', + 'queue-type': 'Queue type', + 'sqs-queue-standard': 'Standard', + 'sqs-queue-fifo': 'FIFO', + 'gcp-project-id': 'GCP project ID', + 'gcp-project-id-required': 'GCP project ID is required', + 'gcp-service-account-key': 'GCP service account key file', + 'gcp-service-account-key-required': 'GCP service account key file is required', + 'pubsub-topic-name': 'Topic name', + 'pubsub-topic-name-required': 'Topic name is required', + 'message-attributes': 'Message attributes', + 'message-attributes-hint': 'Use ${metadataKey} ' + + 'for value from metadata, $[messageKey] ' + + 'for value from message body in name/value fields', + 'connect-timeout': 'Connection timeout (sec)', + 'connect-timeout-required': 'Connection timeout is required.', + 'connect-timeout-range': 'Connection timeout should be in a range from 1 to 200.', + 'client-id': 'Client ID', + 'client-id-hint': 'Hint: Optional. Leave empty for auto-generated client id. Be careful when specifying the Client ID.' + + 'Majority of the MQTT brokers will not allow multiple connections with the same client id. ' + + 'To connect to such brokers, your mqtt client id must be unique. ' + + 'When platform is running in a micro-services mode, the copy of rule nodeis launched in each micro-service. ' + + 'This will automatically lead to multiple mqtt clients with the same id and may cause failures of the rule node.', + 'device-id': 'Device ID', + 'device-id-required': 'Device ID is required.', + 'clean-session': 'Clean session', + 'enable-ssl': 'Enable SSL', + credentials: 'Credentials', + 'credentials-type': 'Credentials type', + 'credentials-type-required': 'Credentials type is required.', + 'credentials-anonymous': 'Anonymous', + 'credentials-basic': 'Basic', + 'credentials-pem': 'PEM', + 'credentials-pem-hint': 'At least Server CA certificate file or a pair of Client certificate and Client private key files are required', + 'credentials-sas': 'Shared Access Signature', + 'sas-key': 'SAS Key', + 'sas-key-required': 'SAS Key is required.', + hostname: 'Hostname', + 'hostname-required': 'Hostname is required.', + 'azure-ca-cert': 'CA certificate file', + 'username-required': 'Username is required.', + 'password-required': 'Password is required.', + 'ca-cert': 'Server CA certificate file *', + 'private-key': 'Client private key file *', + cert: 'Client certificate file *', + 'no-file': 'No file selected.', + 'drop-file': 'Drop a file or click to select a file to upload.', + 'private-key-password': 'Private key password', + 'use-system-smtp-settings': 'Use system SMTP settings', + 'use-metadata-interval-patterns': 'Use interval patterns', + 'use-metadata-interval-patterns-hint': 'If selected, rule node use start and end interval patterns from message metadata or data ' + + 'assuming that intervals are in the milliseconds.', + 'use-message-alarm-data': 'Use message alarm data', + 'use-dynamically-change-the-severity-of-alar': 'Use dynamically change the severity of alarm', + 'check-all-keys': 'Check that all selected keys are present', + 'check-all-keys-hint': 'If selected, checks that all specified keys are present in the message data and metadata.', + 'check-relation-to-specific-entity': 'Check relation to specific entity', + 'check-relation-hint': 'Checks existence of relation to specific entity or to any entity based on direction and relation type.', + 'delete-relation-to-specific-entity': 'Delete relation to specific entity', + 'delete-relation-hint': 'Deletes relation from the originator of the incoming message to the specified ' + + 'entity or list of entities based on direction and type.', + 'remove-current-relations': 'Remove current relations', + 'remove-current-relations-hint': 'Removes current relations from the originator of the incoming message based on direction and type.', + 'change-originator-to-related-entity': 'Change originator to related entity', + 'change-originator-to-related-entity-hint': 'Used to process submitted message as a message from another entity.', + 'start-interval-pattern': 'Start interval pattern', + 'end-interval-pattern': 'End interval pattern', + 'start-interval-pattern-required': 'Start interval pattern is required', + 'end-interval-pattern-required': 'End interval pattern is required', + 'smtp-protocol': 'Protocol', + 'smtp-host': 'SMTP host', + 'smtp-host-required': 'SMTP host is required.', + 'smtp-port': 'SMTP port', + 'smtp-port-required': 'You must supply a smtp port.', + 'smtp-port-range': 'SMTP port should be in a range from 1 to 65535.', + 'timeout-msec': 'Timeout ms', + 'min-timeout-msec-message': 'Only 0 ms minimum value is allowed.', + 'enter-username': 'Enter username', + 'enter-password': 'Enter password', + 'enable-tls': 'Enable TLS', + 'tls-version': 'TLS version', + 'enable-proxy': 'Enable proxy', + 'use-system-proxy-properties': 'Use system proxy properties', + 'proxy-host': 'Proxy host', + 'proxy-host-required': 'Proxy host is required.', + 'proxy-port': 'Proxy port', + 'proxy-port-required': 'Proxy port is required.', + 'proxy-port-range': 'Proxy port should be in a range from 1 to 65535.', + 'proxy-user': 'Proxy user', + 'proxy-password': 'Proxy password', + 'proxy-scheme': 'Proxy scheme', + 'numbers-to-template': 'Phone Numbers To Template', + 'numbers-to-template-required': 'Phone Numbers To Template is required', + 'numbers-to-template-hint': 'Comma separated Phone Numbers, use ${' + + 'metadataKey} for value from metadata, ' + + '$[messageKey] for value from message body', + 'sms-message-template': 'SMS message Template', + 'sms-message-template-required': 'SMS message Template is required', + 'use-system-sms-settings': 'Use system SMS provider settings', + 'min-period-0-seconds-message': 'Only 0 second minimum period is allowed.', + 'max-pending-messages': 'Maximum pending messages', + 'max-pending-messages-required': 'Maximum pending messages is required.', + 'max-pending-messages-range': 'Maximum pending messages should be in a range from 1 to 100000.', + 'originator-types-filter': 'Originator types filter', + 'interval-seconds': 'Interval in seconds', + 'interval-seconds-required': 'Interval is required.', + 'min-interval-seconds-message': 'Only 1 second minimum interval is allowed.', + 'output-timeseries-key-prefix': 'Output timeseries key prefix', + 'output-timeseries-key-prefix-required': 'Output timeseries key prefix required.', + 'separator-hint': 'You should press "enter" to complete field input.', + 'entity-details': 'Select entity details:', + 'entity-details-title': 'Title', + 'entity-details-country': 'Country', + 'entity-details-state': 'State', + 'entity-details-zip': 'Zip', + 'entity-details-address': 'Address', + 'entity-details-address2': 'Address2', + 'entity-details-additional_info': 'Additional Info', + 'entity-details-phone': 'Phone', + 'entity-details-email': 'Email', + 'add-to-metadata': 'Add selected details to message metadata', + 'add-to-metadata-hint': 'If selected, adds the selected details keys to the message metadata instead of message data.', + 'entity-details-list-empty': 'No entity details selected.', + 'no-entity-details-matching': 'No entity details matching were found.', + 'custom-table-name': 'Custom table name', + 'custom-table-name-required': 'Table Name is required', + 'custom-table-hint': 'You should enter the table name without prefix \'cs_tb_\'.', + 'message-field': 'Message field', + 'message-field-required': 'Message field is required.', + 'table-col': 'Table column', + 'table-col-required': 'Table column is required.', + 'latitude-key-name': 'Latitude key name', + 'longitude-key-name': 'Longitude key name', + 'latitude-key-name-required': 'Latitude key name is required.', + 'longitude-key-name-required': 'Longitude key name is required.', + 'fetch-perimeter-info-from-message-metadata': 'Fetch perimeter information from message metadata', + 'perimeter-circle': 'Circle', + 'perimeter-polygon': 'Polygon', + 'perimeter-type': 'Perimeter type', + 'circle-center-latitude': 'Center latitude', + 'circle-center-latitude-required': 'Center latitude is required.', + 'circle-center-longitude': 'Center longitude', + 'circle-center-longitude-required': 'Center longitude is required.', + 'range-unit-meter': 'Meter', + 'range-unit-kilometer': 'Kilometer', + 'range-unit-foot': 'Foot', + 'range-unit-mile': 'Mile', + 'range-unit-nautical-mile': 'Nautical mile', + 'range-units': 'Range units', + range: 'Range', + 'range-required': 'Range is required.', + 'polygon-definition': 'Polygon definition', + 'polygon-definition-required': 'Polygon definition is required.', + 'polygon-definition-hint': 'Please, use the following format for manual definition of polygon: [[lat1,lon1],[lat2,lon2], ... ,[latN,lonN]].', + 'min-inside-duration': 'Minimal inside duration', + 'min-inside-duration-value-required': 'Minimal inside duration is required', + 'min-inside-duration-time-unit': 'Minimal inside duration time unit', + 'min-outside-duration': 'Minimal outside duration', + 'min-outside-duration-value-required': 'Minimal outside duration is required', + 'min-outside-duration-time-unit': 'Minimal outside duration time unit', + 'tell-failure-if-absent': 'Tell Failure', + 'tell-failure-if-absent-hint': 'If at least one selected key doesn\'t exist the outbound message will report "Failure".', + 'get-latest-value-with-ts': 'Fetch Latest telemetry with Timestamp', + 'get-latest-value-with-ts-hint': 'If selected, latest telemetry values will be added to the outbound message metadata with timestamp, ' + + 'e.g: "temp": "{"ts":1574329385897, "value":42}"', + 'use-redis-queue': 'Use redis queue for message persistence', + 'trim-redis-queue': 'Trim redis queue', + 'redis-queue-max-size': 'Redis queue max size', + 'add-metadata-key-values-as-kafka-headers': 'Add Message metadata key-value pairs to Kafka record headers', + 'add-metadata-key-values-as-kafka-headers-hint': 'If selected, key-value pairs from message metadata will be added to the outgoing records headers as byte arrays with predefined charset encoding.', + 'charset-encoding': 'Charset encoding', + 'charset-encoding-required': 'Charset encoding is required.', + 'charset-us-ascii': 'US-ASCII', + 'charset-iso-8859-1': 'ISO-8859-1', + 'charset-utf-8': 'UTF-8', + 'charset-utf-16be': 'UTF-16BE', + 'charset-utf-16le': 'UTF-16LE', + 'charset-utf-16': 'UTF-16', + 'select-queue-hint': 'The queue name can be selected from a drop-down list or add a custom name.', + 'persist-alarm-rules': 'Persist state of alarm rules', + 'fetch-alarm-rules': 'Fetch state of alarm rules', + 'input-value-key': 'Input value key', + 'input-value-key-required': 'Input value key is required.', + 'output-value-key': 'Output value key', + 'output-value-key-required': 'Output value key is required.', + round: 'Decimals', + 'round-range': 'Decimals should be in a range from 0 to 15.', + 'use-cache': 'Use cache for latest value', + 'tell-failure-if-delta-is-negative': 'Tell Failure if delta is negative', + 'add-period-between-msgs': 'Add period between messages', + 'period-value-key': 'Period value key', + 'period-key-required': 'Period value key is required.', + 'general-pattern-hint': 'Hint: use ${metadataKey} ' + + 'for value from metadata, $[messageKey] ' + + 'for value from message body', + 'alarm-severity-pattern-hint': 'Hint: use ${metadataKey} ' + + 'for value from metadata, $[messageKey] ' + + 'for value from message body. Alarm severity should be system (CRITICAL, MAJOR etc.)' + }, + 'key-val': { + key: 'Key', + value: 'Value', + 'remove-entry': 'Remove entry', + 'add-entry': 'Add entry' + }, + 'mail-body-type': { + 'plain-text': 'Plain Text', + html: 'HTML', + dynamic: 'Dynamic' + } + } + }; + translate.setTranslation('en_US', enUS, true); +} + +class RuleNodeCoreConfigModule { + constructor(translate) { + addRuleNodeCoreLocaleEnglish(translate); + } +} +RuleNodeCoreConfigModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RuleNodeCoreConfigModule, deps: [{ token: i4.TranslateService }], target: i0.ɵɵFactoryTarget.NgModule }); +RuleNodeCoreConfigModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RuleNodeCoreConfigModule, declarations: [EmptyConfigComponent], imports: [CommonModule, + SharedModule], exports: [RuleNodeCoreConfigActionModule, + RuleNodeCoreConfigFilterModule, + RulenodeCoreConfigEnrichmentModule, + RulenodeCoreConfigTransformModule, + EmptyConfigComponent] }); +RuleNodeCoreConfigModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RuleNodeCoreConfigModule, imports: [[ + CommonModule, + SharedModule + ], RuleNodeCoreConfigActionModule, + RuleNodeCoreConfigFilterModule, + RulenodeCoreConfigEnrichmentModule, + RulenodeCoreConfigTransformModule] }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RuleNodeCoreConfigModule, decorators: [{ + type: NgModule, + args: [{ + declarations: [ + EmptyConfigComponent + ], + imports: [ + CommonModule, + SharedModule + ], + exports: [ + RuleNodeCoreConfigActionModule, + RuleNodeCoreConfigFilterModule, + RulenodeCoreConfigEnrichmentModule, + RulenodeCoreConfigTransformModule, + EmptyConfigComponent + ] + }] + }], ctorParameters: function () { return [{ type: i4.TranslateService }]; } }); + +/* + * Public API Surface of rule-core-config + */ + +/** + * Generated bundle index. Do not edit. + */ + +export { AssignCustomerConfigComponent, AttributesConfigComponent, AzureIotHubConfigComponent, CalculateDeltaConfigComponent, ChangeOriginatorConfigComponent, CheckAlarmStatusComponent, CheckMessageConfigComponent, CheckPointConfigComponent, CheckRelationConfigComponent, ClearAlarmConfigComponent, CreateAlarmConfigComponent, CreateRelationConfigComponent, CredentialsConfigComponent, CustomerAttributesConfigComponent, DeleteRelationConfigComponent, DeviceAttributesConfigComponent, DeviceProfileConfigComponent, DeviceRelationsQueryConfigComponent, EmptyConfigComponent, EntityDetailsConfigComponent, GeneratorConfigComponent, GetTelemetryFromDatabaseConfigComponent, GpsGeoActionConfigComponent, GpsGeoFilterConfigComponent, KafkaConfigComponent, KvMapConfigComponent, LogConfigComponent, MessageTypeConfigComponent, MessageTypesConfigComponent, MqttConfigComponent, MsgCountConfigComponent, MsgDelayConfigComponent, OriginatorAttributesConfigComponent, OriginatorFieldsConfigComponent, OriginatorTypeConfigComponent, PubSubConfigComponent, PushToCloudConfigComponent, PushToEdgeConfigComponent, RabbitMqConfigComponent, RelatedAttributesConfigComponent, RelationsQueryConfigComponent, RestApiCallConfigComponent, RpcReplyConfigComponent, RpcRequestConfigComponent, RuleNodeCoreConfigActionModule, RuleNodeCoreConfigFilterModule, RuleNodeCoreConfigModule, RulenodeCoreConfigCommonModule, RulenodeCoreConfigEnrichmentModule, RulenodeCoreConfigTransformModule, SafeHtmlPipe, SaveToCustomTableConfigComponent, ScriptConfigComponent, SendEmailConfigComponent, SendSmsConfigComponent, SnsConfigComponent, SqsConfigComponent, SwitchConfigComponent, TenantAttributesConfigComponent, TimeseriesConfigComponent, ToEmailConfigComponent, TransformScriptConfigComponent, UnassignCustomerConfigComponent }; +//# sourceMappingURL=rulenode-core-config.js.map diff --git a/ui-ngx/.browserslistrc b/ui-ngx/.browserslistrc new file mode 100644 index 0000000000..4f9ac26980 --- /dev/null +++ b/ui-ngx/.browserslistrc @@ -0,0 +1,16 @@ +# This file is used by the build system to adjust CSS and JS output to support the specified browsers below. +# For additional information regarding the format and rule options, please see: +# https://github.com/browserslist/browserslist#queries + +# For the full list of supported browsers by the Angular framework, please see: +# https://angular.io/guide/browser-support + +# You can see what browsers were selected by your queries by running: +# npx browserslist + +last 1 Chrome version +last 1 Firefox version +last 2 Edge major versions +last 2 Safari major versions +last 2 iOS major versions +Firefox ESR diff --git a/ui-ngx/angular.json b/ui-ngx/angular.json index 0d6203c88e..7565ae770c 100644 --- a/ui-ngx/angular.json +++ b/ui-ngx/angular.json @@ -11,6 +11,9 @@ "schematics": { "@schematics/angular:component": { "style": "scss" + }, + "@schematics/angular:application": { + "strict": true } }, "architect": { @@ -92,6 +95,7 @@ "node_modules/tinycolor2/dist/tinycolor-min.js", "node_modules/split.js/dist/split.min.js", "node_modules/systemjs/dist/system.js", + "node_modules/systemjs-babel/dist/systemjs-babel.js", "node_modules/marked/lib/marked.js", "node_modules/prismjs/prism.js", "node_modules/prismjs/components/prism-css.min.js", @@ -99,7 +103,7 @@ "node_modules/prismjs/components/prism-json.min.js", "node_modules/prismjs/components/prism-javascript.min.js", "node_modules/prismjs/components/prism-typescript.min.js", - "node_modules/prismjs/plugins/line-numbers/prism-line-numbers.js" + "node_modules/prismjs/plugins/line-numbers/prism-line-numbers.min.js" ], "customWebpackConfig": { "path": "./extra-webpack.config.js" @@ -130,7 +134,9 @@ "jquery.terminal", "tooltipster", "jstree", - "qrcode" + "qrcode", + "wcwidth", + "leaflet-polylinedecorator" ] }, "configurations": { @@ -141,7 +147,14 @@ "with": "src/environments/environment.prod.ts" } ], - "optimization": true, + "optimization": { + "scripts": true, + "styles": { + "minify": true, + "inlineCritical": false + }, + "fonts": false + }, "outputHashing": "all", "sourceMap": false, "namedChunks": false, @@ -155,6 +168,21 @@ "maximumError": "12mb" } ] + }, + "development": { + "buildOptimizer": false, + "optimization": { + "scripts": false, + "styles": { + "minify": false, + "inlineCritical": false + }, + "fonts": false + }, + "vendorChunk": true, + "extractLicenses": false, + "sourceMap": true, + "namedChunks": true } } }, @@ -167,8 +195,12 @@ "configurations": { "production": { "browserTarget": "thingsboard:build:production" + }, + "development": { + "browserTarget": "thingsboard:build:development" } - } + }, + "defaultConfiguration": "development" }, "extract-i18n": { "builder": "@angular-devkit/build-angular:extract-i18n", diff --git a/ui-ngx/extra-webpack.config.js b/ui-ngx/extra-webpack.config.js index ef2e115252..e1efad5e67 100644 --- a/ui-ngx/extra-webpack.config.js +++ b/ui-ngx/extra-webpack.config.js @@ -14,7 +14,7 @@ * limitations under the License. */ const CompressionPlugin = require("compression-webpack-plugin"); -const TerserPlugin = require("terser-webpack-plugin"); +const JavaScriptOptimizerPlugin = require("@angular-devkit/build-angular/src/webpack/plugins/javascript-optimizer-plugin").JavaScriptOptimizerPlugin; const webpack = require("webpack"); const dirTree = require("directory-tree"); const ngWebpack = require('@ngtools/webpack'); @@ -52,7 +52,10 @@ module.exports = (config, options) => { }) ); config.plugins.push( - new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/) + new webpack.IgnorePlugin({ + resourceRegExp: /^\.\/locale$/, + contextRegExp: /moment$/, + }) ); if (config.mode === 'production') { @@ -62,11 +65,10 @@ module.exports = (config, options) => { angularCompilerOptions.emitNgModuleScope = true; config.plugins.splice(index, 1); config.plugins.push(new ngWebpack.ivy.AngularWebpackPlugin(angularCompilerOptions)); - const terserPluginOptions = config.optimization.minimizer[1].options; - delete terserPluginOptions.terserOptions.compress.global_defs.ngJitMode; - terserPluginOptions.terserOptions.compress.side_effects = false; + const javascriptOptimizerOptions = config.optimization.minimizer[1].options; + delete javascriptOptimizerOptions.define.ngJitMode; config.optimization.minimizer.splice(1, 1); - config.optimization.minimizer.push(new TerserPlugin(terserPluginOptions)); + config.optimization.minimizer.push(new JavaScriptOptimizerPlugin(javascriptOptimizerOptions)); } return config; }; diff --git a/ui-ngx/package.json b/ui-ngx/package.json index 44cfd99ff5..1256edc46c 100644 --- a/ui-ngx/package.json +++ b/ui-ngx/package.json @@ -3,7 +3,7 @@ "version": "3.3.3", "scripts": { "ng": "ng", - "start": "node --max_old_space_size=8048 ./node_modules/@angular/cli/bin/ng serve --host 0.0.0.0 --open", + "start": "node --max_old_space_size=8048 ./node_modules/@angular/cli/bin/ng serve --configuration development --host 0.0.0.0 --open", "build": "ng build", "build:prod": "ng build --configuration production --vendor-chunk", "test": "ng test", @@ -25,13 +25,13 @@ "@angular/platform-browser-dynamic": "^12.2.13", "@angular/router": "^12.2.13", "@auth0/angular-jwt": "^5.0.2", - "@date-io/date-fns": "^2.10.11", + "@date-io/date-fns": "^2.11.0", "@flowjs/flow.js": "^2.14.1", "@flowjs/ngx-flow": "~0.4.6", "@geoman-io/leaflet-geoman-free": "^2.11.3", "@juggle/resize-observer": "^3.3.1", "@mat-datetimepicker/core": "~7.0.1", - "@material-ui/core": "^4.11.4", + "@material-ui/core": "^4.12.3", "@material-ui/icons": "^4.11.2", "@material-ui/pickers": "^3.3.10", "@ngrx/effects": "^12.5.1", @@ -39,24 +39,23 @@ "@ngrx/store-devtools": "^12.5.1", "@ngx-translate/core": "^13.0.0", "@ngx-translate/http-loader": "^6.0.0", - "ace-builds": "^1.4.12", - "angular-gridster2": "~11.2.0", + "ace-builds": "^1.4.13", + "angular-gridster2": "~12.1.1", "angular2-hotkeys": "^2.4.0", "canvas-gauges": "^2.1.7", - "compass-sass-mixins": "^0.12.7", - "core-js": "^3.18.3", - "date-fns": "^2.21.3", + "core-js": "^3.19.2", + "date-fns": "^2.26.0", "flot": "git://github.com/thingsboard/flot.git#0.9-work", "flot.curvedlines": "git://github.com/MichaelZinsmaier/CurvedLines.git#master", "font-awesome": "^4.7.0", - "html2canvas": "^1.0.0-rc.7", - "jquery": "^3.5.1", - "jquery.terminal": "^2.24.0", - "js-beautify": "^1.13.13", + "html2canvas": "^1.3.3", + "jquery": "^3.6.0", + "jquery.terminal": "^2.29.4", + "js-beautify": "^1.14.0", "json-schema-defaults": "^0.4.0", - "jstree": "^3.3.11", + "jstree": "^3.3.12", "jstree-bootstrap-theme": "^1.0.1", - "jszip": "^3.6.0", + "jszip": "^3.7.1", "leaflet": "^1.7.1", "leaflet-polylinedecorator": "^1.6.0", "leaflet-providers": "^1.13.0", @@ -65,82 +64,85 @@ "material-design-icons": "^3.0.1", "messageformat": "^2.3.0", "moment": "^2.29.1", - "moment-timezone": "^0.5.33", - "mousetrap": "1.6.3", - "ngx-clipboard": "^14.0.1", + "moment-timezone": "^0.5.34", + "ngx-clipboard": "^14.0.2", "ngx-color-picker": "^11.0.0", - "ngx-daterangepicker-material": "^4.0.1", + "ngx-daterangepicker-material": "^5.0.1", "ngx-drag-drop": "^2.0.0", "ngx-flowchart": "git://github.com/thingsboard/ngx-flowchart.git#master", - "ngx-hm-carousel": "^2.0.0-rc.1", - "ngx-markdown": "^11.1.3", - "ngx-sharebuttons": "^8.0.5", - "ngx-translate-messageformat-compiler": "^4.9.0", + "ngx-hm-carousel": "^2.0.1", + "ngx-markdown": "^12.0.1", + "ngx-sharebuttons": "^9.0.0", + "ngx-translate-messageformat-compiler": "^4.11.0", "objectpath": "^2.0.0", - "prettier": "^2.1.2", + "prettier": "^2.5.0", "prop-types": "^15.7.2", - "qrcode": "^1.4.4", + "qrcode": "^1.5.0", "raphael": "^2.3.0", - "rc-select": "~10.5.1", - "react": "~16.14.0", - "react-ace": "^9.1.4", - "react-dom": "^16.13.1", - "react-dropzone": "^11.2.0", + "rc-select": "~13.2.0", + "react": "~17.0.2", + "react-ace": "^9.5.0", + "react-dom": "^17.0.2", + "react-dropzone": "^11.4.2", "reactcss": "^1.2.3", "rxjs": "~6.6.7", "schema-inspector": "^2.0.1", - "screenfull": "^5.1.0", + "screenfull": "^6.0.0", "split.js": "^1.6.4", - "systemjs": "0.21.5", + "systemjs": "6.11.0", + "systemjs-babel": "^0.3.1", "tinycolor2": "^1.4.2", "tooltipster": "^4.2.8", - "tslib": "^2.2.0", + "tslib": "^2.3.1", "tv4": "^1.3.0", "typeface-roboto": "^1.1.13", "zone.js": "~0.11.4" }, "devDependencies": { - "@angular-builders/custom-webpack": "~11.1.1", + "@angular-builders/custom-webpack": "~12.1.3", "@angular-devkit/build-angular": "^12.2.13", "@angular/cli": "^12.2.13", "@angular/compiler-cli": "^12.2.13", "@angular/language-service": "^12.2.13", "@ngtools/webpack": "~12.2.13", - "@types/canvas-gauges": "^2.1.2", - "@types/flot": "^0.0.31", - "@types/jasmine": "~3.7.4", - "@types/jasminewd2": "^2.0.9", - "@types/jquery": "^3.5.2", - "@types/js-beautify": "^1.13.1", - "@types/jstree": "^3.3.40", + "@types/canvas-gauges": "^2.1.4", + "@types/flot": "^0.0.32", + "@types/jasmine": "~3.10.2", + "@types/jasminewd2": "^2.0.10", + "@types/jquery": "^3.5.9", + "@types/js-beautify": "^1.13.3", + "@types/jstree": "^3.3.41", "@types/leaflet": "^1.7.6", "@types/leaflet-polylinedecorator": "^1.6.1", "@types/leaflet-providers": "^1.2.1", "@types/leaflet.gridlayer.googlemutant": "^0.4.6", "@types/leaflet.markercluster": "^1.4.6", - "@types/lodash": "^4.14.170", + "@types/lodash": "^4.14.177", "@types/moment-timezone": "^0.5.30", - "@types/mousetrap": "1.6.3", - "@types/raphael": "^2.3.1", - "@types/react": "^16.9.51", - "@types/react-dom": "^16.9.8", - "@types/tinycolor2": "^1.4.2", - "@types/tooltipster": "^0.0.30", + "@types/mousetrap": "^1.6.0", + "@types/node": "~15.14.9", + "@types/raphael": "^2.3.2", + "@types/react": "^17.0.37", + "@types/react-dom": "^17.0.11", + "@types/systemjs": "6.1.1", + "@types/tinycolor2": "^1.4.3", + "@types/tooltipster": "^0.0.31", "codelyzer": "^6.0.2", - "compression-webpack-plugin": "^6.1.1", - "directory-tree": "^2.2.4", - "jasmine-core": "~3.7.1", + "compression-webpack-plugin": "^9.0.1", + "directory-tree": "^3.0.1", + "jasmine-core": "~3.10.1", "jasmine-spec-reporter": "~7.0.0", - "karma": "~6.3.2", + "karma": "~6.3.9", "karma-chrome-launcher": "~3.1.0", "karma-coverage-istanbul-reporter": "~3.0.3", - "karma-jasmine": "~4.0.0", - "karma-jasmine-html-reporter": "^1.5.0", + "karma-jasmine": "~4.0.1", + "karma-jasmine-html-reporter": "^1.7.0", "ngrx-store-freeze": "^0.2.4", "patch-package": "^6.4.7", "postinstall-prepare": "^2.0.0", "protractor": "~7.0.0", - "ts-node": "^9.0.0", + "raw-loader": "^4.0.2", + "ts-node": "^10.4.0", "tslint": "~6.1.3", "typescript": "~4.3.5", "webpack": "^5.64.4" @@ -148,4 +150,4 @@ "resolutions": { "lodash": "~4.17.21" } -} \ No newline at end of file +} diff --git a/ui-ngx/src/.browserslistrc b/ui-ngx/src/.browserslistrc deleted file mode 100644 index 6ef5d1aee4..0000000000 --- a/ui-ngx/src/.browserslistrc +++ /dev/null @@ -1,10 +0,0 @@ -# This file is currently used by autoprefixer to adjust CSS to support the below specified browsers -# For additional information regarding the format and rule options, please see: -# https://github.com/browserslist/browserslist#queries -# -# For IE 9-11 support, please remove 'not' from the last line of the file and adjust as needed - -> 0.5% -last 2 versions -Firefox ESR -not dead diff --git a/ui-ngx/src/app/core/http/rule-chain.service.ts b/ui-ngx/src/app/core/http/rule-chain.service.ts index e65e7017e0..0e11c51fcb 100644 --- a/ui-ngx/src/app/core/http/rule-chain.service.ts +++ b/ui-ngx/src/app/core/http/rule-chain.service.ts @@ -45,6 +45,7 @@ import { EntityType } from '@shared/models/entity-type.models'; import { deepClone, snakeCase } from '@core/utils'; import { DebugRuleNodeEventBody } from '@app/shared/models/event.models'; import { Edge } from '@shared/models/edge.models'; +import { IModulesMap } from '@modules/common/modules-map.models'; @Injectable({ providedIn: 'root' @@ -119,14 +120,14 @@ export class RuleChainService { ); } - public getRuleNodeComponents(ruleNodeConfigResourcesModulesMap: {[key: string]: any}, ruleChainType: RuleChainType, config?: RequestConfig): + public getRuleNodeComponents(modulesMap: IModulesMap, ruleChainType: RuleChainType, config?: RequestConfig): Observable> { if (this.ruleNodeComponentsMap.get(ruleChainType)) { return of(this.ruleNodeComponentsMap.get(ruleChainType)); } else { return this.loadRuleNodeComponents(ruleChainType, config).pipe( mergeMap((components) => { - return this.resolveRuleNodeComponentsUiResources(components, ruleNodeConfigResourcesModulesMap).pipe( + return this.resolveRuleNodeComponentsUiResources(components, modulesMap).pipe( map((ruleNodeComponents) => { this.ruleNodeComponentsMap.set(ruleChainType, ruleNodeComponents); this.ruleNodeComponentsMap.get(ruleChainType).push(ruleChainNodeComponent); @@ -220,11 +221,11 @@ export class RuleChainService { } private resolveRuleNodeComponentsUiResources(components: Array, - ruleNodeConfigResourcesModulesMap: {[key: string]: any}): + modulesMap: IModulesMap): Observable> { const tasks: Observable[] = []; components.forEach((component) => { - tasks.push(this.resolveRuleNodeComponentUiResources(component, ruleNodeConfigResourcesModulesMap)); + tasks.push(this.resolveRuleNodeComponentUiResources(component, modulesMap)); }); return forkJoin(tasks).pipe( catchError((err) => { @@ -234,7 +235,7 @@ export class RuleChainService { } private resolveRuleNodeComponentUiResources(component: RuleNodeComponentDescriptor, - ruleNodeConfigResourcesModulesMap: {[key: string]: any}): + modulesMap: IModulesMap): Observable { const nodeDefinition = component.configurationDescriptor.nodeDefinition; const uiResources = nodeDefinition.uiResources; @@ -248,7 +249,7 @@ export class RuleChainService { }); } if (moduleResource) { - tasks.push(this.resourcesService.loadFactories(moduleResource, ruleNodeConfigResourcesModulesMap).pipe( + tasks.push(this.resourcesService.loadFactories(moduleResource, modulesMap).pipe( map((res) => { if (nodeDefinition.configDirective && nodeDefinition.configDirective.length) { const selector = snakeCase(nodeDefinition.configDirective, '-'); diff --git a/ui-ngx/src/app/core/services/resources.service.ts b/ui-ngx/src/app/core/services/resources.service.ts index e87f16d885..f6cd757bbb 100644 --- a/ui-ngx/src/app/core/services/resources.service.ts +++ b/ui-ngx/src/app/core/services/resources.service.ts @@ -26,8 +26,9 @@ import { import { DOCUMENT } from '@angular/common'; import { forkJoin, Observable, ReplaySubject, throwError } from 'rxjs'; import { HttpClient } from '@angular/common/http'; +import { IModulesMap } from '@modules/common/modules-map.models'; -declare const SystemJS; +declare const System; @Injectable({ providedIn: 'root' @@ -63,23 +64,19 @@ export class ResourcesService { return this.loadResourceByType(fileType, url); } - public loadFactories(url: string, modulesMap: {[key: string]: any}): Observable[]> { + public loadFactories(url: string, modulesMap: IModulesMap): Observable[]> { if (this.loadedFactories[url]) { return this.loadedFactories[url].asObservable(); } + modulesMap.init(); const subject = new ReplaySubject[]>(); this.loadedFactories[url] = subject; - if (modulesMap) { - for (const moduleId of Object.keys(modulesMap)) { - SystemJS.set(moduleId, modulesMap[moduleId]); - } - } - SystemJS.import(url).then( - (module) => { - const modules = this.extractNgModules(module); - if (modules.length) { - import('@angular/compiler').then( - () => { + import('@angular/compiler').then( + () => { + System.import(url).then( + (module) => { + const modules = this.extractNgModules(module); + if (modules.length) { const tasks: Promise>[] = []; for (const m of modules) { tasks.push(this.compiler.compileModuleAndAllComponentsAsync(m)); @@ -101,44 +98,41 @@ export class ResourcesService { (e) => { this.loadedFactories[url].error(new Error(`Unable to compile module from url: ${url}`)); delete this.loadedFactories[url]; - }); } - ); - } else { - this.loadedFactories[url].error(new Error(`Module '${url}' doesn't have default export!`)); - delete this.loadedFactories[url]; - } - }, - (e) => { - this.loadedFactories[url].error(new Error(`Unable to load module from url: ${url}`)); - delete this.loadedFactories[url]; + }); + } else { + this.loadedFactories[url].error(new Error(`Module '${url}' doesn't have default export!`)); + delete this.loadedFactories[url]; + } + }, + (e) => { + this.loadedFactories[url].error(new Error(`Unable to load module from url: ${url}`)); + delete this.loadedFactories[url]; + } + ); } ); return subject.asObservable(); } - public loadModules(url: string, modulesMap: {[key: string]: any}): Observable[]> { + public loadModules(url: string, modulesMap: IModulesMap): Observable[]> { if (this.loadedModules[url]) { return this.loadedModules[url].asObservable(); } + modulesMap.init(); const subject = new ReplaySubject[]>(); this.loadedModules[url] = subject; - if (modulesMap) { - for (const moduleId of Object.keys(modulesMap)) { - SystemJS.set(moduleId, modulesMap[moduleId]); - } - } - SystemJS.import(url).then( - (module) => { - try { - let modules; - try { - modules = this.extractNgModules(module); - } catch (e) { - console.error(e); - } - if (modules && modules.length) { - import('@angular/compiler').then( - () => { + import('@angular/compiler').then( + () => { + System.import(url).then( + (module) => { + try { + let modules; + try { + modules = this.extractNgModules(module); + } catch (e) { + console.error(e); + } + if (modules && modules.length) { const tasks: Promise>[] = []; for (const m of modules) { tasks.push(this.compiler.compileModuleAndAllComponentsAsync(m)); @@ -159,21 +153,21 @@ export class ResourcesService { this.loadedModules[url].error(new Error(`Unable to compile module from url: ${url}`)); delete this.loadedModules[url]; }); + } else { + this.loadedModules[url].error(new Error(`Module '${url}' doesn't have default export or not NgModule!`)); + delete this.loadedModules[url]; } - ); - } else { - this.loadedModules[url].error(new Error(`Module '${url}' doesn't have default export or not NgModule!`)); + } catch (e) { + this.loadedModules[url].error(new Error(`Unable to load module from url: ${url}`)); + delete this.loadedModules[url]; + } + }, + (e) => { + this.loadedModules[url].error(new Error(`Unable to load module from url: ${url}`)); delete this.loadedModules[url]; + console.error(`Unable to load module from url: ${url}`, e); } - } catch (e) { - this.loadedModules[url].error(new Error(`Unable to load module from url: ${url}`)); - delete this.loadedModules[url]; - } - }, - (e) => { - this.loadedModules[url].error(new Error(`Unable to load module from url: ${url}`)); - delete this.loadedModules[url]; - console.error(`Unable to load module from url: ${url}`, e); + ); } ); return subject.asObservable(); @@ -184,24 +178,23 @@ export class ResourcesService { let potentialModules = [module]; let currentScanDepth = 0; - while(potentialModules.length && currentScanDepth < 10) { - let newPotentialModules = []; - for (const module of potentialModules) { - if (module && 'ɵmod' in module) { - modules.push(module); + while (potentialModules.length && currentScanDepth < 10) { + const newPotentialModules = []; + for (const potentialModule of potentialModules) { + if (potentialModule && ('ɵmod' in potentialModule)) { + modules.push(potentialModule); } else { - for (const k of Object.keys(module)) { - if(!this.isPrimitive(module[k])) { - newPotentialModules.push(module[k]); + for (const k of Object.keys(potentialModule)) { + if (!this.isPrimitive(potentialModule[k])) { + newPotentialModules.push(potentialModule[k]); } } } } - potentialModules = newPotentialModules; currentScanDepth++; } - } catch(e) { + } catch (e) { console.log('Could not load NgModule', e); } return modules; diff --git a/ui-ngx/src/app/modules/common/modules-map.models.ts b/ui-ngx/src/app/modules/common/modules-map.models.ts new file mode 100644 index 0000000000..436890554e --- /dev/null +++ b/ui-ngx/src/app/modules/common/modules-map.models.ts @@ -0,0 +1,19 @@ +/// +/// Copyright © 2016-2021 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +export interface IModulesMap { + init(): void; +} diff --git a/ui-ngx/src/app/modules/common/modules-map.ts b/ui-ngx/src/app/modules/common/modules-map.ts index dcb4289934..8404a03aa0 100644 --- a/ui-ngx/src/app/modules/common/modules-map.ts +++ b/ui-ngx/src/app/modules/common/modules-map.ts @@ -19,6 +19,9 @@ import * as AngularCore from '@angular/core'; import * as AngularCommon from '@angular/common'; import * as AngularForms from '@angular/forms'; import * as AngularFlexLayout from '@angular/flex-layout'; +import * as AngularFlexLayoutFlex from '@angular/flex-layout/flex'; +import * as AngularFlexLayoutGrid from '@angular/flex-layout/grid'; +import * as AngularFlexLayoutExtended from '@angular/flex-layout/extended'; import * as AngularPlatformBrowser from '@angular/platform-browser'; import * as AngularRouter from '@angular/router'; import * as AngularCdkCoercion from '@angular/cdk/coercion'; @@ -62,76 +65,520 @@ import * as AngularMaterialTabs from '@angular/material/tabs'; import * as AngularMaterialToolbar from '@angular/material/toolbar'; import * as AngularMaterialTooltip from '@angular/material/tooltip'; import * as AngularMaterialTree from '@angular/material/tree'; +import * as DragDropModule from '@angular/cdk/drag-drop'; +import * as HttpClientModule from '@angular/common/http'; + import * as NgrxStore from '@ngrx/store'; import * as RxJs from 'rxjs'; import * as RxJsOperators from 'rxjs/operators'; import * as TranslateCore from '@ngx-translate/core'; +import * as _moment from 'moment'; + import * as TbCore from '@core/public-api'; import * as TbShared from '@shared/public-api'; import * as TbHomeComponents from '@home/components/public-api'; -import * as _moment from 'moment'; -import * as DragDropModule from "@angular/cdk/drag-drop"; -import * as HttpClientModule from "@angular/common/http"; - -declare const SystemJS; - -export const modulesMap: {[key: string]: any} = { - '@angular/animations': SystemJS.newModule(AngularAnimations), - '@angular/core': SystemJS.newModule(AngularCore), - '@angular/common': SystemJS.newModule(AngularCommon), - '@angular/common/http': SystemJS.newModule(HttpClientModule), - '@angular/forms': SystemJS.newModule(AngularForms), - '@angular/flex-layout': SystemJS.newModule(AngularFlexLayout), - '@angular/platform-browser': SystemJS.newModule(AngularPlatformBrowser), - '@angular/router': SystemJS.newModule(AngularRouter), - '@angular/cdk/coercion': SystemJS.newModule(AngularCdkCoercion), - '@angular/cdk/collections': SystemJS.newModule(AngularCdkCollections), - '@angular/cdk/keycodes': SystemJS.newModule(AngularCdkKeycodes), - '@angular/cdk/layout': SystemJS.newModule(AngularCdkLayout), - '@angular/cdk/overlay': SystemJS.newModule(AngularCdkOverlay), - '@angular/cdk/portal': SystemJS.newModule(AngularCdkPortal), - '@angular/cdk/drag-drop': SystemJS.newModule(DragDropModule), - '@angular/material/autocomplete': SystemJS.newModule(AngularMaterialAutocomplete), - '@angular/material/badge': SystemJS.newModule(AngularMaterialBadge), - '@angular/material/bottom-sheet': SystemJS.newModule(AngularMaterialBottomSheet), - '@angular/material/button': SystemJS.newModule(AngularMaterialButton), - '@angular/material/button-toggle': SystemJS.newModule(AngularMaterialButtonToggle), - '@angular/material/card': SystemJS.newModule(AngularMaterialCard), - '@angular/material/checkbox': SystemJS.newModule(AngularMaterialCheckbox), - '@angular/material/chips': SystemJS.newModule(AngularMaterialChips), - '@angular/material/core': SystemJS.newModule(AngularMaterialCore), - '@angular/material/datepicker': SystemJS.newModule(AngularMaterialDatepicker), - '@angular/material/dialog': SystemJS.newModule(AngularMaterialDialog), - '@angular/material/divider': SystemJS.newModule(AngularMaterialDivider), - '@angular/material/expansion': SystemJS.newModule(AngularMaterialExpansion), - '@angular/material/form-field': SystemJS.newModule(AngularMaterialFormField), - '@angular/material/grid-list': SystemJS.newModule(AngularMaterialGridList), - '@angular/material/icon': SystemJS.newModule(AngularMaterialIcon), - '@angular/material/input': SystemJS.newModule(AngularMaterialInput), - '@angular/material/list': SystemJS.newModule(AngularMaterialList), - '@angular/material/menu': SystemJS.newModule(AngularMaterialMenu), - '@angular/material/paginator': SystemJS.newModule(AngularMaterialPaginator), - '@angular/material/progress-bar': SystemJS.newModule(AngularMaterialProgressBar), - '@angular/material/progress-spinner': SystemJS.newModule(AngularMaterialProgressSpinner), - '@angular/material/radio': SystemJS.newModule(AngularMaterialRadio), - '@angular/material/select': SystemJS.newModule(AngularMaterialSelect), - '@angular/material/sidenav': SystemJS.newModule(AngularMaterialSidenav), - '@angular/material/slide-toggle': SystemJS.newModule(AngularMaterialSlideToggle), - '@angular/material/slider': SystemJS.newModule(AngularMaterialSlider), - '@angular/material/snack-bar': SystemJS.newModule(AngularMaterialSnackBar), - '@angular/material/sort': SystemJS.newModule(AngularMaterialSort), - '@angular/material/stepper': SystemJS.newModule(AngularMaterialStepper), - '@angular/material/table': SystemJS.newModule(AngularMaterialTable), - '@angular/material/tabs': SystemJS.newModule(AngularMaterialTabs), - '@angular/material/toolbar': SystemJS.newModule(AngularMaterialToolbar), - '@angular/material/tooltip': SystemJS.newModule(AngularMaterialTooltip), - '@angular/material/tree': SystemJS.newModule(AngularMaterialTree), - '@ngrx/store': SystemJS.newModule(NgrxStore), - rxjs: SystemJS.newModule(RxJs), - 'rxjs/operators': SystemJS.newModule(RxJsOperators), - '@ngx-translate/core': SystemJS.newModule(TranslateCore), - '@core/public-api': SystemJS.newModule(TbCore), - '@shared/public-api': SystemJS.newModule(TbShared), - '@home/components/public-api': SystemJS.newModule(TbHomeComponents), - moment: SystemJS.newModule(_moment) -}; + +import * as MillisecondsToTimeStringPipe from '@shared/pipe/milliseconds-to-time-string.pipe'; +import * as EnumToArrayPipe from '@shared/pipe/enum-to-array.pipe'; +import * as HighlightPipe from '@shared/pipe/highlight.pipe'; +import * as TruncatePipe from '@shared/pipe/truncate.pipe'; +import * as TbJsonPipe from '@shared/pipe/tbJson.pipe'; +import * as FileSizePipe from '@shared/pipe/file-size.pipe'; +import * as NospacePipe from '@shared/pipe/nospace.pipe'; +import * as SelectableColumnsPipe from '@shared/pipe/selectable-columns.pipe'; +import * as KeyboardShortcutPipe from '@shared/pipe/keyboard-shortcut.pipe'; + +import * as FooterComponent from '@shared/components/footer.component'; +import * as LogoComponent from '@shared/components/logo.component'; +import * as FooterFabButtonsComponent from '@shared/components/footer-fab-buttons.component'; +import * as FullscreenDirective from '@shared/components/fullscreen.directive'; +import * as CircularProgressDirective from '@shared/components/circular-progress.directive'; +import * as MatChipDraggableDirective from '@shared/components/mat-chip-draggable.directive'; +import * as TbHotkeysDirective from '@shared/components/hotkeys.directive'; +import * as TbAnchorComponent from '@shared/components/tb-anchor.component'; +import * as TbPopoverComponent from '@shared/components/popover.component'; +import * as TbStringTemplateOutletDirective from '@shared/components/directives/sring-template-outlet.directive'; +import * as TbComponentOutletDirective from '@shared/components/directives/component-outlet.directive'; +import * as TbMarkdownComponent from '@shared/components/markdown.component'; +import * as HelpComponent from '@shared/components/help.component'; +import * as HelpMarkdownComponent from '@shared/components/help-markdown.component'; +import * as HelpPopupComponent from '@shared/components/help-popup.component'; +import * as TbCheckboxComponent from '@shared/components/tb-checkbox.component'; +import * as TbToast from '@shared/components/toast.directive'; +import * as TbErrorComponent from '@shared/components/tb-error.component'; +import * as TbCheatSheetComponent from '@shared/components/cheatsheet.component'; +import * as BreadcrumbComponent from '@shared/components/breadcrumb.component'; +import * as UserMenuComponent from '@shared/components/user-menu.component'; +import * as TimewindowComponent from '@shared/components/time/timewindow.component'; +import * as TimewindowPanelComponent from '@shared/components/time/timewindow-panel.component'; +import * as TimeintervalComponent from '@shared/components/time/timeinterval.component'; +import * as QuickTimeIntervalComponent from '@shared/components/time/quick-time-interval.component'; +import * as DashboardSelectComponent from '@shared/components/dashboard-select.component'; +import * as DashboardSelectPanelComponent from '@shared/components/dashboard-select-panel.component'; +import * as DatetimePeriodComponent from '@shared/components/time/datetime-period.component'; +import * as DatetimeComponent from '@shared/components/time/datetime.component'; +import * as TimezoneSelectComponent from '@shared/components/time/timezone-select.component'; +import * as ValueInputComponent from '@shared/components/value-input.component'; +import * as DashboardAutocompleteComponent from '@shared/components/dashboard-autocomplete.component'; +import * as EntitySubTypeAutocompleteComponent from '@shared/components/entity/entity-subtype-autocomplete.component'; +import * as EntitySubTypeSelectComponent from '@shared/components/entity/entity-subtype-select.component'; +import * as EntitySubTypeListComponent from '@shared/components/entity/entity-subtype-list.component'; +import * as EntityAutocompleteComponent from '@shared/components/entity/entity-autocomplete.component'; +import * as EntityListComponent from '@shared/components/entity/entity-list.component'; +import * as EntityTypeSelectComponent from '@shared/components/entity/entity-type-select.component'; +import * as EntitySelectComponent from '@shared/components/entity/entity-select.component'; +import * as EntityKeysListComponent from '@shared/components/entity/entity-keys-list.component'; +import * as EntityListSelectComponent from '@shared/components/entity/entity-list-select.component'; +import * as EntityTypeListComponent from '@shared/components/entity/entity-type-list.component'; +import * as QueueTypeListComponent from '@shared/components/queue/queue-type-list.component'; +import * as RelationTypeAutocompleteComponent from '@shared/components/relation/relation-type-autocomplete.component'; +import * as SocialSharePanelComponent from '@shared/components/socialshare-panel.component'; +import * as JsonObjectEditComponent from '@shared/components/json-object-edit.component'; +import * as JsonContentComponent from '@shared/components/json-content.component'; +import * as JsFuncComponent from '@shared/components/js-func.component'; +import * as FabToolbarComponent from '@shared/components/fab-toolbar.component'; +import * as WidgetsBundleSelectComponent from '@shared/components/widgets-bundle-select.component'; +import * as ConfirmDialogComponent from '@shared/components/dialog/confirm-dialog.component'; +import * as AlertDialogComponent from '@shared/components/dialog/alert-dialog.component'; +import * as TodoDialogComponent from '@shared/components/dialog/todo-dialog.component'; +import * as ColorPickerDialogComponent from '@shared/components/dialog/color-picker-dialog.component'; +import * as MaterialIconsDialogComponent from '@shared/components/dialog/material-icons-dialog.component'; +import * as ColorInputComponent from '@shared/components/color-input.component'; +import * as MaterialIconSelectComponent from '@shared/components/material-icon-select.component'; +import * as NodeScriptTestDialogComponent from '@shared/components/dialog/node-script-test-dialog.component'; +import * as JsonFormComponent from '@shared/components/json-form/json-form.component'; +import * as ImageInputComponent from '@shared/components/image-input.component'; +import * as FileInputComponent from '@shared/components/file-input.component'; +import * as MessageTypeAutocompleteComponent from '@shared/components/message-type-autocomplete.component'; +import * as KeyValMapComponent from '@shared/components/kv-map.component'; +import * as NavTreeComponent from '@shared/components/nav-tree.component'; +import * as LedLightComponent from '@shared/components/led-light.component'; +import * as TbJsonToStringDirective from '@shared/components/directives/tb-json-to-string.directive'; +import * as JsonObjectEditDialogComponent from '@shared/components/dialog/json-object-edit-dialog.component'; +import * as HistorySelectorComponent from '@shared/components/time/history-selector/history-selector.component'; +import * as EntityGatewaySelectComponent from '@shared/components/entity/entity-gateway-select.component'; +import * as ContactComponent from '@shared/components/contact.component'; +import * as OtaPackageAutocompleteComponent from '@shared/components/ota-package/ota-package-autocomplete.component'; +import * as WidgetsBundleSearchComponent from '@shared/components/widgets-bundle-search.component'; +import * as CopyButtonComponent from '@shared/components/button/copy-button.component'; +import * as TogglePasswordComponent from '@shared/components/button/toggle-password.component'; +import * as ProtobufContentComponent from '@shared/components/protobuf-content.component'; + +import * as AddEntityDialogComponent from '@home/components/entity/add-entity-dialog.component'; +import * as EntitiesTableComponent from '@home/components/entity/entities-table.component'; +import * as DetailsPanelComponent from '@home/components/details-panel.component'; +import * as EntityDetailsPanelComponent from '@home/components/entity/entity-details-panel.component'; +import * as AuditLogDetailsDialogComponent from '@home/components/audit-log/audit-log-details-dialog.component'; +import * as AuditLogTableComponent from '@home/components/audit-log/audit-log-table.component'; +import * as EventTableHeaderComponent from '@home/components/event/event-table-header.component'; +import * as EventTableComponent from '@home/components/event/event-table.component'; +import * as EventFilterPanelComponent from '@home/components/event/event-filter-panel.component'; +import * as RelationTableComponent from '@home/components/relation/relation-table.component'; +import * as RelationDialogComponent from '@home/components/relation/relation-dialog.component'; +import * as AlarmTableHeaderComponent from '@home/components/alarm/alarm-table-header.component'; +import * as AlarmTableComponent from '@home/components/alarm/alarm-table.component'; +import * as AttributeTableComponent from '@home/components/attribute/attribute-table.component'; +import * as AddAttributeDialogComponent from '@home/components/attribute/add-attribute-dialog.component'; +import * as EditAttributeValuePanelComponent from '@home/components/attribute/edit-attribute-value-panel.component'; +import * as DashboardComponent from '@home/components/dashboard/dashboard.component'; +import * as WidgetComponent from '@home/components/widget/widget.component'; +import * as LegendComponent from '@home/components/widget/legend.component'; +import * as AliasesEntitySelectPanelComponent from '@home/components/alias/aliases-entity-select-panel.component'; +import * as AliasesEntitySelectComponent from '@home/components/alias/aliases-entity-select.component'; +import * as WidgetConfigComponent from '@home/components/widget/widget-config.component'; +import * as EntityAliasesDialogComponent from '@home/components/alias/entity-aliases-dialog.component'; +import * as EntityFilterViewComponent from '@home/components/entity/entity-filter-view.component'; +import * as EntityAliasDialogComponent from '@home/components/alias/entity-alias-dialog.component'; +import * as EntityFilterComponent from '@home/components/entity/entity-filter.component'; +import * as RelationFiltersComponent from '@home/components/relation/relation-filters.component'; +import * as EntityAliasSelectComponent from '@home/components/alias/entity-alias-select.component'; +import * as DataKeysComponent from '@home/components/widget/data-keys.component'; +import * as DataKeyConfigDialogComponent from '@home/components/widget/data-key-config-dialog.component'; +import * as DataKeyConfigComponent from '@home/components/widget/data-key-config.component'; +import * as LegendConfigComponent from '@home/components/widget/legend-config.component'; +import * as ManageWidgetActionsComponent from '@home/components/widget/action/manage-widget-actions.component'; +import * as WidgetActionDialogComponent from '@home/components/widget/action/widget-action-dialog.component'; +import * as CustomActionPrettyResourcesTabsComponent from '@home/components/widget/action/custom-action-pretty-resources-tabs.component'; +import * as CustomActionPrettyEditorComponent from '@home/components/widget/action/custom-action-pretty-editor.component'; +import * as MobileActionEditorComponent from '@home/components/widget/action/mobile-action-editor.component'; +import * as CustomDialogService from '@home/components/widget/dialog/custom-dialog.service'; +import * as CustomDialogContainerComponent from '@home/components/widget/dialog/custom-dialog-container.component'; +import * as ImportDialogComponent from '@home/components/import-export/import-dialog.component'; +import * as AddWidgetToDashboardDialogComponent from '@home/components/attribute/add-widget-to-dashboard-dialog.component'; +import * as ImportDialogCsvComponent from '@home/components/import-export/import-dialog-csv.component'; +import * as TableColumnsAssignmentComponent from '@home/components/import-export/table-columns-assignment.component'; +import * as EventContentDialogComponent from '@home/components/event/event-content-dialog.component'; +import * as SharedHomeComponentsModule from '@home/components/shared-home-components.module'; +import * as SelectTargetLayoutDialogComponent from '@home/components/dashboard/select-target-layout-dialog.component'; +import * as SelectTargetStateDialogComponent from '@home/components/dashboard/select-target-state-dialog.component'; +import * as AliasesEntityAutocompleteComponent from '@home/components/alias/aliases-entity-autocomplete.component'; +import * as BooleanFilterPredicateComponent from '@home/components/filter/boolean-filter-predicate.component'; +import * as StringFilterPredicateComponent from '@home/components/filter/string-filter-predicate.component'; +import * as NumericFilterPredicateComponent from '@home/components/filter/numeric-filter-predicate.component'; +import * as ComplexFilterPredicateComponent from '@home/components/filter/complex-filter-predicate.component'; +import * as FilterPredicateComponent from '@home/components/filter/filter-predicate.component'; +import * as FilterPredicateListComponent from '@home/components/filter/filter-predicate-list.component'; +import * as KeyFilterListComponent from '@home/components/filter/key-filter-list.component'; +import * as ComplexFilterPredicateDialogComponent from '@home/components/filter/complex-filter-predicate-dialog.component'; +import * as KeyFilterDialogComponent from '@home/components/filter/key-filter-dialog.component'; +import * as FiltersDialogComponent from '@home/components/filter/filters-dialog.component'; +import * as FilterDialogComponent from '@home/components/filter/filter-dialog.component'; +import * as FilterSelectComponent from '@home/components/filter/filter-select.component'; +import * as FiltersEditComponent from '@home/components/filter/filters-edit.component'; +import * as FiltersEditPanelComponent from '@home/components/filter/filters-edit-panel.component'; +import * as UserFilterDialogComponent from '@home/components/filter/user-filter-dialog.component'; +import * as FilterUserInfoComponent from '@home/components/filter/filter-user-info.component'; +import * as FilterUserInfoDialogComponent from '@home/components/filter/filter-user-info-dialog.component'; +import * as FilterPredicateValueComponent from '@home/components/filter/filter-predicate-value.component'; +import * as TenantProfileComponent from '@home/components/profile/tenant-profile.component'; +import * as TenantProfileDialogComponent from '@home/components/profile/tenant-profile-dialog.component'; +import * as TenantProfileDataComponent from '@home/components/profile/tenant-profile-data.component'; +// tslint:disable-next-line:max-line-length +import * as DefaultDeviceProfileConfigurationComponent from '@home/components/profile/device/default-device-profile-configuration.component'; +import * as DeviceProfileConfigurationComponent from '@home/components/profile/device/device-profile-configuration.component'; +import * as DeviceProfileComponent from '@home/components/profile/device-profile.component'; +import * as DefaultDeviceProfileTransportConfigurationComponent from '@home/components/profile/device/default-device-profile-transport-configuration.component'; +import * as DeviceProfileTransportConfigurationComponent from '@home/components/profile/device/device-profile-transport-configuration.component'; +import * as DeviceProfileDialogComponent from '@home/components/profile/device-profile-dialog.component'; +import * as DeviceProfileAutocompleteComponent from '@home/components/profile/device-profile-autocomplete.component'; +import * as MqttDeviceProfileTransportConfigurationComponent from '@home/components/profile/device/mqtt-device-profile-transport-configuration.component'; +import * as CoapDeviceProfileTransportConfigurationComponent from '@home/components/profile/device/coap-device-profile-transport-configuration.component'; +import * as DeviceProfileAlarmsComponent from '@home/components/profile/alarm/device-profile-alarms.component'; +import * as DeviceProfileAlarmComponent from '@home/components/profile/alarm/device-profile-alarm.component'; +import * as CreateAlarmRulesComponent from '@home/components/profile/alarm/create-alarm-rules.component'; +import * as AlarmRuleComponent from '@home/components/profile/alarm/alarm-rule.component'; +import * as AlarmRuleConditionComponent from '@home/components/profile/alarm/alarm-rule-condition.component'; +import * as FilterTextComponent from '@home/components/filter/filter-text.component'; +import * as AddDeviceProfileDialogComponent from '@home/components/profile/add-device-profile-dialog.component'; +import * as RuleChainAutocompleteComponent from '@home/components/rule-chain/rule-chain-autocomplete.component'; +import * as DeviceProfileProvisionConfigurationComponent from '@home/components/profile/device-profile-provision-configuration.component'; +import * as AlarmScheduleComponent from '@home/components/profile/alarm/alarm-schedule.component'; +import * as DeviceWizardDialogComponent from '@home/components/wizard/device-wizard-dialog.component'; +import * as AlarmScheduleInfoComponent from '@home/components/profile/alarm/alarm-schedule-info.component'; +import * as AlarmScheduleDialogComponent from '@home/components/profile/alarm/alarm-schedule-dialog.component'; +import * as EditAlarmDetailsDialogComponent from '@home/components/profile/alarm/edit-alarm-details-dialog.component'; +import * as AlarmRuleConditionDialogComponent from '@home/components/profile/alarm/alarm-rule-condition-dialog.component'; +// tslint:disable-next-line:max-line-length +import * as DefaultTenantProfileConfigurationComponent from '@home/components/profile/tenant/default-tenant-profile-configuration.component'; +import * as TenantProfileConfigurationComponent from '@home/components/profile/tenant/tenant-profile-configuration.component'; +import * as SmsProviderConfigurationComponent from '@home/components/sms/sms-provider-configuration.component'; +import * as AwsSnsProviderConfigurationComponent from '@home/components/sms/aws-sns-provider-configuration.component'; +import * as TwilioSmsProviderConfigurationComponent from '@home/components/sms/twilio-sms-provider-configuration.component'; +import * as DashboardPageComponent from '@home/components/dashboard-page/dashboard-page.component'; +import * as DashboardToolbarComponent from '@home/components/dashboard-page/dashboard-toolbar.component'; +import * as DashboardLayoutComponent from '@home/components/dashboard-page/layout/dashboard-layout.component'; +import * as EditWidgetComponent from '@home/components/dashboard-page/edit-widget.component'; +import * as DashboardWidgetSelectComponent from '@home/components/dashboard-page/dashboard-widget-select.component'; +import * as AddWidgetDialogComponent from '@home/components/dashboard-page/add-widget-dialog.component'; +import * as ManageDashboardLayoutsDialogComponent from '@home/components/dashboard-page/layout/manage-dashboard-layouts-dialog.component'; +import * as DashboardSettingsDialogComponent from '@home/components/dashboard-page/dashboard-settings-dialog.component'; +import * as ManageDashboardStatesDialogComponent from '@home/components/dashboard-page/states/manage-dashboard-states-dialog.component'; +import * as DashboardStateDialogComponent from '@home/components/dashboard-page/states/dashboard-state-dialog.component'; +import * as EmbedDashboardDialogComponent from '@home/components/widget/dialog/embed-dashboard-dialog.component'; +import * as EdgeDownlinkTableComponent from '@home/components/edge/edge-downlink-table.component'; +import * as EdgeDownlinkTableHeaderComponent from '@home/components/edge/edge-downlink-table-header.component'; +import * as DisplayWidgetTypesPanelComponent from '@home/components/dashboard-page/widget-types-panel.component'; +import * as AlarmDurationPredicateValueComponent from '@home/components/profile/alarm/alarm-duration-predicate-value.component'; +import * as DashboardImageDialogComponent from '@home/components/dashboard-page/dashboard-image-dialog.component'; +import * as WidgetContainerComponent from '@home/components/widget/widget-container.component'; + +import { IModulesMap } from '@modules/common/modules-map.models'; + +declare const System; + +class ModulesMap implements IModulesMap { + + private initialized = false; + + private modulesMap: {[key: string]: any} = { + '@angular/animations': AngularAnimations, + '@angular/core': AngularCore, + '@angular/common': AngularCommon, + '@angular/common/http': HttpClientModule, + '@angular/forms': AngularForms, + '@angular/flex-layout': AngularFlexLayout, + '@angular/flex-layout/flex': AngularFlexLayoutFlex, + '@angular/flex-layout/grid': AngularFlexLayoutGrid, + '@angular/flex-layout/extended': AngularFlexLayoutExtended, + '@angular/platform-browser': AngularPlatformBrowser, + '@angular/router': AngularRouter, + '@angular/cdk/coercion': AngularCdkCoercion, + '@angular/cdk/collections': AngularCdkCollections, + '@angular/cdk/keycodes': AngularCdkKeycodes, + '@angular/cdk/layout': AngularCdkLayout, + '@angular/cdk/overlay': AngularCdkOverlay, + '@angular/cdk/portal': AngularCdkPortal, + '@angular/cdk/drag-drop': DragDropModule, + '@angular/material/autocomplete': AngularMaterialAutocomplete, + '@angular/material/badge': AngularMaterialBadge, + '@angular/material/bottom-sheet': AngularMaterialBottomSheet, + '@angular/material/button': AngularMaterialButton, + '@angular/material/button-toggle': AngularMaterialButtonToggle, + '@angular/material/card': AngularMaterialCard, + '@angular/material/checkbox': AngularMaterialCheckbox, + '@angular/material/chips': AngularMaterialChips, + '@angular/material/core': AngularMaterialCore, + '@angular/material/datepicker': AngularMaterialDatepicker, + '@angular/material/dialog': AngularMaterialDialog, + '@angular/material/divider': AngularMaterialDivider, + '@angular/material/expansion': AngularMaterialExpansion, + '@angular/material/form-field': AngularMaterialFormField, + '@angular/material/grid-list': AngularMaterialGridList, + '@angular/material/icon': AngularMaterialIcon, + '@angular/material/input': AngularMaterialInput, + '@angular/material/list': AngularMaterialList, + '@angular/material/menu': AngularMaterialMenu, + '@angular/material/paginator': AngularMaterialPaginator, + '@angular/material/progress-bar': AngularMaterialProgressBar, + '@angular/material/progress-spinner': AngularMaterialProgressSpinner, + '@angular/material/radio': AngularMaterialRadio, + '@angular/material/select': AngularMaterialSelect, + '@angular/material/sidenav': AngularMaterialSidenav, + '@angular/material/slide-toggle': AngularMaterialSlideToggle, + '@angular/material/slider': AngularMaterialSlider, + '@angular/material/snack-bar': AngularMaterialSnackBar, + '@angular/material/sort': AngularMaterialSort, + '@angular/material/stepper': AngularMaterialStepper, + '@angular/material/table': AngularMaterialTable, + '@angular/material/tabs': AngularMaterialTabs, + '@angular/material/toolbar': AngularMaterialToolbar, + '@angular/material/tooltip': AngularMaterialTooltip, + '@angular/material/tree': AngularMaterialTree, + '@ngrx/store': NgrxStore, + rxjs: RxJs, + 'rxjs/operators': RxJsOperators, + '@ngx-translate/core': TranslateCore, + moment: _moment, + + '@core/public-api': TbCore, + '@shared/public-api': TbShared, + '@home/components/public-api': TbHomeComponents, + + '@shared/pipe/milliseconds-to-time-string.pipe': MillisecondsToTimeStringPipe, + '@shared/pipe/enum-to-array.pipe': EnumToArrayPipe, + '@shared/pipe/highlight.pipe': HighlightPipe, + '@shared/pipe/truncate.pipe': TruncatePipe, + '@shared/pipe/tbJson.pipe': TbJsonPipe, + '@shared/pipe/file-size.pipe': FileSizePipe, + '@shared/pipe/nospace.pipe': NospacePipe, + '@shared/pipe/selectable-columns.pipe': SelectableColumnsPipe, + '@shared/pipe/keyboard-shortcut.pipe': KeyboardShortcutPipe, + + '@shared/components/footer.component': FooterComponent, + '@shared/components/logo.component': LogoComponent, + '@shared/components/footer-fab-buttons.component': FooterFabButtonsComponent, + '@shared/components/fullscreen.directive': FullscreenDirective, + '@shared/components/circular-progress.directive': CircularProgressDirective, + '@shared/components/mat-chip-draggable.directive': MatChipDraggableDirective, + '@shared/components/hotkeys.directive': TbHotkeysDirective, + '@shared/components/tb-anchor.component': TbAnchorComponent, + '@shared/components/popover.component': TbPopoverComponent, + '@shared/components/directives/sring-template-outlet.directive': TbStringTemplateOutletDirective, + '@shared/components/directives/component-outlet.directive': TbComponentOutletDirective, + '@shared/components/markdown.component': TbMarkdownComponent, + '@shared/components/help.component': HelpComponent, + '@shared/components/help-markdown.component': HelpMarkdownComponent, + '@shared/components/help-popup.component': HelpPopupComponent, + '@shared/components/tb-checkbox.component': TbCheckboxComponent, + '@shared/components/toast.directive': TbToast, + '@shared/components/tb-error.component': TbErrorComponent, + '@shared/components/cheatsheet.component': TbCheatSheetComponent, + '@shared/components/breadcrumb.component': BreadcrumbComponent, + '@shared/components/user-menu.component': UserMenuComponent, + '@shared/components/time/timewindow.component': TimewindowComponent, + '@shared/components/time/timewindow-panel.component': TimewindowPanelComponent, + '@shared/components/time/timeinterval.component': TimeintervalComponent, + '@shared/components/time/quick-time-interval.component': QuickTimeIntervalComponent, + '@shared/components/dashboard-select.component': DashboardSelectComponent, + '@shared/components/dashboard-select-panel.component': DashboardSelectPanelComponent, + '@shared/components/time/datetime-period.component': DatetimePeriodComponent, + '@shared/components/time/datetime.component': DatetimeComponent, + '@shared/components/time/timezone-select.component': TimezoneSelectComponent, + '@shared/components/value-input.component': ValueInputComponent, + '@shared/components/dashboard-autocomplete.component': DashboardAutocompleteComponent, + '@shared/components/entity/entity-subtype-autocomplete.component': EntitySubTypeAutocompleteComponent, + '@shared/components/entity/entity-subtype-select.component': EntitySubTypeSelectComponent, + '@shared/components/entity/entity-subtype-list.component': EntitySubTypeListComponent, + '@shared/components/entity/entity-autocomplete.component': EntityAutocompleteComponent, + '@shared/components/entity/entity-list.component': EntityListComponent, + '@shared/components/entity/entity-type-select.component': EntityTypeSelectComponent, + '@shared/components/entity/entity-select.component': EntitySelectComponent, + '@shared/components/entity/entity-keys-list.component': EntityKeysListComponent, + '@shared/components/entity/entity-list-select.component': EntityListSelectComponent, + '@shared/components/entity/entity-type-list.component': EntityTypeListComponent, + '@shared/components/queue/queue-type-list.component': QueueTypeListComponent, + '@shared/components/relation/relation-type-autocomplete.component': RelationTypeAutocompleteComponent, + '@shared/components/socialshare-panel.component': SocialSharePanelComponent, + '@shared/components/json-object-edit.component': JsonObjectEditComponent, + '@shared/components/json-content.component': JsonContentComponent, + '@shared/components/js-func.component': JsFuncComponent, + '@shared/components/fab-toolbar.component': FabToolbarComponent, + '@shared/components/widgets-bundle-select.component': WidgetsBundleSelectComponent, + '@shared/components/dialog/confirm-dialog.component': ConfirmDialogComponent, + '@shared/components/dialog/alert-dialog.component': AlertDialogComponent, + '@shared/components/dialog/todo-dialog.component': TodoDialogComponent, + '@shared/components/dialog/color-picker-dialog.component': ColorPickerDialogComponent, + '@shared/components/dialog/material-icons-dialog.component': MaterialIconsDialogComponent, + '@shared/components/color-input.component': ColorInputComponent, + '@shared/components/material-icon-select.component': MaterialIconSelectComponent, + '@shared/components/dialog/node-script-test-dialog.component': NodeScriptTestDialogComponent, + '@shared/components/json-form/json-form.component': JsonFormComponent, + '@shared/components/image-input.component': ImageInputComponent, + '@shared/components/file-input.component': FileInputComponent, + '@shared/components/message-type-autocomplete.component': MessageTypeAutocompleteComponent, + '@shared/components/kv-map.component': KeyValMapComponent, + '@shared/components/nav-tree.component': NavTreeComponent, + '@shared/components/led-light.component': LedLightComponent, + '@shared/components/directives/tb-json-to-string.directive': TbJsonToStringDirective, + '@shared/components/dialog/json-object-edit-dialog.component': JsonObjectEditDialogComponent, + '@shared/components/time/history-selector/history-selector.component': HistorySelectorComponent, + '@shared/components/entity/entity-gateway-select.component': EntityGatewaySelectComponent, + '@shared/components/contact.component': ContactComponent, + '@shared/components/ota-package/ota-package-autocomplete.component': OtaPackageAutocompleteComponent, + '@shared/components/widgets-bundle-search.component': WidgetsBundleSearchComponent, + '@shared/components/button/copy-button.component': CopyButtonComponent, + '@shared/components/button/toggle-password.component': TogglePasswordComponent, + '@shared/components/protobuf-content.component': ProtobufContentComponent, + + '@home/components/entity/add-entity-dialog.component': AddEntityDialogComponent, + '@home/components/entity/entities-table.component': EntitiesTableComponent, + '@home/components/details-panel.component': DetailsPanelComponent, + '@home/components/entity/entity-details-panel.component': EntityDetailsPanelComponent, + '@home/components/audit-log/audit-log-details-dialog.component': AuditLogDetailsDialogComponent, + '@home/components/audit-log/audit-log-table.component': AuditLogTableComponent, + '@home/components/event/event-table-header.component': EventTableHeaderComponent, + '@home/components/event/event-table.component': EventTableComponent, + '@home/components/event/event-filter-panel.component': EventFilterPanelComponent, + '@home/components/relation/relation-table.component': RelationTableComponent, + '@home/components/relation/relation-dialog.component': RelationDialogComponent, + '@home/components/alarm/alarm-table-header.component': AlarmTableHeaderComponent, + '@home/components/alarm/alarm-table.component': AlarmTableComponent, + '@home/components/attribute/attribute-table.component': AttributeTableComponent, + '@home/components/attribute/add-attribute-dialog.component': AddAttributeDialogComponent, + '@home/components/attribute/edit-attribute-value-panel.component': EditAttributeValuePanelComponent, + '@home/components/dashboard/dashboard.component': DashboardComponent, + '@home/components/widget/widget.component': WidgetComponent, + '@home/components/widget/legend.component': LegendComponent, + '@home/components/alias/aliases-entity-select-panel.component': AliasesEntitySelectPanelComponent, + '@home/components/alias/aliases-entity-select.component': AliasesEntitySelectComponent, + '@home/components/widget/widget-config.component': WidgetConfigComponent, + '@home/components/alias/entity-aliases-dialog.component': EntityAliasesDialogComponent, + '@home/components/entity/entity-filter-view.component': EntityFilterViewComponent, + '@home/components/alias/entity-alias-dialog.component': EntityAliasDialogComponent, + '@home/components/entity/entity-filter.component': EntityFilterComponent, + '@home/components/relation/relation-filters.component': RelationFiltersComponent, + '@home/components/alias/entity-alias-select.component': EntityAliasSelectComponent, + '@home/components/widget/data-keys.component': DataKeysComponent, + '@home/components/widget/data-key-config-dialog.component': DataKeyConfigDialogComponent, + '@home/components/widget/data-key-config.component': DataKeyConfigComponent, + '@home/components/widget/legend-config.component': LegendConfigComponent, + '@home/components/widget/action/manage-widget-actions.component': ManageWidgetActionsComponent, + '@home/components/widget/action/widget-action-dialog.component': WidgetActionDialogComponent, + '@home/components/widget/action/custom-action-pretty-resources-tabs.component': CustomActionPrettyResourcesTabsComponent, + '@home/components/widget/action/custom-action-pretty-editor.component': CustomActionPrettyEditorComponent, + '@home/components/widget/action/mobile-action-editor.component': MobileActionEditorComponent, + '@home/components/widget/dialog/custom-dialog.service': CustomDialogService, + '@home/components/widget/dialog/custom-dialog-container.component': CustomDialogContainerComponent, + '@home/components/import-export/import-dialog.component': ImportDialogComponent, + '@home/components/attribute/add-widget-to-dashboard-dialog.component': AddWidgetToDashboardDialogComponent, + '@home/components/import-export/import-dialog-csv.component': ImportDialogCsvComponent, + '@home/components/import-export/table-columns-assignment.component': TableColumnsAssignmentComponent, + '@home/components/event/event-content-dialog.component': EventContentDialogComponent, + '@home/components/shared-home-components.module': SharedHomeComponentsModule, + '@home/components/dashboard/select-target-layout-dialog.component': SelectTargetLayoutDialogComponent, + '@home/components/dashboard/select-target-state-dialog.component': SelectTargetStateDialogComponent, + '@home/components/alias/aliases-entity-autocomplete.component': AliasesEntityAutocompleteComponent, + '@home/components/filter/boolean-filter-predicate.component': BooleanFilterPredicateComponent, + '@home/components/filter/string-filter-predicate.component': StringFilterPredicateComponent, + '@home/components/filter/numeric-filter-predicate.component': NumericFilterPredicateComponent, + '@home/components/filter/complex-filter-predicate.component': ComplexFilterPredicateComponent, + '@home/components/filter/filter-predicate.component': FilterPredicateComponent, + '@home/components/filter/filter-predicate-list.component': FilterPredicateListComponent, + '@home/components/filter/key-filter-list.component': KeyFilterListComponent, + '@home/components/filter/complex-filter-predicate-dialog.component': ComplexFilterPredicateDialogComponent, + '@home/components/filter/key-filter-dialog.component': KeyFilterDialogComponent, + '@home/components/filter/filters-dialog.component': FiltersDialogComponent, + '@home/components/filter/filter-dialog.component': FilterDialogComponent, + '@home/components/filter/filter-select.component': FilterSelectComponent, + '@home/components/filter/filters-edit.component': FiltersEditComponent, + '@home/components/filter/filters-edit-panel.component': FiltersEditPanelComponent, + '@home/components/filter/user-filter-dialog.component': UserFilterDialogComponent, + '@home/components/filter/filter-user-info.component': FilterUserInfoComponent, + '@home/components/filter/filter-user-info-dialog.component': FilterUserInfoDialogComponent, + '@home/components/filter/filter-predicate-value.component': FilterPredicateValueComponent, + '@home/components/profile/tenant-profile.component': TenantProfileComponent, + '@home/components/profile/tenant-profile-dialog.component': TenantProfileDialogComponent, + '@home/components/profile/tenant-profile-data.component': TenantProfileDataComponent, + '@home/components/profile/device/default-device-profile-configuration.component': DefaultDeviceProfileConfigurationComponent, + '@home/components/profile/device/device-profile-configuration.component': DeviceProfileConfigurationComponent, + '@home/components/profile/device-profile.component': DeviceProfileComponent, + '@home/components/profile/device/default-device-profile-transport-configuration.component': + DefaultDeviceProfileTransportConfigurationComponent, + '@home/components/profile/device/device-profile-transport-configuration.component': DeviceProfileTransportConfigurationComponent, + '@home/components/profile/device-profile-dialog.component': DeviceProfileDialogComponent, + '@home/components/profile/device-profile-autocomplete.component': DeviceProfileAutocompleteComponent, + '@home/components/profile/device/mqtt-device-profile-transport-configuration.component': + MqttDeviceProfileTransportConfigurationComponent, + '@home/components/profile/device/coap-device-profile-transport-configuration.component': + CoapDeviceProfileTransportConfigurationComponent, + '@home/components/profile/alarm/device-profile-alarms.component': DeviceProfileAlarmsComponent, + '@home/components/profile/alarm/device-profile-alarm.component': DeviceProfileAlarmComponent, + '@home/components/profile/alarm/create-alarm-rules.component': CreateAlarmRulesComponent, + '@home/components/profile/alarm/alarm-rule.component': AlarmRuleComponent, + '@home/components/profile/alarm/alarm-rule-condition.component': AlarmRuleConditionComponent, + '@home/components/filter/filter-text.component': FilterTextComponent, + '@home/components/profile/add-device-profile-dialog.component': AddDeviceProfileDialogComponent, + '@home/components/rule-chain/rule-chain-autocomplete.component': RuleChainAutocompleteComponent, + '@home/components/profile/device-profile-provision-configuration.component': DeviceProfileProvisionConfigurationComponent, + '@home/components/profile/alarm/alarm-schedule.component': AlarmScheduleComponent, + '@home/components/wizard/device-wizard-dialog.component': DeviceWizardDialogComponent, + '@home/components/profile/alarm/alarm-schedule-info.component': AlarmScheduleInfoComponent, + '@home/components/profile/alarm/alarm-schedule-dialog.component': AlarmScheduleDialogComponent, + '@home/components/profile/alarm/edit-alarm-details-dialog.component': EditAlarmDetailsDialogComponent, + '@home/components/profile/alarm/alarm-rule-condition-dialog.component': AlarmRuleConditionDialogComponent, + '@home/components/profile/tenant/default-tenant-profile-configuration.component': DefaultTenantProfileConfigurationComponent, + '@home/components/profile/tenant/tenant-profile-configuration.component': TenantProfileConfigurationComponent, + '@home/components/sms/sms-provider-configuration.component': SmsProviderConfigurationComponent, + '@home/components/sms/aws-sns-provider-configuration.component': AwsSnsProviderConfigurationComponent, + '@home/components/sms/twilio-sms-provider-configuration.component': TwilioSmsProviderConfigurationComponent, + '@home/components/dashboard-page/dashboard-page.component': DashboardPageComponent, + '@home/components/dashboard-page/dashboard-toolbar.component': DashboardToolbarComponent, + '@home/components/dashboard-page/layout/dashboard-layout.component': DashboardLayoutComponent, + '@home/components/dashboard-page/edit-widget.component': EditWidgetComponent, + '@home/components/dashboard-page/dashboard-widget-select.component': DashboardWidgetSelectComponent, + '@home/components/dashboard-page/add-widget-dialog.component': AddWidgetDialogComponent, + '@home/components/dashboard-page/layout/manage-dashboard-layouts-dialog.component': ManageDashboardLayoutsDialogComponent, + '@home/components/dashboard-page/dashboard-settings-dialog.component': DashboardSettingsDialogComponent, + '@home/components/dashboard-page/states/manage-dashboard-states-dialog.component': ManageDashboardStatesDialogComponent, + '@home/components/dashboard-page/states/dashboard-state-dialog.component': DashboardStateDialogComponent, + '@home/components/widget/dialog/embed-dashboard-dialog.component': EmbedDashboardDialogComponent, + '@home/components/edge/edge-downlink-table.component': EdgeDownlinkTableComponent, + '@home/components/edge/edge-downlink-table-header.component': EdgeDownlinkTableHeaderComponent, + '@home/components/dashboard-page/widget-types-panel.component': DisplayWidgetTypesPanelComponent, + '@home/components/profile/alarm/alarm-duration-predicate-value.component': AlarmDurationPredicateValueComponent, + '@home/components/dashboard-page/dashboard-image-dialog.component': DashboardImageDialogComponent, + '@home/components/widget/widget-container.component': WidgetContainerComponent, + }; + + init() { + if (!this.initialized) { + System.constructor.prototype.resolve = (id) => { + try { + if (this.modulesMap[id]) { + return 'app:' + id; + } else { + return id; + } + } catch (err) { + return id; + } + }; + for (const moduleId of Object.keys(this.modulesMap)) { + System.set('app:' + moduleId, this.modulesMap[moduleId]); + } + this.initialized = true; + } + } +} + +export const modulesMap = new ModulesMap(); diff --git a/ui-ngx/src/app/modules/home/components/dashboard-page/states/states-controller.module.ts b/ui-ngx/src/app/modules/home/components/dashboard-page/states/states-controller.module.ts index 0f8c60858a..66b14fee44 100644 --- a/ui-ngx/src/app/modules/home/components/dashboard-page/states/states-controller.module.ts +++ b/ui-ngx/src/app/modules/home/components/dashboard-page/states/states-controller.module.ts @@ -17,9 +17,9 @@ import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { SharedModule } from '@shared/shared.module'; -import { StatesControllerService } from './states-controller.service'; -import { EntityStateControllerComponent } from './entity-state-controller.component'; -import { StatesComponentDirective } from './states-component.directive'; +import { StatesControllerService } from '@home/components/dashboard-page/states/states-controller.service'; +import { EntityStateControllerComponent } from '@home/components/dashboard-page/states/entity-state-controller.component'; +import { StatesComponentDirective } from '@home/components/dashboard-page/states/states-component.directive'; import { HomeDialogsModule } from '@app/modules/home/dialogs/home-dialogs.module'; import { DefaultStateControllerComponent } from '@home/components/dashboard-page/states/default-state-controller.component'; diff --git a/ui-ngx/src/app/modules/home/components/device/device-credentials.module.ts b/ui-ngx/src/app/modules/home/components/device/device-credentials.module.ts index 49f1c2c097..ce3bbbbd97 100644 --- a/ui-ngx/src/app/modules/home/components/device/device-credentials.module.ts +++ b/ui-ngx/src/app/modules/home/components/device/device-credentials.module.ts @@ -17,11 +17,11 @@ import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { SharedModule } from '@shared/shared.module'; -import { CopyDeviceCredentialsComponent } from './copy-device-credentials.component'; -import { DeviceCredentialsComponent } from './device-credentials.component'; -import { DeviceCredentialsLwm2mComponent } from './device-credentials-lwm2m.component'; -import { DeviceCredentialsLwm2mServerComponent } from './device-credentials-lwm2m-server.component'; -import { DeviceCredentialsMqttBasicComponent } from './device-credentials-mqtt-basic.component'; +import { CopyDeviceCredentialsComponent } from '@home/components/device/copy-device-credentials.component'; +import { DeviceCredentialsComponent } from '@home/components/device/device-credentials.component'; +import { DeviceCredentialsLwm2mComponent } from '@home/components/device/device-credentials-lwm2m.component'; +import { DeviceCredentialsLwm2mServerComponent } from '@home/components/device/device-credentials-lwm2m-server.component'; +import { DeviceCredentialsMqttBasicComponent } from '@home/components/device/device-credentials-mqtt-basic.component'; @NgModule({ declarations: [ diff --git a/ui-ngx/src/app/modules/home/components/entity/entities-table.component.ts b/ui-ngx/src/app/modules/home/components/entity/entities-table.component.ts index 49386db131..33f1b2afe4 100644 --- a/ui-ngx/src/app/modules/home/components/entity/entities-table.component.ts +++ b/ui-ngx/src/app/modules/home/components/entity/entities-table.component.ts @@ -64,6 +64,7 @@ import { DomSanitizer, SafeHtml } from '@angular/platform-browser'; import { TbAnchorComponent } from '@shared/components/tb-anchor.component'; import { isDefined, isUndefined } from '@core/utils'; import { HasUUID } from '@shared/models/id/has-uuid'; +import { IEntitiesTableComponent } from '@home/models/entity/entity-table-component.models'; @Component({ selector: 'tb-entities-table', @@ -71,7 +72,7 @@ import { HasUUID } from '@shared/models/id/has-uuid'; styleUrls: ['./entities-table.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush }) -export class EntitiesTableComponent extends PageComponent implements AfterViewInit, OnInit, OnChanges { +export class EntitiesTableComponent extends PageComponent implements IEntitiesTableComponent, AfterViewInit, OnInit, OnChanges { @Input() entitiesTableConfig: EntityTableConfig>; diff --git a/ui-ngx/src/app/modules/home/components/filter/complex-filter-predicate-dialog.component.ts b/ui-ngx/src/app/modules/home/components/filter/complex-filter-predicate-dialog.component.ts index 3f1bb3cace..4d61aa2c89 100644 --- a/ui-ngx/src/app/modules/home/components/filter/complex-filter-predicate-dialog.component.ts +++ b/ui-ngx/src/app/modules/home/components/filter/complex-filter-predicate-dialog.component.ts @@ -23,22 +23,12 @@ import { FormBuilder, FormControl, FormGroup, FormGroupDirective, NgForm, Valida import { Router } from '@angular/router'; import { DialogComponent } from '@app/shared/components/dialog.component'; import { - BooleanOperation, booleanOperationTranslationMap, - ComplexFilterPredicate, ComplexFilterPredicateInfo, ComplexOperation, complexOperationTranslationMap, - EntityKeyValueType, - FilterPredicateType, KeyFilterPredicateInfo + ComplexFilterPredicateInfo, + ComplexOperation, + complexOperationTranslationMap, + FilterPredicateType } from '@shared/models/query/query.models'; - -export interface ComplexFilterPredicateDialogData { - complexPredicate: ComplexFilterPredicateInfo; - key: string; - readonly: boolean; - isAdd: boolean; - valueType: EntityKeyValueType; - displayUserParameters: boolean; - allowUserDynamicSource: boolean; - onlyUserDynamicSource: boolean; -} +import { ComplexFilterPredicateDialogData } from '@home/components/filter/filter-component.models'; @Component({ selector: 'tb-complex-filter-predicate-dialog', diff --git a/ui-ngx/src/app/modules/home/components/filter/complex-filter-predicate.component.ts b/ui-ngx/src/app/modules/home/components/filter/complex-filter-predicate.component.ts index b177f118c0..038ff474ae 100644 --- a/ui-ngx/src/app/modules/home/components/filter/complex-filter-predicate.component.ts +++ b/ui-ngx/src/app/modules/home/components/filter/complex-filter-predicate.component.ts @@ -14,15 +14,14 @@ /// limitations under the License. /// -import { Component, forwardRef, Input, OnInit } from '@angular/core'; +import { Component, forwardRef, Inject, Input, OnInit } from '@angular/core'; import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; import { ComplexFilterPredicateInfo, EntityKeyValueType } from '@shared/models/query/query.models'; import { MatDialog } from '@angular/material/dialog'; -import { - ComplexFilterPredicateDialogComponent, - ComplexFilterPredicateDialogData -} from '@home/components/filter/complex-filter-predicate-dialog.component'; import { deepClone } from '@core/utils'; +import { ComplexFilterPredicateDialogData } from '@home/components/filter/filter-component.models'; +import { COMPLEX_FILTER_PREDICATE_DIALOG_COMPONENT_TOKEN } from '@home/components/tokens'; +import { ComponentType } from '@angular/cdk/portal'; @Component({ selector: 'tb-complex-filter-predicate', @@ -54,7 +53,8 @@ export class ComplexFilterPredicateComponent implements ControlValueAccessor, On private complexFilterPredicate: ComplexFilterPredicateInfo; - constructor(private dialog: MatDialog) { + constructor(@Inject(COMPLEX_FILTER_PREDICATE_DIALOG_COMPONENT_TOKEN) private complexFilterPredicateDialogComponent: ComponentType, + private dialog: MatDialog) { } ngOnInit(): void { @@ -76,8 +76,8 @@ export class ComplexFilterPredicateComponent implements ControlValueAccessor, On } public openComplexFilterDialog() { - this.dialog.open(ComplexFilterPredicateDialogComponent, { + this.dialog.open(this.complexFilterPredicateDialogComponent, { disableClose: true, panelClass: ['tb-dialog', 'tb-fullscreen-dialog'], data: { diff --git a/ui-ngx/src/app/modules/home/components/filter/filter-component.models.ts b/ui-ngx/src/app/modules/home/components/filter/filter-component.models.ts new file mode 100644 index 0000000000..325f89a911 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/filter/filter-component.models.ts @@ -0,0 +1,29 @@ +/// +/// Copyright © 2016-2021 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { ComplexFilterPredicateInfo, EntityKeyValueType } from '@shared/models/query/query.models'; + +export interface ComplexFilterPredicateDialogData { + complexPredicate: ComplexFilterPredicateInfo; + key: string; + readonly: boolean; + isAdd: boolean; + valueType: EntityKeyValueType; + displayUserParameters: boolean; + allowUserDynamicSource: boolean; + onlyUserDynamicSource: boolean; +} + diff --git a/ui-ngx/src/app/modules/home/components/filter/filter-predicate-list.component.ts b/ui-ngx/src/app/modules/home/components/filter/filter-predicate-list.component.ts index 75c9bd3ce8..e23c135d9b 100644 --- a/ui-ngx/src/app/modules/home/components/filter/filter-predicate-list.component.ts +++ b/ui-ngx/src/app/modules/home/components/filter/filter-predicate-list.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, forwardRef, Input, OnInit } from '@angular/core'; +import { Component, forwardRef, Inject, Input, OnInit } from '@angular/core'; import { AbstractControl, ControlValueAccessor, @@ -36,12 +36,11 @@ import { EntityKeyValueType, KeyFilterPredicateInfo } from '@shared/models/query/query.models'; -import { - ComplexFilterPredicateDialogComponent, - ComplexFilterPredicateDialogData -} from '@home/components/filter/complex-filter-predicate-dialog.component'; import { MatDialog } from '@angular/material/dialog'; import { map } from 'rxjs/operators'; +import { ComponentType } from '@angular/cdk/portal'; +import { COMPLEX_FILTER_PREDICATE_DIALOG_COMPONENT_TOKEN } from '@home/components/tokens'; +import { ComplexFilterPredicateDialogData } from '@home/components/filter/filter-component.models'; @Component({ selector: 'tb-filter-predicate-list', @@ -87,6 +86,7 @@ export class FilterPredicateListComponent implements ControlValueAccessor, Valid private valueChangeSubscription: Subscription = null; constructor(private fb: FormBuilder, + @Inject(COMPLEX_FILTER_PREDICATE_DIALOG_COMPONENT_TOKEN) private complexFilterPredicateDialogComponent: ComponentType, private dialog: MatDialog) { } @@ -164,8 +164,8 @@ export class FilterPredicateListComponent implements ControlValueAccessor, Valid } private openComplexFilterDialog(predicate: KeyFilterPredicateInfo): Observable { - return this.dialog.open(ComplexFilterPredicateDialogComponent, { + return this.dialog.open(this.complexFilterPredicateDialogComponent, { disableClose: true, panelClass: ['tb-dialog', 'tb-fullscreen-dialog'], data: { diff --git a/ui-ngx/src/app/modules/home/components/home-components.module.ts b/ui-ngx/src/app/modules/home/components/home-components.module.ts index 5e0752fcbc..265c5eb659 100644 --- a/ui-ngx/src/app/modules/home/components/home-components.module.ts +++ b/ui-ngx/src/app/modules/home/components/home-components.module.ts @@ -141,6 +141,10 @@ import { WidgetContainerComponent } from '@home/components/widget/widget-contain import { SnmpDeviceProfileTransportModule } from '@home/components/profile/device/snpm/snmp-device-profile-transport.module'; import { DeviceCredentialsModule } from '@home/components/device/device-credentials.module'; import { DeviceProfileCommonModule } from '@home/components/profile/device/common/device-profile-common.module'; +import { + COMPLEX_FILTER_PREDICATE_DIALOG_COMPONENT_TOKEN, + DASHBOARD_PAGE_COMPONENT_TOKEN +} from '@home/components/tokens'; @NgModule({ declarations: @@ -375,7 +379,9 @@ import { DeviceProfileCommonModule } from '@home/components/profile/device/commo WidgetComponentService, CustomDialogService, ImportExportService, - {provide: EMBED_DASHBOARD_DIALOG_TOKEN, useValue: EmbedDashboardDialogComponent} + {provide: EMBED_DASHBOARD_DIALOG_TOKEN, useValue: EmbedDashboardDialogComponent}, + {provide: COMPLEX_FILTER_PREDICATE_DIALOG_COMPONENT_TOKEN, useValue: ComplexFilterPredicateDialogComponent}, + {provide: DASHBOARD_PAGE_COMPONENT_TOKEN, useValue: DashboardPageComponent} ] }) export class HomeComponentsModule { } diff --git a/ui-ngx/src/app/modules/home/components/profile/device/common/device-profile-common.module.ts b/ui-ngx/src/app/modules/home/components/profile/device/common/device-profile-common.module.ts index 0ddcb507bb..e4bbdc919f 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/common/device-profile-common.module.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device/common/device-profile-common.module.ts @@ -15,10 +15,10 @@ /// import { NgModule } from '@angular/core'; -import { PowerModeSettingComponent } from './power-mode-setting.component'; +import { PowerModeSettingComponent } from '@home/components/profile/device/common/power-mode-setting.component'; import { SharedModule } from '@shared/shared.module'; import { CommonModule } from '@angular/common'; -import { TimeUnitSelectComponent } from './time-unit-select.component'; +import { TimeUnitSelectComponent } from '@home/components/profile/device/common/time-unit-select.component'; @NgModule({ declarations: [ diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-profile-components.module.ts b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-profile-components.module.ts index aa801f84dc..e1c8e9a14c 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-profile-components.module.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-profile-components.module.ts @@ -15,19 +15,19 @@ /// import { NgModule } from '@angular/core'; -import { Lwm2mDeviceProfileTransportConfigurationComponent } from './lwm2m-device-profile-transport-configuration.component'; -import { Lwm2mObjectListComponent } from './lwm2m-object-list.component'; -import { Lwm2mObserveAttrTelemetryComponent } from './lwm2m-observe-attr-telemetry.component'; -import { Lwm2mObserveAttrTelemetryResourcesComponent } from './lwm2m-observe-attr-telemetry-resources.component'; -import { Lwm2mAttributesDialogComponent } from './lwm2m-attributes-dialog.component'; -import { Lwm2mAttributesComponent } from './lwm2m-attributes.component'; -import { Lwm2mAttributesKeyListComponent } from './lwm2m-attributes-key-list.component'; -import { Lwm2mDeviceConfigServerComponent } from './lwm2m-device-config-server.component'; -import { Lwm2mObjectAddInstancesDialogComponent } from './lwm2m-object-add-instances-dialog.component'; -import { Lwm2mObjectAddInstancesListComponent } from './lwm2m-object-add-instances-list.component'; +import { Lwm2mDeviceProfileTransportConfigurationComponent } from '@home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component'; +import { Lwm2mObjectListComponent } from '@home/components/profile/device/lwm2m/lwm2m-object-list.component'; +import { Lwm2mObserveAttrTelemetryComponent } from '@home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry.component'; +import { Lwm2mObserveAttrTelemetryResourcesComponent } from '@home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry-resources.component'; +import { Lwm2mAttributesDialogComponent } from '@home/components/profile/device/lwm2m/lwm2m-attributes-dialog.component'; +import { Lwm2mAttributesComponent } from '@home/components/profile/device/lwm2m/lwm2m-attributes.component'; +import { Lwm2mAttributesKeyListComponent } from '@home/components/profile/device/lwm2m/lwm2m-attributes-key-list.component'; +import { Lwm2mDeviceConfigServerComponent } from '@home/components/profile/device/lwm2m/lwm2m-device-config-server.component'; +import { Lwm2mObjectAddInstancesDialogComponent } from '@home/components/profile/device/lwm2m/lwm2m-object-add-instances-dialog.component'; +import { Lwm2mObjectAddInstancesListComponent } from '@home/components/profile/device/lwm2m/lwm2m-object-add-instances-list.component'; import { CommonModule } from '@angular/common'; import { SharedModule } from '@app/shared/shared.module'; -import { Lwm2mObserveAttrTelemetryInstancesComponent } from './lwm2m-observe-attr-telemetry-instances.component'; +import { Lwm2mObserveAttrTelemetryInstancesComponent } from '@home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry-instances.component'; import { DeviceProfileCommonModule } from '@home/components/profile/device/common/device-profile-common.module'; @NgModule({ diff --git a/ui-ngx/src/app/modules/home/components/profile/device/snpm/snmp-device-profile-transport.module.ts b/ui-ngx/src/app/modules/home/components/profile/device/snpm/snmp-device-profile-transport.module.ts index c0797d9b0e..95b7c0180d 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/snpm/snmp-device-profile-transport.module.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device/snpm/snmp-device-profile-transport.module.ts @@ -18,8 +18,8 @@ import { NgModule } from '@angular/core'; import { SharedModule } from '@shared/shared.module'; import { CommonModule } from '@angular/common'; import { SnmpDeviceProfileTransportConfigurationComponent } from '@home/components/profile/device/snpm/snmp-device-profile-transport-configuration.component'; -import { SnmpDeviceProfileCommunicationConfigComponent } from './snmp-device-profile-communication-config.component'; -import { SnmpDeviceProfileMappingComponent } from './snmp-device-profile-mapping.component'; +import { SnmpDeviceProfileCommunicationConfigComponent } from '@home/components/profile/device/snpm/snmp-device-profile-communication-config.component'; +import { SnmpDeviceProfileMappingComponent } from '@home/components/profile/device/snpm/snmp-device-profile-mapping.component'; @NgModule({ declarations: [ diff --git a/ui-ngx/src/app/modules/home/components/shared-home-components.module.ts b/ui-ngx/src/app/modules/home/components/shared-home-components.module.ts index df6764c573..f2c14a535a 100644 --- a/ui-ngx/src/app/modules/home/components/shared-home-components.module.ts +++ b/ui-ngx/src/app/modules/home/components/shared-home-components.module.ts @@ -18,8 +18,12 @@ import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { SharedModule } from '@app/shared/shared.module'; import { AlarmDetailsDialogComponent } from '@home/components/alarm/alarm-details-dialog.component'; +import { SHARED_HOME_COMPONENTS_MODULE_TOKEN } from '@home/components/tokens'; @NgModule({ + providers: [ + { provide: SHARED_HOME_COMPONENTS_MODULE_TOKEN, useValue: SharedHomeComponentsModule } + ], declarations: [ AlarmDetailsDialogComponent diff --git a/ui-ngx/src/app/modules/home/components/tokens.ts b/ui-ngx/src/app/modules/home/components/tokens.ts new file mode 100644 index 0000000000..b88ea49a03 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/tokens.ts @@ -0,0 +1,27 @@ +/// +/// Copyright © 2016-2021 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { InjectionToken, Type } from '@angular/core'; +import { ComponentType } from '@angular/cdk/portal'; + +export const SHARED_HOME_COMPONENTS_MODULE_TOKEN: InjectionToken> = + new InjectionToken>('SHARED_HOME_COMPONENTS_MODULE_TOKEN'); + +export const COMPLEX_FILTER_PREDICATE_DIALOG_COMPONENT_TOKEN: InjectionToken> = + new InjectionToken>('COMPLEX_FILTER_PREDICATE_DIALOG_COMPONENT_TOKEN'); + +export const DASHBOARD_PAGE_COMPONENT_TOKEN: InjectionToken> = + new InjectionToken>('DASHBOARD_PAGE_COMPONENT_TOKEN'); diff --git a/ui-ngx/src/app/modules/home/components/widget/dialog/custom-dialog.service.ts b/ui-ngx/src/app/modules/home/components/widget/dialog/custom-dialog.service.ts index ac41188485..a2d61a9eaa 100644 --- a/ui-ngx/src/app/modules/home/components/widget/dialog/custom-dialog.service.ts +++ b/ui-ngx/src/app/modules/home/components/widget/dialog/custom-dialog.service.ts @@ -14,21 +14,21 @@ /// limitations under the License. /// -import { Injectable, NgModule } from '@angular/core'; +import { Inject, Injectable, Type } from '@angular/core'; import { Observable } from 'rxjs'; import { MatDialog } from '@angular/material/dialog'; import { TranslateService } from '@ngx-translate/core'; import { AuthService } from '@core/auth/auth.service'; import { DynamicComponentFactoryService } from '@core/services/dynamic-component-factory.service'; import { CommonModule } from '@angular/common'; -import { SharedModule } from '@shared/shared.module'; import { mergeMap, tap } from 'rxjs/operators'; import { CustomDialogComponent } from './custom-dialog.component'; import { CustomDialogContainerComponent, CustomDialogContainerData } from '@home/components/widget/dialog/custom-dialog-container.component'; -import { SharedHomeComponentsModule } from '@home/components/shared-home-components.module'; +import { SHARED_MODULE_TOKEN } from '@shared/components/tokens'; +import { SHARED_HOME_COMPONENTS_MODULE_TOKEN } from '@home/components/tokens'; @Injectable() export class CustomDialogService { @@ -37,6 +37,8 @@ export class CustomDialogService { private translate: TranslateService, private authService: AuthService, private dynamicComponentFactoryService: DynamicComponentFactoryService, + @Inject(SHARED_MODULE_TOKEN) private sharedModule: Type, + @Inject(SHARED_HOME_COMPONENTS_MODULE_TOKEN) private sharedHomeComponentsModule: Type, public dialog: MatDialog ) { } @@ -45,7 +47,7 @@ export class CustomDialogService { return this.dynamicComponentFactoryService.createDynamicComponentFactory( class CustomDialogComponentInstance extends CustomDialogComponent {}, template, - [SharedModule, CustomDialogModule, SharedHomeComponentsModule]).pipe( + [this.sharedModule, CommonModule, this.sharedHomeComponentsModule]).pipe( mergeMap((factory) => { const dialogData: CustomDialogContainerData = { controller, @@ -69,15 +71,3 @@ export class CustomDialogService { } -@NgModule({ - declarations: - [ - ], - imports: [ - CommonModule, - SharedModule - ], - exports: [ - ] -}) -class CustomDialogModule { } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts index db62775c40..27d6fb5edc 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts @@ -168,6 +168,7 @@ export default abstract class LeafletMap { this.selectedEntity = data; this.toggleDrawMode(type); } else { + // @ts-ignore this.map.pm.Toolbar.toggleButton(type, false); } }); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/rpc/led-indicator.component.scss b/ui-ngx/src/app/modules/home/components/widget/lib/rpc/led-indicator.component.scss index b6b1c45e27..2c789bebbd 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/rpc/led-indicator.component.scss +++ b/ui-ngx/src/app/modules/home/components/widget/lib/rpc/led-indicator.component.scss @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -@import "node_modules/compass-sass-mixins/lib/compass"; $error-height: 14px !default; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/rpc/round-switch.component.scss b/ui-ngx/src/app/modules/home/components/widget/lib/rpc/round-switch.component.scss index 96cdcadeff..7931b05131 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/rpc/round-switch.component.scss +++ b/ui-ngx/src/app/modules/home/components/widget/lib/rpc/round-switch.component.scss @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -@import "node_modules/compass-sass-mixins/lib/compass"; $error-height: 14px !default; diff --git a/ui-ngx/src/app/modules/home/components/widget/widget-component.service.ts b/ui-ngx/src/app/modules/home/components/widget/widget-component.service.ts index 9f7da7a747..90b3087ced 100644 --- a/ui-ngx/src/app/modules/home/components/widget/widget-component.service.ts +++ b/ui-ngx/src/app/modules/home/components/widget/widget-component.service.ts @@ -44,6 +44,7 @@ import { SharedModule } from '@shared/shared.module'; import { MODULES_MAP } from '@shared/public-api'; import * as tinycolor_ from 'tinycolor2'; import moment from 'moment'; +import { IModulesMap } from '@modules/common/modules-map.models'; const tinycolor = tinycolor_; @@ -64,7 +65,7 @@ export class WidgetComponentService { private editingWidgetType: WidgetType; constructor(@Inject(WINDOW) private window: Window, - @Optional() @Inject(MODULES_MAP) private modulesMap: {[key: string]: any}, + @Optional() @Inject(MODULES_MAP) private modulesMap: IModulesMap, private dynamicComponentFactoryService: DynamicComponentFactoryService, private widgetService: WidgetService, private utils: UtilsService, diff --git a/ui-ngx/src/app/modules/home/components/widget/widget-components.module.ts b/ui-ngx/src/app/modules/home/components/widget/widget-components.module.ts index ba692ed122..ad7912cdee 100644 --- a/ui-ngx/src/app/modules/home/components/widget/widget-components.module.ts +++ b/ui-ngx/src/app/modules/home/components/widget/widget-components.module.ts @@ -30,10 +30,10 @@ import { DateRangeNavigatorPanelComponent, DateRangeNavigatorWidgetComponent } from '@home/components/widget/lib/date-range-navigator/date-range-navigator.component'; -import { MultipleInputWidgetComponent } from './lib/multiple-input-widget.component'; -import { TripAnimationComponent } from './trip-animation/trip-animation.component'; -import { PhotoCameraInputWidgetComponent } from './lib/photo-camera-input.component'; -import { GatewayFormComponent } from './lib/gateway/gateway-form.component'; +import { MultipleInputWidgetComponent } from '@home/components/widget/lib/multiple-input-widget.component'; +import { TripAnimationComponent } from '@home/components/widget/trip-animation/trip-animation.component'; +import { PhotoCameraInputWidgetComponent } from '@home/components/widget/lib/photo-camera-input.component'; +import { GatewayFormComponent } from '@home/components/widget/lib/gateway/gateway-form.component'; import { ImportExportService } from '@home/components/import-export/import-export.service'; import { NavigationCardsWidgetComponent } from '@home/components/widget/lib/navigation-cards-widget.component'; import { NavigationCardWidgetComponent } from '@home/components/widget/lib/navigation-card-widget.component'; @@ -41,7 +41,7 @@ import { EdgesOverviewWidgetComponent } from '@home/components/widget/lib/edges- import { JsonInputWidgetComponent } from '@home/components/widget/lib/json-input-widget.component'; import { QrCodeWidgetComponent } from '@home/components/widget/lib/qrcode-widget.component'; import { MarkdownWidgetComponent } from '@home/components/widget/lib/markdown-widget.component'; -import { SelectEntityDialogComponent } from './lib/maps/dialogs/select-entity-dialog.component'; +import { SelectEntityDialogComponent } from '@home/components/widget/lib/maps/dialogs/select-entity-dialog.component'; @NgModule({ declarations: diff --git a/ui-ngx/src/app/modules/home/components/widget/widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/widget.component.ts index 05d8686d46..c1208d0241 100644 --- a/ui-ngx/src/app/modules/home/components/widget/widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/widget.component.ts @@ -107,9 +107,11 @@ import { ComponentType } from '@angular/cdk/portal'; import { EMBED_DASHBOARD_DIALOG_TOKEN } from '@home/components/widget/dialog/embed-dashboard-dialog-token'; import { MobileService } from '@core/services/mobile.service'; import { DialogService } from '@core/services/dialog.service'; -import { DashboardPageComponent } from '@home/components/dashboard-page/dashboard-page.component'; import { PopoverPlacement } from '@shared/components/popover.models'; import { TbPopoverService } from '@shared/components/popover.service'; +import { + DASHBOARD_PAGE_COMPONENT_TOKEN +} from '@home/components/tokens'; @Component({ selector: 'tb-widget', @@ -183,6 +185,7 @@ export class WidgetComponent extends PageComponent implements OnInit, AfterViewI private renderer: Renderer2, private popoverService: TbPopoverService, @Inject(EMBED_DASHBOARD_DIALOG_TOKEN) private embedDashboardDialogComponent: ComponentType, + @Inject(DASHBOARD_PAGE_COMPONENT_TOKEN) private dashboardPageComponent: ComponentType, private widgetService: WidgetService, private resources: ResourcesService, private timeService: TimeService, @@ -1354,7 +1357,7 @@ export class WidgetComponent extends PageComponent implements OnInit, AfterViewI ] }); const component = this.popoverService.displayPopover(trigger, this.renderer, - this.widgetContentContainer, DashboardPageComponent, preferredPlacement, hideOnClickOutside, + this.widgetContentContainer, this.dashboardPageComponent, preferredPlacement, hideOnClickOutside, injector, { embed: true, diff --git a/ui-ngx/src/app/modules/home/home.component.ts b/ui-ngx/src/app/modules/home/home.component.ts index 34be8cc8b2..e1ecacc2d4 100644 --- a/ui-ngx/src/app/modules/home/home.component.ts +++ b/ui-ngx/src/app/modules/home/home.component.ts @@ -25,14 +25,12 @@ import { PageComponent } from '@shared/components/page.component'; import { AppState } from '@core/core.state'; import { getCurrentAuthState, selectAuthUser, selectUserDetails } from '@core/auth/auth.selectors'; import { MediaBreakpoints } from '@shared/models/constants'; -import * as _screenfull from 'screenfull'; +import screenfull from 'screenfull'; import { MatSidenav } from '@angular/material/sidenav'; import { AuthState } from '@core/auth/auth.models'; import { WINDOW } from '@core/services/window.service'; import { instanceOfSearchableComponent, ISearchableComponent } from '@home/models/searchable-component.models'; -const screenfull = _screenfull as _screenfull.Screenfull; - @Component({ selector: 'tb-home', templateUrl: './home.component.html', diff --git a/ui-ngx/src/app/modules/home/models/entity/entities-table-config.models.ts b/ui-ngx/src/app/modules/home/models/entity/entities-table-config.models.ts index f554329cc2..2f3d58e61f 100644 --- a/ui-ngx/src/app/modules/home/models/entity/entities-table-config.models.ts +++ b/ui-ngx/src/app/modules/home/models/entity/entities-table-config.models.ts @@ -26,11 +26,11 @@ import { Type } from '@angular/core'; import { EntityAction } from './entity-component.models'; import { HasUUID } from '@shared/models/id/has-uuid'; import { PageLink } from '@shared/models/page/page-link'; -import { EntitiesTableComponent } from '@home/components/entity/entities-table.component'; import { EntityTableHeaderComponent } from '@home/components/entity/entity-table-header.component'; import { ActivatedRoute } from '@angular/router'; import { EntityTabsComponent } from '../../components/entity/entity-tabs.component'; import { DAY, historyInterval } from '@shared/models/time/time.models'; +import { IEntitiesTableComponent } from '@home/models/entity/entity-table-component.models'; export type EntityBooleanFunction> = (entity: T) => boolean; export type EntityStringFunction> = (entity: T) => string; @@ -140,7 +140,7 @@ export class EntityTableConfig, P extends PageLink = P loadDataOnInit = true; onLoadAction: (route: ActivatedRoute) => void = null; - table: EntitiesTableComponent = null; + table: IEntitiesTableComponent = null; useTimePageLink = false; defaultTimewindowInterval = historyInterval(DAY); entityType: EntityType = null; diff --git a/ui-ngx/src/app/modules/home/models/entity/entity-table-component.models.ts b/ui-ngx/src/app/modules/home/models/entity/entity-table-component.models.ts new file mode 100644 index 0000000000..20b1d15b32 --- /dev/null +++ b/ui-ngx/src/app/modules/home/models/entity/entity-table-component.models.ts @@ -0,0 +1,85 @@ +/// +/// Copyright © 2016-2021 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { BaseData, HasId } from '@shared/models/base-data'; +import { EntityTypeTranslation } from '@shared/models/entity-type.models'; +import { SafeHtml } from '@angular/platform-browser'; +import { PageLink } from '@shared/models/page/page-link'; +import { Timewindow } from '@shared/models/time/time.models'; +import { EntitiesDataSource } from '@home/models/datasource/entity-datasource'; +import { ElementRef, EventEmitter } from '@angular/core'; +import { TbAnchorComponent } from '@shared/components/tb-anchor.component'; +import { MatPaginator } from '@angular/material/paginator'; +import { MatSort } from '@angular/material/sort'; +import { EntityAction } from '@home/models/entity/entity-component.models'; +import { + CellActionDescriptor, EntityActionTableColumn, EntityColumn, EntityTableColumn, + EntityTableConfig, + GroupActionDescriptor, + HeaderActionDescriptor +} from '@home/models/entity/entities-table-config.models'; + +export interface IEntitiesTableComponent { + entitiesTableConfig: EntityTableConfig>; + translations: EntityTypeTranslation; + headerActionDescriptors: Array; + groupActionDescriptors: Array>>; + cellActionDescriptors: Array>>; + actionColumns: Array>>; + entityColumns: Array>>; + displayedColumns: string[]; + headerCellStyleCache: Array; + cellContentCache: Array; + cellTooltipCache: Array; + cellStyleCache: Array; + selectionEnabled: boolean; + defaultPageSize: number; + displayPagination: boolean; + pageSizeOptions: number[]; + pageLink: PageLink; + textSearchMode: boolean; + timewindow: Timewindow; + dataSource: EntitiesDataSource>; + isDetailsOpen: boolean; + detailsPanelOpened: EventEmitter; + entityTableHeaderAnchor: TbAnchorComponent; + searchInputField: ElementRef; + paginator: MatPaginator; + sort: MatSort; + + addEnabled(): boolean; + clearSelection(): void; + updateData(closeDetails?: boolean): void; + onRowClick($event: Event, entity): void; + toggleEntityDetails($event: Event, entity); + addEntity($event: Event): void; + onEntityUpdated(entity: BaseData): void; + onEntityAction(action: EntityAction>): void; + deleteEntity($event: Event, entity: BaseData): void; + deleteEntities($event: Event, entities: BaseData[]): void; + onTimewindowChange(): void; + enterFilterMode(): void; + exitFilterMode(): void; + resetSortAndFilter(update?: boolean, preserveTimewindow?: boolean): void; + columnsUpdated(resetData?: boolean): void; + headerCellStyle(column: EntityColumn>): any; + clearCellCache(col: number, row: number): void; + cellContent(entity: BaseData, column: EntityColumn>, row: number): any; + cellTooltip(entity: BaseData, column: EntityColumn>, row: number): string; + cellStyle(entity: BaseData, column: EntityColumn>, row: number): any; + trackByColumnKey(index, column: EntityTableColumn>): string; + trackByEntityId(index: number, entity: BaseData): string; +} diff --git a/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-routing.module.ts b/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-routing.module.ts index d84bdfafcb..80b8dd218e 100644 --- a/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-routing.module.ts +++ b/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-routing.module.ts @@ -41,6 +41,7 @@ import { RuleNodeComponentDescriptor } from '@shared/models/rule-node.models'; import { ConfirmOnExitGuard } from '@core/guards/confirm-on-exit.guard'; import { ItemBufferService } from '@core/public-api'; import { MODULES_MAP } from '@shared/public-api'; +import { IModulesMap } from '@modules/common/modules-map.models'; @Injectable() export class RuleChainResolver implements Resolve { @@ -70,7 +71,7 @@ export class ResolvedRuleChainMetaDataResolver implements Resolve> { constructor(private ruleChainService: RuleChainService, - @Optional() @Inject(MODULES_MAP) private modulesMap: {[key: string]: any}) { + @Optional() @Inject(MODULES_MAP) private modulesMap: IModulesMap) { } resolve(route: ActivatedRouteSnapshot): Observable> { diff --git a/ui-ngx/src/app/shared/components/cheatsheet.component.ts b/ui-ngx/src/app/shared/components/cheatsheet.component.ts index 39a087506a..54ca7c2f88 100644 --- a/ui-ngx/src/app/shared/components/cheatsheet.component.ts +++ b/ui-ngx/src/app/shared/components/cheatsheet.component.ts @@ -16,6 +16,8 @@ import { Component, ElementRef, Input, OnDestroy, OnInit } from '@angular/core'; import { Hotkey, HotkeysService } from 'angular2-hotkeys'; +import { MousetrapInstance } from 'mousetrap'; +import * as Mousetrap from 'mousetrap'; @Component({ selector : 'tb-hotkeys-cheatsheet', diff --git a/ui-ngx/src/app/shared/components/fab-toolbar.component.scss b/ui-ngx/src/app/shared/components/fab-toolbar.component.scss index edb3ff793e..12e66fd003 100644 --- a/ui-ngx/src/app/shared/components/fab-toolbar.component.scss +++ b/ui-ngx/src/app/shared/components/fab-toolbar.component.scss @@ -13,6 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + +@use "sass:math"; + $font-size: 10px !default; @function rem($multiplier) { @return $multiplier * $font-size; @@ -47,10 +50,10 @@ $swift-ease-in: all $swift-ease-in-duration $swift-ease-in-timing-function !defa } @mixin fab-all-positions() { - @include fab-position(bottom-right, auto, ($button-fab-width - $button-fab-padding)/2, ($button-fab-height - $button-fab-padding)/2, auto); - @include fab-position(bottom-left, auto, auto, ($button-fab-height - $button-fab-padding)/2, ($button-fab-width - $button-fab-padding)/2); - @include fab-position(top-right, ($button-fab-height - $button-fab-padding)/2, ($button-fab-width - $button-fab-padding)/2, auto, auto); - @include fab-position(top-left, ($button-fab-height - $button-fab-padding)/2, auto, auto, ($button-fab-width - $button-fab-padding)/2); + @include fab-position(bottom-right, auto, math.div(($button-fab-width - $button-fab-padding), 2), math.div(($button-fab-height - $button-fab-padding), 2), auto); + @include fab-position(bottom-left, auto, auto, math.div(($button-fab-height - $button-fab-padding), 2), math.div(($button-fab-width - $button-fab-padding), 2)); + @include fab-position(top-right, math.div(($button-fab-height - $button-fab-padding), 2), math.div(($button-fab-width - $button-fab-padding), 2), auto, auto); + @include fab-position(top-left, math.div(($button-fab-height - $button-fab-padding), 2), auto, auto, math.div(($button-fab-width - $button-fab-padding), 2)); } mat-fab-toolbar { @@ -175,7 +178,7 @@ mat-fab-toolbar { mat-toolbar { .mat-fab-action-item { transition: $swift-ease-in; - transition-duration: $swift-ease-in-duration / 2; + transition-duration: math.div($swift-ease-in-duration, 2); } } &.mat-is-open { diff --git a/ui-ngx/src/app/shared/components/hotkeys.directive.ts b/ui-ngx/src/app/shared/components/hotkeys.directive.ts index 37723a8407..d1419c0ee4 100644 --- a/ui-ngx/src/app/shared/components/hotkeys.directive.ts +++ b/ui-ngx/src/app/shared/components/hotkeys.directive.ts @@ -16,7 +16,8 @@ import { Directive, ElementRef, Input, OnDestroy, OnInit } from '@angular/core'; import { Hotkey } from 'angular2-hotkeys'; -import 'mousetrap'; +import { MousetrapInstance } from 'mousetrap'; +import * as Mousetrap from 'mousetrap'; import { TbCheatSheetComponent } from '@shared/components/cheatsheet.component'; @Directive({ diff --git a/ui-ngx/src/app/shared/components/json-form/react/json-form-react.tsx b/ui-ngx/src/app/shared/components/json-form/react/json-form-react.tsx index eef3fe5c84..f9fe16bd9c 100644 --- a/ui-ngx/src/app/shared/components/json-form/react/json-form-react.tsx +++ b/ui-ngx/src/app/shared/components/json-form/react/json-form-react.tsx @@ -14,12 +14,12 @@ * limitations under the License. */ import * as React from 'react'; -import { createMuiTheme, ThemeProvider } from '@material-ui/core/styles'; +import { createTheme, ThemeProvider } from '@material-ui/core/styles'; import thingsboardTheme from './styles/thingsboardTheme'; import ThingsboardSchemaForm from './json-form-schema-form'; import { JsonFormProps } from './json-form.models'; -const tbTheme = createMuiTheme(thingsboardTheme); +const tbTheme = createTheme(thingsboardTheme); class ReactSchemaForm extends React.Component { diff --git a/ui-ngx/src/app/shared/components/json-form/react/json-form.scss b/ui-ngx/src/app/shared/components/json-form/react/json-form.scss index fb33d2afc0..67f737953a 100644 --- a/ui-ngx/src/app/shared/components/json-form/react/json-form.scss +++ b/ui-ngx/src/app/shared/components/json-form/react/json-form.scss @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -@import "~compass-sass-mixins/lib/compass"; $swift-ease-out-duration: .4s !default; $swift-ease-out-timing-function: cubic-bezier(.25, .8, .25, 1) !default; diff --git a/ui-ngx/src/app/shared/components/json-form/react/styles/thingsboardTheme.ts b/ui-ngx/src/app/shared/components/json-form/react/styles/thingsboardTheme.ts index ef4ba9fc84..1084a7c4c2 100644 --- a/ui-ngx/src/app/shared/components/json-form/react/styles/thingsboardTheme.ts +++ b/ui-ngx/src/app/shared/components/json-form/react/styles/thingsboardTheme.ts @@ -31,7 +31,7 @@ */ import indigo from '@material-ui/core/colors/indigo'; import deeepOrange from '@material-ui/core/colors/deepOrange'; -import { ThemeOptions } from '@material-ui/core/styles/createMuiTheme'; +import { ThemeOptions } from '@material-ui/core/styles'; import { PaletteOptions } from '@material-ui/core/styles/createPalette'; import { mergeDeep } from '@core/utils'; diff --git a/ui-ngx/src/app/shared/components/nav-tree.component.ts b/ui-ngx/src/app/shared/components/nav-tree.component.ts index 7de7a8902f..1be3ba8bc8 100644 --- a/ui-ngx/src/app/shared/components/nav-tree.component.ts +++ b/ui-ngx/src/app/shared/components/nav-tree.component.ts @@ -76,19 +76,19 @@ export class NavTreeComponent implements OnInit { } @Input() - private loadNodes: LoadNodesCallback; + loadNodes: LoadNodesCallback; @Input() - private searchCallback: NodeSearchCallback; + searchCallback: NodeSearchCallback; @Input() - private onNodeSelected: NodeSelectedCallback; + onNodeSelected: NodeSelectedCallback; @Input() - private onNodesInserted: NodesInsertedCallback; + onNodesInserted: NodesInsertedCallback; @Input() - private editCallbacks: NavTreeEditCallbacks; + editCallbacks: NavTreeEditCallbacks; private treeElement: JSTree; diff --git a/ui-ngx/src/app/shared/components/popover.component.scss b/ui-ngx/src/app/shared/components/popover.component.scss index 48b7eb7d27..6a9c289fa1 100644 --- a/ui-ngx/src/app/shared/components/popover.component.scss +++ b/ui-ngx/src/app/shared/components/popover.component.scss @@ -124,7 +124,7 @@ $box-shadow-base: 0 3px 6px -4px rgba(0, 0, 0, 0.12), 0 6px 16px 0 rgba(0, 0, 0, height: sqrt($popover-arrow-width * $popover-arrow-width * 2) + px; background: transparent; border-style: solid; - border-width: (sqrt($popover-arrow-width * $popover-arrow-width * 2) / 2) + px; + border-width: (sqrt($popover-arrow-width * $popover-arrow-width * 2) * 0.5) + px; transform: rotate(45deg); z-index: 10; } diff --git a/ui-ngx/src/app/shared/components/tokens.ts b/ui-ngx/src/app/shared/components/tokens.ts index 8171d52839..205357b6f9 100644 --- a/ui-ngx/src/app/shared/components/tokens.ts +++ b/ui-ngx/src/app/shared/components/tokens.ts @@ -21,4 +21,4 @@ export const HELP_MARKDOWN_COMPONENT_TOKEN: InjectionToken> = new InjectionToken>('HELP_MARKDOWN_COMPONENT_TOKEN'); export const SHARED_MODULE_TOKEN: InjectionToken> = - new InjectionToken>('HELP_MARKDOWN_COMPONENT_TOKEN'); + new InjectionToken>('SHARED_MODULE_TOKEN'); diff --git a/ui-ngx/src/app/shared/models/constants.ts b/ui-ngx/src/app/shared/models/constants.ts index 03b38345ca..b30ed084ab 100644 --- a/ui-ngx/src/app/shared/models/constants.ts +++ b/ui-ngx/src/app/shared/models/constants.ts @@ -15,6 +15,7 @@ /// import { InjectionToken } from '@angular/core'; +import { IModulesMap } from '@modules/common/modules-map.models'; export const Constants = { serverErrorCode: { @@ -244,4 +245,4 @@ export const contentTypesMap = new Map( export const customTranslationsPrefix = 'custom.'; export const i18nPrefix = 'i18n'; -export const MODULES_MAP = new InjectionToken<{[key: string]: any}>('ModulesMap'); +export const MODULES_MAP = new InjectionToken('ModulesMap'); diff --git a/ui-ngx/src/app/shared/shared.module.ts b/ui-ngx/src/app/shared/shared.module.ts index 90b80393dd..50ffdafa65 100644 --- a/ui-ngx/src/app/shared/shared.module.ts +++ b/ui-ngx/src/app/shared/shared.module.ts @@ -132,7 +132,7 @@ import { NavTreeComponent } from '@shared/components/nav-tree.component'; import { LedLightComponent } from '@shared/components/led-light.component'; import { TbJsonToStringDirective } from '@shared/components/directives/tb-json-to-string.directive'; import { JsonObjectEditDialogComponent } from '@shared/components/dialog/json-object-edit-dialog.component'; -import { HistorySelectorComponent } from './components/time/history-selector/history-selector.component'; +import { HistorySelectorComponent } from '@shared/components/time/history-selector/history-selector.component'; import { EntityGatewaySelectComponent } from '@shared/components/entity/entity-gateway-select.component'; import { DndModule } from 'ngx-drag-drop'; import { QueueTypeListComponent } from '@shared/components/queue/queue-type-list.component'; @@ -155,7 +155,7 @@ import { MarkedOptionsService } from '@shared/components/marked-options.service' import { TbPopoverService } from '@shared/components/popover.service'; import { HELP_MARKDOWN_COMPONENT_TOKEN, SHARED_MODULE_TOKEN } from '@shared/components/tokens'; import { TbMarkdownComponent } from '@shared/components/markdown.component'; -import { ProtobufContentComponent } from './components/protobuf-content.component'; +import { ProtobufContentComponent } from '@shared/components/protobuf-content.component'; export function MarkedOptionsFactory(markedOptionsService: MarkedOptionsService) { return markedOptionsService; diff --git a/ui-ngx/src/scss/animations.scss b/ui-ngx/src/scss/animations.scss index 2d8bf3469e..5a0fcff2b5 100644 --- a/ui-ngx/src/scss/animations.scss +++ b/ui-ngx/src/scss/animations.scss @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -@import "~compass-sass-mixins/lib/animate"; @keyframes tbMoveFromTopFade { from { diff --git a/ui-ngx/src/scss/mixins.scss b/ui-ngx/src/scss/mixins.scss index 2d2495b998..cb3e24a9d7 100644 --- a/ui-ngx/src/scss/mixins.scss +++ b/ui-ngx/src/scss/mixins.scss @@ -13,6 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +@use "sass:math"; + @mixin tb-mat-icon-size($size) { width: #{$size}px; min-width: #{$size}px; @@ -51,7 +53,7 @@ $x1: $x0; @for $i from 1 through 10 { - $x1: $x0 - ($x0 * $x0 - abs($r)) / (2 * $x0); + $x1: $x0 - math.div($x0 * $x0 - abs($r), 2 * $x0); $x0: $x1; } diff --git a/ui-ngx/src/theme.scss b/ui-ngx/src/theme.scss index fdad632bee..6821a0706b 100644 --- a/ui-ngx/src/theme.scss +++ b/ui-ngx/src/theme.scss @@ -158,17 +158,20 @@ $tb-dark-theme: get-tb-dark-theme( } &.mat-primary { .mat-fab-toolbar-background { - @include _mat-toolbar-color($primary); + background: mat.get-color-from-palette($primary); + color: mat.get-color-from-palette($primary, default-contrast); } } &.mat-accent { .mat-fab-toolbar-background { - @include _mat-toolbar-color($accent); + background: mat.get-color-from-palette($accent); + color: mat.get-color-from-palette($accent, default-contrast); } } &.mat-warn { .mat-fab-toolbar-background { - @include _mat-toolbar-color($warn); + background: mat.get-color-from-palette($warn); + color: mat.get-color-from-palette($warn, default-contrast); } } } diff --git a/ui-ngx/src/tsconfig.app.json b/ui-ngx/src/tsconfig.app.json index e73cce9a21..fb8ea9b284 100644 --- a/ui-ngx/src/tsconfig.app.json +++ b/ui-ngx/src/tsconfig.app.json @@ -3,7 +3,7 @@ "compilerOptions": { "outDir": "../out-tsc/app", "types": ["node", "jquery", "flot", "tooltipster", "tinycolor2", "js-beautify", - "react", "react-dom", "jstree", "raphael", "canvas-gauges"] + "react", "react-dom", "jstree", "raphael", "canvas-gauges", "systemjs"] }, "angularCompilerOptions": { "fullTemplateTypeCheck": true diff --git a/ui-ngx/tsconfig.json b/ui-ngx/tsconfig.json index 131a93b826..2243eae689 100644 --- a/ui-ngx/tsconfig.json +++ b/ui-ngx/tsconfig.json @@ -3,15 +3,18 @@ "compilerOptions": { "baseUrl": "./", "outDir": "./dist/out-tsc", + "forceConsistentCasingInFileNames": true, + "noFallthroughCasesInSwitch": true, "sourceMap": true, "declaration": false, - "module": "es2020", + "downlevelIteration": true, + "experimentalDecorators": true, "moduleResolution": "node", + "importHelpers": true, + "target": "es2017", + "module": "es2020", "emitDecoratorMetadata": true, - "experimentalDecorators": true, "allowSyntheticDefaultImports": true, - "importHelpers": true, - "target": "es5", "jsx": "react", "typeRoots": [ "node_modules/@types", @@ -52,9 +55,14 @@ ] }, "lib": [ - "es2018", - "es2019", + "es2020", "dom" ] + }, + "angularCompilerOptions": { + "enableI18nLegacyMessageIdFormat": false, + "strictInjectionParameters": true, + "strictInputAccessModifiers": true, + "strictTemplates": false } } diff --git a/ui-ngx/yarn.lock b/ui-ngx/yarn.lock index 9aae7fabc0..ba822f9116 100644 --- a/ui-ngx/yarn.lock +++ b/ui-ngx/yarn.lock @@ -10,28 +10,20 @@ "@jridgewell/resolve-uri" "1.0.0" sourcemap-codec "1.4.8" -"@angular-builders/custom-webpack@~11.1.1": - version "11.1.1" - resolved "https://registry.yarnpkg.com/@angular-builders/custom-webpack/-/custom-webpack-11.1.1.tgz#5ef535f5c51cb2f5a27f53fcfab54176cd1d14d4" - integrity sha512-9l2yC9+QMwWj9IEsOpQtMIBcH87UMZdoR2+8DbIt53ypst/8aVMhMsKmR5n33wRkLlIJ6/ubyXldQymIHzoF1g== - dependencies: - "@angular-devkit/architect" ">=0.1100.0 < 0.1200.0" - "@angular-devkit/build-angular" ">=0.1100.0 < 0.1200.0" - "@angular-devkit/core" "^11.0.0" +"@angular-builders/custom-webpack@~12.1.3": + version "12.1.3" + resolved "https://registry.yarnpkg.com/@angular-builders/custom-webpack/-/custom-webpack-12.1.3.tgz#3eda78f573dc6d8b5278bb2d0c20937a75dec0cc" + integrity sha512-CzOkwYnO2Xs+z4kMeJkUALeRjVE69SlrqbEsv2Tao5PsBmFCyT5EEVoSvwOuaxZmajuGaXtz7yBIeK2hYp25/A== + dependencies: + "@angular-devkit/architect" ">=0.1200.0 < 0.1300.0" + "@angular-devkit/build-angular" "^12.0.0" + "@angular-devkit/core" "^12.0.0" lodash "^4.17.15" - ts-node "^9.0.0" + ts-node "^10.0.0" tsconfig-paths "^3.9.0" webpack-merge "^5.7.3" -"@angular-devkit/architect@0.1102.13", "@angular-devkit/architect@>=0.1100.0 < 0.1200.0": - version "0.1102.13" - resolved "https://registry.yarnpkg.com/@angular-devkit/architect/-/architect-0.1102.13.tgz#0f6b9d38cb8cda928b24404278f227fe8f169fc1" - integrity sha512-v44YF54DQnxwggZKUVCB2WtgfqMW8VG5AtE+nO0RgEtgnOC3e4bB7dZ/n+2Am0LCauYx45ufQDlIespeX09XgA== - dependencies: - "@angular-devkit/core" "11.2.13" - rxjs "6.6.3" - -"@angular-devkit/architect@0.1202.13": +"@angular-devkit/architect@0.1202.13", "@angular-devkit/architect@>=0.1200.0 < 0.1300.0": version "0.1202.13" resolved "https://registry.yarnpkg.com/@angular-devkit/architect/-/architect-0.1202.13.tgz#b9b883d62f628a6b31ce071da91e268f61da00ef" integrity sha512-LXgiidXwBgyWPqqWK4xR1/kCPQTMTzG5w+s7+LvENUZwbcdl6CKrOMjfgjo6WPr6yeq+WWQvPCD4pZ6nXRTm7A== @@ -39,86 +31,7 @@ "@angular-devkit/core" "12.2.13" rxjs "6.6.7" -"@angular-devkit/build-angular@>=0.1100.0 < 0.1200.0": - version "0.1102.13" - resolved "https://registry.yarnpkg.com/@angular-devkit/build-angular/-/build-angular-0.1102.13.tgz#3d7bac8d471c6f2b7067236151cc5018b2ad1a51" - integrity sha512-1ezVautOtfl16pOT3p7Z9IPd7vSyy6lZ+HZWqMK1AmUjNhsEA2WeuC/XznGatC3K+9IcfV+eSm6cP0iuLyETzw== - dependencies: - "@angular-devkit/architect" "0.1102.13" - "@angular-devkit/build-optimizer" "0.1102.13" - "@angular-devkit/build-webpack" "0.1102.13" - "@angular-devkit/core" "11.2.13" - "@babel/core" "7.12.10" - "@babel/generator" "7.12.11" - "@babel/plugin-transform-async-to-generator" "7.12.1" - "@babel/plugin-transform-runtime" "7.12.10" - "@babel/preset-env" "7.12.11" - "@babel/runtime" "7.12.5" - "@babel/template" "7.12.7" - "@discoveryjs/json-ext" "0.5.2" - "@jsdevtools/coverage-istanbul-loader" "3.0.5" - "@ngtools/webpack" "11.2.13" - ansi-colors "4.1.1" - autoprefixer "10.2.4" - babel-loader "8.2.2" - browserslist "^4.9.1" - cacache "15.0.5" - caniuse-lite "^1.0.30001032" - circular-dependency-plugin "5.2.2" - copy-webpack-plugin "6.3.2" - core-js "3.8.3" - critters "0.0.7" - css-loader "5.0.1" - cssnano "5.0.2" - file-loader "6.2.0" - find-cache-dir "3.3.1" - glob "7.1.6" - https-proxy-agent "5.0.0" - inquirer "7.3.3" - jest-worker "26.6.2" - karma-source-map-support "1.4.0" - less "4.1.1" - less-loader "7.3.0" - license-webpack-plugin "2.3.11" - loader-utils "2.0.0" - mini-css-extract-plugin "1.3.5" - minimatch "3.0.4" - open "7.4.0" - ora "5.3.0" - parse5-html-rewriting-stream "6.0.1" - pnp-webpack-plugin "1.6.4" - postcss "8.2.14" - postcss-import "14.0.0" - postcss-loader "4.2.0" - raw-loader "4.0.2" - regenerator-runtime "0.13.7" - resolve-url-loader "4.0.0" - rimraf "3.0.2" - rollup "2.38.4" - rxjs "6.6.3" - sass "1.32.6" - sass-loader "10.1.1" - semver "7.3.4" - source-map "0.7.3" - source-map-loader "1.1.3" - source-map-support "0.5.19" - speed-measure-webpack-plugin "1.4.2" - style-loader "2.0.0" - stylus "0.54.8" - stylus-loader "4.3.3" - terser "5.5.1" - terser-webpack-plugin "4.2.3" - text-table "0.2.0" - tree-kill "1.2.2" - webpack "4.44.2" - webpack-dev-middleware "3.7.2" - webpack-dev-server "3.11.2" - webpack-merge "5.7.3" - webpack-sources "2.2.0" - webpack-subresource-integrity "1.5.2" - worker-plugin "5.0.0" - -"@angular-devkit/build-angular@^12.2.13": +"@angular-devkit/build-angular@^12.0.0", "@angular-devkit/build-angular@^12.2.13": version "12.2.13" resolved "https://registry.yarnpkg.com/@angular-devkit/build-angular/-/build-angular-12.2.13.tgz#f5564d3ec9db132956473bb904bb3590482f5b36" integrity sha512-iJ1P/RZ1hk2n/HtEqB5ohXvHa+Hf0BXShYskSGrn6/klcTb0eJTCREsFxHk7mNEmRIGPWkjbLAslqpPgwiagXg== @@ -195,17 +108,6 @@ optionalDependencies: esbuild "0.13.8" -"@angular-devkit/build-optimizer@0.1102.13": - version "0.1102.13" - resolved "https://registry.yarnpkg.com/@angular-devkit/build-optimizer/-/build-optimizer-0.1102.13.tgz#5c60fa88db41f22f296f1ee628f4c6abe90dac95" - integrity sha512-OvTsUVe5cC4oKym1pohVzkn50OLnjK/SuOnMgeWceMDkqmzJEdJqhG1SfnXv+MJiuUDlhyUVbbnFwkj5Y0fXYA== - dependencies: - loader-utils "2.0.0" - source-map "0.7.3" - tslib "2.1.0" - typescript "4.1.5" - webpack-sources "2.2.0" - "@angular-devkit/build-optimizer@0.1202.13": version "0.1202.13" resolved "https://registry.yarnpkg.com/@angular-devkit/build-optimizer/-/build-optimizer-0.1202.13.tgz#7f0b13368cc2a08b1f4789ab1296a1609f5049ea" @@ -215,15 +117,6 @@ tslib "2.3.0" typescript "4.3.5" -"@angular-devkit/build-webpack@0.1102.13": - version "0.1102.13" - resolved "https://registry.yarnpkg.com/@angular-devkit/build-webpack/-/build-webpack-0.1102.13.tgz#d7d552500713278cc3ed28c3cc669f31b4f285a6" - integrity sha512-5KMq7jUtk5GOuErR6psG8ypyfHL/sITfpgyRXcsqJEqLEbb5MPmaR9gBjz6TSQGUH2/jNiJjdd82h8ckWxfN8g== - dependencies: - "@angular-devkit/architect" "0.1102.13" - "@angular-devkit/core" "11.2.13" - rxjs "6.6.3" - "@angular-devkit/build-webpack@0.1202.13": version "0.1202.13" resolved "https://registry.yarnpkg.com/@angular-devkit/build-webpack/-/build-webpack-0.1202.13.tgz#875f9f9677bb10056b52230965dc2f00bd3089dd" @@ -232,18 +125,7 @@ "@angular-devkit/architect" "0.1202.13" rxjs "6.6.7" -"@angular-devkit/core@11.2.13", "@angular-devkit/core@^11.0.0": - version "11.2.13" - resolved "https://registry.yarnpkg.com/@angular-devkit/core/-/core-11.2.13.tgz#7829862132555a52009d0af9671b06ffdf9200f1" - integrity sha512-GL97DZXeQCecqZmaIeMfG/XtHv6e7FM+uygMePNF9yn4cml32bSp4P5oRjDMgj7iFl6GIU81n8TstTMmFbt85w== - dependencies: - ajv "6.12.6" - fast-json-stable-stringify "2.1.0" - magic-string "0.25.7" - rxjs "6.6.3" - source-map "0.7.3" - -"@angular-devkit/core@12.2.13": +"@angular-devkit/core@12.2.13", "@angular-devkit/core@^12.0.0": version "12.2.13" resolved "https://registry.yarnpkg.com/@angular-devkit/core/-/core-12.2.13.tgz#db3929d1bfce71010b37fb7c4e6c33ef80a4f35f" integrity sha512-9csMF0p+lTvlWnutxxTZ/+pDRMIbXk/TV4MGLbcqUPPfeG3dCRwErns73xLuMTwp9qO/KCLkFqNaM6cGOoqsDA== @@ -265,9 +147,9 @@ rxjs "6.6.7" "@angular/animations@^12.2.13": - version "12.2.13" - resolved "https://registry.yarnpkg.com/@angular/animations/-/animations-12.2.13.tgz#909b79c56a85bb31c0605ed419850340b5580be9" - integrity sha512-qpdmvu+nxsKnimJ3Hc1joNuzK7xXYyE+VtNMk4K77Ao/9+5C/juGMce85DhqZCcu1xraZ3YYIrzYmL/GgdUK4g== + version "12.2.14" + resolved "https://registry.yarnpkg.com/@angular/animations/-/animations-12.2.14.tgz#5b74f17f5d58993d92511749fa5ceaf2de6c1495" + integrity sha512-1BR5u32auVePvXNNP96DB2008V+Ku0OGqeZQl2h4XA9xzES/Zk5WllIJZXqRmWMRBVARfXsfb0RdMty9gcaVjA== dependencies: tslib "^2.2.0" @@ -306,16 +188,16 @@ uuid "8.3.2" "@angular/common@^12.2.13": - version "12.2.13" - resolved "https://registry.yarnpkg.com/@angular/common/-/common-12.2.13.tgz#fe52ffae8668c1dec41b26cdc3a749101399e1fe" - integrity sha512-I1t/jl9ojCwTJKT7PKHnk23D+vMHTHS/9qZ2nndCjzGusMK8029nn8l3tHAkwefvxZWSaLAk1MgsVcP+rHQNsQ== + version "12.2.14" + resolved "https://registry.yarnpkg.com/@angular/common/-/common-12.2.14.tgz#0cd0d75be8052e8be76966e494f245dc595afe10" + integrity sha512-ffYUYdwZETmFJw0AcWY30WsaWBhJxj/zSmFXWjgEGEGZH56zwbbNwfMZOYZ1jz4haAVxGu+TdXsOl2yMGzN7jQ== dependencies: tslib "^2.2.0" "@angular/compiler-cli@^12.2.13": - version "12.2.13" - resolved "https://registry.yarnpkg.com/@angular/compiler-cli/-/compiler-cli-12.2.13.tgz#3ce463263e80a861e14af2ed3ba81598060e3ce0" - integrity sha512-qmnmihl3SCRooj/mCsNIZLtnQ6qbx1/L6aMIEQosPvQhMeGMt8GCYvQPE8IZ+sahv7fih95HCWNa9TeLpOylug== + version "12.2.14" + resolved "https://registry.yarnpkg.com/@angular/compiler-cli/-/compiler-cli-12.2.14.tgz#fdaca73c6941b1231196d980ac8ef02c07ccf36d" + integrity sha512-EktEOF2xnuMsUyanXjZw3hyn7w97NX9h8LJ3O9l27secbjYXhyrao5bmrMILdDTEJNeZSC/OuCga1pvdaJTYmg== dependencies: "@babel/core" "^7.8.6" "@babel/types" "^7.8.6" @@ -338,9 +220,9 @@ integrity sha512-ctjwuntPfZZT2mNj2NDIVu51t9cvbhl/16epc5xEwyzyDt76pX9UgwvY+MbXrf/C/FWwdtmNtfP698BKI+9leQ== "@angular/compiler@^12.2.13": - version "12.2.13" - resolved "https://registry.yarnpkg.com/@angular/compiler/-/compiler-12.2.13.tgz#7eef6fdb81b9de6fd0e2cdda2ad8a084c1d9535b" - integrity sha512-L0saTTJJtxldjhaGIL6b1BCfodPOEz4Wrev3pEUK5UcODooj5HLiE/aO6jiNb8M4XTbdqByKyqvZyWzGHeexVQ== + version "12.2.14" + resolved "https://registry.yarnpkg.com/@angular/compiler/-/compiler-12.2.14.tgz#360940f5e505a00892b46dd28ca69b9a37bdf6af" + integrity sha512-dwmZi+n66IUzRFlGWu9mjXq170ZEsaDvlNLZzaPgs6vZTa4Kt7PWvIF/Y7TMvnVv/uqNG6kOhfmOkf6rfz1Gjg== dependencies: tslib "^2.2.0" @@ -350,9 +232,9 @@ integrity sha512-6Pxgsrf0qF9iFFqmIcWmjJGkkCaCm6V5QNnxMy2KloO3SDq6QuMVRbN9RtC8Urmo25LP+eZ6ZgYqFYpdD8Hd9w== "@angular/core@^12.2.13": - version "12.2.13" - resolved "https://registry.yarnpkg.com/@angular/core/-/core-12.2.13.tgz#fc40acbdcee5c5878bd249ddc0d643be724076c3" - integrity sha512-tZ5nAnmOi418JDaJIFiiP9z2JrluMJZvUvXO4QDUs52BXaL2yuP7MJ2LczWOVJXrBLZXeZGfjDjZmaFPA24grg== + version "12.2.14" + resolved "https://registry.yarnpkg.com/@angular/core/-/core-12.2.14.tgz#6ae14e63a88c534cd48d03184cbb084ec031bad1" + integrity sha512-dlVk7yqUHL2R/eCmM8LsWuxhEBfzg0y1zHt0UqCuFwlCoiw+IG4HFy4OlZEUw9NUEZJSv0aDv3sWqxLkvK5vvg== dependencies: tslib "^2.2.0" @@ -364,16 +246,16 @@ tslib "^2.1.0" "@angular/forms@^12.2.13": - version "12.2.13" - resolved "https://registry.yarnpkg.com/@angular/forms/-/forms-12.2.13.tgz#4de90e88991c274b5d5e3ab0300267e161ba78f2" - integrity sha512-wa7I5R8sck2q+VWNL262GJTVxtpEHMys8Bt6oE+lyHB5zlZAgOXwAb8GE4XVwuc+BZU1Gvrocn21P/8KvDY1uw== + version "12.2.14" + resolved "https://registry.yarnpkg.com/@angular/forms/-/forms-12.2.14.tgz#cb88c1c1432e3fc75d6832dfa4e97c9667396586" + integrity sha512-/9/gSJUBXVRVdRnzgJnALAQZYJATuGDMkFC9ms9DEMG4PMAhe9x4if1lJjN6noz5RAom3qNuVBNWaYAPUxlcBQ== dependencies: tslib "^2.2.0" "@angular/language-service@^12.2.13": - version "12.2.13" - resolved "https://registry.yarnpkg.com/@angular/language-service/-/language-service-12.2.13.tgz#326045a328f8a962287037d7a85be8120074421c" - integrity sha512-jb9s3IJuWNKTRcM90NOwvMfiy85nnKfTxxLVn8/QFMO6+Ps/hsVZNp+W/TmAEDvCkon+9q0O4hwa4MY1m/Dlkw== + version "12.2.14" + resolved "https://registry.yarnpkg.com/@angular/language-service/-/language-service-12.2.14.tgz#4f0afc2fe7fed6838c640a0da8658767c8372e1d" + integrity sha512-DSEhiBM077z7Gx99KQOQmtJSIdLT39GAAJ30nHO3IuBT7n5Wi+K6b/eO3mOvXrzcQ8K5WFxJboJ2GJRlPXzlwQ== "@angular/material@^12.2.13": version "12.2.13" @@ -383,31 +265,26 @@ tslib "^2.2.0" "@angular/platform-browser-dynamic@^12.2.13": - version "12.2.13" - resolved "https://registry.yarnpkg.com/@angular/platform-browser-dynamic/-/platform-browser-dynamic-12.2.13.tgz#9ee6309f511da419d5d80a1a8279adc806e92f04" - integrity sha512-a7y7R3vOXhMAk9uQWK5/23DefahuF0UYJSFM/wKeVo5zR+qOCVCTfafkJMcWbuZWTrSDbVafJ1xbcWnu3+TkCg== + version "12.2.14" + resolved "https://registry.yarnpkg.com/@angular/platform-browser-dynamic/-/platform-browser-dynamic-12.2.14.tgz#202fd89ba7f758ca998ee5b6498d4a834472f664" + integrity sha512-0NPF7mS91Tct8rBmOLZPmnLSuS4kbLHXo6eTgrg80OC0vlzBiQwGDVW4X3KncCoX9CpevaGJCdSMc+uPNsFOUQ== dependencies: tslib "^2.2.0" "@angular/platform-browser@^12.2.13": - version "12.2.13" - resolved "https://registry.yarnpkg.com/@angular/platform-browser/-/platform-browser-12.2.13.tgz#769fb148b2128663d6b405d2a41023f2cdaa1c95" - integrity sha512-Ua8m2GtG2msqz/Mr/MK7s8RXud554x8cup2THVAwetyTaY5th/1LOZX0hhDIhfsxBCLHnC53LRhMbSsI0cikOg== + version "12.2.14" + resolved "https://registry.yarnpkg.com/@angular/platform-browser/-/platform-browser-12.2.14.tgz#2c00d5f341827dc1de4ade98abcf329f0824790c" + integrity sha512-fWcE2rnJ3ZCISa1oPfsIDV7FBZBoLFEdDuMXAiDYqDPKvF/E5U5nHrS+K4SlLAi094bMobtTOReNWl/Ienniyw== dependencies: tslib "^2.2.0" "@angular/router@^12.2.13": - version "12.2.13" - resolved "https://registry.yarnpkg.com/@angular/router/-/router-12.2.13.tgz#e5b939a9675f9d4834fee3e75eb8d040ef63b3b5" - integrity sha512-HZL/Pzp6I7fQiMLrzfEzhnqhgNcGcFjBgMMOoLp5IA1IV26rp1NU6zYJzPrXtopBx7XLl8BECehAwFqrJsu/PQ== + version "12.2.14" + resolved "https://registry.yarnpkg.com/@angular/router/-/router-12.2.14.tgz#93f965d2e50bb4ecf5a17ff5217cef266fb67c06" + integrity sha512-yP5grSnqBvc4vNhtYdcxDgDYIebUKs5f0xyFkUJM5030UnQ0CV45tBsSxHMkQbPZucIfOuxpRy8xy5+4GizuwQ== dependencies: tslib "^2.2.0" -"@ant-design/css-animation@^1.7.2": - version "1.7.3" - resolved "https://registry.yarnpkg.com/@ant-design/css-animation/-/css-animation-1.7.3.tgz#60a1c970014e86b28f940510d69e503e428f1136" - integrity sha512-LrX0OGZtW+W6iLnTAqnTaoIsRelYeuLZWsrmBJFUXDALQphPsN8cE5DCsmoSlL0QYb94BQxINiuS70Ar/8BNgA== - "@assemblyscript/loader@^0.10.1": version "0.10.1" resolved "https://registry.yarnpkg.com/@assemblyscript/loader/-/loader-0.10.1.tgz#70e45678f06c72fa2e350e8553ec4a4d72b92e06" @@ -420,58 +297,18 @@ dependencies: tslib "^2.0.0" -"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.10.4.tgz#168da1a36e90da68ae8d49c0f1b48c7c6249213a" - integrity sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg== - dependencies: - "@babel/highlight" "^7.10.4" - -"@babel/code-frame@^7.12.13": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.12.13.tgz#dcfc826beef65e75c50e21d3837d7d95798dd658" - integrity sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g== - dependencies: - "@babel/highlight" "^7.12.13" - -"@babel/code-frame@^7.14.5", "@babel/code-frame@^7.16.0": +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.14.5", "@babel/code-frame@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.16.0.tgz#0dfc80309beec8411e65e706461c408b0bb9b431" integrity sha512-IF4EOMEV+bfYwOmNxGzSnjR2EmQod7f1UXOpZM3l4i4o4QNwzjtJAu/HxdjHq0aYBvdqMuQEY1eg0nqW9ZPORA== dependencies: "@babel/highlight" "^7.16.0" -"@babel/compat-data@^7.12.7", "@babel/compat-data@^7.13.15", "@babel/compat-data@^7.14.0": - version "7.14.0" - resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.14.0.tgz#a901128bce2ad02565df95e6ecbf195cf9465919" - integrity sha512-vu9V3uMM/1o5Hl5OekMUowo3FqXLJSw+s+66nt0fSWVWTtmosdzn45JHOB3cPtZoe6CTBDzvSw0RdOY85Q37+Q== - "@babel/compat-data@^7.13.11", "@babel/compat-data@^7.14.7", "@babel/compat-data@^7.16.0": version "7.16.4" resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.16.4.tgz#081d6bbc336ec5c2435c6346b2ae1fb98b5ac68e" integrity sha512-1o/jo7D+kC9ZjHX5v+EHrdjl3PhxMrLSOTGsOdHJ+KL8HCaEK6ehrVL2RS6oHDZp+L7xLirLrPmQtEng769J/Q== -"@babel/core@7.12.10": - version "7.12.10" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.12.10.tgz#b79a2e1b9f70ed3d84bbfb6d8c4ef825f606bccd" - integrity sha512-eTAlQKq65zHfkHZV0sIVODCPGVgoo1HdBlbSLi9CqOzuZanMv2ihzY+4paiKr1mH+XmYESMAmJ/dpZ68eN6d8w== - dependencies: - "@babel/code-frame" "^7.10.4" - "@babel/generator" "^7.12.10" - "@babel/helper-module-transforms" "^7.12.1" - "@babel/helpers" "^7.12.5" - "@babel/parser" "^7.12.10" - "@babel/template" "^7.12.7" - "@babel/traverse" "^7.12.10" - "@babel/types" "^7.12.10" - convert-source-map "^1.7.0" - debug "^4.1.0" - gensync "^1.0.0-beta.1" - json5 "^2.1.2" - lodash "^4.17.19" - semver "^5.4.1" - source-map "^0.5.0" - "@babel/core@7.14.8": version "7.14.8" resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.14.8.tgz#20cdf7c84b5d86d83fac8710a8bc605a7ba3f010" @@ -493,42 +330,20 @@ semver "^6.3.0" source-map "^0.5.0" -"@babel/core@^7.7.5": - version "7.11.6" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.11.6.tgz#3a9455dc7387ff1bac45770650bc13ba04a15651" - integrity sha512-Wpcv03AGnmkgm6uS6k8iwhIwTrcP0m17TL1n1sy7qD0qelDu4XNeW0dN0mHfa+Gei211yDaLoEe/VlbXQzM4Bg== - dependencies: - "@babel/code-frame" "^7.10.4" - "@babel/generator" "^7.11.6" - "@babel/helper-module-transforms" "^7.11.0" - "@babel/helpers" "^7.10.4" - "@babel/parser" "^7.11.5" - "@babel/template" "^7.10.4" - "@babel/traverse" "^7.11.5" - "@babel/types" "^7.11.5" - convert-source-map "^1.7.0" - debug "^4.1.0" - gensync "^1.0.0-beta.1" - json5 "^2.1.2" - lodash "^4.17.19" - resolve "^1.3.2" - semver "^5.4.1" - source-map "^0.5.0" - -"@babel/core@^7.8.6": - version "7.14.3" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.14.3.tgz#5395e30405f0776067fbd9cf0884f15bfb770a38" - integrity sha512-jB5AmTKOCSJIZ72sd78ECEhuPiDMKlQdDI/4QRI6lzYATx5SSogS1oQA2AoPecRCknm30gHi2l+QVvNUu3wZAg== - dependencies: - "@babel/code-frame" "^7.12.13" - "@babel/generator" "^7.14.3" - "@babel/helper-compilation-targets" "^7.13.16" - "@babel/helper-module-transforms" "^7.14.2" - "@babel/helpers" "^7.14.0" - "@babel/parser" "^7.14.3" - "@babel/template" "^7.12.13" - "@babel/traverse" "^7.14.2" - "@babel/types" "^7.14.2" +"@babel/core@^7.7.5", "@babel/core@^7.8.6": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.16.0.tgz#c4ff44046f5fe310525cc9eb4ef5147f0c5374d4" + integrity sha512-mYZEvshBRHGsIAiyH5PzCFTCfbWfoYbO/jcSdXQSUQu1/pW0xDZAUP7KEc32heqWTAfAHhV9j1vH8Sav7l+JNQ== + dependencies: + "@babel/code-frame" "^7.16.0" + "@babel/generator" "^7.16.0" + "@babel/helper-compilation-targets" "^7.16.0" + "@babel/helper-module-transforms" "^7.16.0" + "@babel/helpers" "^7.16.0" + "@babel/parser" "^7.16.0" + "@babel/template" "^7.16.0" + "@babel/traverse" "^7.16.0" + "@babel/types" "^7.16.0" convert-source-map "^1.7.0" debug "^4.1.0" gensync "^1.0.0-beta.2" @@ -536,15 +351,6 @@ semver "^6.3.0" source-map "^0.5.0" -"@babel/generator@7.12.11": - version "7.12.11" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.12.11.tgz#98a7df7b8c358c9a37ab07a24056853016aba3af" - integrity sha512-Ggg6WPOJtSi8yYQvLVjG8F/TlpWDlKx0OpS4Kt+xMQPs5OaGYWy+v1A+1TvxI6sAMGZpKWWoAQ1DaeQbImlItA== - dependencies: - "@babel/types" "^7.12.11" - jsesc "^2.5.1" - source-map "^0.5.0" - "@babel/generator@7.14.8": version "7.14.8" resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.14.8.tgz#bf86fd6af96cf3b74395a8ca409515f89423e070" @@ -554,24 +360,6 @@ jsesc "^2.5.1" source-map "^0.5.0" -"@babel/generator@^7.11.5", "@babel/generator@^7.11.6": - version "7.11.6" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.11.6.tgz#b868900f81b163b4d464ea24545c61cbac4dc620" - integrity sha512-DWtQ1PV3r+cLbySoHrwn9RWEgKMBLLma4OBQloPRyDYvc5msJM9kvTLo1YnlJd1P/ZuKbdli3ijr5q3FvAF3uA== - dependencies: - "@babel/types" "^7.11.5" - jsesc "^2.5.1" - source-map "^0.5.0" - -"@babel/generator@^7.12.10", "@babel/generator@^7.14.2", "@babel/generator@^7.14.3": - version "7.14.3" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.14.3.tgz#0c2652d91f7bddab7cccc6ba8157e4f40dcedb91" - integrity sha512-bn0S6flG/j0xtQdz3hsjJ624h3W0r3llttBMfyHX3YrZ/KtLYr15bjA0FXkgW7FpvrDuTuElXeVjiKlYRpnOFA== - dependencies: - "@babel/types" "^7.14.2" - jsesc "^2.5.1" - source-map "^0.5.0" - "@babel/generator@^7.14.8", "@babel/generator@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.16.0.tgz#d40f3d1d5075e62d3500bccb67f3daa8a95265b2" @@ -588,20 +376,6 @@ dependencies: "@babel/types" "^7.14.5" -"@babel/helper-annotate-as-pure@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.10.4.tgz#5bf0d495a3f757ac3bda48b5bf3b3ba309c72ba3" - integrity sha512-XQlqKQP4vXFB7BN8fEEerrmYvHp3fK/rBkRFz9jaJbzK0B1DSfej9Kc7ZzE8Z/OnId1jpJdNAZ3BFQjWG68rcA== - dependencies: - "@babel/types" "^7.10.4" - -"@babel/helper-annotate-as-pure@^7.12.13": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.12.13.tgz#0f58e86dfc4bb3b1fcd7db806570e177d439b6ab" - integrity sha512-7YXfX5wQ5aYM/BOlbSccHDbuXXFPxeoUmfWtz8le2yTkTZc+BxsiEnENFoi2SlmA8ewDkG2LgIMIVzzn2h8kfw== - dependencies: - "@babel/types" "^7.12.13" - "@babel/helper-annotate-as-pure@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.16.0.tgz#9a1f0ebcda53d9a2d00108c4ceace6a5d5f1f08d" @@ -609,14 +383,6 @@ dependencies: "@babel/types" "^7.16.0" -"@babel/helper-builder-binary-assignment-operator-visitor@^7.12.13": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.12.13.tgz#6bc20361c88b0a74d05137a65cac8d3cbf6f61fc" - integrity sha512-CZOv9tGphhDRlVjVkAgm8Nhklm9RzSmWpX2my+t7Ua/KT616pEzXsQCjinzvkRvHWJ9itO4f296efroX23XCMA== - dependencies: - "@babel/helper-explode-assignable-expression" "^7.12.13" - "@babel/types" "^7.12.13" - "@babel/helper-builder-binary-assignment-operator-visitor@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.16.0.tgz#f1a686b92da794020c26582eb852e9accd0d7882" @@ -625,16 +391,6 @@ "@babel/helper-explode-assignable-expression" "^7.16.0" "@babel/types" "^7.16.0" -"@babel/helper-compilation-targets@^7.12.5", "@babel/helper-compilation-targets@^7.13.16": - version "7.13.16" - resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.13.16.tgz#6e91dccf15e3f43e5556dffe32d860109887563c" - integrity sha512-3gmkYIrpqsLlieFwjkGgLaSHmhnvlAYzZLlYVjlW+QwI+1zE17kGxuJGmIqDQdYp56XdmGeD+Bswx0UTyG18xA== - dependencies: - "@babel/compat-data" "^7.13.15" - "@babel/helper-validator-option" "^7.12.17" - browserslist "^4.14.5" - semver "^6.3.0" - "@babel/helper-compilation-targets@^7.13.0", "@babel/helper-compilation-targets@^7.14.5", "@babel/helper-compilation-targets@^7.16.0": version "7.16.3" resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.16.3.tgz#5b480cd13f68363df6ec4dc8ac8e2da11363cbf0" @@ -645,18 +401,6 @@ browserslist "^4.17.5" semver "^6.3.0" -"@babel/helper-create-class-features-plugin@^7.13.0": - version "7.14.3" - resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.14.3.tgz#832111bcf4f57ca57a4c5b1a000fc125abc6554a" - integrity sha512-BnEfi5+6J2Lte9LeiL6TxLWdIlEv9Woacc1qXzXBgbikcOzMRM2Oya5XGg/f/ngotv1ej2A/b+3iJH8wbS1+lQ== - dependencies: - "@babel/helper-annotate-as-pure" "^7.12.13" - "@babel/helper-function-name" "^7.14.2" - "@babel/helper-member-expression-to-functions" "^7.13.12" - "@babel/helper-optimise-call-expression" "^7.12.13" - "@babel/helper-replace-supers" "^7.14.3" - "@babel/helper-split-export-declaration" "^7.12.13" - "@babel/helper-create-class-features-plugin@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.16.0.tgz#090d4d166b342a03a9fec37ef4fd5aeb9c7c6a4b" @@ -669,23 +413,6 @@ "@babel/helper-replace-supers" "^7.16.0" "@babel/helper-split-export-declaration" "^7.16.0" -"@babel/helper-create-regexp-features-plugin@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.10.4.tgz#fdd60d88524659a0b6959c0579925e425714f3b8" - integrity sha512-2/hu58IEPKeoLF45DBwx3XFqsbCXmkdAay4spVr2x0jYgRxrSNp+ePwvSsy9g6YSaNDcKIQVPXk1Ov8S2edk2g== - dependencies: - "@babel/helper-annotate-as-pure" "^7.10.4" - "@babel/helper-regex" "^7.10.4" - regexpu-core "^4.7.0" - -"@babel/helper-create-regexp-features-plugin@^7.12.13": - version "7.14.3" - resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.14.3.tgz#149aa6d78c016e318c43e2409a0ae9c136a86688" - integrity sha512-JIB2+XJrb7v3zceV2XzDhGIB902CmKGSpSl4q2C6agU9SNLG/2V1RtFRGPG1Ajh9STj3+q6zJMOC+N/pp2P9DA== - dependencies: - "@babel/helper-annotate-as-pure" "^7.12.13" - regexpu-core "^4.7.1" - "@babel/helper-create-regexp-features-plugin@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.16.0.tgz#06b2348ce37fccc4f5e18dcd8d75053f2a7c44ff" @@ -708,13 +435,6 @@ resolve "^1.14.2" semver "^6.1.2" -"@babel/helper-explode-assignable-expression@^7.12.13": - version "7.13.0" - resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.13.0.tgz#17b5c59ff473d9f956f40ef570cf3a76ca12657f" - integrity sha512-qS0peLTDP8kOisG1blKbaoBg/o9OSa1qoumMjTK5pM+KDTtpxpsiubnCGP34vK8BXGcb2M9eigwgvoJryrzwWA== - dependencies: - "@babel/types" "^7.13.0" - "@babel/helper-explode-assignable-expression@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.16.0.tgz#753017337a15f46f9c09f674cff10cee9b9d7778" @@ -722,24 +442,6 @@ dependencies: "@babel/types" "^7.16.0" -"@babel/helper-function-name@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.10.4.tgz#d2d3b20c59ad8c47112fa7d2a94bc09d5ef82f1a" - integrity sha512-YdaSyz1n8gY44EmN7x44zBn9zQ1Ry2Y+3GTA+3vH6Mizke1Vw0aWDM66FOYEPw8//qKkmqOckrGgTYa+6sceqQ== - dependencies: - "@babel/helper-get-function-arity" "^7.10.4" - "@babel/template" "^7.10.4" - "@babel/types" "^7.10.4" - -"@babel/helper-function-name@^7.12.13", "@babel/helper-function-name@^7.14.2": - version "7.14.2" - resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.14.2.tgz#397688b590760b6ef7725b5f0860c82427ebaac2" - integrity sha512-NYZlkZRydxw+YT56IlhIcS8PAhb+FEUiOzuhFTfqDyPmzAhRge6ua0dQYT/Uh0t/EDHq05/i+e5M2d4XvjgarQ== - dependencies: - "@babel/helper-get-function-arity" "^7.12.13" - "@babel/template" "^7.12.13" - "@babel/types" "^7.14.2" - "@babel/helper-function-name@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.16.0.tgz#b7dd0797d00bbfee4f07e9c4ea5b0e30c8bb1481" @@ -749,20 +451,6 @@ "@babel/template" "^7.16.0" "@babel/types" "^7.16.0" -"@babel/helper-get-function-arity@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.10.4.tgz#98c1cbea0e2332f33f9a4661b8ce1505b2c19ba2" - integrity sha512-EkN3YDB+SRDgiIUnNgcmiD361ti+AVbL3f3Henf6dqqUyr5dMsorno0lJWJuLhDhkI5sYEpgj6y9kB8AOU1I2A== - dependencies: - "@babel/types" "^7.10.4" - -"@babel/helper-get-function-arity@^7.12.13": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.12.13.tgz#bc63451d403a3b3082b97e1d8b3fe5bd4091e583" - integrity sha512-DjEVzQNz5LICkzN0REdpD5prGoidvbdYk1BVgRUOINaWJP2t6avB27X1guXK1kXNrX0WMfsrm1A/ZBthYuIMQg== - dependencies: - "@babel/types" "^7.12.13" - "@babel/helper-get-function-arity@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.0.tgz#0088c7486b29a9cb5d948b1a1de46db66e089cfa" @@ -770,14 +458,6 @@ dependencies: "@babel/types" "^7.16.0" -"@babel/helper-hoist-variables@^7.13.0": - version "7.13.16" - resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.13.16.tgz#1b1651249e94b51f8f0d33439843e33e39775b30" - integrity sha512-1eMtTrXtrwscjcAeO4BVK+vvkxaLJSPFz1w1KLawz6HLNi9bPFGBNwwDyVfiu1Tv/vRRFYfoGaKhmAQPGPn5Wg== - dependencies: - "@babel/traverse" "^7.13.15" - "@babel/types" "^7.13.16" - "@babel/helper-hoist-variables@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.0.tgz#4c9023c2f1def7e28ff46fc1dbcd36a39beaa81a" @@ -785,20 +465,6 @@ dependencies: "@babel/types" "^7.16.0" -"@babel/helper-member-expression-to-functions@^7.10.4": - version "7.11.0" - resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.11.0.tgz#ae69c83d84ee82f4b42f96e2a09410935a8f26df" - integrity sha512-JbFlKHFntRV5qKw3YC0CvQnDZ4XMwgzzBbld7Ly4Mj4cbFy3KywcR8NtNctRToMWJOVvLINJv525Gd6wwVEx/Q== - dependencies: - "@babel/types" "^7.11.0" - -"@babel/helper-member-expression-to-functions@^7.13.12": - version "7.13.12" - resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.13.12.tgz#dfe368f26d426a07299d8d6513821768216e6d72" - integrity sha512-48ql1CLL59aKbU94Y88Xgb2VFy7a95ykGRbJJaaVv+LX5U8wFpLfiGXJJGUozsmA1oEh/o5Bp60Voq7ACyA/Sw== - dependencies: - "@babel/types" "^7.13.12" - "@babel/helper-member-expression-to-functions@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.16.0.tgz#29287040efd197c77636ef75188e81da8bccd5a4" @@ -806,54 +472,13 @@ dependencies: "@babel/types" "^7.16.0" -"@babel/helper-module-imports@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.10.4.tgz#4c5c54be04bd31670a7382797d75b9fa2e5b5620" - integrity sha512-nEQJHqYavI217oD9+s5MUBzk6x1IlvoS9WTPfgG43CbMEeStE0v+r+TucWdx8KFGowPGvyOkDT9+7DHedIDnVw== - dependencies: - "@babel/types" "^7.10.4" - -"@babel/helper-module-imports@^7.12.1", "@babel/helper-module-imports@^7.12.13", "@babel/helper-module-imports@^7.12.5", "@babel/helper-module-imports@^7.13.12": - version "7.13.12" - resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.13.12.tgz#c6a369a6f3621cb25da014078684da9196b61977" - integrity sha512-4cVvR2/1B693IuOvSI20xqqa/+bl7lqAMR59R4iu39R9aOX8/JoYY1sFaNvUMyMBGnHdwvJgUrzNLoUZxXypxA== - dependencies: - "@babel/types" "^7.13.12" - -"@babel/helper-module-imports@^7.14.5", "@babel/helper-module-imports@^7.16.0": +"@babel/helper-module-imports@^7.12.13", "@babel/helper-module-imports@^7.14.5", "@babel/helper-module-imports@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.16.0.tgz#90538e60b672ecf1b448f5f4f5433d37e79a3ec3" integrity sha512-kkH7sWzKPq0xt3H1n+ghb4xEMP8k0U7XV3kkB+ZGy69kDk2ySFW1qPi06sjKzFY3t1j6XbJSqr4mF9L7CYVyhg== dependencies: "@babel/types" "^7.16.0" -"@babel/helper-module-transforms@^7.11.0": - version "7.11.0" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.11.0.tgz#b16f250229e47211abdd84b34b64737c2ab2d359" - integrity sha512-02EVu8COMuTRO1TAzdMtpBPbe6aQ1w/8fePD2YgQmxZU4gpNWaL9gK3Jp7dxlkUlUCJOTaSeA+Hrm1BRQwqIhg== - dependencies: - "@babel/helper-module-imports" "^7.10.4" - "@babel/helper-replace-supers" "^7.10.4" - "@babel/helper-simple-access" "^7.10.4" - "@babel/helper-split-export-declaration" "^7.11.0" - "@babel/template" "^7.10.4" - "@babel/types" "^7.11.0" - lodash "^4.17.19" - -"@babel/helper-module-transforms@^7.12.1", "@babel/helper-module-transforms@^7.13.0", "@babel/helper-module-transforms@^7.14.0", "@babel/helper-module-transforms@^7.14.2": - version "7.14.2" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.14.2.tgz#ac1cc30ee47b945e3e0c4db12fa0c5389509dfe5" - integrity sha512-OznJUda/soKXv0XhpvzGWDnml4Qnwp16GN+D/kZIdLsWoHj05kyu8Rm5kXmMef+rVJZ0+4pSGLkeixdqNUATDA== - dependencies: - "@babel/helper-module-imports" "^7.13.12" - "@babel/helper-replace-supers" "^7.13.12" - "@babel/helper-simple-access" "^7.13.12" - "@babel/helper-split-export-declaration" "^7.12.13" - "@babel/helper-validator-identifier" "^7.14.0" - "@babel/template" "^7.12.13" - "@babel/traverse" "^7.14.2" - "@babel/types" "^7.14.2" - "@babel/helper-module-transforms@^7.14.8", "@babel/helper-module-transforms@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.16.0.tgz#1c82a8dd4cb34577502ebd2909699b194c3e9bb5" @@ -868,20 +493,6 @@ "@babel/traverse" "^7.16.0" "@babel/types" "^7.16.0" -"@babel/helper-optimise-call-expression@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.10.4.tgz#50dc96413d594f995a77905905b05893cd779673" - integrity sha512-n3UGKY4VXwXThEiKrgRAoVPBMqeoPgHVqiHZOanAJCG9nQUL2pLRQirUzl0ioKclHGpGqRgIOkgcIJaIWLpygg== - dependencies: - "@babel/types" "^7.10.4" - -"@babel/helper-optimise-call-expression@^7.12.13": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.12.13.tgz#5c02d171b4c8615b1e7163f888c1c81c30a2aaea" - integrity sha512-BdWQhoVJkp6nVjB7nkFWcn43dkprYauqtk++Py2eaf/GRDFm5BxRqEIZCiHlZUGAVmtwKcsVL1dC68WmzeFmiA== - dependencies: - "@babel/types" "^7.12.13" - "@babel/helper-optimise-call-expression@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.16.0.tgz#cecdb145d70c54096b1564f8e9f10cd7d193b338" @@ -889,37 +500,11 @@ dependencies: "@babel/types" "^7.16.0" -"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz#2f75a831269d4f677de49986dff59927533cf375" - integrity sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg== - -"@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.13.0": - version "7.13.0" - resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz#806526ce125aed03373bc416a828321e3a6a33af" - integrity sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ== - -"@babel/helper-plugin-utils@^7.14.5": +"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.13.0", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3": version "7.14.5" resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.14.5.tgz#5ac822ce97eec46741ab70a517971e443a70c5a9" integrity sha512-/37qQCE3K0vvZKwoK4XU/irIJQdIfCJuhU5eKnNxpFDsOkgFaUAwbv+RYw6eYgsC0E4hS7r5KqGULUogqui0fQ== -"@babel/helper-regex@^7.10.4": - version "7.10.5" - resolved "https://registry.yarnpkg.com/@babel/helper-regex/-/helper-regex-7.10.5.tgz#32dfbb79899073c415557053a19bd055aae50ae0" - integrity sha512-68kdUAzDrljqBrio7DYAEgCoJHxppJOERHOgOrDN7WjOzP0ZQ1LsSDRXcemzVZaLvjaJsJEESb6qt+znNuENDg== - dependencies: - lodash "^4.17.19" - -"@babel/helper-remap-async-to-generator@^7.12.1", "@babel/helper-remap-async-to-generator@^7.13.0": - version "7.13.0" - resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.13.0.tgz#376a760d9f7b4b2077a9dd05aa9c3927cadb2209" - integrity sha512-pUQpFBE9JvC9lrQbpX0TmeNIy5s7GnZjna2lhhcHC7DzgBs6fWn722Y5cfwgrtrqc7NAJwMvOa0mKhq6XaE4jg== - dependencies: - "@babel/helper-annotate-as-pure" "^7.12.13" - "@babel/helper-wrap-function" "^7.13.0" - "@babel/types" "^7.13.0" - "@babel/helper-remap-async-to-generator@^7.14.5", "@babel/helper-remap-async-to-generator@^7.16.0", "@babel/helper-remap-async-to-generator@^7.16.4": version "7.16.4" resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.16.4.tgz#5d7902f61349ff6b963e07f06a389ce139fbfe6e" @@ -929,26 +514,6 @@ "@babel/helper-wrap-function" "^7.16.0" "@babel/types" "^7.16.0" -"@babel/helper-replace-supers@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.10.4.tgz#d585cd9388ea06e6031e4cd44b6713cbead9e6cf" - integrity sha512-sPxZfFXocEymYTdVK1UNmFPBN+Hv5mJkLPsYWwGBxZAxaWfFu+xqp7b6qWD0yjNuNL2VKc6L5M18tOXUP7NU0A== - dependencies: - "@babel/helper-member-expression-to-functions" "^7.10.4" - "@babel/helper-optimise-call-expression" "^7.10.4" - "@babel/traverse" "^7.10.4" - "@babel/types" "^7.10.4" - -"@babel/helper-replace-supers@^7.12.13", "@babel/helper-replace-supers@^7.13.12", "@babel/helper-replace-supers@^7.14.3": - version "7.14.3" - resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.14.3.tgz#ca17b318b859d107f0e9b722d58cf12d94436600" - integrity sha512-Rlh8qEWZSTfdz+tgNV/N4gz1a0TMNwCUcENhMjHTHKp3LseYH5Jha0NSlyTQWMnjbYcwFt+bqAMqSLHVXkQ6UA== - dependencies: - "@babel/helper-member-expression-to-functions" "^7.13.12" - "@babel/helper-optimise-call-expression" "^7.12.13" - "@babel/traverse" "^7.14.2" - "@babel/types" "^7.14.2" - "@babel/helper-replace-supers@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.16.0.tgz#73055e8d3cf9bcba8ddb55cad93fedc860f68f17" @@ -959,21 +524,6 @@ "@babel/traverse" "^7.16.0" "@babel/types" "^7.16.0" -"@babel/helper-simple-access@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.10.4.tgz#0f5ccda2945277a2a7a2d3a821e15395edcf3461" - integrity sha512-0fMy72ej/VEvF8ULmX6yb5MtHG4uH4Dbd6I/aHDb/JVg0bbivwt9Wg+h3uMvX+QSFtwr5MeItvazbrc4jtRAXw== - dependencies: - "@babel/template" "^7.10.4" - "@babel/types" "^7.10.4" - -"@babel/helper-simple-access@^7.13.12": - version "7.13.12" - resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.13.12.tgz#dd6c538afb61819d205a012c31792a39c7a5eaf6" - integrity sha512-7FEjbrx5SL9cWvXioDbnlYTppcZGuCY6ow3/D5vMggb2Ywgu4dMrpTJX0JdQAIcRRUElOIxF3yEooa9gUb9ZbA== - dependencies: - "@babel/types" "^7.13.12" - "@babel/helper-simple-access@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.16.0.tgz#21d6a27620e383e37534cf6c10bba019a6f90517" @@ -981,13 +531,6 @@ dependencies: "@babel/types" "^7.16.0" -"@babel/helper-skip-transparent-expression-wrappers@^7.12.1": - version "7.12.1" - resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.12.1.tgz#462dc63a7e435ade8468385c63d2b84cce4b3cbf" - integrity sha512-Mf5AUuhG1/OCChOJ/HcADmvcHM42WJockombn8ATJG3OnyiSxBK/Mm5x78BQWvmtXZKHgbjdGL2kin/HOLlZGA== - dependencies: - "@babel/types" "^7.12.1" - "@babel/helper-skip-transparent-expression-wrappers@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.16.0.tgz#0ee3388070147c3ae051e487eca3ebb0e2e8bb09" @@ -995,20 +538,6 @@ dependencies: "@babel/types" "^7.16.0" -"@babel/helper-split-export-declaration@^7.11.0": - version "7.11.0" - resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.11.0.tgz#f8a491244acf6a676158ac42072911ba83ad099f" - integrity sha512-74Vejvp6mHkGE+m+k5vHY93FX2cAtrw1zXrZXRlG4l410Nm9PxfEiVTn1PjDPV5SnmieiueY4AFg2xqhNFuuZg== - dependencies: - "@babel/types" "^7.11.0" - -"@babel/helper-split-export-declaration@^7.12.13": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.12.13.tgz#e9430be00baf3e88b0e13e6f9d4eaf2136372b05" - integrity sha512-tCJDltF83htUtXx5NLcaDqRmknv652ZWCHyoTETf1CXYJdPC7nohZohjUgieXhv0hTJdRf2FjDueFehdNucpzg== - dependencies: - "@babel/types" "^7.12.13" - "@babel/helper-split-export-declaration@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.0.tgz#29672f43663e936df370aaeb22beddb3baec7438" @@ -1016,41 +545,16 @@ dependencies: "@babel/types" "^7.16.0" -"@babel/helper-validator-identifier@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz#a78c7a7251e01f616512d31b10adcf52ada5e0d2" - integrity sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw== - -"@babel/helper-validator-identifier@^7.12.11", "@babel/helper-validator-identifier@^7.14.0": - version "7.14.0" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.0.tgz#d26cad8a47c65286b15df1547319a5d0bcf27288" - integrity sha512-V3ts7zMSu5lfiwWDVWzRDGIN+lnCEUdaXgtVHJgLb1rGaA6jMrtB9EmE7L18foXJIE8Un/A/h6NJfGQp/e1J4A== - "@babel/helper-validator-identifier@^7.15.7": version "7.15.7" resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz#220df993bfe904a4a6b02ab4f3385a5ebf6e2389" integrity sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w== -"@babel/helper-validator-option@^7.12.11", "@babel/helper-validator-option@^7.12.17": - version "7.12.17" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.12.17.tgz#d1fbf012e1a79b7eebbfdc6d270baaf8d9eb9831" - integrity sha512-TopkMDmLzq8ngChwRlyjR6raKD6gMSae4JdYDB8bByKreQgG0RBTuKe9LRxW3wFtUnjxOPRKBDwEH6Mg5KeDfw== - "@babel/helper-validator-option@^7.14.5": version "7.14.5" resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.14.5.tgz#6e72a1fff18d5dfcb878e1e62f1a021c4b72d5a3" integrity sha512-OX8D5eeX4XwcroVW45NMvoYaIuFI+GQpA2a8Gi+X/U/cDUIRsV37qQfF905F0htTRCREQIB4KqPeaveRJUl3Ow== -"@babel/helper-wrap-function@^7.13.0": - version "7.13.0" - resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.13.0.tgz#bdb5c66fda8526ec235ab894ad53a1235c79fcc4" - integrity sha512-1UX9F7K3BS42fI6qd2A4BjKzgGjToscyZTdp1DjknHLCIvpgne6918io+aL5LXFcER/8QWiwpoY902pVEqgTXA== - dependencies: - "@babel/helper-function-name" "^7.12.13" - "@babel/template" "^7.12.13" - "@babel/traverse" "^7.13.0" - "@babel/types" "^7.13.0" - "@babel/helper-wrap-function@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.16.0.tgz#b3cf318afce774dfe75b86767cd6d68f3482e57c" @@ -1061,25 +565,7 @@ "@babel/traverse" "^7.16.0" "@babel/types" "^7.16.0" -"@babel/helpers@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.10.4.tgz#2abeb0d721aff7c0a97376b9e1f6f65d7a475044" - integrity sha512-L2gX/XeUONeEbI78dXSrJzGdz4GQ+ZTA/aazfUsFaWjSe95kiCuOZ5HsXvkiw3iwF+mFHSRUfJU8t6YavocdXA== - dependencies: - "@babel/template" "^7.10.4" - "@babel/traverse" "^7.10.4" - "@babel/types" "^7.10.4" - -"@babel/helpers@^7.12.5", "@babel/helpers@^7.14.0": - version "7.14.0" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.14.0.tgz#ea9b6be9478a13d6f961dbb5f36bf75e2f3b8f62" - integrity sha512-+ufuXprtQ1D1iZTO/K9+EBRn+qPWMJjZSw/S0KlFrxCw4tkrzv9grgpDHkY9MeQTjTY8i2sp7Jep8DfU6tN9Mg== - dependencies: - "@babel/template" "^7.12.13" - "@babel/traverse" "^7.14.0" - "@babel/types" "^7.14.0" - -"@babel/helpers@^7.14.8": +"@babel/helpers@^7.14.8", "@babel/helpers@^7.16.0": version "7.16.3" resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.16.3.tgz#27fc64f40b996e7074dc73128c3e5c3e7f55c43c" integrity sha512-Xn8IhDlBPhvYTvgewPKawhADichOsbkZuzN7qz2BusOM0brChsyXMDJvldWaYMMUNiCQdQzNEioXTp3sC8Nt8w== @@ -1088,24 +574,6 @@ "@babel/traverse" "^7.16.3" "@babel/types" "^7.16.0" -"@babel/highlight@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.10.4.tgz#7d1bdfd65753538fabe6c38596cdb76d9ac60143" - integrity sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA== - dependencies: - "@babel/helper-validator-identifier" "^7.10.4" - chalk "^2.0.0" - js-tokens "^4.0.0" - -"@babel/highlight@^7.12.13": - version "7.14.0" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.14.0.tgz#3197e375711ef6bf834e67d0daec88e4f46113cf" - integrity sha512-YSCOwxvTYEIMSGaBQb5kDDsCopDdiUGsqpatp3fOlI4+2HQSkTmEVWnVuySdAC5EWCqSWWTv0ib63RjR7dTBdg== - dependencies: - "@babel/helper-validator-identifier" "^7.14.0" - chalk "^2.0.0" - js-tokens "^4.0.0" - "@babel/highlight@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.16.0.tgz#6ceb32b2ca4b8f5f361fb7fd821e3fddf4a1725a" @@ -1115,16 +583,6 @@ chalk "^2.0.0" js-tokens "^4.0.0" -"@babel/parser@^7.10.4", "@babel/parser@^7.11.5": - version "7.11.5" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.11.5.tgz#c7ff6303df71080ec7a4f5b8c003c58f1cf51037" - integrity sha512-X9rD8qqm695vgmeaQ4fvz/o3+Wk4ZzQvSHkDBgpYKxpD4qTAUm88ZKtHkVqIOsYFFbIQ6wQYhC6q7pjqVK0E0Q== - -"@babel/parser@^7.12.10", "@babel/parser@^7.12.13", "@babel/parser@^7.12.7", "@babel/parser@^7.14.2", "@babel/parser@^7.14.3": - version "7.14.3" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.14.3.tgz#9b530eecb071fd0c93519df25c5ff9f14759f298" - integrity sha512-7MpZDIfI7sUC5zWo2+foJ50CSI5lcqDehZ0lVgIhSi4bFEk94fLAKlF3Q0nzSQQ+ca0lm+O6G9ztKVBeu8PMRQ== - "@babel/parser@^7.14.5", "@babel/parser@^7.14.8", "@babel/parser@^7.16.0", "@babel/parser@^7.16.3": version "7.16.4" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.16.4.tgz#d5f92f57cf2c74ffe9b37981c0e72fee7311372e" @@ -1148,15 +606,6 @@ "@babel/helper-remap-async-to-generator" "^7.14.5" "@babel/plugin-syntax-async-generators" "^7.8.4" -"@babel/plugin-proposal-async-generator-functions@^7.12.1": - version "7.14.2" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.14.2.tgz#3a2085abbf5d5f962d480dbc81347385ed62eb1e" - integrity sha512-b1AM4F6fwck4N8ItZ/AtC4FP/cqZqmKRQ4FaTDutwSYyjuhtvsGEMLK4N/ztV/ImP40BjIDyMgBQAeAMsQYVFQ== - dependencies: - "@babel/helper-plugin-utils" "^7.13.0" - "@babel/helper-remap-async-to-generator" "^7.13.0" - "@babel/plugin-syntax-async-generators" "^7.8.4" - "@babel/plugin-proposal-async-generator-functions@^7.14.7": version "7.16.4" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.16.4.tgz#e606eb6015fec6fa5978c940f315eae4e300b081" @@ -1166,14 +615,6 @@ "@babel/helper-remap-async-to-generator" "^7.16.4" "@babel/plugin-syntax-async-generators" "^7.8.4" -"@babel/plugin-proposal-class-properties@^7.12.1": - version "7.13.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.13.0.tgz#146376000b94efd001e57a40a88a525afaab9f37" - integrity sha512-KnTDjFNC1g+45ka0myZNvSBFLhNCLN+GeGYLDEA8Oq7MZ6yMgfLoIRh86GRT0FjtJhZw8JyUskP9uvj5pHM9Zg== - dependencies: - "@babel/helper-create-class-features-plugin" "^7.13.0" - "@babel/helper-plugin-utils" "^7.13.0" - "@babel/plugin-proposal-class-properties@^7.14.5": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.16.0.tgz#c029618267ddebc7280fa286e0f8ca2a278a2d1a" @@ -1191,14 +632,6 @@ "@babel/helper-plugin-utils" "^7.14.5" "@babel/plugin-syntax-class-static-block" "^7.14.5" -"@babel/plugin-proposal-dynamic-import@^7.12.1": - version "7.14.2" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.14.2.tgz#01ebabd7c381cff231fa43e302939a9de5be9d9f" - integrity sha512-oxVQZIWFh91vuNEMKltqNsKLFWkOIyJc95k2Gv9lWVyDfPUQGSSlbDEgWuJUU1afGE9WwlzpucMZ3yDRHIItkA== - dependencies: - "@babel/helper-plugin-utils" "^7.13.0" - "@babel/plugin-syntax-dynamic-import" "^7.8.3" - "@babel/plugin-proposal-dynamic-import@^7.14.5": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.16.0.tgz#783eca61d50526202f9b296095453977e88659f1" @@ -1207,14 +640,6 @@ "@babel/helper-plugin-utils" "^7.14.5" "@babel/plugin-syntax-dynamic-import" "^7.8.3" -"@babel/plugin-proposal-export-namespace-from@^7.12.1": - version "7.14.2" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.14.2.tgz#62542f94aa9ce8f6dba79eec698af22112253791" - integrity sha512-sRxW3z3Zp3pFfLAgVEvzTFutTXax837oOatUIvSG9o5gRj9mKwm3br1Se5f4QalTQs9x4AzlA/HrCWbQIHASUQ== - dependencies: - "@babel/helper-plugin-utils" "^7.13.0" - "@babel/plugin-syntax-export-namespace-from" "^7.8.3" - "@babel/plugin-proposal-export-namespace-from@^7.14.5": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.16.0.tgz#9c01dee40b9d6b847b656aaf4a3976a71740f222" @@ -1223,14 +648,6 @@ "@babel/helper-plugin-utils" "^7.14.5" "@babel/plugin-syntax-export-namespace-from" "^7.8.3" -"@babel/plugin-proposal-json-strings@^7.12.1": - version "7.14.2" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.14.2.tgz#830b4e2426a782e8b2878fbfe2cba85b70cbf98c" - integrity sha512-w2DtsfXBBJddJacXMBhElGEYqCZQqN99Se1qeYn8DVLB33owlrlLftIbMzn5nz1OITfDVknXF433tBrLEAOEjA== - dependencies: - "@babel/helper-plugin-utils" "^7.13.0" - "@babel/plugin-syntax-json-strings" "^7.8.3" - "@babel/plugin-proposal-json-strings@^7.14.5": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.16.0.tgz#cae35a95ed1d2a7fa29c4dc41540b84a72e9ab25" @@ -1239,14 +656,6 @@ "@babel/helper-plugin-utils" "^7.14.5" "@babel/plugin-syntax-json-strings" "^7.8.3" -"@babel/plugin-proposal-logical-assignment-operators@^7.12.1": - version "7.14.2" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.14.2.tgz#222348c080a1678e0e74ea63fe76f275882d1fd7" - integrity sha512-1JAZtUrqYyGsS7IDmFeaem+/LJqujfLZ2weLR9ugB0ufUPjzf8cguyVT1g5im7f7RXxuLq1xUxEzvm68uYRtGg== - dependencies: - "@babel/helper-plugin-utils" "^7.13.0" - "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" - "@babel/plugin-proposal-logical-assignment-operators@^7.14.5": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.16.0.tgz#a711b8ceb3ffddd3ef88d3a49e86dbd3cc7db3fd" @@ -1255,14 +664,6 @@ "@babel/helper-plugin-utils" "^7.14.5" "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" -"@babel/plugin-proposal-nullish-coalescing-operator@^7.12.1": - version "7.14.2" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.14.2.tgz#425b11dc62fc26939a2ab42cbba680bdf5734546" - integrity sha512-ebR0zU9OvI2N4qiAC38KIAK75KItpIPTpAtd2r4OZmMFeKbKJpUFLYP2EuDut82+BmYi8sz42B+TfTptJ9iG5Q== - dependencies: - "@babel/helper-plugin-utils" "^7.13.0" - "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" - "@babel/plugin-proposal-nullish-coalescing-operator@^7.14.5": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.16.0.tgz#44e1cce08fe2427482cf446a91bb451528ed0596" @@ -1271,14 +672,6 @@ "@babel/helper-plugin-utils" "^7.14.5" "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" -"@babel/plugin-proposal-numeric-separator@^7.12.7": - version "7.14.2" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.14.2.tgz#82b4cc06571143faf50626104b335dd71baa4f9e" - integrity sha512-DcTQY9syxu9BpU3Uo94fjCB3LN9/hgPS8oUL7KrSW3bA2ePrKZZPJcc5y0hoJAM9dft3pGfErtEUvxXQcfLxUg== - dependencies: - "@babel/helper-plugin-utils" "^7.13.0" - "@babel/plugin-syntax-numeric-separator" "^7.10.4" - "@babel/plugin-proposal-numeric-separator@^7.14.5": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.16.0.tgz#5d418e4fbbf8b9b7d03125d3a52730433a373734" @@ -1287,17 +680,6 @@ "@babel/helper-plugin-utils" "^7.14.5" "@babel/plugin-syntax-numeric-separator" "^7.10.4" -"@babel/plugin-proposal-object-rest-spread@^7.12.1": - version "7.14.2" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.14.2.tgz#e17d418f81cc103fedd4ce037e181c8056225abc" - integrity sha512-hBIQFxwZi8GIp934+nj5uV31mqclC1aYDhctDu5khTi9PCCUOczyy0b34W0oE9U/eJXiqQaKyVsmjeagOaSlbw== - dependencies: - "@babel/compat-data" "^7.14.0" - "@babel/helper-compilation-targets" "^7.13.16" - "@babel/helper-plugin-utils" "^7.13.0" - "@babel/plugin-syntax-object-rest-spread" "^7.8.3" - "@babel/plugin-transform-parameters" "^7.14.2" - "@babel/plugin-proposal-object-rest-spread@^7.14.7": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.16.0.tgz#5fb32f6d924d6e6712810362a60e12a2609872e6" @@ -1309,14 +691,6 @@ "@babel/plugin-syntax-object-rest-spread" "^7.8.3" "@babel/plugin-transform-parameters" "^7.16.0" -"@babel/plugin-proposal-optional-catch-binding@^7.12.1": - version "7.14.2" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.14.2.tgz#150d4e58e525b16a9a1431bd5326c4eed870d717" - integrity sha512-XtkJsmJtBaUbOxZsNk0Fvrv8eiqgneug0A6aqLFZ4TSkar2L5dSXWcnUKHgmjJt49pyB/6ZHvkr3dPgl9MOWRQ== - dependencies: - "@babel/helper-plugin-utils" "^7.13.0" - "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" - "@babel/plugin-proposal-optional-catch-binding@^7.14.5": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.16.0.tgz#5910085811ab4c28b00d6ebffa4ab0274d1e5f16" @@ -1325,15 +699,6 @@ "@babel/helper-plugin-utils" "^7.14.5" "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" -"@babel/plugin-proposal-optional-chaining@^7.12.7": - version "7.14.2" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.14.2.tgz#df8171a8b9c43ebf4c1dabe6311b432d83e1b34e" - integrity sha512-qQByMRPwMZJainfig10BoaDldx/+VDtNcrA7qdNaEOAj6VXud+gfrkA8j4CRAU5HjnWREXqIpSpH30qZX1xivA== - dependencies: - "@babel/helper-plugin-utils" "^7.13.0" - "@babel/helper-skip-transparent-expression-wrappers" "^7.12.1" - "@babel/plugin-syntax-optional-chaining" "^7.8.3" - "@babel/plugin-proposal-optional-chaining@^7.14.5", "@babel/plugin-proposal-optional-chaining@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.16.0.tgz#56dbc3970825683608e9efb55ea82c2a2d6c8dc0" @@ -1343,14 +708,6 @@ "@babel/helper-skip-transparent-expression-wrappers" "^7.16.0" "@babel/plugin-syntax-optional-chaining" "^7.8.3" -"@babel/plugin-proposal-private-methods@^7.12.1": - version "7.13.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.13.0.tgz#04bd4c6d40f6e6bbfa2f57e2d8094bad900ef787" - integrity sha512-MXyyKQd9inhx1kDYPkFRVOBXQ20ES8Pto3T7UZ92xj2mY0EVD8oAVzeyYuVfy/mxAdTSIayOvg+aVzcHV2bn6Q== - dependencies: - "@babel/helper-create-class-features-plugin" "^7.13.0" - "@babel/helper-plugin-utils" "^7.13.0" - "@babel/plugin-proposal-private-methods@^7.14.5": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.16.0.tgz#b4dafb9c717e4301c5776b30d080d6383c89aff6" @@ -1369,15 +726,7 @@ "@babel/helper-plugin-utils" "^7.14.5" "@babel/plugin-syntax-private-property-in-object" "^7.14.5" -"@babel/plugin-proposal-unicode-property-regex@^7.12.1": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.12.13.tgz#bebde51339be829c17aaaaced18641deb62b39ba" - integrity sha512-XyJmZidNfofEkqFV5VC/bLabGmO5QzenPO/YOfGuEbgU+2sSwMmio3YLb4WtBgcmmdwZHyVyv8on77IUjQ5Gvg== - dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.12.13" - "@babel/helper-plugin-utils" "^7.12.13" - -"@babel/plugin-proposal-unicode-property-regex@^7.14.5": +"@babel/plugin-proposal-unicode-property-regex@^7.14.5", "@babel/plugin-proposal-unicode-property-regex@^7.4.4": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.16.0.tgz#890482dfc5ea378e42e19a71e709728cabf18612" integrity sha512-ti7IdM54NXv29cA4+bNNKEMS4jLMCbJgl+Drv+FgYy0erJLAxNAIXcNjNjrRZEcWq0xJHsNVwQezskMFpF8N9g== @@ -1385,22 +734,14 @@ "@babel/helper-create-regexp-features-plugin" "^7.16.0" "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-proposal-unicode-property-regex@^7.4.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.10.4.tgz#4483cda53041ce3413b7fe2f00022665ddfaa75d" - integrity sha512-H+3fOgPnEXFL9zGYtKQe4IDOPKYlZdF1kqFDQRRb8PK4B8af1vAGK04tF5iQAAsui+mHNBQSAtd2/ndEDe9wuA== - dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.10.4" - "@babel/helper-plugin-utils" "^7.10.4" - -"@babel/plugin-syntax-async-generators@^7.8.0", "@babel/plugin-syntax-async-generators@^7.8.4": +"@babel/plugin-syntax-async-generators@^7.8.4": version "7.8.4" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d" integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw== dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-class-properties@^7.12.1", "@babel/plugin-syntax-class-properties@^7.12.13": +"@babel/plugin-syntax-class-properties@^7.12.13": version "7.12.13" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz#b5c987274c4a3a82b89714796931a6b53544ae10" integrity sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA== @@ -1414,7 +755,7 @@ dependencies: "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-syntax-dynamic-import@^7.8.0", "@babel/plugin-syntax-dynamic-import@^7.8.3": +"@babel/plugin-syntax-dynamic-import@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz#62bf98b2da3cd21d626154fc96ee5b3cb68eacb3" integrity sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ== @@ -1428,7 +769,7 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-syntax-json-strings@^7.8.0", "@babel/plugin-syntax-json-strings@^7.8.3": +"@babel/plugin-syntax-json-strings@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a" integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA== @@ -1442,7 +783,7 @@ dependencies: "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-syntax-nullish-coalescing-operator@^7.8.0", "@babel/plugin-syntax-nullish-coalescing-operator@^7.8.3": +"@babel/plugin-syntax-nullish-coalescing-operator@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz#167ed70368886081f74b5c36c65a88c03b66d1a9" integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ== @@ -1456,21 +797,21 @@ dependencies: "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-syntax-object-rest-spread@^7.8.0", "@babel/plugin-syntax-object-rest-spread@^7.8.3": +"@babel/plugin-syntax-object-rest-spread@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871" integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-optional-catch-binding@^7.8.0", "@babel/plugin-syntax-optional-catch-binding@^7.8.3": +"@babel/plugin-syntax-optional-catch-binding@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz#6111a265bcfb020eb9efd0fdfd7d26402b9ed6c1" integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q== dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-optional-chaining@^7.8.0", "@babel/plugin-syntax-optional-chaining@^7.8.3": +"@babel/plugin-syntax-optional-chaining@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz#4f69c2ab95167e0180cd5336613f8c5788f7d48a" integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg== @@ -1484,13 +825,6 @@ dependencies: "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-syntax-top-level-await@^7.12.1": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.12.13.tgz#c5f0fa6e249f5b739727f923540cf7a806130178" - integrity sha512-A81F9pDwyS7yM//KwbCSDqy3Uj4NMIurtplxphWxoYtNPov7cJsDkAFNNyVlIZ3jwGycVsurZ+LtOA8gZ376iQ== - dependencies: - "@babel/helper-plugin-utils" "^7.12.13" - "@babel/plugin-syntax-top-level-await@^7.14.5": version "7.14.5" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz#c1cfdadc35a646240001f06138247b741c34d94c" @@ -1498,13 +832,6 @@ dependencies: "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-transform-arrow-functions@^7.12.1": - version "7.13.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.13.0.tgz#10a59bebad52d637a027afa692e8d5ceff5e3dae" - integrity sha512-96lgJagobeVmazXFaDrbmCLQxBysKu7U6Do3mLsx27gf5Dk85ezysrs2BZUpXD703U/Su1xTBDxxar2oa4jAGg== - dependencies: - "@babel/helper-plugin-utils" "^7.13.0" - "@babel/plugin-transform-arrow-functions@^7.14.5": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.16.0.tgz#951706f8b449c834ed07bd474c0924c944b95a8e" @@ -1512,15 +839,6 @@ dependencies: "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-transform-async-to-generator@7.12.1": - version "7.12.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.12.1.tgz#3849a49cc2a22e9743cbd6b52926d30337229af1" - integrity sha512-SDtqoEcarK1DFlRJ1hHRY5HvJUj5kX4qmtpMAm2QnhOlyuMC4TMdCRgW6WXpv93rZeYNeLP22y8Aq2dbcDRM1A== - dependencies: - "@babel/helper-module-imports" "^7.12.1" - "@babel/helper-plugin-utils" "^7.10.4" - "@babel/helper-remap-async-to-generator" "^7.12.1" - "@babel/plugin-transform-async-to-generator@7.14.5": version "7.14.5" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.14.5.tgz#72c789084d8f2094acb945633943ef8443d39e67" @@ -1530,15 +848,6 @@ "@babel/helper-plugin-utils" "^7.14.5" "@babel/helper-remap-async-to-generator" "^7.14.5" -"@babel/plugin-transform-async-to-generator@^7.12.1": - version "7.13.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.13.0.tgz#8e112bf6771b82bf1e974e5e26806c5c99aa516f" - integrity sha512-3j6E004Dx0K3eGmhxVJxwwI89CTJrce7lg3UrtFuDAVQ/2+SJ/h/aSFOeE6/n0WB1GsOffsJp6MnPQNQ8nmwhg== - dependencies: - "@babel/helper-module-imports" "^7.12.13" - "@babel/helper-plugin-utils" "^7.13.0" - "@babel/helper-remap-async-to-generator" "^7.13.0" - "@babel/plugin-transform-async-to-generator@^7.14.5": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.16.0.tgz#df12637f9630ddfa0ef9d7a11bc414d629d38604" @@ -1548,13 +857,6 @@ "@babel/helper-plugin-utils" "^7.14.5" "@babel/helper-remap-async-to-generator" "^7.16.0" -"@babel/plugin-transform-block-scoped-functions@^7.12.1": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.12.13.tgz#a9bf1836f2a39b4eb6cf09967739de29ea4bf4c4" - integrity sha512-zNyFqbc3kI/fVpqwfqkg6RvBgFpC4J18aKKMmv7KdQ/1GgREapSJAykLMVNwfRGO3BtHj3YQZl8kxCXPcVMVeg== - dependencies: - "@babel/helper-plugin-utils" "^7.12.13" - "@babel/plugin-transform-block-scoped-functions@^7.14.5": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.16.0.tgz#c618763233ad02847805abcac4c345ce9de7145d" @@ -1562,13 +864,6 @@ dependencies: "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-transform-block-scoping@^7.12.11": - version "7.14.2" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.14.2.tgz#761cb12ab5a88d640ad4af4aa81f820e6b5fdf5c" - integrity sha512-neZZcP19NugZZqNwMTH+KoBjx5WyvESPSIOQb4JHpfd+zPfqcH65RMu5xJju5+6q/Y2VzYrleQTr+b6METyyxg== - dependencies: - "@babel/helper-plugin-utils" "^7.13.0" - "@babel/plugin-transform-block-scoping@^7.14.5": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.16.0.tgz#bcf433fb482fe8c3d3b4e8a66b1c4a8e77d37c16" @@ -1576,19 +871,6 @@ dependencies: "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-transform-classes@^7.12.1": - version "7.14.2" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.14.2.tgz#3f1196c5709f064c252ad056207d87b7aeb2d03d" - integrity sha512-7oafAVcucHquA/VZCsXv/gmuiHeYd64UJyyTYU+MPfNu0KeNlxw06IeENBO8bJjXVbolu+j1MM5aKQtH1OMCNg== - dependencies: - "@babel/helper-annotate-as-pure" "^7.12.13" - "@babel/helper-function-name" "^7.14.2" - "@babel/helper-optimise-call-expression" "^7.12.13" - "@babel/helper-plugin-utils" "^7.13.0" - "@babel/helper-replace-supers" "^7.13.12" - "@babel/helper-split-export-declaration" "^7.12.13" - globals "^11.1.0" - "@babel/plugin-transform-classes@^7.14.5": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.16.0.tgz#54cf5ff0b2242c6573d753cd4bfc7077a8b282f5" @@ -1602,13 +884,6 @@ "@babel/helper-split-export-declaration" "^7.16.0" globals "^11.1.0" -"@babel/plugin-transform-computed-properties@^7.12.1": - version "7.13.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.13.0.tgz#845c6e8b9bb55376b1fa0b92ef0bdc8ea06644ed" - integrity sha512-RRqTYTeZkZAz8WbieLTvKUEUxZlUTdmL5KGMyZj7FnMfLNKV4+r5549aORG/mgojRmFlQMJDUupwAMiF2Q7OUg== - dependencies: - "@babel/helper-plugin-utils" "^7.13.0" - "@babel/plugin-transform-computed-properties@^7.14.5": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.16.0.tgz#e0c385507d21e1b0b076d66bed6d5231b85110b7" @@ -1616,13 +891,6 @@ dependencies: "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-transform-destructuring@^7.12.1": - version "7.13.17" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.13.17.tgz#678d96576638c19d5b36b332504d3fd6e06dea27" - integrity sha512-UAUqiLv+uRLO+xuBKKMEpC+t7YRNVRqBsWWq1yKXbBZBje/t3IXCiSinZhjn/DC3qzBfICeYd2EFGEbHsh5RLA== - dependencies: - "@babel/helper-plugin-utils" "^7.13.0" - "@babel/plugin-transform-destructuring@^7.14.7": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.16.0.tgz#ad3d7e74584ad5ea4eadb1e6642146c590dee33c" @@ -1630,15 +898,7 @@ dependencies: "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-transform-dotall-regex@^7.12.1": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.12.13.tgz#3f1601cc29905bfcb67f53910f197aeafebb25ad" - integrity sha512-foDrozE65ZFdUC2OfgeOCrEPTxdB3yjqxpXh8CH+ipd9CHd4s/iq81kcUpyH8ACGNEPdFqbtzfgzbT/ZGlbDeQ== - dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.12.13" - "@babel/helper-plugin-utils" "^7.12.13" - -"@babel/plugin-transform-dotall-regex@^7.14.5": +"@babel/plugin-transform-dotall-regex@^7.14.5", "@babel/plugin-transform-dotall-regex@^7.4.4": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.16.0.tgz#50bab00c1084b6162d0a58a818031cf57798e06f" integrity sha512-FXlDZfQeLILfJlC6I1qyEwcHK5UpRCFkaoVyA1nk9A1L1Yu583YO4un2KsLBsu3IJb4CUbctZks8tD9xPQubLw== @@ -1646,21 +906,6 @@ "@babel/helper-create-regexp-features-plugin" "^7.16.0" "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-transform-dotall-regex@^7.4.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.10.4.tgz#469c2062105c1eb6a040eaf4fac4b488078395ee" - integrity sha512-ZEAVvUTCMlMFAbASYSVQoxIbHm2OkG2MseW6bV2JjIygOjdVv8tuxrCTzj1+Rynh7ODb8GivUy7dzEXzEhuPaA== - dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.10.4" - "@babel/helper-plugin-utils" "^7.10.4" - -"@babel/plugin-transform-duplicate-keys@^7.12.1": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.12.13.tgz#6f06b87a8b803fd928e54b81c258f0a0033904de" - integrity sha512-NfADJiiHdhLBW3pulJlJI2NB0t4cci4WTZ8FtdIuNc2+8pslXdPtRRAEWqUY+m9kNOk2eRYbTAOipAxlrOcwwQ== - dependencies: - "@babel/helper-plugin-utils" "^7.12.13" - "@babel/plugin-transform-duplicate-keys@^7.14.5": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.16.0.tgz#8bc2e21813e3e89e5e5bf3b60aa5fc458575a176" @@ -1668,14 +913,6 @@ dependencies: "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-transform-exponentiation-operator@^7.12.1": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.12.13.tgz#4d52390b9a273e651e4aba6aee49ef40e80cd0a1" - integrity sha512-fbUelkM1apvqez/yYx1/oICVnGo2KM5s63mhGylrmXUxK/IAXSIf87QIxVfZldWf4QsOafY6vV3bX8aMHSvNrA== - dependencies: - "@babel/helper-builder-binary-assignment-operator-visitor" "^7.12.13" - "@babel/helper-plugin-utils" "^7.12.13" - "@babel/plugin-transform-exponentiation-operator@^7.14.5": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.16.0.tgz#a180cd2881e3533cef9d3901e48dad0fbeff4be4" @@ -1684,13 +921,6 @@ "@babel/helper-builder-binary-assignment-operator-visitor" "^7.16.0" "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-transform-for-of@^7.12.1": - version "7.13.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.13.0.tgz#c799f881a8091ac26b54867a845c3e97d2696062" - integrity sha512-IHKT00mwUVYE0zzbkDgNRP6SRzvfGCYsOxIRz8KsiaaHCcT9BWIkO+H9QRJseHBLOGBZkHUdHiqj6r0POsdytg== - dependencies: - "@babel/helper-plugin-utils" "^7.13.0" - "@babel/plugin-transform-for-of@^7.14.5": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.16.0.tgz#f7abaced155260e2461359bbc7c7248aca5e6bd2" @@ -1698,14 +928,6 @@ dependencies: "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-transform-function-name@^7.12.1": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.12.13.tgz#bb024452f9aaed861d374c8e7a24252ce3a50051" - integrity sha512-6K7gZycG0cmIwwF7uMK/ZqeCikCGVBdyP2J5SKNCXO5EOHcqi+z7Jwf8AmyDNcBgxET8DrEtCt/mPKPyAzXyqQ== - dependencies: - "@babel/helper-function-name" "^7.12.13" - "@babel/helper-plugin-utils" "^7.12.13" - "@babel/plugin-transform-function-name@^7.14.5": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.16.0.tgz#02e3699c284c6262236599f751065c5d5f1f400e" @@ -1714,13 +936,6 @@ "@babel/helper-function-name" "^7.16.0" "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-transform-literals@^7.12.1": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.12.13.tgz#2ca45bafe4a820197cf315794a4d26560fe4bdb9" - integrity sha512-FW+WPjSR7hiUxMcKqyNjP05tQ2kmBCdpEpZHY1ARm96tGQCCBvXKnpjILtDplUnJ/eHZ0lALLM+d2lMFSpYJrQ== - dependencies: - "@babel/helper-plugin-utils" "^7.12.13" - "@babel/plugin-transform-literals@^7.14.5": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.16.0.tgz#79711e670ffceb31bd298229d50f3621f7980cac" @@ -1728,13 +943,6 @@ dependencies: "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-transform-member-expression-literals@^7.12.1": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.12.13.tgz#5ffa66cd59b9e191314c9f1f803b938e8c081e40" - integrity sha512-kxLkOsg8yir4YeEPHLuO2tXP9R/gTjpuTOjshqSpELUN3ZAg2jfDnKUvzzJxObun38sw3wm4Uu69sX/zA7iRvg== - dependencies: - "@babel/helper-plugin-utils" "^7.12.13" - "@babel/plugin-transform-member-expression-literals@^7.14.5": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.16.0.tgz#5251b4cce01eaf8314403d21aedb269d79f5e64b" @@ -1742,15 +950,6 @@ dependencies: "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-transform-modules-amd@^7.12.1": - version "7.14.2" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.14.2.tgz#6622806fe1a7c07a1388444222ef9535f2ca17b0" - integrity sha512-hPC6XBswt8P3G2D1tSV2HzdKvkqOpmbyoy+g73JG0qlF/qx2y3KaMmXb1fLrpmWGLZYA0ojCvaHdzFWjlmV+Pw== - dependencies: - "@babel/helper-module-transforms" "^7.14.2" - "@babel/helper-plugin-utils" "^7.13.0" - babel-plugin-dynamic-import-node "^2.3.3" - "@babel/plugin-transform-modules-amd@^7.14.5": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.16.0.tgz#09abd41e18dcf4fd479c598c1cef7bd39eb1337e" @@ -1760,16 +959,6 @@ "@babel/helper-plugin-utils" "^7.14.5" babel-plugin-dynamic-import-node "^2.3.3" -"@babel/plugin-transform-modules-commonjs@^7.12.1": - version "7.14.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.14.0.tgz#52bc199cb581e0992edba0f0f80356467587f161" - integrity sha512-EX4QePlsTaRZQmw9BsoPeyh5OCtRGIhwfLquhxGp5e32w+dyL8htOcDwamlitmNFK6xBZYlygjdye9dbd9rUlQ== - dependencies: - "@babel/helper-module-transforms" "^7.14.0" - "@babel/helper-plugin-utils" "^7.13.0" - "@babel/helper-simple-access" "^7.13.12" - babel-plugin-dynamic-import-node "^2.3.3" - "@babel/plugin-transform-modules-commonjs@^7.14.5": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.16.0.tgz#add58e638c8ddc4875bd9a9ecb5c594613f6c922" @@ -1780,17 +969,6 @@ "@babel/helper-simple-access" "^7.16.0" babel-plugin-dynamic-import-node "^2.3.3" -"@babel/plugin-transform-modules-systemjs@^7.12.1": - version "7.13.8" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.13.8.tgz#6d066ee2bff3c7b3d60bf28dec169ad993831ae3" - integrity sha512-hwqctPYjhM6cWvVIlOIe27jCIBgHCsdH2xCJVAYQm7V5yTMoilbVMi9f6wKg0rpQAOn6ZG4AOyvCqFF/hUh6+A== - dependencies: - "@babel/helper-hoist-variables" "^7.13.0" - "@babel/helper-module-transforms" "^7.13.0" - "@babel/helper-plugin-utils" "^7.13.0" - "@babel/helper-validator-identifier" "^7.12.11" - babel-plugin-dynamic-import-node "^2.3.3" - "@babel/plugin-transform-modules-systemjs@^7.14.5": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.16.0.tgz#a92cf240afeb605f4ca16670453024425e421ea4" @@ -1802,14 +980,6 @@ "@babel/helper-validator-identifier" "^7.15.7" babel-plugin-dynamic-import-node "^2.3.3" -"@babel/plugin-transform-modules-umd@^7.12.1": - version "7.14.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.14.0.tgz#2f8179d1bbc9263665ce4a65f305526b2ea8ac34" - integrity sha512-nPZdnWtXXeY7I87UZr9VlsWme3Y0cfFFE41Wbxz4bbaexAjNMInXPFUpRRUJ8NoMm0Cw+zxbqjdPmLhcjfazMw== - dependencies: - "@babel/helper-module-transforms" "^7.14.0" - "@babel/helper-plugin-utils" "^7.13.0" - "@babel/plugin-transform-modules-umd@^7.14.5": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.16.0.tgz#195f26c2ad6d6a391b70880effce18ce625e06a7" @@ -1818,13 +988,6 @@ "@babel/helper-module-transforms" "^7.16.0" "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-transform-named-capturing-groups-regex@^7.12.1": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.12.13.tgz#2213725a5f5bbbe364b50c3ba5998c9599c5c9d9" - integrity sha512-Xsm8P2hr5hAxyYblrfACXpQKdQbx4m2df9/ZZSQ8MAhsadw06+jW7s9zsSw6he+mJZXRlVMyEnVktJo4zjk1WA== - dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.12.13" - "@babel/plugin-transform-named-capturing-groups-regex@^7.14.7": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.16.0.tgz#d3db61cc5d5b97986559967cd5ea83e5c32096ca" @@ -1832,13 +995,6 @@ dependencies: "@babel/helper-create-regexp-features-plugin" "^7.16.0" -"@babel/plugin-transform-new-target@^7.12.1": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.12.13.tgz#e22d8c3af24b150dd528cbd6e685e799bf1c351c" - integrity sha512-/KY2hbLxrG5GTQ9zzZSc3xWiOy379pIETEhbtzwZcw9rvuaVV4Fqy7BYGYOWZnaoXIQYbbJ0ziXLa/sKcGCYEQ== - dependencies: - "@babel/helper-plugin-utils" "^7.12.13" - "@babel/plugin-transform-new-target@^7.14.5": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.16.0.tgz#af823ab576f752215a49937779a41ca65825ab35" @@ -1846,14 +1002,6 @@ dependencies: "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-transform-object-super@^7.12.1": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.12.13.tgz#b4416a2d63b8f7be314f3d349bd55a9c1b5171f7" - integrity sha512-JzYIcj3XtYspZDV8j9ulnoMPZZnF/Cj0LUxPOjR89BdBVx+zYJI9MdMIlUZjbXDX+6YVeS6I3e8op+qQ3BYBoQ== - dependencies: - "@babel/helper-plugin-utils" "^7.12.13" - "@babel/helper-replace-supers" "^7.12.13" - "@babel/plugin-transform-object-super@^7.14.5": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.16.0.tgz#fb20d5806dc6491a06296ac14ea8e8d6fedda72b" @@ -1862,13 +1010,6 @@ "@babel/helper-plugin-utils" "^7.14.5" "@babel/helper-replace-supers" "^7.16.0" -"@babel/plugin-transform-parameters@^7.12.1", "@babel/plugin-transform-parameters@^7.14.2": - version "7.14.2" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.14.2.tgz#e4290f72e0e9e831000d066427c4667098decc31" - integrity sha512-NxoVmA3APNCC1JdMXkdYXuQS+EMdqy0vIwyDHeKHiJKRxmp1qGSdb0JLEIoPRhkx6H/8Qi3RJ3uqOCYw8giy9A== - dependencies: - "@babel/helper-plugin-utils" "^7.13.0" - "@babel/plugin-transform-parameters@^7.14.5", "@babel/plugin-transform-parameters@^7.16.0": version "7.16.3" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.16.3.tgz#fa9e4c874ee5223f891ee6fa8d737f4766d31d15" @@ -1876,13 +1017,6 @@ dependencies: "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-transform-property-literals@^7.12.1": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.12.13.tgz#4e6a9e37864d8f1b3bc0e2dce7bf8857db8b1a81" - integrity sha512-nqVigwVan+lR+g8Fj8Exl0UQX2kymtjcWfMOYM1vTYEKujeyv2SkMgazf2qNcK7l4SDiKyTA/nHCPqL4e2zo1A== - dependencies: - "@babel/helper-plugin-utils" "^7.12.13" - "@babel/plugin-transform-property-literals@^7.14.5": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.16.0.tgz#a95c552189a96a00059f6776dc4e00e3690c78d1" @@ -1890,13 +1024,6 @@ dependencies: "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-transform-regenerator@^7.12.1": - version "7.13.15" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.13.15.tgz#e5eb28945bf8b6563e7f818945f966a8d2997f39" - integrity sha512-Bk9cOLSz8DiurcMETZ8E2YtIVJbFCPGW28DJWUakmyVWtQSm6Wsf0p4B4BfEr/eL2Nkhe/CICiUiMOCi1TPhuQ== - dependencies: - regenerator-transform "^0.14.2" - "@babel/plugin-transform-regenerator@^7.14.5": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.16.0.tgz#eaee422c84b0232d03aea7db99c97deeaf6125a4" @@ -1904,13 +1031,6 @@ dependencies: regenerator-transform "^0.14.2" -"@babel/plugin-transform-reserved-words@^7.12.1": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.12.13.tgz#7d9988d4f06e0fe697ea1d9803188aa18b472695" - integrity sha512-xhUPzDXxZN1QfiOy/I5tyye+TRz6lA7z6xaT4CLOjPRMVg1ldRf0LHw0TDBpYL4vG78556WuHdyO9oi5UmzZBg== - dependencies: - "@babel/helper-plugin-utils" "^7.12.13" - "@babel/plugin-transform-reserved-words@^7.14.5": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.16.0.tgz#fff4b9dcb19e12619394bda172d14f2d04c0379c" @@ -1918,15 +1038,6 @@ dependencies: "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-transform-runtime@7.12.10": - version "7.12.10" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.12.10.tgz#af0fded4e846c4b37078e8e5d06deac6cd848562" - integrity sha512-xOrUfzPxw7+WDm9igMgQCbO3cJKymX7dFdsgRr1eu9n3KjjyU4pptIXbXPseQDquw+W+RuJEJMHKHNsPNNm3CA== - dependencies: - "@babel/helper-module-imports" "^7.12.5" - "@babel/helper-plugin-utils" "^7.10.4" - semver "^5.5.1" - "@babel/plugin-transform-runtime@7.14.5": version "7.14.5" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.14.5.tgz#30491dad49c6059f8f8fa5ee8896a0089e987523" @@ -1939,13 +1050,6 @@ babel-plugin-polyfill-regenerator "^0.2.2" semver "^6.3.0" -"@babel/plugin-transform-shorthand-properties@^7.12.1": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.12.13.tgz#db755732b70c539d504c6390d9ce90fe64aff7ad" - integrity sha512-xpL49pqPnLtf0tVluuqvzWIgLEhuPpZzvs2yabUHSKRNlN7ScYU7aMlmavOeyXJZKgZKQRBlh8rHbKiJDraTSw== - dependencies: - "@babel/helper-plugin-utils" "^7.12.13" - "@babel/plugin-transform-shorthand-properties@^7.14.5": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.16.0.tgz#090372e3141f7cc324ed70b3daf5379df2fa384d" @@ -1953,14 +1057,6 @@ dependencies: "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-transform-spread@^7.12.1": - version "7.13.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.13.0.tgz#84887710e273c1815ace7ae459f6f42a5d31d5fd" - integrity sha512-V6vkiXijjzYeFmQTr3dBxPtZYLPcUfY34DebOU27jIl2M/Y8Egm52Hw82CSjjPqd54GTlJs5x+CR7HeNr24ckg== - dependencies: - "@babel/helper-plugin-utils" "^7.13.0" - "@babel/helper-skip-transparent-expression-wrappers" "^7.12.1" - "@babel/plugin-transform-spread@^7.14.6": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.16.0.tgz#d21ca099bbd53ab307a8621e019a7bd0f40cdcfb" @@ -1969,13 +1065,6 @@ "@babel/helper-plugin-utils" "^7.14.5" "@babel/helper-skip-transparent-expression-wrappers" "^7.16.0" -"@babel/plugin-transform-sticky-regex@^7.12.7": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.12.13.tgz#760ffd936face73f860ae646fb86ee82f3d06d1f" - integrity sha512-Jc3JSaaWT8+fr7GRvQP02fKDsYk4K/lYwWq38r/UGfaxo89ajud321NH28KRQ7xy1Ybc0VUE5Pz8psjNNDUglg== - dependencies: - "@babel/helper-plugin-utils" "^7.12.13" - "@babel/plugin-transform-sticky-regex@^7.14.5": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.16.0.tgz#c35ea31a02d86be485f6aa510184b677a91738fd" @@ -1983,13 +1072,6 @@ dependencies: "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-transform-template-literals@^7.12.1": - version "7.13.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.13.0.tgz#a36049127977ad94438dee7443598d1cefdf409d" - integrity sha512-d67umW6nlfmr1iehCcBv69eSUSySk1EsIS8aTDX4Xo9qajAh6mYtcl4kJrBkGXuxZPEgVr7RVfAvNW6YQkd4Mw== - dependencies: - "@babel/helper-plugin-utils" "^7.13.0" - "@babel/plugin-transform-template-literals@^7.14.5": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.16.0.tgz#a8eced3a8e7b8e2d40ec4ec4548a45912630d302" @@ -1997,13 +1079,6 @@ dependencies: "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-transform-typeof-symbol@^7.12.10": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.12.13.tgz#785dd67a1f2ea579d9c2be722de8c84cb85f5a7f" - integrity sha512-eKv/LmUJpMnu4npgfvs3LiHhJua5fo/CysENxa45YCQXZwKnGCQKAg87bvoqSW1fFT+HA32l03Qxsm8ouTY3ZQ== - dependencies: - "@babel/helper-plugin-utils" "^7.12.13" - "@babel/plugin-transform-typeof-symbol@^7.14.5": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.16.0.tgz#8b19a244c6f8c9d668dca6a6f754ad6ead1128f2" @@ -2011,13 +1086,6 @@ dependencies: "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-transform-unicode-escapes@^7.12.1": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.12.13.tgz#840ced3b816d3b5127dd1d12dcedc5dead1a5e74" - integrity sha512-0bHEkdwJ/sN/ikBHfSmOXPypN/beiGqjo+o4/5K+vxEFNPRPdImhviPakMKG4x96l85emoa0Z6cDflsdBusZbw== - dependencies: - "@babel/helper-plugin-utils" "^7.12.13" - "@babel/plugin-transform-unicode-escapes@^7.14.5": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.16.0.tgz#1a354064b4c45663a32334f46fa0cf6100b5b1f3" @@ -2025,14 +1093,6 @@ dependencies: "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-transform-unicode-regex@^7.12.1": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.12.13.tgz#b52521685804e155b1202e83fc188d34bb70f5ac" - integrity sha512-mDRzSNY7/zopwisPZ5kM9XKCfhchqIYwAKRERtEnhYscZB79VRekuRSoYbN0+KVe3y8+q1h6A4svXtP7N+UoCA== - dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.12.13" - "@babel/helper-plugin-utils" "^7.12.13" - "@babel/plugin-transform-unicode-regex@^7.14.5": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.16.0.tgz#293b80950177c8c85aede87cef280259fb995402" @@ -2041,78 +1101,6 @@ "@babel/helper-create-regexp-features-plugin" "^7.16.0" "@babel/helper-plugin-utils" "^7.14.5" -"@babel/preset-env@7.12.11": - version "7.12.11" - resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.12.11.tgz#55d5f7981487365c93dbbc84507b1c7215e857f9" - integrity sha512-j8Tb+KKIXKYlDBQyIOy4BLxzv1NUOwlHfZ74rvW+Z0Gp4/cI2IMDPBWAgWceGcE7aep9oL/0K9mlzlMGxA8yNw== - dependencies: - "@babel/compat-data" "^7.12.7" - "@babel/helper-compilation-targets" "^7.12.5" - "@babel/helper-module-imports" "^7.12.5" - "@babel/helper-plugin-utils" "^7.10.4" - "@babel/helper-validator-option" "^7.12.11" - "@babel/plugin-proposal-async-generator-functions" "^7.12.1" - "@babel/plugin-proposal-class-properties" "^7.12.1" - "@babel/plugin-proposal-dynamic-import" "^7.12.1" - "@babel/plugin-proposal-export-namespace-from" "^7.12.1" - "@babel/plugin-proposal-json-strings" "^7.12.1" - "@babel/plugin-proposal-logical-assignment-operators" "^7.12.1" - "@babel/plugin-proposal-nullish-coalescing-operator" "^7.12.1" - "@babel/plugin-proposal-numeric-separator" "^7.12.7" - "@babel/plugin-proposal-object-rest-spread" "^7.12.1" - "@babel/plugin-proposal-optional-catch-binding" "^7.12.1" - "@babel/plugin-proposal-optional-chaining" "^7.12.7" - "@babel/plugin-proposal-private-methods" "^7.12.1" - "@babel/plugin-proposal-unicode-property-regex" "^7.12.1" - "@babel/plugin-syntax-async-generators" "^7.8.0" - "@babel/plugin-syntax-class-properties" "^7.12.1" - "@babel/plugin-syntax-dynamic-import" "^7.8.0" - "@babel/plugin-syntax-export-namespace-from" "^7.8.3" - "@babel/plugin-syntax-json-strings" "^7.8.0" - "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" - "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.0" - "@babel/plugin-syntax-numeric-separator" "^7.10.4" - "@babel/plugin-syntax-object-rest-spread" "^7.8.0" - "@babel/plugin-syntax-optional-catch-binding" "^7.8.0" - "@babel/plugin-syntax-optional-chaining" "^7.8.0" - "@babel/plugin-syntax-top-level-await" "^7.12.1" - "@babel/plugin-transform-arrow-functions" "^7.12.1" - "@babel/plugin-transform-async-to-generator" "^7.12.1" - "@babel/plugin-transform-block-scoped-functions" "^7.12.1" - "@babel/plugin-transform-block-scoping" "^7.12.11" - "@babel/plugin-transform-classes" "^7.12.1" - "@babel/plugin-transform-computed-properties" "^7.12.1" - "@babel/plugin-transform-destructuring" "^7.12.1" - "@babel/plugin-transform-dotall-regex" "^7.12.1" - "@babel/plugin-transform-duplicate-keys" "^7.12.1" - "@babel/plugin-transform-exponentiation-operator" "^7.12.1" - "@babel/plugin-transform-for-of" "^7.12.1" - "@babel/plugin-transform-function-name" "^7.12.1" - "@babel/plugin-transform-literals" "^7.12.1" - "@babel/plugin-transform-member-expression-literals" "^7.12.1" - "@babel/plugin-transform-modules-amd" "^7.12.1" - "@babel/plugin-transform-modules-commonjs" "^7.12.1" - "@babel/plugin-transform-modules-systemjs" "^7.12.1" - "@babel/plugin-transform-modules-umd" "^7.12.1" - "@babel/plugin-transform-named-capturing-groups-regex" "^7.12.1" - "@babel/plugin-transform-new-target" "^7.12.1" - "@babel/plugin-transform-object-super" "^7.12.1" - "@babel/plugin-transform-parameters" "^7.12.1" - "@babel/plugin-transform-property-literals" "^7.12.1" - "@babel/plugin-transform-regenerator" "^7.12.1" - "@babel/plugin-transform-reserved-words" "^7.12.1" - "@babel/plugin-transform-shorthand-properties" "^7.12.1" - "@babel/plugin-transform-spread" "^7.12.1" - "@babel/plugin-transform-sticky-regex" "^7.12.7" - "@babel/plugin-transform-template-literals" "^7.12.1" - "@babel/plugin-transform-typeof-symbol" "^7.12.10" - "@babel/plugin-transform-unicode-escapes" "^7.12.1" - "@babel/plugin-transform-unicode-regex" "^7.12.1" - "@babel/preset-modules" "^0.1.3" - "@babel/types" "^7.12.11" - core-js-compat "^3.8.0" - semver "^5.5.0" - "@babel/preset-env@7.14.8": version "7.14.8" resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.14.8.tgz#254942f5ca80ccabcfbb2a9f524c74bca574005b" @@ -2192,17 +1180,6 @@ core-js-compat "^3.15.0" semver "^6.3.0" -"@babel/preset-modules@^0.1.3": - version "0.1.4" - resolved "https://registry.yarnpkg.com/@babel/preset-modules/-/preset-modules-0.1.4.tgz#362f2b68c662842970fdb5e254ffc8fc1c2e415e" - integrity sha512-J36NhwnfdzpmH41M1DrnkkgAqhZaqr/NBdPfQ677mLzlaXo+oDiv1deyCDtgAhz8p328otdob0Du7+xgHGZbKg== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-proposal-unicode-property-regex" "^7.4.4" - "@babel/plugin-transform-dotall-regex" "^7.4.4" - "@babel/types" "^7.4.4" - esutils "^2.0.2" - "@babel/preset-modules@^0.1.4": version "0.1.5" resolved "https://registry.yarnpkg.com/@babel/preset-modules/-/preset-modules-0.1.5.tgz#ef939d6e7f268827e1841638dc6ff95515e115d9" @@ -2214,13 +1191,6 @@ "@babel/types" "^7.4.4" esutils "^2.0.2" -"@babel/runtime@7.12.5", "@babel/runtime@^7.12.5": - version "7.12.5" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.12.5.tgz#410e7e487441e1b360c29be715d870d9b985882e" - integrity sha512-plcc+hbExy3McchJCEQG3knOsuh3HH+Prx1P6cLIkET/0dLuQDEnrT+s27Axgc9bqfsmNUNHfscgMUdBpC9xfg== - dependencies: - regenerator-runtime "^0.13.4" - "@babel/runtime@7.14.8": version "7.14.8" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.14.8.tgz#7119a56f421018852694290b9f9148097391b446" @@ -2228,22 +1198,13 @@ dependencies: regenerator-runtime "^0.13.4" -"@babel/runtime@^7.10.1", "@babel/runtime@^7.11.1", "@babel/runtime@^7.11.2", "@babel/runtime@^7.3.1", "@babel/runtime@^7.4.4", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.0", "@babel/runtime@^7.8.3", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7": - version "7.11.2" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.11.2.tgz#f549c13c754cc40b87644b9fa9f09a6a95fe0736" - integrity sha512-TeWkU52so0mPtDcaCTxNBI/IHiz0pZgr8VEFqXFtZWpYD08ZB6FaSwVAS8MKRQAP3bYKiVjwysOJgMFY28o6Tw== +"@babel/runtime@^7.10.1", "@babel/runtime@^7.11.1", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.3.1", "@babel/runtime@^7.4.4", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.0", "@babel/runtime@^7.8.3", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7": + version "7.16.3" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.16.3.tgz#b86f0db02a04187a3c17caa77de69840165d42d5" + integrity sha512-WBwekcqacdY2e9AF/Q7WLFUWmdJGJTkbjqTjoMDgXkVZ3ZRUvOPsLb5KdwISoQVsbP+DQzVZW4Zhci0DvpbNTQ== dependencies: regenerator-runtime "^0.13.4" -"@babel/template@7.12.7": - version "7.12.7" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.12.7.tgz#c817233696018e39fbb6c491d2fb684e05ed43bc" - integrity sha512-GkDzmHS6GV7ZeXfJZ0tLRBhZcMcY0/Lnb+eEbXDBfCAcZCjrZKe6p3J4we/D24O9Y8enxWAg1cWwof59yLh2ow== - dependencies: - "@babel/code-frame" "^7.10.4" - "@babel/parser" "^7.12.7" - "@babel/types" "^7.12.7" - "@babel/template@7.14.5": version "7.14.5" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.14.5.tgz#a9bc9d8b33354ff6e55a9c60d1109200a68974f4" @@ -2253,24 +1214,6 @@ "@babel/parser" "^7.14.5" "@babel/types" "^7.14.5" -"@babel/template@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.10.4.tgz#3251996c4200ebc71d1a8fc405fba940f36ba278" - integrity sha512-ZCjD27cGJFUB6nmCB1Enki3r+L5kJveX9pq1SvAUKoICy6CZ9yD8xO086YXdYhvNjBdnekm4ZnaP5yC8Cs/1tA== - dependencies: - "@babel/code-frame" "^7.10.4" - "@babel/parser" "^7.10.4" - "@babel/types" "^7.10.4" - -"@babel/template@^7.12.13", "@babel/template@^7.12.7": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.12.13.tgz#530265be8a2589dbb37523844c5bcb55947fb327" - integrity sha512-/7xxiGA57xMo/P2GVvdEumr8ONhFOhfgq2ihK3h1e6THqzTAkHbkXgB0xI9yeTfIUoH3+oAeHhqm/I43OTbbjA== - dependencies: - "@babel/code-frame" "^7.12.13" - "@babel/parser" "^7.12.13" - "@babel/types" "^7.12.13" - "@babel/template@^7.14.5", "@babel/template@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.16.0.tgz#d16a35ebf4cd74e202083356fab21dd89363ddd6" @@ -2280,36 +1223,7 @@ "@babel/parser" "^7.16.0" "@babel/types" "^7.16.0" -"@babel/traverse@^7.10.4", "@babel/traverse@^7.11.5": - version "7.11.5" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.11.5.tgz#be777b93b518eb6d76ee2e1ea1d143daa11e61c3" - integrity sha512-EjiPXt+r7LiCZXEfRpSJd+jUMnBd4/9OUv7Nx3+0u9+eimMwJmG0Q98lw4/289JCoxSE8OolDMNZaaF/JZ69WQ== - dependencies: - "@babel/code-frame" "^7.10.4" - "@babel/generator" "^7.11.5" - "@babel/helper-function-name" "^7.10.4" - "@babel/helper-split-export-declaration" "^7.11.0" - "@babel/parser" "^7.11.5" - "@babel/types" "^7.11.5" - debug "^4.1.0" - globals "^11.1.0" - lodash "^4.17.19" - -"@babel/traverse@^7.12.10", "@babel/traverse@^7.13.0", "@babel/traverse@^7.13.15", "@babel/traverse@^7.14.0", "@babel/traverse@^7.14.2": - version "7.14.2" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.14.2.tgz#9201a8d912723a831c2679c7ebbf2fe1416d765b" - integrity sha512-TsdRgvBFHMyHOOzcP9S6QU0QQtjxlRpEYOy3mcCO5RgmC305ki42aSAmfZEMSSYBla2oZ9BMqYlncBaKmD/7iA== - dependencies: - "@babel/code-frame" "^7.12.13" - "@babel/generator" "^7.14.2" - "@babel/helper-function-name" "^7.14.2" - "@babel/helper-split-export-declaration" "^7.12.13" - "@babel/parser" "^7.14.2" - "@babel/types" "^7.14.2" - debug "^4.1.0" - globals "^11.1.0" - -"@babel/traverse@^7.14.8", "@babel/traverse@^7.16.0", "@babel/traverse@^7.16.3": +"@babel/traverse@^7.13.0", "@babel/traverse@^7.14.8", "@babel/traverse@^7.16.0", "@babel/traverse@^7.16.3": version "7.16.3" resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.16.3.tgz#f63e8a938cc1b780f66d9ed3c54f532ca2d14787" integrity sha512-eolumr1vVMjqevCpwVO99yN/LoGL0EyHiLO5I043aYQvwOJ9eR5UsZSClHVCzfhBduMAsSzgA/6AyqPjNayJag== @@ -2324,24 +1238,7 @@ debug "^4.1.0" globals "^11.1.0" -"@babel/types@^7.10.4", "@babel/types@^7.11.0", "@babel/types@^7.11.5", "@babel/types@^7.4.4": - version "7.11.5" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.11.5.tgz#d9de577d01252d77c6800cee039ee64faf75662d" - integrity sha512-bvM7Qz6eKnJVFIn+1LPtjlBFPVN5jNDc1XmN15vWe7Q3DPBufWWsLiIvUu7xW87uTG6QoggpIDnUgLQvPheU+Q== - dependencies: - "@babel/helper-validator-identifier" "^7.10.4" - lodash "^4.17.19" - to-fast-properties "^2.0.0" - -"@babel/types@^7.12.1", "@babel/types@^7.12.10", "@babel/types@^7.12.11", "@babel/types@^7.12.13", "@babel/types@^7.12.7", "@babel/types@^7.13.0", "@babel/types@^7.13.12", "@babel/types@^7.13.16", "@babel/types@^7.14.0", "@babel/types@^7.14.2", "@babel/types@^7.8.6": - version "7.14.2" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.14.2.tgz#4208ae003107ef8a057ea8333e56eb64d2f6a2c3" - integrity sha512-SdjAG/3DikRHpUOjxZgnkbR11xUlyDMUFJdvnIgZEE16mqmY0BINMmc4//JMJglEmn6i7sq6p+mGrFWyZ98EEw== - dependencies: - "@babel/helper-validator-identifier" "^7.14.0" - to-fast-properties "^2.0.0" - -"@babel/types@^7.14.5", "@babel/types@^7.14.8", "@babel/types@^7.16.0": +"@babel/types@^7.14.5", "@babel/types@^7.14.8", "@babel/types@^7.16.0", "@babel/types@^7.4.4", "@babel/types@^7.8.6": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.16.0.tgz#db3b313804f96aadd0b776c4823e127ad67289ba" integrity sha512-PJgg/k3SdLsGb3hhisFvtLOw5ts113klrpLuIPtCJIU+BB24fqq6lf8RWqKJEjzqXR9AEH1rIb5XTqwBHB+kQg== @@ -2349,6 +1246,18 @@ "@babel/helper-validator-identifier" "^7.15.7" to-fast-properties "^2.0.0" +"@cspotcode/source-map-consumer@0.8.0": + version "0.8.0" + resolved "https://registry.yarnpkg.com/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz#33bf4b7b39c178821606f669bbc447a6a629786b" + integrity sha512-41qniHzTU8yAGbCp04ohlmSrZf8bkf/iJsl3V0dRGsQN/5GFfx+LbCSsCpp2gqrqjTVg/K6O8ycoV35JIwAzAg== + +"@cspotcode/source-map-support@0.7.0": + version "0.7.0" + resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.7.0.tgz#4789840aa859e46d2f3173727ab707c66bf344f5" + integrity sha512-X4xqRHqN8ACt2aHVe51OxeA2HjbcL4MqFqXkrmQszJ1NOUuUu5u6Vqx/0lZSVNku7velL5FC/s5uEAj1lsBMhA== + dependencies: + "@cspotcode/source-map-consumer" "0.8.0" + "@csstools/convert-colors@^1.4.0": version "1.4.0" resolved "https://registry.yarnpkg.com/@csstools/convert-colors/-/convert-colors-1.4.0.tgz#ad495dc41b12e75d588c6db8b9834f08fa131eb7" @@ -2359,22 +1268,17 @@ resolved "https://registry.yarnpkg.com/@date-io/core/-/core-1.3.13.tgz#90c71da493f20204b7a972929cc5c482d078b3fa" integrity sha512-AlEKV7TxjeK+jxWVKcCFrfYAk8spX9aCyiToFIiLPtfQbsjmRGLIhb5VZgptQcJdHtLXo7+m0DuurwFgUToQuA== -"@date-io/core@^2.10.11": - version "2.10.11" - resolved "https://registry.yarnpkg.com/@date-io/core/-/core-2.10.11.tgz#b1a3d57730f3eaaab54d5658be4a71727297e357" - integrity sha512-keXQnwH0LM8wyvu+j5Z2KGK56D+eItjy7DnwuWl/oV+DM2UEYl0z5WhdPMpfswSyt/kjuPOzcVF/7u/skMLaoA== +"@date-io/core@^2.11.0": + version "2.11.0" + resolved "https://registry.yarnpkg.com/@date-io/core/-/core-2.11.0.tgz#28580cda1c8228ab2c7ed6aee673ef0495f913e6" + integrity sha512-DvPBnNoeuLaoSJZaxgpu54qzRhRKjSYVyQjhznTFrllKuDpm0sDFjHo6lvNLCM/cfMx2gb2PM2zY2kc9C8nmuw== -"@date-io/date-fns@^2.10.11": - version "2.10.11" - resolved "https://registry.yarnpkg.com/@date-io/date-fns/-/date-fns-2.10.11.tgz#1f3b40c6f2ea2e659260ca329fef80cb6dc64704" - integrity sha512-QG9IAZ4bvwkJftoSVKtdb5ISH+Qp4zilrjhzcL4RXaeqkfIWiFeXqQPgJljvPl6gQ04zf2SjGkWjdh1eJxxwmQ== +"@date-io/date-fns@^2.11.0": + version "2.11.0" + resolved "https://registry.yarnpkg.com/@date-io/date-fns/-/date-fns-2.11.0.tgz#142fbf954eda7ad66514af7a2802d78c4ea40053" + integrity sha512-mPQ71plBeFrArvBSHtjWMHXA89IUbZ6kuo2dsjlRC/1uNOybo91spIb+wTu03NxKTl8ut07s0jJ9svF71afpRg== dependencies: - "@date-io/core" "^2.10.11" - -"@discoveryjs/json-ext@0.5.2": - version "0.5.2" - resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.2.tgz#8f03a22a04de437254e8ce8cc84ba39689288752" - integrity sha512-HyYEUDeIj5rRQU2Hk5HTB2uHsbRQpF70nvMhVzi+VJR0X+xNEhjPui4/kBf3VeH/wqD28PT4sVOm8qqLjBrSZg== + "@date-io/core" "^2.11.0" "@discoveryjs/json-ext@0.5.3": version "0.5.3" @@ -2417,9 +1321,14 @@ polygon-clipping "0.15.3" "@istanbuljs/schema@^0.1.2": - version "0.1.2" - resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.2.tgz#26520bf09abe4a5644cd5414e37125a8954241dd" - integrity sha512-tsAQNx32a8CoFhjhijUIhI4kccIAgmGhy8LZMZgGfmXcpMbPRUqn5LWmgRttILi6yeGmBJd2xsPkFMs0PzgPCw== + version "0.1.3" + resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.3.tgz#e45e384e4b8ec16bce2fd903af78450f6bf7ec98" + integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA== + +"@jcubic/lily@^0.3.0": + version "0.3.0" + resolved "https://registry.yarnpkg.com/@jcubic/lily/-/lily-0.3.0.tgz#00b229aab69fe094a57fd37f27d32dd4f380c1d1" + integrity sha512-4z6p4jLGSthc8gQ7wu4nHfGYn/IgCKFr+7hjuf80VdXUs7sm029mZGGDpS8sb29PVZWUBvMMTBCVGFhH2nN4Vw== "@jridgewell/resolve-uri@1.0.0": version "1.0.0" @@ -2449,14 +1358,14 @@ dependencies: tslib "^2.3.0" -"@material-ui/core@^4.11.4": - version "4.11.4" - resolved "https://registry.yarnpkg.com/@material-ui/core/-/core-4.11.4.tgz#4fb9fe5dec5dcf780b687e3a40cff78b2b9640a4" - integrity sha512-oqb+lJ2Dl9HXI9orc6/aN8ZIAMkeThufA5iZELf2LQeBn2NtjVilF5D2w7e9RpntAzDb4jK5DsVhkfOvFY/8fg== +"@material-ui/core@^4.12.3": + version "4.12.3" + resolved "https://registry.yarnpkg.com/@material-ui/core/-/core-4.12.3.tgz#80d665caf0f1f034e52355c5450c0e38b099d3ca" + integrity sha512-sdpgI/PL56QVsEJldwEe4FFaFTLUqN+rd7sSZiRCdx2E/C7z5yK0y/khAWVBH24tXwto7I1hCzNWfJGZIYJKnw== dependencies: "@babel/runtime" "^7.4.4" "@material-ui/styles" "^4.11.4" - "@material-ui/system" "^4.11.3" + "@material-ui/system" "^4.12.1" "@material-ui/types" "5.1.0" "@material-ui/utils" "^4.11.2" "@types/react-transition-group" "^4.2.0" @@ -2508,10 +1417,10 @@ jss-plugin-vendor-prefixer "^10.5.1" prop-types "^15.7.2" -"@material-ui/system@^4.11.3": - version "4.11.3" - resolved "https://registry.yarnpkg.com/@material-ui/system/-/system-4.11.3.tgz#466bc14c9986798fd325665927c963eb47cc4143" - integrity sha512-SY7otguNGol41Mu2Sg6KbBP1ZRFIbFLHGK81y4KYbsV2yIcaEPOmsCK6zwWlp+2yTV3J/VwT6oSBARtGIVdXPw== +"@material-ui/system@^4.12.1": + version "4.12.1" + resolved "https://registry.yarnpkg.com/@material-ui/system/-/system-4.12.1.tgz#2dd96c243f8c0a331b2bb6d46efd7771a399707c" + integrity sha512-lUdzs4q9kEXZGhbN7BptyiS1rLNHe6kG9o8Y307HCvF4sQxbCgpL2qi+gUk+yI8a2DNk48gISEQxoxpgph0xIw== dependencies: "@babel/runtime" "^7.4.4" "@material-ui/utils" "^4.11.2" @@ -2553,15 +1462,6 @@ dependencies: tslib "^2.0.0" -"@ngtools/webpack@11.2.13": - version "11.2.13" - resolved "https://registry.yarnpkg.com/@ngtools/webpack/-/webpack-11.2.13.tgz#dbd77deb37ab57fd98678bd637fe87693fd71f4f" - integrity sha512-Wbv1zjLaS1zXcJ1wryYc6vhKWq8r/+ZrdN5SlRIf3xf7fwuTymbvL41SndUibssXir6s4vePYqZL241nkThx9g== - dependencies: - "@angular-devkit/core" "11.2.13" - enhanced-resolve "5.7.0" - webpack-sources "2.2.0" - "@ngtools/webpack@12.2.13", "@ngtools/webpack@~12.2.13": version "12.2.13" resolved "https://registry.yarnpkg.com/@ngtools/webpack/-/webpack-12.2.13.tgz#44d711edfa39d175a2d655aa5c6f9968dfedcc35" @@ -2581,25 +1481,25 @@ dependencies: tslib "^2.0.0" -"@nodelib/fs.scandir@2.1.3": - version "2.1.3" - resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz#3a582bdb53804c6ba6d146579c46e52130cf4a3b" - integrity sha512-eGmwYQn3gxo4r7jdQnkrrN6bY478C3P+a/y72IJukF8LjB6ZHeB3c+Ehacj3sYeSmUXGlnA67/PmbM9CVwL7Dw== +"@nodelib/fs.scandir@2.1.5": + version "2.1.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" + integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== dependencies: - "@nodelib/fs.stat" "2.0.3" + "@nodelib/fs.stat" "2.0.5" run-parallel "^1.1.9" -"@nodelib/fs.stat@2.0.3", "@nodelib/fs.stat@^2.0.2": - version "2.0.3" - resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.3.tgz#34dc5f4cabbc720f4e60f75a747e7ecd6c175bd3" - integrity sha512-bQBFruR2TAwoevBEd/NWMoAAtNGzTRgdrqnYCc7dhzfoNvqPzLyqlEQnzZ3kVnNrSp25iyxE00/3h2fqGAGArA== +"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": + version "2.0.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" + integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== "@nodelib/fs.walk@^1.2.3": - version "1.2.4" - resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.4.tgz#011b9202a70a6366e436ca5c065844528ab04976" - integrity sha512-1V9XOY4rDW0rehzbrcqAmHnz8e7SKvX27gh8Gt2WgB0+pdzdiLV83p72kZPU+jvMbS1qU5mauP2iOvO8rhmurQ== + version "1.2.8" + resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" + integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== dependencies: - "@nodelib/fs.scandir" "2.1.3" + "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" "@npmcli/fs@^1.0.0": @@ -2633,16 +1533,17 @@ npm-normalize-package-bin "^1.0.1" "@npmcli/move-file@^1.0.1": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@npmcli/move-file/-/move-file-1.0.1.tgz#de103070dac0f48ce49cf6693c23af59c0f70464" - integrity sha512-Uv6h1sT+0DrblvIrolFtbvM1FgWm+/sy4B3pvLp67Zys+thcukzS5ekn7HsZFGpWP4Q3fYJCljbWQE/XivMRLw== + version "1.1.2" + resolved "https://registry.yarnpkg.com/@npmcli/move-file/-/move-file-1.1.2.tgz#1a82c3e372f7cae9253eb66d72543d6b8685c674" + integrity sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg== dependencies: mkdirp "^1.0.4" + rimraf "^3.0.2" "@npmcli/node-gyp@^1.0.2": - version "1.0.2" - resolved "https://registry.yarnpkg.com/@npmcli/node-gyp/-/node-gyp-1.0.2.tgz#3cdc1f30e9736dbc417373ed803b42b1a0a29ede" - integrity sha512-yrJUe6reVMpktcvagumoqD9r08fH1iRo01gn1u0zoCApa9lnZGEigVKUd2hzsCId4gdtkZZIVscLhNxMECKgRg== + version "1.0.3" + resolved "https://registry.yarnpkg.com/@npmcli/node-gyp/-/node-gyp-1.0.3.tgz#a912e637418ffc5f2db375e93b85837691a43a33" + integrity sha512-fnkhw+fmX65kiLqk6E3BFLXNC26rUhK90zVwe2yncPliVT/Qos3xjhTLE59Df8KnPlcwIERXKVlU1bXoUQ+liA== "@npmcli/promise-spawn@^1.2.0", "@npmcli/promise-spawn@^1.3.2": version "1.3.2" @@ -2675,16 +1576,31 @@ resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82" integrity sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw== -"@trysound/sax@0.1.1": - version "0.1.1" - resolved "https://registry.yarnpkg.com/@trysound/sax/-/sax-0.1.1.tgz#3348564048e7a2d7398c935d466c0414ebb6a669" - integrity sha512-Z6DoceYb/1xSg5+e+ZlPZ9v0N16ZvZ+wYMraFue4HYrE4ttONKtsvruIRf6t9TBR0YvSOfi1hUU0fJfBLCDYow== - "@trysound/sax@0.2.0": version "0.2.0" resolved "https://registry.yarnpkg.com/@trysound/sax/-/sax-0.2.0.tgz#cccaab758af56761eb7bf37af6f03f326dd798ad" integrity sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA== +"@tsconfig/node10@^1.0.7": + version "1.0.8" + resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.8.tgz#c1e4e80d6f964fbecb3359c43bd48b40f7cadad9" + integrity sha512-6XFfSQmMgq0CFLY1MslA/CPUfhIL919M1rMsa5lP2P097N2Wd1sSX0tx1u4olM16fLNhtHZpRhedZJphNJqmZg== + +"@tsconfig/node12@^1.0.7": + version "1.0.9" + resolved "https://registry.yarnpkg.com/@tsconfig/node12/-/node12-1.0.9.tgz#62c1f6dee2ebd9aead80dc3afa56810e58e1a04c" + integrity sha512-/yBMcem+fbvhSREH+s14YJi18sp7J9jpuhYByADT2rypfajMZZN4WQ6zBGgBKp53NKmqI36wFYDb3yaMPurITw== + +"@tsconfig/node14@^1.0.0": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@tsconfig/node14/-/node14-1.0.1.tgz#95f2d167ffb9b8d2068b0b235302fafd4df711f2" + integrity sha512-509r2+yARFfHHE7T6Puu2jjkoycftovhXRqW328PDXTVGKihlb1P8Z9mMZH04ebyajfRY7dedfGynlrFHJUQCg== + +"@tsconfig/node16@^1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.2.tgz#423c77877d0569db20e1fc80885ac4118314010e" + integrity sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA== + "@turf/bbox@*", "@turf/bbox@^6.3.0": version "6.5.0" resolved "https://registry.yarnpkg.com/@turf/bbox/-/bbox-6.5.0.tgz#bec30a744019eae420dac9ea46fb75caa44d8dc5" @@ -2846,25 +1762,25 @@ "@turf/helpers" "^6.5.0" "@turf/meta" "^6.5.0" -"@types/canvas-gauges@^2.1.2": - version "2.1.2" - resolved "https://registry.yarnpkg.com/@types/canvas-gauges/-/canvas-gauges-2.1.2.tgz#fb9ece324cb15ae137791ad21eb2db70e11a7210" - integrity sha512-oWCq0XjsTBXPtMKXoW23ORbMWguC2Fa8o5NiZVYiUoQMMrpNLKj1E+LDznlMpcib3iyWVIy+TEpc/ea6LMbW3Q== +"@types/canvas-gauges@^2.1.4": + version "2.1.4" + resolved "https://registry.yarnpkg.com/@types/canvas-gauges/-/canvas-gauges-2.1.4.tgz#063881264597d098e78cf5ad921e8ed20ae2ad16" + integrity sha512-JTvqQWrqcrgzCp/9+uzwUvPef2qAEnBJvm+bL9kvulzhXapDeNaGQXCIAZp+hOryusjOyndvP1za2HZooUV0XA== "@types/component-emitter@^1.2.10": - version "1.2.10" - resolved "https://registry.yarnpkg.com/@types/component-emitter/-/component-emitter-1.2.10.tgz#ef5b1589b9f16544642e473db5ea5639107ef3ea" - integrity sha512-bsjleuRKWmGqajMerkzox19aGbscQX5rmmvvXl3wlIp5gMG1HgkiwPxsN5p070fBDKTNSPgojVbuY1+HWMbFhg== + version "1.2.11" + resolved "https://registry.yarnpkg.com/@types/component-emitter/-/component-emitter-1.2.11.tgz#50d47d42b347253817a39709fef03ce66a108506" + integrity sha512-SRXjM+tfsSlA9VuG8hGO2nft2p8zjXCK1VcC6N4NXbBbYbSia9kzCChYQajIjzIqOOOuh5Ock6MmV2oux4jDZQ== -"@types/cookie@^0.4.0": - version "0.4.0" - resolved "https://registry.yarnpkg.com/@types/cookie/-/cookie-0.4.0.tgz#14f854c0f93d326e39da6e3b6f34f7d37513d108" - integrity sha512-y7mImlc/rNkvCRmg8gC3/lj87S7pTUIJ6QGjwHR9WQJcFs+ZMTOaoPrkdFA/YdbuqVEmEbb5RdhVxMkAcgOnpg== +"@types/cookie@^0.4.1": + version "0.4.1" + resolved "https://registry.yarnpkg.com/@types/cookie/-/cookie-0.4.1.tgz#bfd02c1f2224567676c1545199f87c3a861d878d" + integrity sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q== -"@types/cors@^2.8.8": - version "2.8.10" - resolved "https://registry.yarnpkg.com/@types/cors/-/cors-2.8.10.tgz#61cc8469849e5bcdd0c7044122265c39cec10cf4" - integrity sha512-C7srjHiVG3Ey1nR6d511dtDkCEjxuN9W1HWAEjGq8kpcwmNM6JJkpC0xvabM7BXTG2wDq8Eu33iH9aQKa7IvLQ== +"@types/cors@^2.8.12": + version "2.8.12" + resolved "https://registry.yarnpkg.com/@types/cors/-/cors-2.8.12.tgz#6b2c510a7ad7039e98e7b8d3d6598f4359e5c080" + integrity sha512-vt+kDhq/M2ayberEtJcIN/hxXy1Pk+59g2FV/ZQceeaTyCtCucjL2Q7FXlFjtWn4n15KCr1NE2lNNFhp0lEThw== "@types/eslint-scope@^3.7.0": version "3.7.1" @@ -2887,10 +1803,10 @@ resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.50.tgz#1e0caa9364d3fccd2931c3ed96fdbeaa5d4cca83" integrity sha512-C6N5s2ZFtuZRj54k2/zyRhNDjJwwcViAM3Nbm8zjBpbqAdZ00mr0CFxvSKeO8Y/e03WVFLpQMdHYVfUd6SB+Hw== -"@types/flot@^0.0.31": - version "0.0.31" - resolved "https://registry.yarnpkg.com/@types/flot/-/flot-0.0.31.tgz#0daca37c6c855b69a0a7e2e37dd0f84b3db8c8c1" - integrity sha512-X+RcMQCqPlQo8zPT6cUFTd/PoYBShMQlHUeOXf05jWlfYnvLuRmluB9z+2EsOKFgUzqzZve5brx+gnFxBaHEUw== +"@types/flot@^0.0.32": + version "0.0.32" + resolved "https://registry.yarnpkg.com/@types/flot/-/flot-0.0.32.tgz#2ab260f2958dcab1acfb5c24b87898f1d22417d8" + integrity sha512-aturel4TWMY86N4Pkpc9pSoUd/p8c3BjGj4fTDkaZIpkRPzLH1VXZCAKGUywcFkTqgZMhPJFPWxd4pl87y8h/w== dependencies: "@types/jquery" "*" @@ -2899,84 +1815,62 @@ resolved "https://registry.yarnpkg.com/@types/flowjs/-/flowjs-2.13.3.tgz#4f1ba77d9259f4be83ecaa985db96fa758b2fd22" integrity sha512-VeWuL+Whk6lUSWX/g0LzLNyZywyTB5wZ2L6mPvD8/u5pgLF2HwyV7nZ1UArOifalJ5UE1CcJbPLKS+jc5+Z2ig== -"@types/geojson@*": - version "7946.0.7" - resolved "https://registry.yarnpkg.com/@types/geojson/-/geojson-7946.0.7.tgz#c8fa532b60a0042219cdf173ca21a975ef0666ad" - integrity sha512-wE2v81i4C4Ol09RtsWFAqg3BUitWbHSpSlIo+bNdsCJijO9sjme+zm+73ZMCa/qMC8UEERxzGbvmr1cffo2SiQ== - -"@types/geojson@7946.0.8": +"@types/geojson@*", "@types/geojson@7946.0.8": version "7946.0.8" resolved "https://registry.yarnpkg.com/@types/geojson/-/geojson-7946.0.8.tgz#30744afdb385e2945e22f3b033f897f76b1f12ca" integrity sha512-1rkryxURpr6aWP7R786/UQOkJ3PcpQiWkAXBmdWc7ryFWqN6a4xfK7BtjXvFBKO9LjQ+MWQSWxYeZX1OApnArA== "@types/glob@^7.1.1": - version "7.1.3" - resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.1.3.tgz#e6ba80f36b7daad2c685acd9266382e68985c183" - integrity sha512-SEYeGAIQIQX8NN6LDKprLjbrd5dARM5EXsd8GI/A5l0apYI1fGMWgPHSe4ZKL4eozlAyI+doUE9XbYS4xCkQ1w== + version "7.2.0" + resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.2.0.tgz#bc1b5bf3aa92f25bd5dd39f35c57361bdce5b2eb" + integrity sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA== dependencies: "@types/minimatch" "*" "@types/node" "*" -"@types/jasmine@*": - version "3.5.14" - resolved "https://registry.yarnpkg.com/@types/jasmine/-/jasmine-3.5.14.tgz#f41a14e8ffa939062a71cf9722e5ee7d4e1f94af" - integrity sha512-Fkgk536sHPqcOtd+Ow+WiUNuk0TSo/BntKkF8wSvcd6M2FvPjeXcUE6Oz/bwDZiUZEaXLslAgw00Q94Pnx6T4w== +"@types/hammerjs@^2.0.39": + version "2.0.40" + resolved "https://registry.yarnpkg.com/@types/hammerjs/-/hammerjs-2.0.40.tgz#ded0240b6ea1ad7afc1e60374c49087aaea5dbd8" + integrity sha512-VbjwR1fhsn2h2KXAY4oy1fm7dCxaKy0D+deTb8Ilc3Eo3rc5+5eA4rfYmZaHgNJKxVyI0f6WIXzO2zLkVmQPHA== -"@types/jasmine@~3.7.4": - version "3.7.4" - resolved "https://registry.yarnpkg.com/@types/jasmine/-/jasmine-3.7.4.tgz#99a49aa9a5f8dc86fc249ed13ed59552c6ce862d" - integrity sha512-L3FKeEwMm8e8hqGvt7cSesVmGtavpRyHV1FNDq+Pm5pS4x5eFmE70ZERXCSBWAiLQqXBcZRUrwV59FZLQl/GxQ== +"@types/jasmine@*", "@types/jasmine@~3.10.2": + version "3.10.2" + resolved "https://registry.yarnpkg.com/@types/jasmine/-/jasmine-3.10.2.tgz#1b9f9ba9ad7bfd7d322f7ed9d8753220b1c84b52" + integrity sha512-qs4xjVm4V/XjM6owGm/x6TNmhGl5iKX8dkTdsgdgl9oFnqgzxLepnS7rN9Tdo7kDmnFD/VEqKrW57cGD2odbEg== -"@types/jasminewd2@^2.0.9": - version "2.0.9" - resolved "https://registry.yarnpkg.com/@types/jasminewd2/-/jasminewd2-2.0.9.tgz#db3946314605deea9d5c7aea0b61d807089ba76d" - integrity sha512-Oz+Faunpe2SimFvkMYMXxpK89WXl7rZHG8abTOKcGndu4xOoSbUZ+jUdZ0LQpmDqPEGLBWXF/yZP1tlsplGhzw== +"@types/jasminewd2@^2.0.10": + version "2.0.10" + resolved "https://registry.yarnpkg.com/@types/jasminewd2/-/jasminewd2-2.0.10.tgz#ae31c237aa6421bde30f1058b1d20f4577e54443" + integrity sha512-J7mDz7ovjwjc+Y9rR9rY53hFWKATcIkrr9DwQWmOas4/pnIPJTXawnzjwpHm3RSxz/e3ZVUvQ7cRbd5UQLo10g== dependencies: "@types/jasmine" "*" -"@types/jquery@*", "@types/jquery@^3.5.2": - version "3.5.2" - resolved "https://registry.yarnpkg.com/@types/jquery/-/jquery-3.5.2.tgz#e17c1756ecf7bbb431766c6761674a5d1de16579" - integrity sha512-+MFOdKF5Zr41t3y2wfzJvK1PrUK0KtPLAFwYownp/0nCoMIANDDu5aFSpWfb8S0ZajCSNeaBnMrBGxksXK5yeg== - dependencies: - "@types/sizzle" "*" - -"@types/jquery@^3.5.5": - version "3.5.5" - resolved "https://registry.yarnpkg.com/@types/jquery/-/jquery-3.5.5.tgz#2c63f47c9c8d96693d272f5453602afd8338c903" - integrity sha512-6RXU9Xzpc6vxNrS6FPPapN1SxSHgQ336WC6Jj/N8q30OiaBZ00l1GBgeP7usjVZPivSkGUfL1z/WW6TX989M+w== +"@types/jquery@*", "@types/jquery@^3.5.6", "@types/jquery@^3.5.9": + version "3.5.9" + resolved "https://registry.yarnpkg.com/@types/jquery/-/jquery-3.5.9.tgz#08e4b1dcff0626926ffe545a2bc90f18140c53d6" + integrity sha512-B8pDk+sH/tSv/HKdx6EQER6BfUOb2GtKs0LOmozziS4h7cbe8u/eYySfUAeTwD+J09SqV3man7AMWIA5mgzCBA== dependencies: "@types/sizzle" "*" -"@types/js-beautify@^1.13.1": - version "1.13.1" - resolved "https://registry.yarnpkg.com/@types/js-beautify/-/js-beautify-1.13.1.tgz#d4739266c5dcad561226cd1ec5407fa0542d863d" - integrity sha512-F3YCoZS//n74Wu+hxoVrxX1H8qaWo+WAgQ+ObmFH4ZFwI0fIwiJTW7pvkCRShw8ST7+ej7sB68K+ZHAZgK4S4Q== +"@types/js-beautify@^1.13.3": + version "1.13.3" + resolved "https://registry.yarnpkg.com/@types/js-beautify/-/js-beautify-1.13.3.tgz#53839bb5b766d0fb45e87386100bb3bcbb7dca9d" + integrity sha512-ucIPw5gmNyvRKi6mpeojlqp+T+6ZBJeU+kqMDnIEDlijEU4QhLTon90sZ3cz9HZr+QTwXILjNsMZImzA7+zuJA== -"@types/json-schema@*", "@types/json-schema@^7.0.8": +"@types/json-schema@*", "@types/json-schema@^7.0.5", "@types/json-schema@^7.0.8", "@types/json-schema@^7.0.9": version "7.0.9" resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.9.tgz#97edc9037ea0c38585320b28964dde3b39e4660d" integrity sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ== -"@types/json-schema@^7.0.5": - version "7.0.6" - resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.6.tgz#f4c7ec43e81b319a9815115031709f26987891f0" - integrity sha512-3c+yGKvVP5Y9TYBEibGNR+kLtijnj7mYrXRg+WpFb2X9xm04g/DXYkfg4hmzJQosc9snFNUPkbYIhu+KAm6jJw== - -"@types/json-schema@^7.0.6": - version "7.0.7" - resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.7.tgz#98a993516c859eb0d5c4c8f098317a9ea68db9ad" - integrity sha512-cxWFQVseBm6O9Gbw1IWb8r6OS4OhSt3hPZLkFApLjM8TEXROBuQGLAH2i2gZpcXdLBIrpXuTDhH7Vbm1iXmNGA== - "@types/json5@^0.0.29": version "0.0.29" resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" integrity sha1-7ihweulOEdK4J7y+UnC86n8+ce4= -"@types/jstree@^3.3.40": - version "3.3.40" - resolved "https://registry.yarnpkg.com/@types/jstree/-/jstree-3.3.40.tgz#835737a262ea2572df9ffafc68c08633f4554aa4" - integrity sha512-+6mdAX+vaj962NSd1nnzSLBWD2obUQf5+1yxR+4/g+abpEIQFsI+CcqP4l+cS6H9P07sTONMbR3Z09bPpDzkNg== +"@types/jstree@^3.3.41": + version "3.3.41" + resolved "https://registry.yarnpkg.com/@types/jstree/-/jstree-3.3.41.tgz#820ce1f82bbb2441eaf9fb76451750e2810f5856" + integrity sha512-M4ia6tSKOAU/8v2Ir1Kyo3/XE4EWxw5ulnzbE/nmvw7YugxWhRfTIc6i2ubvJ3GQpdXzJ11bH+GT3VhJNcJadQ== dependencies: "@types/jquery" "*" @@ -3008,24 +1902,17 @@ dependencies: "@types/leaflet" "*" -"@types/leaflet@*": - version "1.5.17" - resolved "https://registry.yarnpkg.com/@types/leaflet/-/leaflet-1.5.17.tgz#b2153dc12c344e6896a93ffc6b61ac79da251e5b" - integrity sha512-2XYq9k6kNjhNI7PaTz8Rdxcc8Vzwu97OaS9CtcrTxnTSxFUGwjlGjTDvhTLJU+JRSfZ4lBwGcl0SjZHALdVr6g== - dependencies: - "@types/geojson" "*" - -"@types/leaflet@^1.7.6": +"@types/leaflet@*", "@types/leaflet@^1.7.6": version "1.7.6" resolved "https://registry.yarnpkg.com/@types/leaflet/-/leaflet-1.7.6.tgz#6580f4babb648972c5af3abc3d66866753fa9311" integrity sha512-Emkz3V08QnlelSbpT46OEAx+TBZYTOX2r1yM7W+hWg5+djHtQ1GbEXBDRLaqQDOYcDI51Ss0ayoqoKD4CtLUDA== dependencies: "@types/geojson" "*" -"@types/lodash@^4.14.170": - version "4.14.170" - resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.170.tgz#0d67711d4bf7f4ca5147e9091b847479b87925d6" - integrity sha512-bpcvu/MKHHeYX+qeEN8GE7DIravODWdACVA1ctevD8CN24RhPZIKMn9ntfAsrvLfSX3cR5RrBKAbYm9bGs0A+Q== +"@types/lodash@^4.14.177": + version "4.14.177" + resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.177.tgz#f70c0d19c30fab101cad46b52be60363c43c4578" + integrity sha512-0fDwydE2clKe9MNfvXHBHF9WEahRuj+msTuQqOmAApNORFvhMYZKNGGJdCzuhheVjMps/ti0Ak/iJPACMaevvw== "@types/marked@^2.0.0": version "2.0.5" @@ -3033,9 +1920,9 @@ integrity sha512-shRZ7XnYFD/8n8zSjKvFdto1QNSf4tONZIlNEZGrJe8GsOE8DL/hG1Hbl8gZlfLnjS7+f5tZGIaTgfpyW38h4w== "@types/minimatch@*": - version "3.0.3" - resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d" - integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA== + version "3.0.5" + resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.5.tgz#1001cc5e6a3704b83c236027e77f2f58ea010f40" + integrity sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ== "@types/moment-timezone@^0.5.30": version "0.5.30" @@ -3044,25 +1931,20 @@ dependencies: moment-timezone "*" -"@types/mousetrap@1.6.3": - version "1.6.3" - resolved "https://registry.yarnpkg.com/@types/mousetrap/-/mousetrap-1.6.3.tgz#3159a01a2b21c9155a3d8f85588885d725dc987d" - integrity sha512-13gmo3M2qVvjQrWNseqM3+cR6S2Ss3grbR2NZltgMq94wOwqJYQdgn8qzwDshzgXqMlSUtyPZjysImmktu22ew== - "@types/mousetrap@^1.6.0": - version "1.6.4" - resolved "https://registry.yarnpkg.com/@types/mousetrap/-/mousetrap-1.6.4.tgz#32503197fca4168b10bf251c1d677a9b5b1c2415" - integrity sha512-+Y900DGhe+f+4lRwHm9krsKfsiXcbdOhzTsLbytU4MiG8wE9xOw7CFKtgYKfqEAcUdWEGZRyuTxoyFl2Gx6Rdg== + version "1.6.8" + resolved "https://registry.yarnpkg.com/@types/mousetrap/-/mousetrap-1.6.8.tgz#448929e6dc21126392830465fdb9d4a2cfc16a88" + integrity sha512-zTqjvgCUT5EoXqbqmd8iJMb4NJqyV/V7pK7AIKq7qcaAsJIpGlTVJS1HQM6YkdHCdnkNSbhcQI7MXYxFfE3iCA== -"@types/node@*": - version "14.11.5" - resolved "https://registry.yarnpkg.com/@types/node/-/node-14.11.5.tgz#fecad41c041cae7f2404ad4b2d0742fdb628b305" - integrity sha512-jVFzDV6NTbrLMxm4xDSIW/gKnk8rQLF9wAzLWIOg+5nU6ACrIMndeBdXci0FGtqJbP9tQvm6V39eshc96TO2wQ== +"@types/node@*", "@types/node@>=10.0.0": + version "16.11.11" + resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.11.tgz#6ea7342dfb379ea1210835bada87b3c512120234" + integrity sha512-KB0sixD67CeecHC33MYn+eYARkqTheIRNuu97y2XMjR7Wu3XibO1vaY6VBV6O/a89SPI81cEUIYT87UqUWlZNw== -"@types/node@>=10.0.0": - version "15.6.1" - resolved "https://registry.yarnpkg.com/@types/node/-/node-15.6.1.tgz#32d43390d5c62c5b6ec486a9bc9c59544de39a08" - integrity sha512-7EIraBEyRHEe7CH+Fm1XvgqU6uwZN8Q7jppJGcqjROMT29qhAuuOxYB1uEY5UMYQKEmA5D+5tBnhdaPXSsLONA== +"@types/node@~15.14.9": + version "15.14.9" + resolved "https://registry.yarnpkg.com/@types/node/-/node-15.14.9.tgz#bc43c990c3c9be7281868bbc7b8fdd6e2b57adfa" + integrity sha512-qjd88DrCxupx/kJD5yQgZdcYKZKSIGBVDIBE1/LTGcNm3d2Np/jxojkdePDdfnBHJc5W7vSMpbJ1aB7p/Py69A== "@types/parse-json@^4.0.0": version "4.0.0" @@ -3070,51 +1952,57 @@ integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA== "@types/prop-types@*": - version "15.7.3" - resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.3.tgz#2ab0d5da2e5815f94b0b9d4b95d1e5f243ab2ca7" - integrity sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw== + version "15.7.4" + resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.4.tgz#fcf7205c25dff795ee79af1e30da2c9790808f11" + integrity sha512-rZ5drC/jWjrArrS8BR6SIr4cWpW09RNTYt9AMZo3Jwwif+iacXAqgVjm0B0Bv/S1jhDXKHqRVNCbACkJ89RAnQ== "@types/q@^0.0.32": version "0.0.32" resolved "https://registry.yarnpkg.com/@types/q/-/q-0.0.32.tgz#bd284e57c84f1325da702babfc82a5328190c0c5" integrity sha1-vShOV8hPEyXacCur/IKlMoGQwMU= -"@types/raphael@^2.3.1": - version "2.3.1" - resolved "https://registry.yarnpkg.com/@types/raphael/-/raphael-2.3.1.tgz#5e8e69c35f2c8a89a6e5cf0f9ff87004bbc6f3bb" - integrity sha512-zsocvfGMgQT9kVwGYthhWifd5iUw3nhzXZyO7+V9+B69kNYi6x0FN9W2k9dLJecXsk4HR6aKVmaSQjkWGo3N9w== +"@types/raphael@^2.3.2": + version "2.3.2" + resolved "https://registry.yarnpkg.com/@types/raphael/-/raphael-2.3.2.tgz#833eff033c33fb1a3935882bc29c82908cb9a734" + integrity sha512-RbEkYHuQbb2LYN0MN+Gk3CN3y0122uTLI41z8l62BFhnxS/ylVkZT2D1PLdmLTu5itV1iHh9SF+kDomY3DrZig== -"@types/react-dom@^16.9.8": - version "16.9.8" - resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-16.9.8.tgz#fe4c1e11dfc67155733dfa6aa65108b4971cb423" - integrity sha512-ykkPQ+5nFknnlU6lDd947WbQ6TE3NNzbQAkInC2EKY1qeYdTKp7onFusmYZb+ityzx2YviqT6BXSu+LyWWJwcA== +"@types/react-dom@^17.0.11": + version "17.0.11" + resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-17.0.11.tgz#e1eadc3c5e86bdb5f7684e00274ae228e7bcc466" + integrity sha512-f96K3k+24RaLGVu/Y2Ng3e1EbZ8/cVJvypZWd7cy0ofCBaf2lcM46xNhycMZ2xGwbBjRql7hOlZ+e2WlJ5MH3Q== dependencies: "@types/react" "*" "@types/react-transition-group@^4.2.0": - version "4.4.0" - resolved "https://registry.yarnpkg.com/@types/react-transition-group/-/react-transition-group-4.4.0.tgz#882839db465df1320e4753e6e9f70ca7e9b4d46d" - integrity sha512-/QfLHGpu+2fQOqQaXh8MG9q03bFENooTb/it4jr5kKaZlDQfWvjqWZg48AwzPVMBHlRuTRAY7hRHCEOXz5kV6w== + version "4.4.4" + resolved "https://registry.yarnpkg.com/@types/react-transition-group/-/react-transition-group-4.4.4.tgz#acd4cceaa2be6b757db61ed7b432e103242d163e" + integrity sha512-7gAPz7anVK5xzbeQW9wFBDg7G++aPLAFY0QaSMOou9rJZpbuI58WAuJrgu+qR92l61grlnCUe7AFX8KGahAgug== dependencies: "@types/react" "*" -"@types/react@*", "@types/react@^16.9.51": - version "16.9.51" - resolved "https://registry.yarnpkg.com/@types/react/-/react-16.9.51.tgz#f8aa51ffa9996f1387f63686696d9b59713d2b60" - integrity sha512-lQa12IyO+DMlnSZ3+AGHRUiUcpK47aakMMoBG8f7HGxJT8Yfe+WE128HIXaHOHVPReAW0oDS3KAI0JI2DDe1PQ== +"@types/react@*", "@types/react@^17.0.37": + version "17.0.37" + resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.37.tgz#6884d0aa402605935c397ae689deed115caad959" + integrity sha512-2FS1oTqBGcH/s0E+CjrCCR9+JMpsu9b69RTFO+40ua43ZqP5MmQ4iUde/dMjWR909KxZwmOQIFq6AV6NjEG5xg== dependencies: "@types/prop-types" "*" + "@types/scheduler" "*" csstype "^3.0.2" +"@types/scheduler@*": + version "0.16.2" + resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.2.tgz#1a62f89525723dde24ba1b01b092bf5df8ad4d39" + integrity sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew== + "@types/selenium-webdriver@^3.0.0": - version "3.0.17" - resolved "https://registry.yarnpkg.com/@types/selenium-webdriver/-/selenium-webdriver-3.0.17.tgz#50bea0c3c2acc31c959c5b1e747798b3b3d06d4b" - integrity sha512-tGomyEuzSC1H28y2zlW6XPCaDaXFaD6soTdb4GNdmte2qfHtrKqhy0ZFs4r/1hpazCfEZqeTSRLvSasmEx89uw== + version "3.0.19" + resolved "https://registry.yarnpkg.com/@types/selenium-webdriver/-/selenium-webdriver-3.0.19.tgz#28ecede76f15b13553b4e86074d4cf9a0bbe49c4" + integrity sha512-OFUilxQg+rWL2FMxtmIgCkUDlJB6pskkpvmew7yeXfzzsOBb5rc+y2+DjHm+r3r1ZPPcJefK3DveNSYWGiy68g== "@types/sizzle@*": - version "2.3.2" - resolved "https://registry.yarnpkg.com/@types/sizzle/-/sizzle-2.3.2.tgz#a811b8c18e2babab7d542b3365887ae2e4d9de47" - integrity sha512-7EJYyKTL7tFR8+gDbB6Wwz/arpGa0Mywk1TJbNzKzHtzbwVmY4HR9WqS5VV7dsBUKQmPNr192jHr/VpBluj/hg== + version "2.3.3" + resolved "https://registry.yarnpkg.com/@types/sizzle/-/sizzle-2.3.3.tgz#ff5e2f1902969d305225a047c8a0fd5c915cebef" + integrity sha512-JYM8x9EGF163bEyhdJBpR2QX1R5naCJHC8ucJylJ3w9/CVBaskdQ8WqBf8MmQrd1kRvp/a4TS8HJ+bxzR7ZJYQ== "@types/source-list-map@*": version "0.1.2" @@ -3122,28 +2010,33 @@ integrity sha512-K5K+yml8LTo9bWJI/rECfIPrGgxdpeNbj+d53lwN4QjW1MCwlkhUms+gtdzigTeUyBr09+u8BwOIY3MXvHdcsA== "@types/styled-jsx@^2.2.8": - version "2.2.8" - resolved "https://registry.yarnpkg.com/@types/styled-jsx/-/styled-jsx-2.2.8.tgz#b50d13d8a3c34036282d65194554cf186bab7234" - integrity sha512-Yjye9VwMdYeXfS71ihueWRSxrruuXTwKCbzue4+5b2rjnQ//AtyM7myZ1BEhNhBQ/nL/RE7bdToUoLln2miKvg== + version "2.2.9" + resolved "https://registry.yarnpkg.com/@types/styled-jsx/-/styled-jsx-2.2.9.tgz#e50b3f868c055bcbf9bc353eca6c10fdad32a53f" + integrity sha512-W/iTlIkGEyTBGTEvZCey8EgQlQ5l0DwMqi3iOXlLs2kyBwYTXHKEiU6IZ5EwoRwngL8/dGYuzezSup89ttVHLw== dependencies: "@types/react" "*" -"@types/tinycolor2@^1.4.2": - version "1.4.2" - resolved "https://registry.yarnpkg.com/@types/tinycolor2/-/tinycolor2-1.4.2.tgz#721ca5c5d1a2988b4a886e35c2ffc5735b6afbdf" - integrity sha512-PeHg/AtdW6aaIO2a+98Xj7rWY4KC1E6yOy7AFknJQ7VXUGNrMlyxDFxJo7HqLtjQms/ZhhQX52mLVW/EX3JGOw== +"@types/systemjs@6.1.1": + version "6.1.1" + resolved "https://registry.yarnpkg.com/@types/systemjs/-/systemjs-6.1.1.tgz#eae17f2a080e867d01a2dd614f524ab227cf5a41" + integrity sha512-d1M6eDKBGWx7RbYy295VEFoOF9YDJkPI959QYnmzcmeaV+SP4D0xV7dEh3sN5XF3GvO3PhGzm+17Z598nvHQuQ== -"@types/tooltipster@^0.0.30": - version "0.0.30" - resolved "https://registry.yarnpkg.com/@types/tooltipster/-/tooltipster-0.0.30.tgz#10deda04d1ce52e0fefc18079ae91548663e2400" - integrity sha512-JqgcjpkDOMjsiVg3tqMIDgxnealN9/+DY6+z9OMeSd4fRovHINr/tHKtBJXDHI2DKh+ygyqMHsPTct+flNS+bw== +"@types/tinycolor2@^1.4.3": + version "1.4.3" + resolved "https://registry.yarnpkg.com/@types/tinycolor2/-/tinycolor2-1.4.3.tgz#ed4a0901f954b126e6a914b4839c77462d56e706" + integrity sha512-Kf1w9NE5HEgGxCRyIcRXR/ZYtDv0V8FVPtYHwLxl0O+maGX0erE77pQlD0gpP+/KByMZ87mOA79SjifhSB3PjQ== + +"@types/tooltipster@^0.0.31": + version "0.0.31" + resolved "https://registry.yarnpkg.com/@types/tooltipster/-/tooltipster-0.0.31.tgz#db6c78b5ad709fe5dc9c78cf15a6a2068b4f72b0" + integrity sha512-tDAxe2Q67VoQyeEW6oweNDfw4nNmodFGkHdPQdeBCCusf2d3qFbDLFkYnntgSwcD00Fkhh8mSguaP6w5muvZpg== dependencies: "@types/jquery" "*" "@types/webpack-sources@^0.1.5": - version "0.1.8" - resolved "https://registry.yarnpkg.com/@types/webpack-sources/-/webpack-sources-0.1.8.tgz#078d75410435993ec8a0a2855e88706f3f751f81" - integrity sha512-JHB2/xZlXOjzjBB6fMOpH1eQAfsrpqVVIbneE0Rok16WXwFaznaI5vfg75U5WgGJm7V9W1c4xeRQDjX/zwvghA== + version "0.1.9" + resolved "https://registry.yarnpkg.com/@types/webpack-sources/-/webpack-sources-0.1.9.tgz#da69b06eb34f6432e6658acb5a6893c55d983920" + integrity sha512-bvzMnzqoK16PQIC8AYHNdW45eREJQMd6WG/msQWX5V2+vZmODCOPb4TJcbgRljTZZTwTM4wUMcsI8FftNA7new== dependencies: "@types/node" "*" "@types/source-list-map" "*" @@ -3157,64 +2050,21 @@ "@webassemblyjs/helper-numbers" "1.11.1" "@webassemblyjs/helper-wasm-bytecode" "1.11.1" -"@webassemblyjs/ast@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.9.0.tgz#bd850604b4042459a5a41cd7d338cbed695ed964" - integrity sha512-C6wW5L+b7ogSDVqymbkkvuW9kruN//YisMED04xzeBBqjHa2FYnmvOlS6Xj68xWQRgWvI9cIglsjFowH/RJyEA== - dependencies: - "@webassemblyjs/helper-module-context" "1.9.0" - "@webassemblyjs/helper-wasm-bytecode" "1.9.0" - "@webassemblyjs/wast-parser" "1.9.0" - "@webassemblyjs/floating-point-hex-parser@1.11.1": version "1.11.1" resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz#f6c61a705f0fd7a6aecaa4e8198f23d9dc179e4f" integrity sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ== -"@webassemblyjs/floating-point-hex-parser@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.9.0.tgz#3c3d3b271bddfc84deb00f71344438311d52ffb4" - integrity sha512-TG5qcFsS8QB4g4MhrxK5TqfdNe7Ey/7YL/xN+36rRjl/BlGE/NcBvJcqsRgCP6Z92mRE+7N50pRIi8SmKUbcQA== - "@webassemblyjs/helper-api-error@1.11.1": version "1.11.1" resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz#1a63192d8788e5c012800ba6a7a46c705288fd16" integrity sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg== -"@webassemblyjs/helper-api-error@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.9.0.tgz#203f676e333b96c9da2eeab3ccef33c45928b6a2" - integrity sha512-NcMLjoFMXpsASZFxJ5h2HZRcEhDkvnNFOAKneP5RbKRzaWJN36NC4jqQHKwStIhGXu5mUWlUUk7ygdtrO8lbmw== - "@webassemblyjs/helper-buffer@1.11.1": version "1.11.1" resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz#832a900eb444884cde9a7cad467f81500f5e5ab5" integrity sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA== -"@webassemblyjs/helper-buffer@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.9.0.tgz#a1442d269c5feb23fcbc9ef759dac3547f29de00" - integrity sha512-qZol43oqhq6yBPx7YM3m9Bv7WMV9Eevj6kMi6InKOuZxhw+q9hOkvq5e/PpKSiLfyetpaBnogSbNCfBwyB00CA== - -"@webassemblyjs/helper-code-frame@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.9.0.tgz#647f8892cd2043a82ac0c8c5e75c36f1d9159f27" - integrity sha512-ERCYdJBkD9Vu4vtjUYe8LZruWuNIToYq/ME22igL+2vj2dQ2OOujIZr3MEFvfEaqKoVqpsFKAGsRdBSBjrIvZA== - dependencies: - "@webassemblyjs/wast-printer" "1.9.0" - -"@webassemblyjs/helper-fsm@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-fsm/-/helper-fsm-1.9.0.tgz#c05256b71244214671f4b08ec108ad63b70eddb8" - integrity sha512-OPRowhGbshCb5PxJ8LocpdX9Kl0uB4XsAjl6jH/dWKlk/mzsANvhwbiULsaiqT5GZGT9qinTICdj6PLuM5gslw== - -"@webassemblyjs/helper-module-context@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-module-context/-/helper-module-context-1.9.0.tgz#25d8884b76839871a08a6c6f806c3979ef712f07" - integrity sha512-MJCW8iGC08tMk2enck1aPW+BE5Cw8/7ph/VGZxwyvGbJwjktKkDK7vy7gAmMDx88D7mhDTCNKAW5tED+gZ0W8g== - dependencies: - "@webassemblyjs/ast" "1.9.0" - "@webassemblyjs/helper-numbers@1.11.1": version "1.11.1" resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz#64d81da219fbbba1e3bd1bfc74f6e8c4e10a62ae" @@ -3229,11 +2079,6 @@ resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz#f328241e41e7b199d0b20c18e88429c4433295e1" integrity sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q== -"@webassemblyjs/helper-wasm-bytecode@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.9.0.tgz#4fed8beac9b8c14f8c58b70d124d549dd1fe5790" - integrity sha512-R7FStIzyNcd7xKxCZH5lE0Bqy+hGTwS3LJjuv1ZVxd9O7eHCedSdrId/hMOd20I+v8wDXEn+bjfKDLzTepoaUw== - "@webassemblyjs/helper-wasm-section@1.11.1": version "1.11.1" resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz#21ee065a7b635f319e738f0dd73bfbda281c097a" @@ -3244,16 +2089,6 @@ "@webassemblyjs/helper-wasm-bytecode" "1.11.1" "@webassemblyjs/wasm-gen" "1.11.1" -"@webassemblyjs/helper-wasm-section@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.9.0.tgz#5a4138d5a6292ba18b04c5ae49717e4167965346" - integrity sha512-XnMB8l3ek4tvrKUUku+IVaXNHz2YsJyOOmz+MMkZvh8h1uSJpSen6vYnw3IoQ7WwEuAhL8Efjms1ZWjqh2agvw== - dependencies: - "@webassemblyjs/ast" "1.9.0" - "@webassemblyjs/helper-buffer" "1.9.0" - "@webassemblyjs/helper-wasm-bytecode" "1.9.0" - "@webassemblyjs/wasm-gen" "1.9.0" - "@webassemblyjs/ieee754@1.11.1": version "1.11.1" resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz#963929e9bbd05709e7e12243a099180812992614" @@ -3261,13 +2096,6 @@ dependencies: "@xtuc/ieee754" "^1.2.0" -"@webassemblyjs/ieee754@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.9.0.tgz#15c7a0fbaae83fb26143bbacf6d6df1702ad39e4" - integrity sha512-dcX8JuYU/gvymzIHc9DgxTzUUTLexWwt8uCTWP3otys596io0L5aW02Gb1RjYpx2+0Jus1h4ZFqjla7umFniTg== - dependencies: - "@xtuc/ieee754" "^1.2.0" - "@webassemblyjs/leb128@1.11.1": version "1.11.1" resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.11.1.tgz#ce814b45574e93d76bae1fb2644ab9cdd9527aa5" @@ -3275,23 +2103,11 @@ dependencies: "@xtuc/long" "4.2.2" -"@webassemblyjs/leb128@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.9.0.tgz#f19ca0b76a6dc55623a09cffa769e838fa1e1c95" - integrity sha512-ENVzM5VwV1ojs9jam6vPys97B/S65YQtv/aanqnU7D8aSoHFX8GyhGg0CMfyKNIHBuAVjy3tlzd5QMMINa7wpw== - dependencies: - "@xtuc/long" "4.2.2" - "@webassemblyjs/utf8@1.11.1": version "1.11.1" resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.11.1.tgz#d1f8b764369e7c6e6bae350e854dec9a59f0a3ff" integrity sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ== -"@webassemblyjs/utf8@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.9.0.tgz#04d33b636f78e6a6813227e82402f7637b6229ab" - integrity sha512-GZbQlWtopBTP0u7cHrEx+73yZKrQoBMpwkGEIqlacljhXCkVM1kMQge/Mf+csMJAjEdSwhOyLAS0AoR3AG5P8w== - "@webassemblyjs/wasm-edit@1.11.1": version "1.11.1" resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz#ad206ebf4bf95a058ce9880a8c092c5dec8193d6" @@ -3306,20 +2122,6 @@ "@webassemblyjs/wasm-parser" "1.11.1" "@webassemblyjs/wast-printer" "1.11.1" -"@webassemblyjs/wasm-edit@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.9.0.tgz#3fe6d79d3f0f922183aa86002c42dd256cfee9cf" - integrity sha512-FgHzBm80uwz5M8WKnMTn6j/sVbqilPdQXTWraSjBwFXSYGirpkSWE2R9Qvz9tNiTKQvoKILpCuTjBKzOIm0nxw== - dependencies: - "@webassemblyjs/ast" "1.9.0" - "@webassemblyjs/helper-buffer" "1.9.0" - "@webassemblyjs/helper-wasm-bytecode" "1.9.0" - "@webassemblyjs/helper-wasm-section" "1.9.0" - "@webassemblyjs/wasm-gen" "1.9.0" - "@webassemblyjs/wasm-opt" "1.9.0" - "@webassemblyjs/wasm-parser" "1.9.0" - "@webassemblyjs/wast-printer" "1.9.0" - "@webassemblyjs/wasm-gen@1.11.1": version "1.11.1" resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz#86c5ea304849759b7d88c47a32f4f039ae3c8f76" @@ -3331,17 +2133,6 @@ "@webassemblyjs/leb128" "1.11.1" "@webassemblyjs/utf8" "1.11.1" -"@webassemblyjs/wasm-gen@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.9.0.tgz#50bc70ec68ded8e2763b01a1418bf43491a7a49c" - integrity sha512-cPE3o44YzOOHvlsb4+E9qSqjc9Qf9Na1OO/BHFy4OI91XDE14MjFN4lTMezzaIWdPqHnsTodGGNP+iRSYfGkjA== - dependencies: - "@webassemblyjs/ast" "1.9.0" - "@webassemblyjs/helper-wasm-bytecode" "1.9.0" - "@webassemblyjs/ieee754" "1.9.0" - "@webassemblyjs/leb128" "1.9.0" - "@webassemblyjs/utf8" "1.9.0" - "@webassemblyjs/wasm-opt@1.11.1": version "1.11.1" resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz#657b4c2202f4cf3b345f8a4c6461c8c2418985f2" @@ -3352,16 +2143,6 @@ "@webassemblyjs/wasm-gen" "1.11.1" "@webassemblyjs/wasm-parser" "1.11.1" -"@webassemblyjs/wasm-opt@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.9.0.tgz#2211181e5b31326443cc8112eb9f0b9028721a61" - integrity sha512-Qkjgm6Anhm+OMbIL0iokO7meajkzQD71ioelnfPEj6r4eOFuqm4YC3VBPqXjFyyNwowzbMD+hizmprP/Fwkl2A== - dependencies: - "@webassemblyjs/ast" "1.9.0" - "@webassemblyjs/helper-buffer" "1.9.0" - "@webassemblyjs/wasm-gen" "1.9.0" - "@webassemblyjs/wasm-parser" "1.9.0" - "@webassemblyjs/wasm-parser@1.11.1": version "1.11.1" resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz#86ca734534f417e9bd3c67c7a1c75d8be41fb199" @@ -3374,30 +2155,6 @@ "@webassemblyjs/leb128" "1.11.1" "@webassemblyjs/utf8" "1.11.1" -"@webassemblyjs/wasm-parser@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.9.0.tgz#9d48e44826df4a6598294aa6c87469d642fff65e" - integrity sha512-9+wkMowR2AmdSWQzsPEjFU7njh8HTO5MqO8vjwEHuM+AMHioNqSBONRdr0NQQ3dVQrzp0s8lTcYqzUdb7YgELA== - dependencies: - "@webassemblyjs/ast" "1.9.0" - "@webassemblyjs/helper-api-error" "1.9.0" - "@webassemblyjs/helper-wasm-bytecode" "1.9.0" - "@webassemblyjs/ieee754" "1.9.0" - "@webassemblyjs/leb128" "1.9.0" - "@webassemblyjs/utf8" "1.9.0" - -"@webassemblyjs/wast-parser@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-parser/-/wast-parser-1.9.0.tgz#3031115d79ac5bd261556cecc3fa90a3ef451914" - integrity sha512-qsqSAP3QQ3LyZjNC/0jBJ/ToSxfYJ8kYyuiGvtn/8MK89VrNEfwj7BPQzJVHi0jGTRK2dGdJ5PRqhtjzoww+bw== - dependencies: - "@webassemblyjs/ast" "1.9.0" - "@webassemblyjs/floating-point-hex-parser" "1.9.0" - "@webassemblyjs/helper-api-error" "1.9.0" - "@webassemblyjs/helper-code-frame" "1.9.0" - "@webassemblyjs/helper-fsm" "1.9.0" - "@xtuc/long" "4.2.2" - "@webassemblyjs/wast-printer@1.11.1": version "1.11.1" resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz#d0c73beda8eec5426f10ae8ef55cee5e7084c2f0" @@ -3406,15 +2163,6 @@ "@webassemblyjs/ast" "1.11.1" "@xtuc/long" "4.2.2" -"@webassemblyjs/wast-printer@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.9.0.tgz#4935d54c85fef637b00ce9f52377451d00d47899" - integrity sha512-2J0nE95rHXHyQ24cWjMKJ1tqB/ds8z/cyeOZxJhcb+rW+SQASVjuznUSmdz5GpVJTzU8JkhYut0D3siFDD6wsA== - dependencies: - "@webassemblyjs/ast" "1.9.0" - "@webassemblyjs/wast-parser" "1.9.0" - "@xtuc/long" "4.2.2" - "@xtuc/ieee754@^1.2.0": version "1.2.0" resolved "https://registry.yarnpkg.com/@xtuc/ieee754/-/ieee754-1.2.0.tgz#eef014a3145ae477a1cbc00cd1e552336dceb790" @@ -3448,33 +2196,26 @@ accepts@~1.3.4, accepts@~1.3.5, accepts@~1.3.7: mime-types "~2.1.24" negotiator "0.6.2" -ace-builds@^1.4.12, ace-builds@^1.4.6: - version "1.4.12" - resolved "https://registry.yarnpkg.com/ace-builds/-/ace-builds-1.4.12.tgz#888efa386e36f4345f40b5233fcc4fe4c588fae7" - integrity sha512-G+chJctFPiiLGvs3+/Mly3apXTcfgE45dT5yp12BcWZ1kUs+gm0qd3/fv4gsz6fVag4mM0moHVpjHDIgph6Psg== +ace-builds@^1.4.13: + version "1.4.13" + resolved "https://registry.yarnpkg.com/ace-builds/-/ace-builds-1.4.13.tgz#186f42d3849ebcc6a48b93088a058489897514c1" + integrity sha512-SOLzdaQkY6ecPKYRDDg+MY1WoGgXA34cIvYJNNoBMGGUswHmlauU2Hy0UL96vW0Fs/LgFbMUjD+6vqzWTldIYQ== acorn-import-assertions@^1.7.6: version "1.8.0" resolved "https://registry.yarnpkg.com/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz#ba2b5939ce62c238db6d93d81c9b111b29b855e9" integrity sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw== -acorn@^6.4.1: - version "6.4.2" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.4.2.tgz#35866fd710528e92de10cf06016498e47e39e1e6" - integrity sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ== +acorn-walk@^8.1.1: + version "8.2.0" + resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.2.0.tgz#741210f2e2426454508853a2f44d0ab83b7f69c1" + integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA== acorn@^8.4.1: version "8.6.0" resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.6.0.tgz#e3692ba0eb1a0c83eaa4f37f5fa7368dd7142895" integrity sha512-U1riIR+lBSNi3IbxtaHOIKdH8sLFv3NYfNv8sg7ZsNhcfl4HF2++BfqqrNAxoCLQW1iiylOj76ecnaUxz+z9yw== -add-dom-event-listener@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/add-dom-event-listener/-/add-dom-event-listener-1.1.0.tgz#6a92db3a0dd0abc254e095c0f1dc14acbbaae310" - integrity sha512-WCxx1ixHT0GQU9hb0KI/mhgRQhnU+U3GvwY6ZvVjYq8rsihIGoaIOUbY0yMPBxLH5MDtr0kz3fisWGNcbWW7Jw== - dependencies: - object-assign "4.x" - adjust-sourcemap-loader@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/adjust-sourcemap-loader/-/adjust-sourcemap-loader-4.0.0.tgz#fc4a0fd080f7d10471f30a7320f25560ade28c99" @@ -3531,20 +2272,24 @@ ajv-formats@2.1.0: dependencies: ajv "^8.0.0" -ajv-keywords@^3.1.0, ajv-keywords@^3.4.1, ajv-keywords@^3.5.2: +ajv-formats@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ajv-formats/-/ajv-formats-2.1.1.tgz#6e669400659eb74973bbf2e33327180a0996b520" + integrity sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA== + dependencies: + ajv "^8.0.0" + +ajv-keywords@^3.1.0, ajv-keywords@^3.5.2: version "3.5.2" resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d" integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ== -ajv@6.12.6, ajv@^6.12.5: - version "6.12.6" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" - integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== +ajv-keywords@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-5.1.0.tgz#69d4d385a4733cdbeab44964a1170a88f87f0e16" + integrity sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw== dependencies: - fast-deep-equal "^3.1.1" - fast-json-stable-stringify "^2.0.0" - json-schema-traverse "^0.4.1" - uri-js "^4.2.2" + fast-deep-equal "^3.1.3" ajv@8.6.2: version "8.6.2" @@ -3556,17 +2301,17 @@ ajv@8.6.2: require-from-string "^2.0.2" uri-js "^4.2.2" -ajv@^6.1.0, ajv@^6.10.2, ajv@^6.12.3, ajv@^6.12.4: - version "6.12.5" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.5.tgz#19b0e8bae8f476e5ba666300387775fb1a00a4da" - integrity sha512-lRF8RORchjpKG50/WFf8xmg7sgCLFiYNNnqdKflk63whMQcWR5ngGjiSXkL9bjxy6B2npOK2HSMN49jEBMSkag== +ajv@^6.1.0, ajv@^6.12.3, ajv@^6.12.4, ajv@^6.12.5: + version "6.12.6" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" + integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== dependencies: fast-deep-equal "^3.1.1" fast-json-stable-stringify "^2.0.0" json-schema-traverse "^0.4.1" uri-js "^4.2.2" -ajv@^8.0.0: +ajv@^8.0.0, ajv@^8.8.0: version "8.8.2" resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.8.2.tgz#01b4fef2007a28bf75f0b7fc009f62679de4abbb" integrity sha512-x9VuX+R/jcFj1DHo/fCp99esgGDWiHENrKxaCENuCxpoMCmAt/COCGVDwA7kleEpEzJjDnvh3yGoOuLu0Dtllw== @@ -3581,12 +2326,12 @@ alphanum-sort@^1.0.2: resolved "https://registry.yarnpkg.com/alphanum-sort/-/alphanum-sort-1.0.2.tgz#97a1119649b211ad33691d9f9f486a8ec9fbe0a3" integrity sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM= -angular-gridster2@~11.2.0: - version "11.2.0" - resolved "https://registry.yarnpkg.com/angular-gridster2/-/angular-gridster2-11.2.0.tgz#57239e639d16b7b1bcd6255aa8fee55151dd65d7" - integrity sha512-9+4Qt2/mPKAzGhhzp2Ag++WQbvr3Ry3dbfHG1XI596jpKh1ZtYvTLrh0Fn6jJEq248F1VN0xob9K9PzTH4P/2A== +angular-gridster2@~12.1.1: + version "12.1.1" + resolved "https://registry.yarnpkg.com/angular-gridster2/-/angular-gridster2-12.1.1.tgz#699cd0a2477b81b052f6bd7b336ba7cc2adc8bc3" + integrity sha512-HK7vf212LSn7mp8g4sNA6/X8TQN4wJyHupKemx+PUPmTs6FHDyquUMUFXYxANR47jdyLEMW/DxCDI0bEhIIChw== dependencies: - tslib "^2.0.0" + tslib "^2.1.0" angular2-hotkeys@^2.4.0: version "2.4.0" @@ -3608,11 +2353,11 @@ ansi-colors@^3.0.0: integrity sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA== ansi-escapes@^4.2.1: - version "4.3.1" - resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.1.tgz#a5c47cc43181f1f38ffd7076837700d395522a61" - integrity sha512-JWF7ocqNrp8u9oqpgV+wH5ftbt+cfvv+PTjOvKLT3AdYly/LmORARfEVT1iyjwN+4MqE5UmVKoAdIBqeoCHgLA== + version "4.3.2" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" + integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== dependencies: - type-fest "^0.11.0" + type-fest "^0.21.3" ansi-html@0.0.7: version "0.0.7" @@ -3624,20 +2369,15 @@ ansi-regex@^2.0.0: resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8= -ansi-regex@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" - integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= - ansi-regex@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg== -ansi-regex@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.0.tgz#388539f55179bf39339c81af30a654d69f87cb75" - integrity sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg== +ansi-regex@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" + integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== ansi-styles@^2.2.1: version "2.2.1" @@ -3658,6 +2398,11 @@ ansi-styles@^4.0.0, ansi-styles@^4.1.0: dependencies: color-convert "^2.0.1" +ansidec@^0.3.4: + version "0.3.4" + resolved "https://registry.yarnpkg.com/ansidec/-/ansidec-0.3.4.tgz#e12d267d6b1f122d2da5b98fe0de1f98d14ac62b" + integrity sha512-Ydgbey4zqUmmNN2i2OVeVHXig3PxHRbok2X6B2Sogmb92JzZUFfTL806dT7os6tBL1peXItfeFt76CP3zsoXUg== + anymatch@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb" @@ -3666,14 +2411,6 @@ anymatch@^2.0.0: micromatch "^3.1.4" normalize-path "^2.1.1" -anymatch@~3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.1.tgz#c55ecf02185e2469259399310c173ce31233b142" - integrity sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg== - dependencies: - normalize-path "^3.0.0" - picomatch "^2.0.4" - anymatch@~3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716" @@ -3687,15 +2424,15 @@ app-root-path@^3.0.0: resolved "https://registry.yarnpkg.com/app-root-path/-/app-root-path-3.0.0.tgz#210b6f43873227e18a4b810a032283311555d5ad" integrity sha512-qMcx+Gy2UZynHjOHOIXPNvpf+9cjvk3cWrBBK7zg4gH9+clobJRb9NGzcT7mQTcV/6Gm/1WelUtqxVXnNlrwcw== -aproba@^1.0.3, aproba@^1.1.1: +aproba@^1.0.3: version "1.2.0" resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw== are-we-there-yet@~1.1.2: - version "1.1.5" - resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz#4b35c2944f062a8bfcda66410760350fe9ddfc21" - integrity sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w== + version "1.1.7" + resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.7.tgz#b15474a932adab4ff8a50d9adfa7e4e926f21146" + integrity sha512-nxwy40TuMiUGqMyRHgCSWZ9FM4VAoRP4xUYSTv5ImRog+h9yISPbVH7H8fASCIzYn9wlEv4zvFL7uKDMCFQm3g== dependencies: delegates "^1.0.0" readable-stream "^2.0.6" @@ -3772,20 +2509,10 @@ arrify@^1.0.0: resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" integrity sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0= -asn1.js@^5.2.0: - version "5.4.1" - resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-5.4.1.tgz#11a980b84ebb91781ce35b0fdc2ee294e3783f07" - integrity sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA== - dependencies: - bn.js "^4.0.0" - inherits "^2.0.1" - minimalistic-assert "^1.0.0" - safer-buffer "^2.1.0" - asn1@~0.2.3: - version "0.2.4" - resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136" - integrity sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg== + version "0.2.6" + resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.6.tgz#0d3a7bb6e64e02a90c0303b31f292868ea09a08d" + integrity sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ== dependencies: safer-buffer "~2.1.0" @@ -3794,14 +2521,6 @@ assert-plus@1.0.0, assert-plus@^1.0.0: resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" integrity sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU= -assert@^1.1.1: - version "1.5.0" - resolved "https://registry.yarnpkg.com/assert/-/assert-1.5.0.tgz#55c109aaf6e0aefdb3dc4b71240c70bf574b18eb" - integrity sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA== - dependencies: - object-assign "^4.1.1" - util "0.10.3" - assign-symbols@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" @@ -3839,23 +2558,11 @@ atob@^2.1.2: resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== -attr-accept@^2.0.0: +attr-accept@^2.2.1: version "2.2.2" resolved "https://registry.yarnpkg.com/attr-accept/-/attr-accept-2.2.2.tgz#646613809660110749e92f2c10833b70968d929b" integrity sha512-7prDjvt9HmqiZ0cl5CRjtS84sEyhsHP2coDkaZKRKVfCDo9s7iw7ChVmar78Gu9pC4SoR/28wFu/G5JJhTnqEg== -autoprefixer@10.2.4: - version "10.2.4" - resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-10.2.4.tgz#c0e7cf24fcc6a1ae5d6250c623f0cb8beef2f7e1" - integrity sha512-DCCdUQiMD+P/as8m3XkeTUkUKuuRqLGcwD0nll7wevhqoJfMRpJlkFd1+MQh1pvupjiQuip42lc/VFvfUTMSKw== - dependencies: - browserslist "^4.16.1" - caniuse-lite "^1.0.30001181" - colorette "^1.2.1" - fraction.js "^4.0.13" - normalize-range "^0.1.2" - postcss-value-parser "^4.1.0" - autoprefixer@^9.6.1: version "9.8.8" resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-9.8.8.tgz#fd4bd4595385fa6f06599de749a4d5f7a474957a" @@ -3875,9 +2582,9 @@ aws-sign2@~0.7.0: integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg= aws4@^1.8.0: - version "1.10.1" - resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.10.1.tgz#e1e82e4f3e999e2cfd61b161280d16a111f86428" - integrity sha512-zg7Hz2k5lI8kb7U32998pRRFin7zJlkfezGJjUc2heaD4Pw2wObakCDVzkKztTm/Ln7eiVvYsjqak0Ed4LkMDA== + version "1.11.0" + resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.11.0.tgz#d61f46d83b2519250e2784daf5b09479a8b41c59" + integrity sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA== axobject-query@2.0.2: version "2.0.2" @@ -3928,24 +2635,19 @@ babel-plugin-polyfill-regenerator@^0.2.2: "@babel/helper-define-polyfill-provider" "^0.2.4" balanced-match@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" - integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= - -base64-arraybuffer@0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/base64-arraybuffer/-/base64-arraybuffer-0.1.4.tgz#9818c79e059b1355f97e0428a017c838e90ba812" - integrity sha1-mBjHngWbE1X5fgQooBfIOOkLqBI= + version "1.0.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== base64-arraybuffer@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/base64-arraybuffer/-/base64-arraybuffer-0.2.0.tgz#4b944fac0191aa5907afe2d8c999ccc57ce80f45" integrity sha512-7emyCsu1/xiBXgQZrscw/8KPRT44I4Yq9Pe6EGs3aPRTsWuggML1/1DTuZUuIaJPIm1FTDUVXl4x/yW8s0kQDQ== -base64-js@^1.0.2: - version "1.3.1" - resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.1.tgz#58ece8cb75dd07e71ed08c736abc5fac4dbf8df1" - integrity sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g== +base64-arraybuffer@^1.0.1, base64-arraybuffer@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/base64-arraybuffer/-/base64-arraybuffer-1.0.1.tgz#87bd13525626db4a9838e00a508c2b73efcf348c" + integrity sha512-vFIUq7FdLtjZMhATwDul5RZWv2jpXQ09Pd6jcVEOvIsqCWTRFD/ONHNfyOS8dA/Ippi5dsIgpyKWKZaAKZltbA== base64-js@^1.2.0, base64-js@^1.3.1: version "1.5.1" @@ -3993,9 +2695,9 @@ binary-extensions@^1.0.0: integrity sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw== binary-extensions@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.1.0.tgz#30fa40c9e7fe07dbc895678cd287024dea241dd9" - integrity sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ== + version "2.2.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" + integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== bindings@^1.5.0: version "1.5.0" @@ -4004,7 +2706,7 @@ bindings@^1.5.0: dependencies: file-uri-to-path "1.0.0" -bl@^4.0.3, bl@^4.1.0: +bl@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/bl/-/bl-4.1.0.tgz#451535264182bec2fbbc83a62ab98cf11d9f7b3a" integrity sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w== @@ -4020,21 +2722,6 @@ blocking-proxy@^1.0.0: dependencies: minimist "^1.2.0" -bluebird@^3.5.5: - version "3.7.2" - resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" - integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== - -bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.4.0: - version "4.11.9" - resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.9.tgz#26d556829458f9d1e81fc48952493d0ba3507828" - integrity sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw== - -bn.js@^5.1.1: - version "5.1.3" - resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.1.3.tgz#beca005408f642ebebea80b042b4d18d2ac0ee6b" - integrity sha512-GkTiFpjFtUzU9CbMeJ5iazkCzGL3jrhzerzZIuqLABjbwRaFt33I9tUdSNryIptM+RxDet6OKm2WnLXzW51KsQ== - body-parser@1.19.0, body-parser@^1.19.0: version "1.19.0" resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.0.tgz#96b2709e57c9c4e09a6fd66a8fd979844f69f08a" @@ -4099,83 +2786,7 @@ braces@^3.0.1, braces@^3.0.2, braces@~3.0.2: dependencies: fill-range "^7.0.1" -brorand@^1.0.1: - version "1.1.0" - resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" - integrity sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8= - -browserify-aes@^1.0.0, browserify-aes@^1.0.4: - version "1.2.0" - resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.2.0.tgz#326734642f403dabc3003209853bb70ad428ef48" - integrity sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA== - dependencies: - buffer-xor "^1.0.3" - cipher-base "^1.0.0" - create-hash "^1.1.0" - evp_bytestokey "^1.0.3" - inherits "^2.0.1" - safe-buffer "^5.0.1" - -browserify-cipher@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/browserify-cipher/-/browserify-cipher-1.0.1.tgz#8d6474c1b870bfdabcd3bcfcc1934a10e94f15f0" - integrity sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w== - dependencies: - browserify-aes "^1.0.4" - browserify-des "^1.0.0" - evp_bytestokey "^1.0.0" - -browserify-des@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/browserify-des/-/browserify-des-1.0.2.tgz#3af4f1f59839403572f1c66204375f7a7f703e9c" - integrity sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A== - dependencies: - cipher-base "^1.0.1" - des.js "^1.0.0" - inherits "^2.0.1" - safe-buffer "^5.1.2" - -browserify-rsa@^4.0.0, browserify-rsa@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/browserify-rsa/-/browserify-rsa-4.0.1.tgz#21e0abfaf6f2029cf2fafb133567a701d4135524" - integrity sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ= - dependencies: - bn.js "^4.1.0" - randombytes "^2.0.1" - -browserify-sign@^4.0.0: - version "4.2.1" - resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.2.1.tgz#eaf4add46dd54be3bb3b36c0cf15abbeba7956c3" - integrity sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg== - dependencies: - bn.js "^5.1.1" - browserify-rsa "^4.0.1" - create-hash "^1.2.0" - create-hmac "^1.1.7" - elliptic "^6.5.3" - inherits "^2.0.4" - parse-asn1 "^5.1.5" - readable-stream "^3.6.0" - safe-buffer "^5.2.0" - -browserify-zlib@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/browserify-zlib/-/browserify-zlib-0.2.0.tgz#2869459d9aa3be245fe8fe2ca1f46e2e7f54d73f" - integrity sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA== - dependencies: - pako "~1.0.5" - -browserslist@^4.0.0, browserslist@^4.9.1: - version "4.14.5" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.14.5.tgz#1c751461a102ddc60e40993639b709be7f2c4015" - integrity sha512-Z+vsCZIvCBvqLoYkBFTwEYH3v5MCQbsAjp50ERycpOjnPmolg1Gjy4+KaWWpm8QOJt9GHkhdqAl14NpCX73CWA== - dependencies: - caniuse-lite "^1.0.30001135" - electron-to-chromium "^1.3.571" - escalade "^3.1.0" - node-releases "^1.1.61" - -browserslist@^4.12.0, browserslist@^4.17.5, browserslist@^4.18.1, browserslist@^4.6.4: +browserslist@^4.0.0, browserslist@^4.12.0, browserslist@^4.14.5, browserslist@^4.16.0, browserslist@^4.16.6, browserslist@^4.17.5, browserslist@^4.18.1, browserslist@^4.6.4, browserslist@^4.9.1: version "4.18.1" resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.18.1.tgz#60d3920f25b6860eb917c6c7b185576f4d8b017f" integrity sha512-8ScCzdpPwR2wQh8IT82CA2VgDwjHyqMovPBZSNH54+tm4Jk2pCuv90gmAdH6J84OCRWi0b4gMe6O6XPXuJnjgQ== @@ -4186,67 +2797,24 @@ browserslist@^4.12.0, browserslist@^4.17.5, browserslist@^4.18.1, browserslist@^ node-releases "^2.0.1" picocolors "^1.0.0" -browserslist@^4.14.5, browserslist@^4.16.0, browserslist@^4.16.1, browserslist@^4.16.6: - version "4.16.6" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.16.6.tgz#d7901277a5a88e554ed305b183ec9b0c08f66fa2" - integrity sha512-Wspk/PqO+4W9qp5iUTJsa1B/QrYn1keNCcEP5OvP7WBwT4KaDly0uONYmC6Xa3Z5IqnUgS0KcgLYu1l74x0ZXQ== - dependencies: - caniuse-lite "^1.0.30001219" - colorette "^1.2.2" - electron-to-chromium "^1.3.723" - escalade "^3.1.1" - node-releases "^1.1.71" - browserstack@^1.5.1: - version "1.6.0" - resolved "https://registry.yarnpkg.com/browserstack/-/browserstack-1.6.0.tgz#5a56ab90987605d9c138d7a8b88128370297f9bf" - integrity sha512-HJDJ0TSlmkwnt9RZ+v5gFpa1XZTBYTj0ywvLwJ3241J7vMw2jAsGNVhKHtmCOyg+VxeLZyaibO9UL71AsUeDIw== + version "1.6.1" + resolved "https://registry.yarnpkg.com/browserstack/-/browserstack-1.6.1.tgz#e051f9733ec3b507659f395c7a4765a1b1e358b3" + integrity sha512-GxtFjpIaKdbAyzHfFDKixKO8IBT7wR3NjbzrGc78nNs/Ciys9wU3/nBtsqsWv5nDSrdI5tz0peKuzCPuNXNUiw== dependencies: https-proxy-agent "^2.2.1" -buffer-alloc-unsafe@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz#bd7dc26ae2972d0eda253be061dba992349c19f0" - integrity sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg== - -buffer-alloc@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/buffer-alloc/-/buffer-alloc-1.2.0.tgz#890dd90d923a873e08e10e5fd51a57e5b7cce0ec" - integrity sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow== - dependencies: - buffer-alloc-unsafe "^1.1.0" - buffer-fill "^1.0.0" - -buffer-fill@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/buffer-fill/-/buffer-fill-1.0.0.tgz#f8f78b76789888ef39f205cd637f68e702122b2c" - integrity sha1-+PeLdniYiO858gXNY39o5wISKyw= - -buffer-from@^1.0.0, buffer-from@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" - integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== +buffer-from@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" + integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== buffer-indexof@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/buffer-indexof/-/buffer-indexof-1.1.1.tgz#52fabcc6a606d1a00302802648ef68f639da268c" integrity sha512-4/rOEg86jivtPTeOUUT61jJO1Ya1TrR/OkqCSZDyq84WJh3LuuiphBYJN+fm5xufIk4XAFcEwte/8WzC8If/1g== -buffer-xor@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" - integrity sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk= - -buffer@^4.3.0: - version "4.9.2" - resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.2.tgz#230ead344002988644841ab0244af8c44bbe3ef8" - integrity sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg== - dependencies: - base64-js "^1.0.2" - ieee754 "^1.1.4" - isarray "^1.0.0" - -buffer@^5.4.3, buffer@^5.5.0: +buffer@^5.5.0: version "5.7.1" resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== @@ -4259,11 +2827,6 @@ builtin-modules@^1.1.1: resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" integrity sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8= -builtin-status-codes@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8" - integrity sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug= - builtins@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/builtins/-/builtins-1.0.3.tgz#cb94faeb61c8696451db36534e1422f94f0aee88" @@ -4279,29 +2842,6 @@ bytes@3.1.0: resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6" integrity sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg== -cacache@15.0.5, cacache@^15.0.5: - version "15.0.5" - resolved "https://registry.yarnpkg.com/cacache/-/cacache-15.0.5.tgz#69162833da29170d6732334643c60e005f5f17d0" - integrity sha512-lloiL22n7sOjEEXdL8NAjTgv9a1u43xICE9/203qonkZUCj5X1UEWIdf2/Y0d6QcCtMzbKQyhrcDbdvlZTs/+A== - dependencies: - "@npmcli/move-file" "^1.0.1" - chownr "^2.0.0" - fs-minipass "^2.0.0" - glob "^7.1.4" - infer-owner "^1.0.4" - lru-cache "^6.0.0" - minipass "^3.1.1" - minipass-collect "^1.0.2" - minipass-flush "^1.0.5" - minipass-pipeline "^1.2.2" - mkdirp "^1.0.3" - p-map "^4.0.0" - promise-inflight "^1.0.1" - rimraf "^3.0.2" - ssri "^8.0.0" - tar "^6.0.2" - unique-filename "^1.1.1" - cacache@15.2.0: version "15.2.0" resolved "https://registry.yarnpkg.com/cacache/-/cacache-15.2.0.tgz#73af75f77c58e72d8c630a7a2858cb18ef523389" @@ -4325,28 +2865,7 @@ cacache@15.2.0: tar "^6.0.2" unique-filename "^1.1.1" -cacache@^12.0.2: - version "12.0.4" - resolved "https://registry.yarnpkg.com/cacache/-/cacache-12.0.4.tgz#668bcbd105aeb5f1d92fe25570ec9525c8faa40c" - integrity sha512-a0tMB40oefvuInr4Cwb3GerbL9xTj1D5yg0T5xrjGCGyfvbxseIXX7BAO/u/hIXdafzOI5JC3wDwHyf24buOAQ== - dependencies: - bluebird "^3.5.5" - chownr "^1.1.1" - figgy-pudding "^3.5.1" - glob "^7.1.4" - graceful-fs "^4.1.15" - infer-owner "^1.0.3" - lru-cache "^5.1.1" - mississippi "^3.0.0" - mkdirp "^0.5.1" - move-concurrently "^1.0.1" - promise-inflight "^1.0.1" - rimraf "^2.6.3" - ssri "^6.0.1" - unique-filename "^1.1.1" - y18n "^4.0.0" - -cacache@^15.2.0: +cacache@^15.0.5, cacache@^15.2.0: version "15.3.0" resolved "https://registry.yarnpkg.com/cacache/-/cacache-15.3.0.tgz#dc85380fb2f556fe3dda4c719bfa0ec875a7f1eb" integrity sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ== @@ -4385,6 +2904,14 @@ cache-base@^1.0.1: union-value "^1.0.0" unset-value "^1.0.0" +call-bind@^1.0.0, call-bind@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" + integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA== + dependencies: + function-bind "^1.1.1" + get-intrinsic "^1.0.2" + callsites@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" @@ -4395,11 +2922,6 @@ camelcase@^5.0.0: resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== -camelcase@^6.2.0: - version "6.2.0" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.2.0.tgz#924af881c9d525ac9d87f40d964e5cea982a1809" - integrity sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg== - caniuse-api@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/caniuse-api/-/caniuse-api-3.0.0.tgz#5e4d90e2274961d46291997df599e3ed008ee4c0" @@ -4410,20 +2932,10 @@ caniuse-api@^3.0.0: lodash.memoize "^4.1.2" lodash.uniq "^4.5.0" -caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001032, caniuse-lite@^1.0.30001135: - version "1.0.30001146" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001146.tgz#c61fcb1474520c1462913689201fb292ba6f447c" - integrity sha512-VAy5RHDfTJhpxnDdp2n40GPPLp3KqNrXz1QqFv4J64HvArKs8nuNMOWkB3ICOaBTU/Aj4rYAo/ytdQDDFF/Pug== - -caniuse-lite@^1.0.30000981, caniuse-lite@^1.0.30001109, caniuse-lite@^1.0.30001280: - version "1.0.30001283" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001283.tgz#8573685bdae4d733ef18f78d44ba0ca5fe9e896b" - integrity sha512-9RoKo841j1GQFSJz/nCXOj0sD7tHBtlowjYlrqIUS812x9/emfBLBt6IyMz1zIaYc/eRL8Cs6HPUVi2Hzq4sIg== - -caniuse-lite@^1.0.30001181, caniuse-lite@^1.0.30001219: - version "1.0.30001228" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001228.tgz#bfdc5942cd3326fa51ee0b42fbef4da9d492a7fa" - integrity sha512-QQmLOGJ3DEgokHbMSA8cj2a+geXqmnpyOFT0lhQV6P3/YOJvGDEwoedcwxEQ30gJIwIIunHIicunJ2rzK5gB2A== +caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000981, caniuse-lite@^1.0.30001032, caniuse-lite@^1.0.30001109, caniuse-lite@^1.0.30001280: + version "1.0.30001284" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001284.tgz#d3653929ded898cd0c1f09a56fd8ca6952df4fca" + integrity sha512-t28SKa7g6kiIQi6NHeOcKrOrGMzCRrXvlasPwWC26TH2QNdglgzQIRUuJ0cR3NeQPH+5jpuveeeSFDLm2zbkEw== canonical-path@1.0.0: version "1.0.0" @@ -4460,15 +2972,7 @@ chalk@^2.0.0, chalk@^2.3.0, chalk@^2.4.2: escape-string-regexp "^1.0.5" supports-color "^5.3.0" -chalk@^4.0.0, chalk@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.0.tgz#4e14870a618d9e2edd97dd8345fd9d9dc315646a" - integrity sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A== - dependencies: - ansi-styles "^4.1.0" - supports-color "^7.1.0" - -chalk@^4.1.1: +chalk@^4.1.0, chalk@^4.1.1: version "4.1.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== @@ -4481,22 +2985,7 @@ chardet@^0.7.0: resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== -"chokidar@>=2.0.0 <4.0.0", chokidar@^3.0.0, chokidar@^3.4.1: - version "3.4.2" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.4.2.tgz#38dc8e658dec3809741eb3ef7bb0a47fe424232d" - integrity sha512-IZHaDeBeI+sZJRX7lGcXsdzgvZqKv6sECqsbErJA4mHWfpRrD8B97kSFN4cQz6nGBGiuFia1MKR4d6c1o8Cv7A== - dependencies: - anymatch "~3.1.1" - braces "~3.0.2" - glob-parent "~5.1.0" - is-binary-path "~2.1.0" - is-glob "~4.0.1" - normalize-path "~3.0.0" - readdirp "~3.4.0" - optionalDependencies: - fsevents "~2.1.2" - -"chokidar@>=3.0.0 <4.0.0": +"chokidar@>=3.0.0 <4.0.0", chokidar@^3.0.0, chokidar@^3.5.1: version "3.5.2" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.2.tgz#dba3976fcadb016f66fd365021d91600d01c1e75" integrity sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ== @@ -4530,51 +3019,21 @@ chokidar@^2.1.8: optionalDependencies: fsevents "^1.2.7" -chokidar@^3.4.2: - version "3.5.1" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.1.tgz#ee9ce7bbebd2b79f49f304799d5468e31e14e68a" - integrity sha512-9+s+Od+W0VJJzawDma/gvBNQqkTiqYTWLuZoyAsivsI4AaWTCzHG06/TMjsf1cYe9Cb97UCEhjz7HvnPk2p/tw== - dependencies: - anymatch "~3.1.1" - braces "~3.0.2" - glob-parent "~5.1.0" - is-binary-path "~2.1.0" - is-glob "~4.0.1" - normalize-path "~3.0.0" - readdirp "~3.5.0" - optionalDependencies: - fsevents "~2.3.1" - -chownr@^1.1.1: - version "1.1.4" - resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" - integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg== - chownr@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/chownr/-/chownr-2.0.0.tgz#15bfbe53d2eab4cf70f18a8cd68ebe5b3cb1dece" integrity sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ== chrome-trace-event@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.2.tgz#234090ee97c7d4ad1a2c4beae27505deffc608a4" - integrity sha512-9e/zx1jw7B4CO+c/RXoCsfg/x1AfUBioy4owYH0bJprEYAx5hRFLRhWBqHAG57D0ZM4H7vxbP7bPe0VwhQRYDQ== - dependencies: - tslib "^1.9.0" + version "1.0.3" + resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz#1015eced4741e15d06664a957dbbf50d041e26ac" + integrity sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg== ci-info@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46" integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ== -cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" - integrity sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q== - dependencies: - inherits "^2.0.1" - safe-buffer "^5.0.1" - circular-dependency-plugin@5.2.2: version "5.2.2" resolved "https://registry.yarnpkg.com/circular-dependency-plugin/-/circular-dependency-plugin-5.2.2.tgz#39e836079db1d3cf2f988dc48c5188a44058b600" @@ -4591,9 +3050,9 @@ class-utils@^0.3.5: static-extend "^0.1.1" classnames@2.x, classnames@^2.2.1, classnames@^2.2.6: - version "2.2.6" - resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.2.6.tgz#43935bffdd291f326dad0a205309b38d00f650ce" - integrity sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q== + version "2.3.1" + resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.3.1.tgz#dfcfa3891e306ec1dad105d0e88f4417b8535e8e" + integrity sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA== clean-stack@^2.0.0: version "2.2.0" @@ -4608,24 +3067,15 @@ cli-cursor@^3.1.0: restore-cursor "^3.1.0" cli-spinners@^2.5.0: - version "2.6.0" - resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-2.6.0.tgz#36c7dc98fb6a9a76bd6238ec3f77e2425627e939" - integrity sha512-t+4/y50K/+4xcCRosKkA7W4gTr1MySvLV0q+PxmG7FJ5g+66ChKurYjxBCjHggHH3HA5Hh9cy+lcUGWDqVH+4Q== + version "2.6.1" + resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-2.6.1.tgz#adc954ebe281c37a6319bfa401e6dd2488ffb70d" + integrity sha512-x/5fWmGMnbKQAaNwN+UZlV79qBLM9JFnJuJ03gIi5whrob0xV0ofNVHy9DhwGdsMJQc2OKv0oGmLzvaqvAVv+g== cli-width@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-3.0.0.tgz#a2f48437a2caa9a22436e794bf071ec9e61cedf6" integrity sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw== -clipboard@^2.0.0: - version "2.0.6" - resolved "https://registry.yarnpkg.com/clipboard/-/clipboard-2.0.6.tgz#52921296eec0fdf77ead1749421b21c968647376" - integrity sha512-g5zbiixBRk/wyKakSwCKd7vQXDjFnAMGHoEyBogG/bw9kTD9GvdAvaoRR1ALcEzt3pVKxZR0pViekPMIS0QyGg== - dependencies: - good-listener "^1.2.2" - select "^1.1.2" - tiny-emitter "^2.0.0" - cliui@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/cliui/-/cliui-5.0.0.tgz#deefcfdb2e800784aa34f46fa08e06851c7bbbc5" @@ -4729,25 +3179,15 @@ color-name@~1.1.4: resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== -colord@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/colord/-/colord-2.0.0.tgz#f8c19f2526b7dc5b22d6e57ef102f03a2a43a3d8" - integrity sha512-WMDFJfoY3wqPZNpKUFdse3HhD5BHCbE9JCdxRzoVH+ywRITGOeWAHNkGEmyxLlErEpN9OLMWgdM9dWQtDk5dog== - colord@^2.9.1: version "2.9.1" resolved "https://registry.yarnpkg.com/colord/-/colord-2.9.1.tgz#c961ea0efeb57c9f0f4834458f26cb9cc4a3f90e" integrity sha512-4LBMSt09vR0uLnPVkOUBnmxgoaeN4ewRbx801wY/bXcltXfpR/G46OdWn96XpYmCWuYvO46aBZP4NgX8HpNAcw== -colorette@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.2.1.tgz#4d0b921325c14faf92633086a536db6e89564b1b" - integrity sha512-puCDz0CzydiSYOrnXpz/PKd69zRrribezjtE9yd4zvytoRc8+RY/KJPvtPFKZS3E3wP6neGyMe0vOTlHO5L3Pw== - colorette@^1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.2.2.tgz#cbcc79d5e99caea2dbf10eb3a26fd8b3e6acfa94" - integrity sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w== + version "1.4.0" + resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.4.0.tgz#5190fbb87276259a86ad700bff2c6d6faa3fca40" + integrity sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g== colors@1.4.0, colors@^1.4.0: version "1.4.0" @@ -4766,26 +3206,21 @@ commander@^2.11.0, commander@^2.12.1, commander@^2.19.0, commander@^2.20.0: resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== -commander@^6.0.0: - version "6.2.1" - resolved "https://registry.yarnpkg.com/commander/-/commander-6.2.1.tgz#0792eb682dfbc325999bb2b84fddddba110ac73c" - integrity sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA== - -commander@^7.1.0, commander@^7.2.0: +commander@^7.2.0: version "7.2.0" resolved "https://registry.yarnpkg.com/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7" integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw== +commander@^8.0.0: + version "8.3.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-8.3.0.tgz#4837ea1b2da67b9c616a67afbb0fafee567bca66" + integrity sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww== + commondir@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" integrity sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs= -compass-sass-mixins@^0.12.7: - version "0.12.7" - resolved "https://registry.yarnpkg.com/compass-sass-mixins/-/compass-sass-mixins-0.12.7.tgz#2ac4d310f2ebe518b7d6aca4ae24f1d325409e8c" - integrity sha1-KsTTEPLr5Ri31qykriTx0yVAnow= - component-emitter@^1.2.1, component-emitter@~1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" @@ -4798,16 +3233,13 @@ compressible@~2.0.16: dependencies: mime-db ">= 1.43.0 < 2" -compression-webpack-plugin@^6.1.1: - version "6.1.1" - resolved "https://registry.yarnpkg.com/compression-webpack-plugin/-/compression-webpack-plugin-6.1.1.tgz#ae8e4b2ffdb7396bb776e66918d751a20d8ccf0e" - integrity sha512-BEHft9M6lwOqVIQFMS/YJGmeCYXVOakC5KzQk05TFpMBlODByh1qNsZCWjUBxCQhUP9x0WfGidxTbGkjbWO/TQ== +compression-webpack-plugin@^9.0.1: + version "9.0.1" + resolved "https://registry.yarnpkg.com/compression-webpack-plugin/-/compression-webpack-plugin-9.0.1.tgz#fd80350670ca88cc8a1c0edac40ee92a0e06fcd4" + integrity sha512-vqlhZIPSyCpy6eaYWy8iPhteLWpARKotRiN5B/jr7lLowJv1GVc98Snn1Dcxe0+SKbfydLu7qZcnNuP+AyG19Q== dependencies: - cacache "^15.0.5" - find-cache-dir "^3.3.1" - schema-utils "^3.0.0" - serialize-javascript "^5.0.1" - webpack-sources "^1.4.3" + schema-utils "^4.0.0" + serialize-javascript "^6.0.0" compression@^1.7.4: version "1.7.4" @@ -4827,20 +3259,10 @@ concat-map@0.0.1: resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= -concat-stream@^1.5.0: - version "1.6.2" - resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" - integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw== - dependencies: - buffer-from "^1.0.0" - inherits "^2.0.3" - readable-stream "^2.2.2" - typedarray "^0.0.6" - config-chain@^1.1.12: - version "1.1.12" - resolved "https://registry.yarnpkg.com/config-chain/-/config-chain-1.1.12.tgz#0fde8d091200eb5e808caf25fe618c02f48e4efa" - integrity sha512-a1eOIcu8+7lUInge4Rpf/n4Krkf3Dd9lqhljRzII1/Zno/kRtUWnznPO3jOKBmTEktkt3fkxisUcivoj0ebzoA== + version "1.1.13" + resolved "https://registry.yarnpkg.com/config-chain/-/config-chain-1.1.13.tgz#fad0795aa6a6cdaff9ed1b68e9dff94372c232f4" + integrity sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ== dependencies: ini "^1.3.4" proto-list "~1.2.1" @@ -4860,21 +3282,11 @@ connect@^3.7.0: parseurl "~1.3.3" utils-merge "1.0.1" -console-browserify@^1.1.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.2.0.tgz#67063cef57ceb6cf4993a2ab3a55840ae8c49336" - integrity sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA== - console-control-strings@^1.0.0, console-control-strings@~1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4= -constants-browserify@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75" - integrity sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U= - content-disposition@0.5.3: version "0.5.3" resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.3.tgz#e130caf7e7279087c5616c2007d0485698984fbd" @@ -4888,9 +3300,9 @@ content-type@~1.0.4: integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== convert-source-map@^1.5.1, convert-source-map@^1.7.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.7.0.tgz#17a2cb882d7f77d3490585e2ce6c524424a3a442" - integrity sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA== + version "1.8.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.8.0.tgz#f3373c32d21b4d780dd8004514684fb791ca4369" + integrity sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA== dependencies: safe-buffer "~5.1.1" @@ -4916,40 +3328,11 @@ copy-anything@^2.0.1: dependencies: is-what "^3.12.0" -copy-concurrently@^1.0.0: - version "1.0.5" - resolved "https://registry.yarnpkg.com/copy-concurrently/-/copy-concurrently-1.0.5.tgz#92297398cae34937fcafd6ec8139c18051f0b5e0" - integrity sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A== - dependencies: - aproba "^1.1.1" - fs-write-stream-atomic "^1.0.8" - iferr "^0.1.5" - mkdirp "^0.5.1" - rimraf "^2.5.4" - run-queue "^1.0.0" - copy-descriptor@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= -copy-webpack-plugin@6.3.2: - version "6.3.2" - resolved "https://registry.yarnpkg.com/copy-webpack-plugin/-/copy-webpack-plugin-6.3.2.tgz#0e920a6c181a5052aa6e2861b164bda03f83afeb" - integrity sha512-MgJ1uouLIbDg4ST1GzqrGQyKoXY5iPqi6fghFqarijam7FQcBa/r6Rg0VkoIuzx75Xq8iAMghyOueMkWUQ5OaA== - dependencies: - cacache "^15.0.5" - fast-glob "^3.2.4" - find-cache-dir "^3.3.1" - glob-parent "^5.1.1" - globby "^11.0.1" - loader-utils "^2.0.0" - normalize-path "^3.0.0" - p-limit "^3.0.2" - schema-utils "^3.0.0" - serialize-javascript "^5.0.1" - webpack-sources "^1.4.3" - copy-webpack-plugin@9.0.1: version "9.0.1" resolved "https://registry.yarnpkg.com/copy-webpack-plugin/-/copy-webpack-plugin-9.0.1.tgz#b71d21991599f61a4ee00ba79087b8ba279bbb59" @@ -4971,34 +3354,26 @@ core-js-compat@^3.15.0, core-js-compat@^3.16.2: browserslist "^4.18.1" semver "7.0.0" -core-js-compat@^3.8.0: - version "3.12.1" - resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.12.1.tgz#2c302c4708505fa7072b0adb5156d26f7801a18b" - integrity sha512-i6h5qODpw6EsHAoIdQhKoZdWn+dGBF3dSS8m5tif36RlWvW3A6+yu2S16QHUo3CrkzrnEskMAt9f8FxmY9fhWQ== - dependencies: - browserslist "^4.16.6" - semver "7.0.0" - core-js@3.16.0: version "3.16.0" resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.16.0.tgz#1d46fb33720bc1fa7f90d20431f36a5540858986" integrity sha512-5+5VxRFmSf97nM8Jr2wzOwLqRo6zphH2aX+7KsAUONObyzakDNq2G/bgbhinxB4PoV9L3aXQYhiDKyIKWd2c8g== -core-js@3.8.3: - version "3.8.3" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.8.3.tgz#c21906e1f14f3689f93abcc6e26883550dd92dd0" - integrity sha512-KPYXeVZYemC2TkNEkX/01I+7yd+nX3KddKwZ1Ww7SKWdI2wQprSgLmrTddT8nw92AjEklTsPBoSdQBhbI1bQ6Q== - -core-js@^3.18.3: - version "3.18.3" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.18.3.tgz#86a0bba2d8ec3df860fefcc07a8d119779f01509" - integrity sha512-tReEhtMReZaPFVw7dajMx0vlsz3oOb8ajgPoHVYGxr8ErnZ6PcYEvvmjGmXlfpnxpkYSdOQttjB+MvVbCGfvLw== +core-js@^3.19.2: + version "3.19.2" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.19.2.tgz#ae216d7f4f7e924d9a2e3ff1e4b1940220f9157b" + integrity sha512-ciYCResnLIATSsXuXnIOH4CbdfgV+H1Ltg16hJFN7/v6OxqnFr/IFGeLacaZ+fHLAm0TBbXwNK9/DNBzBUrO/g== -core-util-is@1.0.2, core-util-is@~1.0.0: +core-util-is@1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= +core-util-is@~1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" + integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== + cors@~2.8.5: version "2.8.5" resolved "https://registry.yarnpkg.com/cors/-/cors-2.8.5.tgz#eac11da51592dd86b9f06f6e7ac293b3df875d29" @@ -5008,9 +3383,9 @@ cors@~2.8.5: vary "^1" cosmiconfig@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-7.0.0.tgz#ef9b44d773959cae63ddecd122de23853b60f8d3" - integrity sha512-pondGvTuVYDk++upghXJabWzL6Kxu6f26ljFw64Swq9v6sQPUL3EUlVDV56diOjpCayKihL6hVe8exIACU4XcA== + version "7.0.1" + resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-7.0.1.tgz#714d756522cace867867ccb4474c5d01bbae5d6d" + integrity sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ== dependencies: "@types/parse-json" "^4.0.0" import-fresh "^3.2.1" @@ -5018,36 +3393,10 @@ cosmiconfig@^7.0.0: path-type "^4.0.0" yaml "^1.10.0" -create-ecdh@^4.0.0: - version "4.0.4" - resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.4.tgz#d6e7f4bffa66736085a0762fd3a632684dabcc4e" - integrity sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A== - dependencies: - bn.js "^4.1.0" - elliptic "^6.5.3" - -create-hash@^1.1.0, create-hash@^1.1.2, create-hash@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.2.0.tgz#889078af11a63756bcfb59bd221996be3a9ef196" - integrity sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg== - dependencies: - cipher-base "^1.0.1" - inherits "^2.0.1" - md5.js "^1.3.4" - ripemd160 "^2.0.1" - sha.js "^2.4.0" - -create-hmac@^1.1.0, create-hmac@^1.1.4, create-hmac@^1.1.7: - version "1.1.7" - resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.7.tgz#69170c78b3ab957147b2b8b04572e47ead2243ff" - integrity sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg== - dependencies: - cipher-base "^1.0.3" - create-hash "^1.1.0" - inherits "^2.0.1" - ripemd160 "^2.0.0" - safe-buffer "^5.0.1" - sha.js "^2.4.8" +create-require@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" + integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== critters@0.0.12: version "0.0.12" @@ -5061,17 +3410,6 @@ critters@0.0.12: postcss "^8.3.7" pretty-bytes "^5.3.0" -critters@0.0.7: - version "0.0.7" - resolved "https://registry.yarnpkg.com/critters/-/critters-0.0.7.tgz#548b470360f4f3c51e622de3b7aa733c8f0b17bf" - integrity sha512-qUF2SaAWFYjNPdCcPpu68p2DnHiosia84yx5mPTlUMQjkjChR+n6sO1/I7yn2U2qNDgSPTd2SoaTIDQcUL+EwQ== - dependencies: - chalk "^4.1.0" - css "^3.0.0" - parse5 "^6.0.1" - parse5-htmlparser2-tree-adapter "^6.0.1" - pretty-bytes "^5.3.0" - cross-spawn@^6.0.0, cross-spawn@^6.0.5: version "6.0.5" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" @@ -5083,23 +3421,6 @@ cross-spawn@^6.0.0, cross-spawn@^6.0.5: shebang-command "^1.2.0" which "^1.2.9" -crypto-browserify@^3.11.0: - version "3.12.0" - resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec" - integrity sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg== - dependencies: - browserify-cipher "^1.0.0" - browserify-sign "^4.0.0" - create-ecdh "^4.0.0" - create-hash "^1.1.0" - create-hmac "^1.1.0" - diffie-hellman "^5.0.0" - inherits "^2.0.1" - pbkdf2 "^3.0.3" - public-encrypt "^4.0.0" - randombytes "^2.0.0" - randomfill "^1.0.3" - css-blank-pseudo@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/css-blank-pseudo/-/css-blank-pseudo-0.1.4.tgz#dfdefd3254bf8a82027993674ccf35483bfcb3c5" @@ -5107,20 +3428,10 @@ css-blank-pseudo@^0.1.4: dependencies: postcss "^7.0.5" -css-color-names@^0.0.4: - version "0.0.4" - resolved "https://registry.yarnpkg.com/css-color-names/-/css-color-names-0.0.4.tgz#808adc2e79cf84738069b646cb20ec27beb629e0" - integrity sha1-gIrcLnnPhHOAabZGyyDsJ762KeA= - -css-color-names@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/css-color-names/-/css-color-names-1.0.1.tgz#6ff7ee81a823ad46e020fa2fd6ab40a887e2ba67" - integrity sha512-/loXYOch1qU1biStIFsHH8SxTmOseh1IJqFvy8IujXOm1h+QjUdDhkzOrR5HG8K8mlxREj0yfi8ewCHx0eMxzA== - css-declaration-sorter@^6.0.3: - version "6.0.3" - resolved "https://registry.yarnpkg.com/css-declaration-sorter/-/css-declaration-sorter-6.0.3.tgz#9dfd8ea0df4cc7846827876fafb52314890c21a9" - integrity sha512-52P95mvW1SMzuRZegvpluT6yEv0FqQusydKQPZsNN5Q7hh8EwQvN8E2nwuJ16BBvNN6LcoIZXu/Bk58DAhrrxw== + version "6.1.3" + resolved "https://registry.yarnpkg.com/css-declaration-sorter/-/css-declaration-sorter-6.1.3.tgz#e9852e4cf940ba79f509d9425b137d1f94438dc2" + integrity sha512-SvjQjNRZgh4ULK1LDJ2AduPKUKxIqmtU7ZAyi47BTV+M90Qvxr9AB6lKlLbDUfXqI9IQeYA8LbAsCZPpJEV3aA== dependencies: timsort "^0.3.0" @@ -5132,31 +3443,13 @@ css-has-pseudo@^0.10.0: postcss "^7.0.6" postcss-selector-parser "^5.0.0-rc.4" -css-line-break@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/css-line-break/-/css-line-break-1.1.1.tgz#d5e9bdd297840099eb0503c7310fd34927a026ef" - integrity sha512-1feNVaM4Fyzdj4mKPIQNL2n70MmuYzAXZ1aytlROFX1JsOo070OsugwGjj7nl6jnDJWHDM8zRZswkmeYVWZJQA== +css-line-break@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/css-line-break/-/css-line-break-2.0.1.tgz#3dc74c2ed5eb64211480281932475790243e7338" + integrity sha512-gwKYIMUn7xodIcb346wgUhE2Dt5O1Kmrc16PWi8sL4FTfyDj8P5095rzH7+O8CTZudJr+uw2GCI/hwEkDJFI2w== dependencies: base64-arraybuffer "^0.2.0" -css-loader@5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-5.0.1.tgz#9e4de0d6636a6266a585bd0900b422c85539d25f" - integrity sha512-cXc2ti9V234cq7rJzFKhirb2L2iPy8ZjALeVJAozXYz9te3r4eqLSixNAbMDJSgJEQywqXzs8gonxaboeKqwiw== - dependencies: - camelcase "^6.2.0" - cssesc "^3.0.0" - icss-utils "^5.0.0" - loader-utils "^2.0.0" - postcss "^8.1.4" - postcss-modules-extract-imports "^3.0.0" - postcss-modules-local-by-default "^4.0.0" - postcss-modules-scope "^3.0.0" - postcss-modules-values "^4.0.0" - postcss-value-parser "^4.1.0" - schema-utils "^3.0.0" - semver "^7.3.2" - css-loader@6.2.0: version "6.2.0" resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-6.2.0.tgz#9663d9443841de957a3cb9bcea2eda65b3377071" @@ -5198,17 +3491,6 @@ css-prefers-color-scheme@^3.1.1: dependencies: postcss "^7.0.5" -css-select@^3.1.2: - version "3.1.2" - resolved "https://registry.yarnpkg.com/css-select/-/css-select-3.1.2.tgz#d52cbdc6fee379fba97fb0d3925abbd18af2d9d8" - integrity sha512-qmss1EihSuBNWNNhHjxzxSfJoFBM/lERB/Q4EnsJQQC62R2evJDW481091oAdOr9uh46/0n4nrg0It5cAnj1RA== - dependencies: - boolbase "^1.0.0" - css-what "^4.0.0" - domhandler "^4.0.0" - domutils "^2.4.3" - nth-check "^2.0.0" - css-select@^4.1.3: version "4.1.3" resolved "https://registry.yarnpkg.com/css-select/-/css-select-4.1.3.tgz#a70440f70317f2669118ad74ff105e65849c7067" @@ -5244,11 +3526,6 @@ css-vendor@^2.0.8: "@babel/runtime" "^7.8.3" is-in-browser "^1.0.2" -css-what@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/css-what/-/css-what-4.0.0.tgz#35e73761cab2eeb3d3661126b23d7aa0e8432233" - integrity sha512-teijzG7kwYfNVsUh2H/YN62xW3KK9YhXEgSlbxMlcyjPNvdKJqFx5lrwlJgoFP1ZHlB89iGDlo/JyshKeRhv5A== - css-what@^5.0.0: version "5.1.0" resolved "https://registry.yarnpkg.com/css-what/-/css-what-5.1.0.tgz#3f7b707aadf633baf62c2ceb8579b545bb40f7fe" @@ -5264,15 +3541,6 @@ css@^2.0.0: source-map-resolve "^0.5.2" urix "^0.1.0" -css@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/css/-/css-3.0.0.tgz#4447a4d58fdd03367c516ca9f64ae365cee4aa5d" - integrity sha512-DG9pFfwOrzc+hawpmqX/dHYHJG+Bsdb0klhyi1sDneOgGOXy9wQIC8hzyVp1e4NRYDBdxcylvywPkkXCHAzTyQ== - dependencies: - inherits "^2.0.4" - source-map "^0.6.1" - source-map-resolve "^0.6.0" - cssauron@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/cssauron/-/cssauron-1.4.0.tgz#a6602dff7e04a8306dc0db9a551e92e8b5662ad8" @@ -5295,41 +3563,6 @@ cssesc@^3.0.0: resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg== -cssnano-preset-default@^5.0.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/cssnano-preset-default/-/cssnano-preset-default-5.1.1.tgz#5cd783caed942cc94159aeb10583af4691445b8c" - integrity sha512-kAhR71Tascmnjlhl4UegGA3KGGbMLXHkkqVpA9idsRT1JmIhIsz1C3tDpBeQMUw5EX5Rfb1HGc/PRqD2AFk3Vg== - dependencies: - css-declaration-sorter "^6.0.3" - cssnano-utils "^2.0.1" - postcss-calc "^8.0.0" - postcss-colormin "^5.1.1" - postcss-convert-values "^5.0.1" - postcss-discard-comments "^5.0.1" - postcss-discard-duplicates "^5.0.1" - postcss-discard-empty "^5.0.1" - postcss-discard-overridden "^5.0.1" - postcss-merge-longhand "^5.0.2" - postcss-merge-rules "^5.0.1" - postcss-minify-font-values "^5.0.1" - postcss-minify-gradients "^5.0.1" - postcss-minify-params "^5.0.1" - postcss-minify-selectors "^5.1.0" - postcss-normalize-charset "^5.0.1" - postcss-normalize-display-values "^5.0.1" - postcss-normalize-positions "^5.0.1" - postcss-normalize-repeat-style "^5.0.1" - postcss-normalize-string "^5.0.1" - postcss-normalize-timing-functions "^5.0.1" - postcss-normalize-unicode "^5.0.1" - postcss-normalize-url "^5.0.1" - postcss-normalize-whitespace "^5.0.1" - postcss-ordered-values "^5.0.1" - postcss-reduce-initial "^5.0.1" - postcss-reduce-transforms "^5.0.1" - postcss-svgo "^5.0.1" - postcss-unique-selectors "^5.0.1" - cssnano-preset-default@^5.1.8: version "5.1.8" resolved "https://registry.yarnpkg.com/cssnano-preset-default/-/cssnano-preset-default-5.1.8.tgz#7525feb1b72f7b06e57f55064cbdae341d79dea2" @@ -5365,19 +3598,10 @@ cssnano-preset-default@^5.1.8: postcss-svgo "^5.0.3" postcss-unique-selectors "^5.0.2" -cssnano-utils@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/cssnano-utils/-/cssnano-utils-2.0.1.tgz#8660aa2b37ed869d2e2f22918196a9a8b6498ce2" - integrity sha512-i8vLRZTnEH9ubIyfdZCAdIdgnHAUeQeByEeQ2I7oTilvP9oHO6RScpeq3GsFUVqeB8uZgOQ9pw8utofNn32hhQ== - -cssnano@5.0.2: - version "5.0.2" - resolved "https://registry.yarnpkg.com/cssnano/-/cssnano-5.0.2.tgz#3f6de4fd5ecb7b5fb636c1a606de5f38cd241493" - integrity sha512-8JK3EnPsjQsULme9/e5M2hF564f/480hwsdcHvQ7ZtAIMfQ1O3SCfs+b8Mjf5KJxhYApyRshR2QSovEJi2K72Q== - dependencies: - cosmiconfig "^7.0.0" - cssnano-preset-default "^5.0.1" - is-resolvable "^1.1.0" +cssnano-utils@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/cssnano-utils/-/cssnano-utils-2.0.1.tgz#8660aa2b37ed869d2e2f22918196a9a8b6498ce2" + integrity sha512-i8vLRZTnEH9ubIyfdZCAdIdgnHAUeQeByEeQ2I7oTilvP9oHO6RScpeq3GsFUVqeB8uZgOQ9pw8utofNn32hhQ== cssnano@^5.0.6: version "5.0.12" @@ -5397,29 +3621,24 @@ csso@^4.2.0: css-tree "^1.1.2" csstype@^2.5.2: - version "2.6.13" - resolved "https://registry.yarnpkg.com/csstype/-/csstype-2.6.13.tgz#a6893015b90e84dd6e85d0e3b442a1e84f2dbe0f" - integrity sha512-ul26pfSQTZW8dcOnD2iiJssfXw0gdNVX9IJDH/X3K5DGPfj+fUYe3kB+swUY6BF3oZDxaID3AJt+9/ojSAE05A== + version "2.6.19" + resolved "https://registry.yarnpkg.com/csstype/-/csstype-2.6.19.tgz#feeb5aae89020bb389e1f63669a5ed490e391caa" + integrity sha512-ZVxXaNy28/k3kJg0Fou5MiYpp88j7H9hLZp8PDC3jV0WFjfH5E9xHb56L0W59cPbKbcHXeP4qyT8PrHp8t6LcQ== csstype@^3.0.2: - version "3.0.3" - resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.0.3.tgz#2b410bbeba38ba9633353aff34b05d9755d065f8" - integrity sha512-jPl+wbWPOWJ7SXsWyqGRk3lGecbar0Cb0OvZF/r/ZU011R4YqiRehgkQ9p4eQfo9DSDLqLL3wHwfxeJiuIsNag== + version "3.0.10" + resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.0.10.tgz#2ad3a7bed70f35b965707c092e5f30b327c290e5" + integrity sha512-2u44ZG2OcNUO9HDp/Jl8C07x6pU/eTR3ncV91SiK3dhG9TWvRVsCoJw14Ckx5DgWkzGA3waZWO3d7pgqpUI/XA== custom-event@~1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/custom-event/-/custom-event-1.0.1.tgz#5d02a46850adf1b4a317946a3928fccb5bfd0425" integrity sha1-XQKkaFCt8bSjF5RqOSj8y1v9BCU= -cyclist@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/cyclist/-/cyclist-1.0.1.tgz#596e9698fd0c80e12038c2b82d6eb1b35b6224d9" - integrity sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk= - damerau-levenshtein@^1.0.4: - version "1.0.6" - resolved "https://registry.yarnpkg.com/damerau-levenshtein/-/damerau-levenshtein-1.0.6.tgz#143c1641cb3d85c60c32329e26899adea8701791" - integrity sha512-JVrozIeElnj3QzfUIt8tB8YMluBJom4Vw9qTPpjGYQ9fYlB3D/rb6OordUxf3xeFB35LKWs0xqcO5U6ySvBtug== + version "1.0.7" + resolved "https://registry.yarnpkg.com/damerau-levenshtein/-/damerau-levenshtein-1.0.7.tgz#64368003512a1a6992593741a09a9d31a836f55d" + integrity sha512-VvdQIPGdWP0SqFXghj79Wf/5LArmreyMsGLa6FG6iC4t3j7j5s71TrwWmT/4akbDQIqjfACkLZmjXhA7g2oUZw== dashdash@^1.12.0: version "1.14.1" @@ -5428,10 +3647,10 @@ dashdash@^1.12.0: dependencies: assert-plus "^1.0.0" -date-fns@^2.21.3: - version "2.21.3" - resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.21.3.tgz#8f5f6889d7a96bbcc1f0ea50239b397a83357f9b" - integrity sha512-HeYdzCaFflc1i4tGbj7JKMjM4cKGYoyxwcIIkHzNgCkX8xXDNJDZXgDDVchIWpN4eQc3lH37WarduXFZJOtxfw== +date-fns@^2.26.0: + version "2.27.0" + resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.27.0.tgz#e1ff3c3ddbbab8a2eaadbb6106be2929a5a2d92b" + integrity sha512-sj+J0Mo2p2X1e306MHq282WS4/A8Pz/95GIFcsPNMPMZVI3EUrAdSv90al1k+p74WGLCruMXk23bfEDZa71X9Q== date-format@^2.1.0: version "2.1.0" @@ -5443,6 +3662,11 @@ date-format@^3.0.0: resolved "https://registry.yarnpkg.com/date-format/-/date-format-3.0.0.tgz#eb8780365c7d2b1511078fb491e6479780f3ad95" integrity sha512-eyTcpKOcamdhWJXj56DpQMo1ylSQpcGtGKXcU0Tb97+K56/CF5amAqqqNj0+KvA0iw2ynxtHWFsPDSClCxe48w== +dayjs@^1.10.4: + version "1.10.7" + resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.10.7.tgz#2cf5f91add28116748440866a0a1d26f3a6ce468" + integrity sha512-P6twpd70BcPK34K26uJ1KT3wlhpuOAPoMwJzpsIWUxHZ7wpmbdZL/hQqBDfz7hGurYSa5PhzdhDHtt319hL3ig== + debug@2.6.9, debug@^2.2.0, debug@^2.3.3: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" @@ -5450,10 +3674,10 @@ debug@2.6.9, debug@^2.2.0, debug@^2.3.3: dependencies: ms "2.0.0" -debug@4, debug@~4.3.1: - version "4.3.1" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.1.tgz#f0d229c505e0c6d8c49ac553d1b13dc183f6b2ee" - integrity sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ== +debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@~4.3.1, debug@~4.3.2: + version "4.3.3" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.3.tgz#04266e0b70a98d4462e6e288e38259213332b664" + integrity sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q== dependencies: ms "2.1.2" @@ -5464,34 +3688,13 @@ debug@4.3.2: dependencies: ms "2.1.2" -debug@^3.1.0, debug@^3.1.1: - version "3.2.6" - resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" - integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== - dependencies: - ms "^2.1.1" - -debug@^3.2.6: +debug@^3.1.0, debug@^3.1.1, debug@^3.2.6: version "3.2.7" resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== dependencies: ms "^2.1.1" -debug@^4.1.0, debug@^4.1.1: - version "4.2.0" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.2.0.tgz#7f150f93920e94c58f5574c2fd01a3110effe7f1" - integrity sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg== - dependencies: - ms "2.1.2" - -debug@^4.3.1: - version "4.3.3" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.3.tgz#04266e0b70a98d4462e6e288e38259213332b664" - integrity sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q== - dependencies: - ms "2.1.2" - debug@~3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" @@ -5606,11 +3809,6 @@ delayed-stream@~1.0.0: resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= -delegate@^3.1.2: - version "3.2.0" - resolved "https://registry.yarnpkg.com/delegate/-/delegate-3.2.0.tgz#b66b71c3158522e8ab5744f720d8ca0c2af59166" - integrity sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw== - delegates@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" @@ -5626,30 +3824,22 @@ dependency-graph@^0.11.0: resolved "https://registry.yarnpkg.com/dependency-graph/-/dependency-graph-0.11.0.tgz#ac0ce7ed68a54da22165a85e97a01d53f5eb2e27" integrity sha512-JeMq7fEshyepOWDfcfHK06N3MhyPhz++vtqWhMT5O9A3K42rdsEDpfdVqjaqaAhsw6a+ZqeDvQVtD0hFHQWrzg== -des.js@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.0.1.tgz#5382142e1bdc53f85d86d53e5f4aa7deb91e0843" - integrity sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA== - dependencies: - inherits "^2.0.1" - minimalistic-assert "^1.0.0" - destroy@~1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA= detect-node@^2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.0.4.tgz#014ee8f8f669c5c58023da64b8179c083a28c46c" - integrity sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw== + version "2.1.0" + resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.1.0.tgz#c9c70775a49c3d03bc2c06d9a73be550f978f8b1" + integrity sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g== di@^0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/di/-/di-0.0.1.tgz#806649326ceaa7caa3306d75d985ea2748ba913c" integrity sha1-gGZJMmzqp8qjMG112YXqJ0i6kTw= -diff-match-patch@^1.0.4: +diff-match-patch@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/diff-match-patch/-/diff-match-patch-1.0.5.tgz#abb584d5f10cd1196dfc55aa03701592ae3f7b37" integrity sha512-IayShXAgj/QMXgB0IWmKx+rOPuGMhqm5w6jvFxmVenXKIzRqTAAsbBPT3kWQeGANj3jGgvcvv4yK6SxqYmikgw== @@ -5659,15 +3849,6 @@ diff@^4.0.1: resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== -diffie-hellman@^5.0.0: - version "5.0.3" - resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875" - integrity sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg== - dependencies: - bn.js "^4.1.0" - miller-rabin "^4.0.0" - randombytes "^2.0.0" - dijkstrajs@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/dijkstrajs/-/dijkstrajs-1.0.2.tgz#2e48c0d3b825462afe75ab4ad5e829c8ece36257" @@ -5680,10 +3861,10 @@ dir-glob@^3.0.1: dependencies: path-type "^4.0.0" -directory-tree@^2.2.4: - version "2.2.4" - resolved "https://registry.yarnpkg.com/directory-tree/-/directory-tree-2.2.4.tgz#6d5bd7d82e48378e256a1e87b678a43c50076e2e" - integrity sha512-2N43msQptKbi3WMfIs+U09yi6bfyKL+MWyj5VMj8t1F/Tx04bt1cn/EEIU3o1JBltlJk7NQnzOEuTNa/KQvbWA== +directory-tree@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/directory-tree/-/directory-tree-3.0.1.tgz#ce7e087d7a9a58947ab802125b4c45481270db72" + integrity sha512-IJL5L/zd73xbchfsIKMrhaRJCt28ek1UsS6LNZ6b9r7m+VbU1fd7JZAypn6gl1g4hpxn21QF3/scAWKIOMk4Ug== dns-equal@^1.0.0: version "1.0.0" @@ -5691,9 +3872,9 @@ dns-equal@^1.0.0: integrity sha1-s55/HabrCnW6nBcySzR1PEfgZU0= dns-packet@^1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/dns-packet/-/dns-packet-1.3.1.tgz#12aa426981075be500b910eedcd0b47dd7deda5a" - integrity sha512-0UxfQkMhYAUaZI+xrNZOz/as5KgDU0M/fQ9b6SpkyLbk3GEswDi6PADJVaYJradtRVsRIlF1zLyOodbcTCDzUg== + version "1.3.4" + resolved "https://registry.yarnpkg.com/dns-packet/-/dns-packet-1.3.4.tgz#e3455065824a2507ba886c55a89963bb107dec6f" + integrity sha512-BQ6F4vycLXBvdrJZ6S3gZewt6rcrks9KBgM9vrhW+knGRqc8uEdT7fuCwloc7nny5xNoMJ17HGH0R/6fpo8ECA== dependencies: ip "^1.1.0" safe-buffer "^5.0.1" @@ -5706,14 +3887,14 @@ dns-txt@^2.0.2: buffer-indexof "^1.0.0" dom-align@^1.7.0: - version "1.12.0" - resolved "https://registry.yarnpkg.com/dom-align/-/dom-align-1.12.0.tgz#56fb7156df0b91099830364d2d48f88963f5a29c" - integrity sha512-YkoezQuhp3SLFGdOlr5xkqZ640iXrnHAwVYcDg8ZKRUtO7mSzSC2BA5V0VuyAwPSJA4CLIc6EDDJh4bEsD2+zA== + version "1.12.2" + resolved "https://registry.yarnpkg.com/dom-align/-/dom-align-1.12.2.tgz#0f8164ebd0c9c21b0c790310493cd855892acd4b" + integrity sha512-pHuazgqrsTFrGU2WLDdXxCFabkdQDx72ddkraZNih1KsMcN5qsRSTR9O4VJRlwTPCPb5COYg3LOfiMHHcPInHg== dom-helpers@^5.0.1: - version "5.2.0" - resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-5.2.0.tgz#57fd054c5f8f34c52a3eeffdb7e7e93cd357d95b" - integrity sha512-Ru5o9+V8CpunKnz5LGgWXkmrH/20cGKwcHwS4m73zIvs54CN9epEmT/HLqFJW3kXpakAFkEdzgy1hzlJe3E4OQ== + version "5.2.1" + resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-5.2.1.tgz#d9400536b2bf8225ad98fe052e029451ac40e902" + integrity sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA== dependencies: "@babel/runtime" "^7.8.7" csstype "^3.0.2" @@ -5737,36 +3918,17 @@ dom-serializer@^1.0.1: domhandler "^4.2.0" entities "^2.0.0" -domain-browser@^1.1.1: - version "1.2.0" - resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.2.0.tgz#3d31f50191a6749dd1375a7f522e823d42e54eda" - integrity sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA== - -domelementtype@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.0.2.tgz#f3b6e549201e46f588b59463dd77187131fe6971" - integrity sha512-wFwTwCVebUrMgGeAwRL/NhZtHAUyT9n9yg4IMDwf10+6iCMxSkVq9MGCVEH+QZWo1nNidy8kNvwmv4zWHDTqvA== - -domelementtype@^2.2.0: +domelementtype@^2.0.1, domelementtype@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.2.0.tgz#9a0b6c2782ed6a1c7323d42267183df9bd8b1d57" integrity sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A== -domhandler@^4.0.0, domhandler@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-4.2.0.tgz#f9768a5f034be60a89a27c2e4d0f74eba0d8b059" - integrity sha512-zk7sgt970kzPks2Bf+dwT/PLzghLnsivb9CcxkvR8Mzr66Olr0Ofd8neSbglHJHaHa2MadfoSdNlKYAaafmWfA== - dependencies: - domelementtype "^2.2.0" - -domutils@^2.4.3: - version "2.6.0" - resolved "https://registry.yarnpkg.com/domutils/-/domutils-2.6.0.tgz#2e15c04185d43fb16ae7057cb76433c6edb938b7" - integrity sha512-y0BezHuy4MDYxh6OvolXYsH+1EMGmFbwv5FKW7ovwMG6zTPWqNPq3WF9ayZssFq+UlKdffGLbOEaghNdaOm1WA== +domhandler@^4.2.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-4.3.0.tgz#16c658c626cf966967e306f966b431f77d4a5626" + integrity sha512-fC0aXNQXqKSFTr2wDNZDhsEYjCiYsDWl3D01kwt25hm1YIPyDGHvvi3rw+PLqHAl/m71MaiF7d5zvBr0p5UB2g== dependencies: - dom-serializer "^1.0.1" domelementtype "^2.2.0" - domhandler "^4.2.0" domutils@^2.6.0: version "2.8.0" @@ -5777,16 +3939,6 @@ domutils@^2.6.0: domelementtype "^2.2.0" domhandler "^4.2.0" -duplexify@^3.4.2, duplexify@^3.6.0: - version "3.7.1" - resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.7.1.tgz#2a4df5317f6ccfd91f86d6fd25d8d8a103b88309" - integrity sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g== - dependencies: - end-of-stream "^1.0.0" - inherits "^2.0.1" - readable-stream "^2.0.0" - stream-shift "^1.0.0" - ecc-jsbn@~0.1.1: version "0.1.2" resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" @@ -5810,33 +3962,10 @@ ee-first@1.1.1: resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= -electron-to-chromium@^1.3.571: - version "1.3.578" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.578.tgz#e6671936f4571a874eb26e2e833aa0b2c0b776e0" - integrity sha512-z4gU6dA1CbBJsAErW5swTGAaU2TBzc2mPAonJb00zqW1rOraDo2zfBMDRvaz9cVic+0JEZiYbHWPw/fTaZlG2Q== - -electron-to-chromium@^1.3.723: - version "1.3.737" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.737.tgz#196f2e9656f4f3c31930750e1899c091b72d36b5" - integrity sha512-P/B84AgUSQXaum7a8m11HUsYL8tj9h/Pt5f7Hg7Ty6bm5DxlFq+e5+ouHUoNQMsKDJ7u4yGfI8mOErCmSH9wyg== - electron-to-chromium@^1.3.896: - version "1.4.5" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.5.tgz#912e8fd1645edee2f0f212558f40916eb538b1f9" - integrity sha512-YKaB+t8ul5crdh6OeqT2qXdxJGI0fAYb6/X8pDIyye+c3a7ndOCk5gVeKX+ABwivCGNS56vOAif3TN0qJMpEHw== - -elliptic@^6.5.3: - version "6.5.3" - resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.3.tgz#cb59eb2efdaf73a0bd78ccd7015a62ad6e0f93d6" - integrity sha512-IMqzv5wNQf+E6aHeIqATs0tOLeOTwj1QKbRcS3jBbYkl5oLAserA8yJTT7/VyHUYG91PRmPyeQDObKLPpeS4dw== - dependencies: - bn.js "^4.4.0" - brorand "^1.0.1" - hash.js "^1.0.0" - hmac-drbg "^1.0.0" - inherits "^2.0.1" - minimalistic-assert "^1.0.0" - minimalistic-crypto-utils "^1.0.0" + version "1.4.10" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.10.tgz#5f44ae6f6725b1949d6e8d34352f80d4c1880734" + integrity sha512-tFgA40Iq2oy4k2PnZrLJowbgpij+lD6ZLxkw8Ht1NKTYyN8dvSvC5xlo8X0WW2jqhKSzITrbr5mpB4/AZ/8OUA== emoji-regex@^7.0.1: version "7.0.3" @@ -5848,7 +3977,7 @@ emoji-regex@^8.0.0: resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== -emoji-toolkit@^6.0.1: +emoji-toolkit@^6.5.0: version "6.6.0" resolved "https://registry.yarnpkg.com/emoji-toolkit/-/emoji-toolkit-6.6.0.tgz#e7287c43a96f940ec4c5428cd7100a40e57518f1" integrity sha512-pEu0kow2p1N8zCKnn/L6H0F3rWUBB3P3hVjr/O5yl1fK7N9jU4vO4G7EFapC5Y3XwZLUCY0FZbOPyTkH+4V2eQ== @@ -5858,6 +3987,11 @@ emojis-list@^3.0.0: resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-3.0.0.tgz#5570662046ad29e2e916e71aae260abdff4f6a78" integrity sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q== +encode-utf8@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/encode-utf8/-/encode-utf8-1.0.3.tgz#f30fdd31da07fb596f281beb2f6b027851994cda" + integrity sha512-ucAnuBEhUK4boH2HjVYG5Q2mQyPorvv0u/ocS+zhdw0S8AlHYY+GOFhP1Gio5z4icpP2ivFSvhtFjQi8+T9ppw== + encodeurl@~1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" @@ -5870,49 +4004,35 @@ encoding@^0.1.12: dependencies: iconv-lite "^0.6.2" -end-of-stream@^1.0.0, end-of-stream@^1.1.0: +end-of-stream@^1.1.0: version "1.4.4" resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== dependencies: once "^1.4.0" -engine.io-parser@~4.0.0: - version "4.0.2" - resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-4.0.2.tgz#e41d0b3fb66f7bf4a3671d2038a154024edb501e" - integrity sha512-sHfEQv6nmtJrq6TKuIz5kyEKH/qSdK56H/A+7DnAuUPWosnIZAS2NHNcPLmyjtY3cGS/MqJdZbUjW97JU72iYg== +engine.io-parser@~5.0.0: + version "5.0.2" + resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-5.0.2.tgz#69a2ec3ed431da021f0666712d07f106bcffa6ce" + integrity sha512-wuiO7qO/OEkPJSFueuATIXtrxF7/6GTbAO9QLv7nnbjwZ5tYhLm9zxvLwxstRs0dcT0KUlWTjtIOs1T86jt12g== dependencies: - base64-arraybuffer "0.1.4" + base64-arraybuffer "~1.0.1" -engine.io@~4.1.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/engine.io/-/engine.io-4.1.1.tgz#9a8f8a5ac5a5ea316183c489bf7f5b6cf91ace5b" - integrity sha512-t2E9wLlssQjGw0nluF6aYyfX8LwYU8Jj0xct+pAhfWfv/YrBn6TSNtEYsgxHIfaMqfrLx07czcMg9bMN6di+3w== +engine.io@~6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/engine.io/-/engine.io-6.1.0.tgz#459eab0c3724899d7b63a20c3a6835cf92857939" + integrity sha512-ErhZOVu2xweCjEfYcTdkCnEYUiZgkAcBBAhW4jbIvNG8SLU3orAqoJCiytZjYF7eTpVmmCrLDjLIEaPlUAs1uw== dependencies: + "@types/cookie" "^0.4.1" + "@types/cors" "^2.8.12" + "@types/node" ">=10.0.0" accepts "~1.3.4" base64id "2.0.0" cookie "~0.4.1" cors "~2.8.5" debug "~4.3.1" - engine.io-parser "~4.0.0" - ws "~7.4.2" - -enhanced-resolve@5.7.0: - version "5.7.0" - resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.7.0.tgz#525c5d856680fbd5052de453ac83e32049958b5c" - integrity sha512-6njwt/NsZFUKhM6j9U8hzVyD4E4r0x7NQzhTCbcWOJ0IQjNSAoalWmb0AE51Wn+fwan5qVESWi7t2ToBxs9vrw== - dependencies: - graceful-fs "^4.2.4" - tapable "^2.2.0" - -enhanced-resolve@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-4.3.0.tgz#3b806f3bfafc1ec7de69551ef93cca46c1704126" - integrity sha512-3e87LvavsdxyoCfGusJnrZ5G8SLPOFeHSNpZI/ATL9a5leXo2k0w6MKnbqhdBad9qTobSfB20Ld7UmgoNbAZkQ== - dependencies: - graceful-fs "^4.1.2" - memory-fs "^0.5.0" - tapable "^1.0.0" + engine.io-parser "~5.0.0" + ws "~8.2.3" enhanced-resolve@^5.8.0, enhanced-resolve@^5.8.3: version "5.8.3" @@ -5928,9 +4048,9 @@ ent@~2.2.0: integrity sha1-6WQhkyWiHQX0RGai9obtbOX13R0= entities@^2.0.0: - version "2.0.3" - resolved "https://registry.yarnpkg.com/entities/-/entities-2.0.3.tgz#5c487e5742ab93c15abb5da22759b8590ec03b7f" - integrity sha512-MyoZ0jgnLvB2X3Lg5HqpFmn1kybDiIfEQmKzTb5apr51Rb+T3KdmMiqa70T+bhGnyv7bQ6WMj2QMHpGMmlrUYQ== + version "2.2.0" + resolved "https://registry.yarnpkg.com/entities/-/entities-2.2.0.tgz#098dc90ebb83d8dffa089d55256b351d34c4da55" + integrity sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A== env-paths@^2.2.0: version "2.2.1" @@ -5942,10 +4062,10 @@ err-code@^2.0.2: resolved "https://registry.yarnpkg.com/err-code/-/err-code-2.0.3.tgz#23c2f3b756ffdfc608d30e27c9a941024807e7f9" integrity sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA== -errno@^0.1.1, errno@^0.1.3, errno@~0.1.7: - version "0.1.7" - resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.7.tgz#4684d71779ad39af177e3f007996f7c67c852618" - integrity sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg== +errno@^0.1.1, errno@^0.1.3: + version "0.1.8" + resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.8.tgz#8bb3e9c7d463be4976ff888f76b4809ebc2e811f" + integrity sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A== dependencies: prr "~1.0.1" @@ -5956,41 +4076,6 @@ error-ex@^1.3.1: dependencies: is-arrayish "^0.2.1" -es-abstract@^1.17.0-next.1, es-abstract@^1.17.5: - version "1.17.7" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.17.7.tgz#a4de61b2f66989fc7421676c1cb9787573ace54c" - integrity sha512-VBl/gnfcJ7OercKA9MVaegWsBHFjV492syMudcnQZvt/Dw8ezpcOHYZXa/J96O8vx+g4x65YKhxOwDUh63aS5g== - dependencies: - es-to-primitive "^1.2.1" - function-bind "^1.1.1" - has "^1.0.3" - has-symbols "^1.0.1" - is-callable "^1.2.2" - is-regex "^1.1.1" - object-inspect "^1.8.0" - object-keys "^1.1.1" - object.assign "^4.1.1" - string.prototype.trimend "^1.0.1" - string.prototype.trimstart "^1.0.1" - -es-abstract@^1.18.0-next.0, es-abstract@^1.18.0-next.1: - version "1.18.0-next.1" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.18.0-next.1.tgz#6e3a0a4bda717e5023ab3b8e90bec36108d22c68" - integrity sha512-I4UGspA0wpZXWENrdA0uHbnhte683t3qT/1VFH9aX2dA5PPSf6QW5HHXf5HImaqPmjXaVeVk4RGWnaylmV7uAA== - dependencies: - es-to-primitive "^1.2.1" - function-bind "^1.1.1" - has "^1.0.3" - has-symbols "^1.0.1" - is-callable "^1.2.2" - is-negative-zero "^2.0.0" - is-regex "^1.1.1" - object-inspect "^1.8.0" - object-keys "^1.1.1" - object.assign "^4.1.1" - string.prototype.trimend "^1.0.1" - string.prototype.trimstart "^1.0.1" - es-module-lexer@^0.7.1: version "0.7.1" resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-0.7.1.tgz#c2c8e0f46f2df06274cdaf0dd3f3b33e0a0b267d" @@ -6001,15 +4086,6 @@ es-module-lexer@^0.9.0: resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-0.9.3.tgz#6f13db00cc38417137daf74366f535c8eb438f19" integrity sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ== -es-to-primitive@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" - integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA== - dependencies: - is-callable "^1.1.4" - is-date-object "^1.0.1" - is-symbol "^1.0.2" - es6-promise@^4.0.3: version "4.2.8" resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.8.tgz#4eb21594c972bc40553d276e510539143db53e0a" @@ -6135,11 +4211,6 @@ esbuild@0.13.8: esbuild-windows-64 "0.13.8" esbuild-windows-arm64 "0.13.8" -escalade@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.0.tgz#e8e2d7c7a8b76f6ee64c2181d6b8151441602d4e" - integrity sha512-mAk+hPSO8fLDkhV7V0dXazH5pDc6MrjBTPyD3VeKzxnVFjH1MIxbCdqGZB9O8+EwWakZs3ZCbDS4IpRt79V1ig== - escalade@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" @@ -6163,20 +4234,12 @@ eslint-scope@5.1.1: esrecurse "^4.3.0" estraverse "^4.1.1" -eslint-scope@^4.0.3: - version "4.0.3" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-4.0.3.tgz#ca03833310f6889a3264781aa82e63eb9cfe7848" - integrity sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg== - dependencies: - esrecurse "^4.1.0" - estraverse "^4.1.1" - esprima@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== -esrecurse@^4.1.0, esrecurse@^4.3.0: +esrecurse@^4.3.0: version "4.3.0" resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== @@ -6189,9 +4252,9 @@ estraverse@^4.1.1: integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== estraverse@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.2.0.tgz#307df42547e6cc7324d3cf03c155d5cdb8c53880" - integrity sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ== + version "5.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" + integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== esutils@^2.0.2: version "2.0.3" @@ -6218,31 +4281,18 @@ eventemitter3@^4.0.0: resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== -events@^3.0.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/events/-/events-3.2.0.tgz#93b87c18f8efcd4202a461aec4dfc0556b639379" - integrity sha512-/46HWwbfCX2xTawVfkKLGxMifJYQBWMwY1mjywRtb4c9x8l5NP3KoJtnIOiL1hfdRkIuYhETxQlo62IF8tcnlg== - events@^3.2.0: version "3.3.0" resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== eventsource@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/eventsource/-/eventsource-1.0.7.tgz#8fbc72c93fcd34088090bc0a4e64f4b5cee6d8d0" - integrity sha512-4Ln17+vVT0k8aWq+t/bF5arcS3EpT9gYtW66EPacdj/mAFevznsnyoHLPy2BA8gbIQeIHoPsvwmfBftfcG//BQ== + version "1.1.0" + resolved "https://registry.yarnpkg.com/eventsource/-/eventsource-1.1.0.tgz#00e8ca7c92109e94b0ddf32dac677d841028cfaf" + integrity sha512-VSJjT5oCNrFvCS6igjzPAt5hBzQ2qPBFIbJ03zLI9SE0mxwZpMw6BfJrbFHm1a141AavMEB8JHmBhWAd66PfCg== dependencies: original "^1.0.0" -evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz#7fcbdb198dc71959432efe13842684e0525acb02" - integrity sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA== - dependencies: - md5.js "^1.3.4" - safe-buffer "^5.1.1" - execa@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8" @@ -6359,28 +4409,16 @@ extsprintf@1.3.0: integrity sha1-lpGEQOMEGnpBT4xS48V06zw+HgU= extsprintf@^1.2.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" - integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8= + version "1.4.1" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.1.tgz#8d172c064867f235c0c84a596806d279bf4bcc07" + integrity sha512-Wrk35e8ydCKDj/ArClo1VrPVmN8zph5V4AtHwIuHhvMXsKf73UT3BOD+azBIW+3wOJ4FhEH7zyaJCFvChjYvMA== -fast-deep-equal@^3.1.1: +fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: version "3.1.3" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== -fast-glob@^3.1.1, fast-glob@^3.2.4: - version "3.2.4" - resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.4.tgz#d20aefbf99579383e7f3cc66529158c9b98554d3" - integrity sha512-kr/Oo6PX51265qeuCYsyGypiO5uJFgBS0jksyG7FUeCyQzNwYnzrNIMR1NXfkZXsMYXYLRAHgISHBz8gQcxKHQ== - dependencies: - "@nodelib/fs.stat" "^2.0.2" - "@nodelib/fs.walk" "^1.2.3" - glob-parent "^5.1.0" - merge2 "^1.3.0" - micromatch "^4.0.2" - picomatch "^2.2.1" - -fast-glob@^3.2.5: +fast-glob@^3.1.1, fast-glob@^3.2.5: version "3.2.7" resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.7.tgz#fd6cb7a2d7e9aa7a7846111e85a196d6b2f766a1" integrity sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q== @@ -6402,9 +4440,9 @@ fastparse@^1.1.2: integrity sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ== fastq@^1.6.0: - version "1.8.0" - resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.8.0.tgz#550e1f9f59bbc65fe185cb6a9b4d95357107f481" - integrity sha512-SMIZoZdLh/fgofivvIkmknUXyPnvxRE3DhtZ5Me3Mrsk5gyPL42F0xr51TdRXskBxHfMp+07bcYzfsYEsSQA9Q== + version "1.13.0" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.13.0.tgz#616760f88a7526bdfc596b7cab8c18938c36b98c" + integrity sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw== dependencies: reusify "^1.0.4" @@ -6415,11 +4453,6 @@ faye-websocket@^0.11.3: dependencies: websocket-driver ">=0.5.1" -figgy-pudding@^3.5.1: - version "3.5.2" - resolved "https://registry.yarnpkg.com/figgy-pudding/-/figgy-pudding-3.5.2.tgz#b4eee8148abb01dcf1d1ac34367d59e12fa61d6e" - integrity sha512-0btnI/H8f2pavGMN8w40mlSKOfTK2SVJmBfBeVIj3kNw0swwgzyRq0d5TJVOwodFmtvpPeWPN/MCcfuWF0Ezbw== - figures@^3.0.0: version "3.2.0" resolved "https://registry.yarnpkg.com/figures/-/figures-3.2.0.tgz#625c18bd293c604dc4a8ddb2febf0c88341746af" @@ -6427,20 +4460,12 @@ figures@^3.0.0: dependencies: escape-string-regexp "^1.0.5" -file-loader@6.2.0: - version "6.2.0" - resolved "https://registry.yarnpkg.com/file-loader/-/file-loader-6.2.0.tgz#baef7cf8e1840df325e4390b4484879480eebe4d" - integrity sha512-qo3glqyTa61Ytg4u73GultjHGjdRyig3tG6lPtyX/jOEJvHif9uB0/OCI2Kif6ctF3caQTW2G5gym21oAsI4pw== - dependencies: - loader-utils "^2.0.0" - schema-utils "^3.0.0" - -file-selector@^0.1.12: - version "0.1.13" - resolved "https://registry.yarnpkg.com/file-selector/-/file-selector-0.1.13.tgz#5efd977ca2bca1700992df1b10e254f4e73d2df4" - integrity sha512-T2efCBY6Ps+jLIWdNQsmzt/UnAjKOEAlsZVdnQztg/BtAZGNL4uX1Jet9cMM8gify/x4CSudreji2HssGBNVIQ== +file-selector@^0.2.2: + version "0.2.4" + resolved "https://registry.yarnpkg.com/file-selector/-/file-selector-0.2.4.tgz#7b98286f9dbb9925f420130ea5ed0a69238d4d80" + integrity sha512-ZDsQNbrv6qRi1YTDOEWzf5J2KjZ9KMI1Q2SGeTkCJmNNW25Jg4TW4UMcmoqcg4WrAyKRcpBXdbWRxkfrOzVRbA== dependencies: - tslib "^2.0.1" + tslib "^2.0.3" file-uri-to-path@1.0.0: version "1.0.0" @@ -6477,7 +4502,7 @@ finalhandler@1.1.2, finalhandler@~1.1.2: statuses "~1.5.0" unpipe "~1.0.0" -find-cache-dir@3.3.1, find-cache-dir@^3.3.1: +find-cache-dir@3.3.1: version "3.3.1" resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-3.3.1.tgz#89b33fad4a4670daa94f855f7fbe31d6d84fe880" integrity sha512-t2GDMt3oGC/v+BMwzmllWDuJF/xcDtE5j/fCGbqDD7OLuJkj0cfh1YSA5VKPvwMeLFLNDBkwOKZ2X85jGLVftQ== @@ -6486,14 +4511,14 @@ find-cache-dir@3.3.1, find-cache-dir@^3.3.1: make-dir "^3.0.2" pkg-dir "^4.1.0" -find-cache-dir@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-2.1.0.tgz#8d0f94cd13fe43c6c7c261a0d86115ca918c05f7" - integrity sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ== +find-cache-dir@^3.3.1: + version "3.3.2" + resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-3.3.2.tgz#b30c5b6eff0730731aea9bbd9dbecbd80256d64b" + integrity sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig== dependencies: commondir "^1.0.1" - make-dir "^2.0.0" - pkg-dir "^3.0.0" + make-dir "^3.0.2" + pkg-dir "^4.1.0" find-up@^3.0.0: version "3.0.0" @@ -6535,18 +4560,10 @@ flatten@^1.0.2: version "0.9.0-alpha" resolved "git://github.com/thingsboard/flot.git#0ff0c775db7c74e705f6c3c2bba92080a202ccd4" -flush-write-stream@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/flush-write-stream/-/flush-write-stream-1.1.1.tgz#8dd7d873a1babc207d94ead0c2e0e44276ebf2e8" - integrity sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w== - dependencies: - inherits "^2.0.3" - readable-stream "^2.3.6" - follow-redirects@^1.0.0: - version "1.13.0" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.13.0.tgz#b42e8d93a2a7eea5ed88633676d6597bc8e384db" - integrity sha512-aq6gF1BEKje4a9i9+5jimNFIpq4Q1WiwBToeRK5NvZBd/TRsmW8BsJfOEGkr76TbOyPVD3OVDN910EcUNtRYEA== + version "1.14.5" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.5.tgz#f09a5848981d3c772b5392309778523f8d85c381" + integrity sha512-wtphSXy7d4/OR+MvIFbCVBDzZ5520qV8XfPklSN5QtxuMUJZ+b0Wnst1e1lCDocfzuCkHqj8k0FpZqO+UIaKNA== font-awesome@^4.7.0: version "4.7.0" @@ -6572,15 +4589,10 @@ form-data@~2.3.2: combined-stream "^1.0.6" mime-types "^2.1.12" -forwarded@~0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84" - integrity sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ= - -fraction.js@^4.0.13: - version "4.1.1" - resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.1.1.tgz#ac4e520473dae67012d618aab91eda09bcb400ff" - integrity sha512-MHOhvvxHTfRFpF1geTK9czMIZ6xclsEor2wkIGYYq+PxcQqT7vStJqjhe6S1TenZrMZzo+wlqOufBDVepUEgPg== +forwarded@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" + integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== fragment-cache@^0.2.1: version "0.2.1" @@ -6594,14 +4606,6 @@ fresh@0.5.2: resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= -from2@^2.1.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/from2/-/from2-2.3.0.tgz#8bfb5502bde4a4d36cfdeea007fcca21d7e382af" - integrity sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8= - dependencies: - inherits "^2.0.1" - readable-stream "^2.0.0" - fs-extra@^7.0.1: version "7.0.1" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-7.0.1.tgz#4f189c44aa123b895f722804f55ea23eadc348e9" @@ -6632,16 +4636,6 @@ fs-monkey@1.0.3: resolved "https://registry.yarnpkg.com/fs-monkey/-/fs-monkey-1.0.3.tgz#ae3ac92d53bb328efe0e9a1d9541f6ad8d48e2d3" integrity sha512-cybjIfiiE+pTWicSCLFHSrXZ6EilF30oh91FDP9S2B051prEa7QWfrVTQm10/dDpswBDXZugPa1Ogu8Yh+HV0Q== -fs-write-stream-atomic@^1.0.8: - version "1.0.10" - resolved "https://registry.yarnpkg.com/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz#b47df53493ef911df75731e70a9ded0189db40c9" - integrity sha1-tH31NJPvkR33VzHnCp3tAYnbQMk= - dependencies: - graceful-fs "^4.1.2" - iferr "^0.1.5" - imurmurhash "^0.1.4" - readable-stream "1 || 2" - fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" @@ -6655,12 +4649,7 @@ fsevents@^1.2.7: bindings "^1.5.0" nan "^2.12.1" -fsevents@~2.1.2: - version "2.1.3" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.1.3.tgz#fb738703ae8d2f9fe900c33836ddebee8b97f23e" - integrity sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ== - -fsevents@~2.3.1, fsevents@~2.3.2: +fsevents@^2.3.2, fsevents@~2.3.2: version "2.3.2" resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== @@ -6684,11 +4673,6 @@ gauge@~2.7.3: strip-ansi "^3.0.1" wide-align "^1.1.0" -gensync@^1.0.0-beta.1: - version "1.0.0-beta.1" - resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.1.tgz#58f4361ff987e5ff6e1e7a210827aa371eaac269" - integrity sha512-r8EC6NO1sngH/zdD9fiRDLdcgnbayXah+mLgManTaIZJqEC1MZstmnox8KpnI2/fxQwrp5OpCOYWLp4rBl4Jcg== - gensync@^1.0.0-beta.2: version "1.0.0-beta.2" resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" @@ -6710,6 +4694,15 @@ get-caller-file@^2.0.1, get-caller-file@^2.0.5: resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== +get-intrinsic@^1.0.2: + version "1.1.1" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.1.tgz#15f59f376f855c446963948f0d24cd3637b4abc6" + integrity sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q== + dependencies: + function-bind "^1.1.1" + has "^1.0.3" + has-symbols "^1.0.1" + get-stream@^4.0.0: version "4.1.0" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" @@ -6737,13 +4730,6 @@ glob-parent@^3.1.0: is-glob "^3.1.0" path-dirname "^1.0.0" -glob-parent@^5.1.0, glob-parent@^5.1.1, glob-parent@~5.1.0: - version "5.1.1" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.1.tgz#b6c1ef417c4e5663ea498f1c45afac6916bbc229" - integrity sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ== - dependencies: - is-glob "^4.0.1" - glob-parent@^5.1.2, glob-parent@~5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" @@ -6763,10 +4749,10 @@ glob-to-regexp@^0.4.1: resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e" integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw== -glob@7.1.6, glob@^7.0.3, glob@^7.0.6, glob@^7.1.1, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6: - version "7.1.6" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" - integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== +glob@7.1.7: + version "7.1.7" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.7.tgz#3b193e9233f01d42d0b3f78294bbeeb418f94a90" + integrity sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ== dependencies: fs.realpath "^1.0.0" inflight "^1.0.4" @@ -6775,10 +4761,10 @@ glob@7.1.6, glob@^7.0.3, glob@^7.0.6, glob@^7.1.1, glob@^7.1.3, glob@^7.1.4, glo once "^1.3.0" path-is-absolute "^1.0.0" -glob@7.1.7: - version "7.1.7" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.7.tgz#3b193e9233f01d42d0b3f78294bbeeb418f94a90" - integrity sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ== +glob@^7.0.3, glob@^7.0.6, glob@^7.1.1, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6, glob@^7.1.7: + version "7.2.0" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023" + integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q== dependencies: fs.realpath "^1.0.0" inflight "^1.0.4" @@ -6792,18 +4778,6 @@ globals@^11.1.0: resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== -globby@^11.0.1: - version "11.0.1" - resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.1.tgz#9a2bf107a068f3ffeabc49ad702c79ede8cfd357" - integrity sha512-iH9RmgwCmUJHi2z5o2l3eTtGBtXek1OYlHrbcxOYugyHLmAsZrPj43OtHThd62Buh/Vv6VyCBD2bdyWcGNQqoQ== - dependencies: - array-union "^2.1.0" - dir-glob "^3.0.1" - fast-glob "^3.1.1" - ignore "^5.1.4" - merge2 "^1.3.0" - slash "^3.0.0" - globby@^11.0.3: version "11.0.4" resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.4.tgz#2cbaff77c2f2a62e71e9b2813a67b97a3a3001a5" @@ -6839,22 +4813,10 @@ globby@^6.1.0: pify "^2.0.0" pinkie-promise "^2.0.0" -good-listener@^1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/good-listener/-/good-listener-1.2.2.tgz#d53b30cdf9313dffb7dc9a0d477096aa6d145c50" - integrity sha1-1TswzfkxPf+33JoNR3CWqm0UXFA= - dependencies: - delegate "^3.1.2" - -graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4: - version "4.2.4" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.4.tgz#2256bde14d3632958c465ebc96dc467ca07a29fb" - integrity sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw== - -graceful-fs@^4.2.3: - version "4.2.6" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.6.tgz#ff040b2b0853b23c3d31027523706f1885d76bee" - integrity sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ== +graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.3, graceful-fs@^4.2.4, graceful-fs@^4.2.6: + version "4.2.8" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.8.tgz#e412b8d33f5e006593cbd3cee6df9f2cebbe802a" + integrity sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg== hammerjs@^2.0.8: version "2.0.8" @@ -6896,10 +4858,17 @@ has-flag@^4.0.0: resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== -has-symbols@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.1.tgz#9f5214758a44196c406d9bd76cebf81ec2dd31e8" - integrity sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg== +has-symbols@^1.0.1, has-symbols@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.2.tgz#165d3070c00309752a1236a479331e3ac56f1423" + integrity sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw== + +has-tostringtag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.0.tgz#7e133818a7d394734f941e73c3d3f9291e658b25" + integrity sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ== + dependencies: + has-symbols "^1.0.2" has-unicode@^2.0.0: version "2.0.1" @@ -6944,23 +4913,6 @@ has@^1.0.3: dependencies: function-bind "^1.1.1" -hash-base@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.1.0.tgz#55c381d9e06e1d2997a883b4a3fddfe7f0d3af33" - integrity sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA== - dependencies: - inherits "^2.0.4" - readable-stream "^3.6.0" - safe-buffer "^5.2.0" - -hash.js@^1.0.0, hash.js@^1.0.3: - version "1.1.7" - resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42" - integrity sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA== - dependencies: - inherits "^2.0.3" - minimalistic-assert "^1.0.1" - hdr-histogram-js@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/hdr-histogram-js/-/hdr-histogram-js-2.0.1.tgz#ecb1ff2bcb6181c3e93ff4af9472c28c7e97284e" @@ -6975,20 +4927,6 @@ hdr-histogram-percentiles-obj@^3.0.0: resolved "https://registry.yarnpkg.com/hdr-histogram-percentiles-obj/-/hdr-histogram-percentiles-obj-3.0.0.tgz#9409f4de0c2dda78e61de2d9d78b1e9f3cba283c" integrity sha512-7kIufnBqdsBGcSZLPJwqHT3yhk1QTsSlFsVD3kx5ixH/AlgBs9yM1q6DPhXZ8f8gtdqgh7N7/5btRLpQsS2gHw== -hex-color-regex@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/hex-color-regex/-/hex-color-regex-1.1.0.tgz#4c06fccb4602fe2602b3c93df82d7e7dbf1a8a8e" - integrity sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ== - -hmac-drbg@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" - integrity sha1-0nRXAQJabHdabFRXk+1QL8DGSaE= - dependencies: - hash.js "^1.0.3" - minimalistic-assert "^1.0.0" - minimalistic-crypto-utils "^1.0.1" - hoist-non-react-statics@^3.3.2: version "3.3.2" resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45" @@ -6996,13 +4934,6 @@ hoist-non-react-statics@^3.3.2: dependencies: react-is "^16.7.0" -hosted-git-info@^3.0.2: - version "3.0.5" - resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-3.0.5.tgz#bea87905ef7317442e8df3087faa3c842397df03" - integrity sha512-i4dpK6xj9BIpVOTboXIlKG9+8HMKggcrMX7WA24xZtKwX0TPelq/rbaS5rCKeNX8sJXZJGdSxpnEGtta+wismQ== - dependencies: - lru-cache "^6.0.0" - hosted-git-info@^4.0.1: version "4.0.2" resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-4.0.2.tgz#5e425507eede4fea846b7262f0838456c4209961" @@ -7020,32 +4951,23 @@ hpack.js@^2.1.6: readable-stream "^2.0.1" wbuf "^1.1.0" -hsl-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/hsl-regex/-/hsl-regex-1.0.0.tgz#d49330c789ed819e276a4c0d272dffa30b18fe6e" - integrity sha1-1JMwx4ntgZ4nakwNJy3/owsY/m4= - -hsla-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/hsla-regex/-/hsla-regex-1.0.0.tgz#c1ce7a3168c8c6614033a4b5f7877f3b225f9c38" - integrity sha1-wc56MWjIxmFAM6S194d/OyJfnDg= - html-entities@^1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-1.3.1.tgz#fb9a1a4b5b14c5daba82d3e34c6ae4fe701a0e44" - integrity sha512-rhE/4Z3hIhzHAUKbW8jVcCyuT5oJCXXqhN/6mXXVCpzTmvJnoH2HL/bt3EZ6p55jbFJBeAe1ZNpL5BugLujxNA== + version "1.4.0" + resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-1.4.0.tgz#cfbd1b01d2afaf9adca1b10ae7dffab98c71d2dc" + integrity sha512-8nxjcBcd8wovbeKx7h3wTji4e6+rhaVuPNpMqwWgnHh+N9ToqsCs6XztWRBPQ+UtzsoMAdKZtUENoVzU/EMtZA== html-escaper@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== -html2canvas@^1.0.0-rc.7: - version "1.0.0-rc.7" - resolved "https://registry.yarnpkg.com/html2canvas/-/html2canvas-1.0.0-rc.7.tgz#70c159ce0e63954a91169531894d08ad5627ac98" - integrity sha512-yvPNZGejB2KOyKleZspjK/NruXVQuowu8NnV2HYG7gW7ytzl+umffbtUI62v2dCHQLDdsK6HIDtyJZ0W3neerA== +html2canvas@^1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/html2canvas/-/html2canvas-1.3.3.tgz#f01531f9bf7c73a771c5ee73b4a5cab6576bf876" + integrity sha512-nQi0ayEY1cMiUMbq/F5hRwMAqsRMo7NIP6VaCqaXnXO6b/FfZO49oSfIJjdyRha28EuY8D6FBCzQOXPQV0TCrA== dependencies: - css-line-break "1.1.1" + css-line-break "2.0.1" + text-segmentation "^1.0.2" http-cache-semantics@^4.1.0: version "4.1.0" @@ -7090,9 +5012,9 @@ http-errors@~1.7.2: toidentifier "1.0.0" http-parser-js@>=0.5.1: - version "0.5.2" - resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.5.2.tgz#da2e31d237b393aae72ace43882dd7e270a8ff77" - integrity sha512-opCO9ASqg5Wy2FNo7A0sxy71yGbbkJJXLdgMK04Tcypw9jr2MgWbyubb0+WdmDmGnFflO7fRbqbaihh/ENDlRQ== + version "0.5.5" + resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.5.5.tgz#d7c30d5d3c90d865b4a2e870181f9d6f22ac7ac5" + integrity sha512-x+JVEkO2PoM8qqpbPbOL3cqHPwerep7OwzK7Ay+sMQjKzaKCqWvjoXm5tqMP9tXWWTnTzAjIhXg+J99XYuPhPA== http-proxy-agent@^4.0.1: version "4.0.1" @@ -7131,11 +5053,6 @@ http-signature@~1.2.0: jsprim "^1.2.2" sshpk "^1.7.0" -https-browserify@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73" - integrity sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM= - https-proxy-agent@5.0.0, https-proxy-agent@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz#e2a90542abb68a762e0a0850f6c9edadfd8506b2" @@ -7171,10 +5088,10 @@ iconv-lite@0.4.24, iconv-lite@^0.4.24, iconv-lite@^0.4.4: dependencies: safer-buffer ">= 2.1.2 < 3" -iconv-lite@^0.6.2: - version "0.6.2" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.2.tgz#ce13d1875b0c3a674bd6a04b7f76b01b1b6ded01" - integrity sha512-2y91h5OpQlolefMPmUlivelittSWy0rP+oYVpn6A7GwVHNE8AWzoYOBNmlwks3LobaJxgHCYZAnyNo2GgpNRNQ== +iconv-lite@^0.6.2, iconv-lite@^0.6.3: + version "0.6.3" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501" + integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw== dependencies: safer-buffer ">= 2.1.2 < 3.0.0" @@ -7188,16 +5105,6 @@ ieee754@^1.1.13: resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== -ieee754@^1.1.4: - version "1.1.13" - resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.13.tgz#ec168558e95aa181fd87d37f55c32bbcb6708b84" - integrity sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg== - -iferr@^0.1.5: - version "0.1.5" - resolved "https://registry.yarnpkg.com/iferr/-/iferr-0.1.5.tgz#c60eed69e6d8fdb6b3104a1fcbca1c192dc5b501" - integrity sha1-xg7taebY/bazEEofy8ocGS3FtQE= - ignore-walk@^3.0.3: version "3.0.4" resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-3.0.4.tgz#c9a09f69b7c7b479a5d74ac1a3c0d4236d2a6335" @@ -7206,9 +5113,9 @@ ignore-walk@^3.0.3: minimatch "^3.0.4" ignore@^5.1.4: - version "5.1.8" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.8.tgz#f150a8b50a34289b33e22f5889abd4d8016f0e57" - integrity sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw== + version "5.1.9" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.9.tgz#9ec1a5cbe8e1446ec60d4420060d43aa6e7382fb" + integrity sha512-2zeMQpbKz5dhZ9IwL0gbxSW5w0NK/MSAMtNuhgIHEPmaU3vPdKPL0UdvUCXs5SS4JAwsBxysK5sFMW8ocFiVjQ== image-size@~0.5.0: version "0.5.5" @@ -7241,13 +5148,6 @@ imurmurhash@^0.1.4: resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= -indefinite-observable@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/indefinite-observable/-/indefinite-observable-2.0.1.tgz#574af29bfbc17eb5947793797bddc94c9d859400" - integrity sha512-G8vgmork+6H9S8lUAg1gtXEj2JxIQTo0g2PbFiYOdjkziSI0F7UYBiVwhZRuixhBCNGczAls34+5HJPyZysvxQ== - dependencies: - symbol-observable "1.2.0" - indent-string@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" @@ -7258,7 +5158,7 @@ indexes-of@^1.0.1: resolved "https://registry.yarnpkg.com/indexes-of/-/indexes-of-1.0.1.tgz#f30f716c8e2bd346c7b67d3df3915566a7c05607" integrity sha1-8w9xbI4r00bHtn0985FVZqfAVgc= -infer-owner@^1.0.3, infer-owner@^1.0.4: +infer-owner@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/infer-owner/-/infer-owner-1.0.4.tgz#c4cefcaa8e51051c2a40ba2ce8a3d27295af9467" integrity sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A== @@ -7271,16 +5171,11 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.1, inherits@~2.0.3: +inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3: version "2.0.4" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== -inherits@2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1" - integrity sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE= - inherits@2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" @@ -7292,28 +5187,9 @@ ini@2.0.0: integrity sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA== ini@^1.3.4: - version "1.3.5" - resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" - integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw== - -inquirer@7.3.3: - version "7.3.3" - resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-7.3.3.tgz#04d176b2af04afc157a83fd7c100e98ee0aad003" - integrity sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA== - dependencies: - ansi-escapes "^4.2.1" - chalk "^4.1.0" - cli-cursor "^3.1.0" - cli-width "^3.0.0" - external-editor "^3.0.3" - figures "^3.0.0" - lodash "^4.17.19" - mute-stream "0.0.8" - run-async "^2.4.0" - rxjs "^6.6.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - through "^2.3.6" + version "1.3.8" + resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" + integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== inquirer@8.1.2: version "8.1.2" @@ -7378,9 +5254,12 @@ is-accessor-descriptor@^1.0.0: kind-of "^6.0.0" is-arguments@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.0.4.tgz#3faf966c7cba0ff437fb31f6250082fcf0448cf3" - integrity sha512-xPh0Rmt8NE65sNzvyUmWgI1tz3mKq74lGA0mL8LYZcoIzKOzDh6HmrYm3d18k60nHerC8A9Km8kYu87zfSFnLA== + version "1.1.1" + resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.1.1.tgz#15b3f88fda01f2a97fec84ca761a560f123efa9b" + integrity sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA== + dependencies: + call-bind "^1.0.2" + has-tostringtag "^1.0.0" is-arrayish@^0.2.1: version "0.2.1" @@ -7406,11 +5285,6 @@ is-buffer@^1.1.5: resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== -is-callable@^1.1.4, is-callable@^1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.2.tgz#c7c6715cd22d4ddb48d3e19970223aceabb080d9" - integrity sha512-dnMqspv5nU3LoewK2N/y7KLtxtakvTuaCsU9FU50/QDmdbHNy/4/JuRtMHqRU22o3q+W89YQndQEeCVwK+3qrA== - is-ci@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-2.0.0.tgz#6bc6334181810e04b5c22b3d589fdca55026404c" @@ -7418,18 +5292,6 @@ is-ci@^2.0.0: dependencies: ci-info "^2.0.0" -is-color-stop@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-color-stop/-/is-color-stop-1.1.0.tgz#cfff471aee4dd5c9e158598fbe12967b5cdad345" - integrity sha1-z/9HGu5N1cnhWFmPvhKWe1za00U= - dependencies: - css-color-names "^0.0.4" - hex-color-regex "^1.1.0" - hsl-regex "^1.0.0" - hsla-regex "^1.0.0" - rgb-regex "^1.0.1" - rgba-regex "^1.0.0" - is-core-module@^2.2.0: version "2.8.0" resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.8.0.tgz#0321336c3d0925e497fd97f5d95cb114a5ccd548" @@ -7452,9 +5314,11 @@ is-data-descriptor@^1.0.0: kind-of "^6.0.0" is-date-object@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.2.tgz#bda736f2cd8fd06d32844e7743bfa7494c3bfd7e" - integrity sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g== + version "1.0.5" + resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f" + integrity sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ== + dependencies: + has-tostringtag "^1.0.0" is-descriptor@^0.1.0: version "0.1.6" @@ -7474,12 +5338,7 @@ is-descriptor@^1.0.0, is-descriptor@^1.0.2: is-data-descriptor "^1.0.0" kind-of "^6.0.2" -is-docker@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.1.1.tgz#4125a88e44e450d384e09047ede71adc2d144156" - integrity sha512-ZOoqiXfEwtGknTiuDEy8pN2CfE3TxMHprvNer1mXiqwkOT77Rw3YVrUQ52EqAOU3QAWDQ+bQdx7HJzrv7LS2Hw== - -is-docker@^2.1.1: +is-docker@^2.0.0, is-docker@^2.1.1: version "2.2.1" resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa" integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ== @@ -7525,14 +5384,7 @@ is-glob@^3.1.0: dependencies: is-extglob "^2.1.0" -is-glob@^4.0.0, is-glob@^4.0.1, is-glob@~4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc" - integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg== - dependencies: - is-extglob "^2.1.1" - -is-glob@^4.0.3: +is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: version "4.0.3" resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== @@ -7554,11 +5406,6 @@ is-lambda@^1.0.1: resolved "https://registry.yarnpkg.com/is-lambda/-/is-lambda-1.0.1.tgz#3d9877899e6a53efc0160504cde15f82e6f061d5" integrity sha1-PZh3iZ5qU+/AFgUEzeFfgubwYdU= -is-negative-zero@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.0.tgz#9553b121b0fac28869da9ed459e20c7543788461" - integrity sha1-lVOxIbD6wohp2p7UWeIMdUN4hGE= - is-number@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" @@ -7616,12 +5463,13 @@ is-plain-object@^2.0.3, is-plain-object@^2.0.4: dependencies: isobject "^3.0.1" -is-regex@^1.0.4, is-regex@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.1.tgz#c6f98aacc546f6cec5468a07b7b153ab564a57b9" - integrity sha512-1+QkEcxiLlB7VEyFtyBg94e08OAsvq7FUBgApTq/w2ymCLyKJgDPsybBENVtA7XCQEgEXxKPonG+mvYRxh/LIg== +is-regex@^1.0.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958" + integrity sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg== dependencies: - has-symbols "^1.0.1" + call-bind "^1.0.2" + has-tostringtag "^1.0.0" is-resolvable@^1.1.0: version "1.1.0" @@ -7633,13 +5481,6 @@ is-stream@^1.1.0: resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ= -is-symbol@^1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.3.tgz#38e1014b9e6329be0de9d24a414fd7441ec61937" - integrity sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ== - dependencies: - has-symbols "^1.0.1" - is-typedarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" @@ -7672,20 +5513,15 @@ is-wsl@^2.1.1, is-wsl@^2.2.0: dependencies: is-docker "^2.0.0" -isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: +isarray@1.0.0, isarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= -isarray@^2.0.1: - version "2.0.5" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.5.tgz#8af1e4c1221244cc62459faf38940d4e644a5723" - integrity sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw== - -isbinaryfile@^4.0.6: - version "4.0.6" - resolved "https://registry.yarnpkg.com/isbinaryfile/-/isbinaryfile-4.0.6.tgz#edcb62b224e2b4710830b67498c8e4e5a4d2610b" - integrity sha512-ORrEy+SNVqUhrCaal4hA4fBzhggQQ+BaLntyPOdoEiwlKZW9BZiJXjg3RMiruE4tPEI3pyVPpySHQF/dKWperg== +isbinaryfile@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/isbinaryfile/-/isbinaryfile-4.0.8.tgz#5d34b94865bd4946633ecc78a026fc76c5b11fcf" + integrity sha512-53h6XFniq77YdW+spoRrebh0mnmTxRPTlcuIArO57lmMdq4uBKFKaeTjnb92oYWrSn/LVL+LT+Hap2tFQj8V+w== isexe@^2.0.0: version "2.0.0" @@ -7715,9 +5551,9 @@ istanbul-lib-coverage@^2.0.5: integrity sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA== istanbul-lib-coverage@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz#f5944a37c70b550b02a78a5c3b2055b280cec8ec" - integrity sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg== + version "3.2.0" + resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz#189e7909d0a39fa5a3dfad5b03f71947770191d3" + integrity sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw== istanbul-lib-instrument@^4.0.3: version "4.0.3" @@ -7750,28 +5586,23 @@ istanbul-lib-source-maps@^3.0.6: source-map "^0.6.1" istanbul-reports@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.0.2.tgz#d593210e5000683750cb09fc0644e4b6e27fd53b" - integrity sha512-9tZvz7AiR3PEDNGiV9vIouQ/EAcqMXFmkcA1CDFTwOB98OZVDL0PH9glHotf5Ugp6GCOTypfzGWI/OqjWNCRUw== + version "3.1.1" + resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.1.1.tgz#7085857f17d2441053c6ce5c3b8fdf6882289397" + integrity sha512-q1kvhAXWSsXfMjCdNHNPKZZv94OlspKnoGv+R9RGbnqOOQ0VbNfLFgQDVgi7hHenKsndGq3/o0OBdzDXthWcNw== dependencies: html-escaper "^2.0.0" istanbul-lib-report "^3.0.0" -jasmine-core@^3.6.0: - version "3.6.0" - resolved "https://registry.yarnpkg.com/jasmine-core/-/jasmine-core-3.6.0.tgz#491f3bb23941799c353ceb7a45b38a950ebc5a20" - integrity sha512-8uQYa7zJN8hq9z+g8z1bqCfdC8eoDAeVnM5sfqs7KHv9/ifoJ500m018fpFc7RDaO6SWCLCXwo/wPSNcdYTgcw== +jasmine-core@^3.6.0, jasmine-core@~3.10.1: + version "3.10.1" + resolved "https://registry.yarnpkg.com/jasmine-core/-/jasmine-core-3.10.1.tgz#7aa6fa2b834a522315c651a128d940eca553989a" + integrity sha512-ooZWSDVAdh79Rrj4/nnfklL3NQVra0BcuhcuWoAwwi+znLDoUeH87AFfeX8s+YeYi6xlv5nveRyaA1v7CintfA== jasmine-core@~2.8.0: version "2.8.0" resolved "https://registry.yarnpkg.com/jasmine-core/-/jasmine-core-2.8.0.tgz#bcc979ae1f9fd05701e45e52e65d3a5d63f1a24e" integrity sha1-vMl5rh+f0FcB5F5S5l06XWPxok4= -jasmine-core@~3.7.1: - version "3.7.1" - resolved "https://registry.yarnpkg.com/jasmine-core/-/jasmine-core-3.7.1.tgz#0401327f6249eac993d47bbfa18d4e8efacfb561" - integrity sha512-DH3oYDS/AUvvr22+xUBW62m1Xoy7tUlY1tsxKEJvl5JeJ7q8zd1K5bUwiOxdH+erj6l2vAMM3hV25Xs9/WrmuQ== - jasmine-spec-reporter@~7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/jasmine-spec-reporter/-/jasmine-spec-reporter-7.0.0.tgz#94b939448e63d4e2bd01668142389f20f0a8ea49" @@ -7793,53 +5624,43 @@ jasminewd2@^2.1.0: resolved "https://registry.yarnpkg.com/jasminewd2/-/jasminewd2-2.2.0.tgz#e37cf0b17f199cce23bea71b2039395246b4ec4e" integrity sha1-43zwsX8ZnM4jvqcbIDk5Uka07E4= -jest-worker@26.6.2, jest-worker@^26.5.0: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-26.6.2.tgz#7f72cbc4d643c365e27b9fd775f9d0eaa9c7a8ed" - integrity sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ== - dependencies: - "@types/node" "*" - merge-stream "^2.0.0" - supports-color "^7.0.0" - jest-worker@^27.0.2, jest-worker@^27.0.6: - version "27.4.0" - resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.4.0.tgz#fa10dddc611cbb47a4153543dd16a0c7e7fd745c" - integrity sha512-4WuKcUxtzxBoKOUFbt1MtTY9fJwPVD4aN/4Cgxee7OLetPZn5as2bjfZz98XSf2Zq1JFfhqPZpS+43BmWXKgCA== + version "27.4.2" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.4.2.tgz#0fb123d50955af1a450267787f340a1bf7e12bc4" + integrity sha512-0QMy/zPovLfUPyHuOuuU4E+kGACXXE84nRnq6lBVI9GJg5DCBiA97SATi+ZP8CpiJwEQy1oCPjRBf8AnLjN+Ag== dependencies: "@types/node" "*" merge-stream "^2.0.0" supports-color "^8.0.0" -jquery.terminal@^2.24.0: - version "2.24.0" - resolved "https://registry.yarnpkg.com/jquery.terminal/-/jquery.terminal-2.24.0.tgz#779a92b4478ac7542e7adaf5e17f4d4d92fd622c" - integrity sha512-rtjTBj7/FYoBiWawiNTYNXIRqVI4n39WF/x1h/bEKFb48Rzgr4/dpkKGd1dgZau714ewzczAi7CEBTKvhM6RjA== +jquery.terminal@^2.29.4: + version "2.29.4" + resolved "https://registry.yarnpkg.com/jquery.terminal/-/jquery.terminal-2.29.4.tgz#0403942e3f68a23d54ba9ad7c592f1da2b2829cd" + integrity sha512-ugzctBbbJmw3ZGIhYziBFEK8QnWAZy2q6sZUtmPgjni4ILg59tO0WJI9DkKiDZ4LQtdCVexQ5oP0J90jMN+TzA== dependencies: - "@types/jquery" "^3.5.5" + "@jcubic/lily" "^0.3.0" + "@types/jquery" "^3.5.6" + ansidec "^0.3.4" + iconv-lite "^0.6.3" jquery "^3.6.0" - prismjs "^1.23.0" + prismjs "^1.25.0" wcwidth "^1.0.1" + optionalDependencies: + fsevents "^2.3.2" -jquery@>=1.9.1, jquery@^3.5.1: - version "3.5.1" - resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.5.1.tgz#d7b4d08e1bfdb86ad2f1a3d039ea17304717abb5" - integrity sha512-XwIBPqcMn57FxfT+Go5pzySnm4KWkT1Tv7gjrpT1srtf8Weynl6R273VJ5GjkRb51IzMp5nbaPjJXMWeju2MKg== - -jquery@^3.6.0: +jquery@>=1.9.1, jquery@^3.6.0: version "3.6.0" resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.6.0.tgz#c72a09f15c1bdce142f49dbf1170bdf8adac2470" integrity sha512-JVzAR/AjBvVt2BmYhxRCSYysDsPcssdmTFnzyLEts9qNwmjmu4JTAMYubEfwVOSwpQ1I1sKKFcxhZCI2buerfw== -js-beautify@^1.13.13: - version "1.13.13" - resolved "https://registry.yarnpkg.com/js-beautify/-/js-beautify-1.13.13.tgz#756907d1728f329f2b84c42efd56ad17514620bf" - integrity sha512-oH+nc0U5mOAqX8M5JO1J0Pw/7Q35sAdOsM5W3i87pir9Ntx6P/5Gx1xLNoK+MGyvHk4rqqRCE4Oq58H6xl2W7A== +js-beautify@^1.14.0: + version "1.14.0" + resolved "https://registry.yarnpkg.com/js-beautify/-/js-beautify-1.14.0.tgz#2ce790c555d53ce1e3d7363227acf5dc69024c2d" + integrity sha512-yuck9KirNSCAwyNJbqW+BxJqJ0NLJ4PwBUzQQACl5O3qHMBXVkXb/rD0ilh/Lat/tn88zSZ+CAHOlk0DsY7GuQ== dependencies: config-chain "^1.1.12" editorconfig "^0.15.3" glob "^7.1.3" - mkdirp "^1.0.4" nopt "^5.0.0" "js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: @@ -7848,9 +5669,9 @@ js-beautify@^1.13.13: integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== js-yaml@^3.13.1: - version "3.14.0" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.0.tgz#a7a34170f26a21bb162424d8adacb4113a69e482" - integrity sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A== + version "3.14.1" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" + integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== dependencies: argparse "^1.0.7" esprima "^4.0.0" @@ -7897,10 +5718,10 @@ json-schema-traverse@^1.0.0: resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2" integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== -json-schema@0.2.3: - version "0.2.3" - resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" - integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM= +json-schema@0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.4.0.tgz#f7de4cf6efab838ebaeb3236474cbba5a1930ab5" + integrity sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA== json-stringify-safe@~5.0.1: version "5.0.1" @@ -7920,9 +5741,9 @@ json5@^1.0.1: minimist "^1.2.0" json5@^2.1.2: - version "2.1.3" - resolved "https://registry.yarnpkg.com/json5/-/json5-2.1.3.tgz#c9b0f7fa9233bfe5807fe66fcf3a5617ed597d43" - integrity sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA== + version "2.2.0" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.0.tgz#2dfefe720c6ba525d9ebd909950f0515316c89a3" + integrity sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA== dependencies: minimist "^1.2.5" @@ -7944,83 +5765,82 @@ jsonparse@^1.3.1: integrity sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA= jsprim@^1.2.2: - version "1.4.1" - resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" - integrity sha1-MT5mvB5cwG5Di8G3SZwuXFastqI= + version "1.4.2" + resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.2.tgz#712c65533a15c878ba59e9ed5f0e26d5b77c5feb" + integrity sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw== dependencies: assert-plus "1.0.0" extsprintf "1.3.0" - json-schema "0.2.3" + json-schema "0.4.0" verror "1.10.0" jss-plugin-camel-case@^10.5.1: - version "10.6.0" - resolved "https://registry.yarnpkg.com/jss-plugin-camel-case/-/jss-plugin-camel-case-10.6.0.tgz#93d2cd704bf0c4af70cc40fb52d74b8a2554b170" - integrity sha512-JdLpA3aI/npwj3nDMKk308pvnhoSzkW3PXlbgHAzfx0yHWnPPVUjPhXFtLJzgKZge8lsfkUxvYSQ3X2OYIFU6A== + version "10.8.2" + resolved "https://registry.yarnpkg.com/jss-plugin-camel-case/-/jss-plugin-camel-case-10.8.2.tgz#8d7f915c8115afaff8cbde08faf610ec9892fba6" + integrity sha512-2INyxR+1UdNuKf4v9It3tNfPvf7IPrtkiwzofeKuMd5D58/dxDJVUQYRVg/n460rTlHUfsEQx43hDrcxi9dSPA== dependencies: "@babel/runtime" "^7.3.1" hyphenate-style-name "^1.0.3" - jss "10.6.0" + jss "10.8.2" jss-plugin-default-unit@^10.5.1: - version "10.6.0" - resolved "https://registry.yarnpkg.com/jss-plugin-default-unit/-/jss-plugin-default-unit-10.6.0.tgz#af47972486819b375f0f3a9e0213403a84b5ef3b" - integrity sha512-7y4cAScMHAxvslBK2JRK37ES9UT0YfTIXWgzUWD5euvR+JR3q+o8sQKzBw7GmkQRfZijrRJKNTiSt1PBsLI9/w== + version "10.8.2" + resolved "https://registry.yarnpkg.com/jss-plugin-default-unit/-/jss-plugin-default-unit-10.8.2.tgz#c66f12e02e0815d911b85c02c2a979ee7b4ce69a" + integrity sha512-UZ7cwT9NFYSG+SEy7noRU50s4zifulFdjkUNKE+u6mW7vFP960+RglWjTgMfh79G6OENZmaYnjHV/gcKV4nSxg== dependencies: "@babel/runtime" "^7.3.1" - jss "10.6.0" + jss "10.8.2" jss-plugin-global@^10.5.1: - version "10.6.0" - resolved "https://registry.yarnpkg.com/jss-plugin-global/-/jss-plugin-global-10.6.0.tgz#3e8011f760f399cbadcca7f10a485b729c50e3ed" - integrity sha512-I3w7ji/UXPi3VuWrTCbHG9rVCgB4yoBQLehGDTmsnDfXQb3r1l3WIdcO8JFp9m0YMmyy2CU7UOV6oPI7/Tmu+w== + version "10.8.2" + resolved "https://registry.yarnpkg.com/jss-plugin-global/-/jss-plugin-global-10.8.2.tgz#1a35632a693cf50113bcc5ffe6b51969df79c4ec" + integrity sha512-UaYMSPsYZ7s/ECGoj4KoHC2jwQd5iQ7K+FFGnCAILdQrv7hPmvM2Ydg45ThT/sH46DqktCRV2SqjRuxeBH8nRA== dependencies: "@babel/runtime" "^7.3.1" - jss "10.6.0" + jss "10.8.2" jss-plugin-nested@^10.5.1: - version "10.6.0" - resolved "https://registry.yarnpkg.com/jss-plugin-nested/-/jss-plugin-nested-10.6.0.tgz#5f83c5c337d3b38004834e8426957715a0251641" - integrity sha512-fOFQWgd98H89E6aJSNkEh2fAXquC9aZcAVjSw4q4RoQ9gU++emg18encR4AT4OOIFl4lQwt5nEyBBRn9V1Rk8g== + version "10.8.2" + resolved "https://registry.yarnpkg.com/jss-plugin-nested/-/jss-plugin-nested-10.8.2.tgz#79f3c7f75ea6a36ae72fe52e777035bb24d230c7" + integrity sha512-acRvuPJOb930fuYmhkJaa994EADpt8TxI63Iyg96C8FJ9T2xRyU5T6R1IYKRwUiqZo+2Sr7fdGzRTDD4uBZaMA== dependencies: "@babel/runtime" "^7.3.1" - jss "10.6.0" + jss "10.8.2" tiny-warning "^1.0.2" jss-plugin-props-sort@^10.5.1: - version "10.6.0" - resolved "https://registry.yarnpkg.com/jss-plugin-props-sort/-/jss-plugin-props-sort-10.6.0.tgz#297879f35f9fe21196448579fee37bcde28ce6bc" - integrity sha512-oMCe7hgho2FllNc60d9VAfdtMrZPo9n1Iu6RNa+3p9n0Bkvnv/XX5San8fTPujrTBScPqv9mOE0nWVvIaohNuw== + version "10.8.2" + resolved "https://registry.yarnpkg.com/jss-plugin-props-sort/-/jss-plugin-props-sort-10.8.2.tgz#e25a7471868652c394562b6dc5433dcaea7dff6f" + integrity sha512-wqdcjayKRWBZnNpLUrXvsWqh+5J5YToAQ+8HNBNw0kZxVvCDwzhK2Nx6AKs7p+5/MbAh2PLgNW5Ym/ysbVAuqQ== dependencies: "@babel/runtime" "^7.3.1" - jss "10.6.0" + jss "10.8.2" jss-plugin-rule-value-function@^10.5.1: - version "10.6.0" - resolved "https://registry.yarnpkg.com/jss-plugin-rule-value-function/-/jss-plugin-rule-value-function-10.6.0.tgz#3c1a557236a139d0151e70a82c810ccce1c1c5ea" - integrity sha512-TKFqhRTDHN1QrPTMYRlIQUOC2FFQb271+AbnetURKlGvRl/eWLswcgHQajwuxI464uZk91sPiTtdGi7r7XaWfA== + version "10.8.2" + resolved "https://registry.yarnpkg.com/jss-plugin-rule-value-function/-/jss-plugin-rule-value-function-10.8.2.tgz#55354b55f1b2968a15976729968f767f02d64049" + integrity sha512-bW0EKAs+0HXpb6BKJhrn94IDdiWb0CnSluTkh0rGEgyzY/nmD1uV/Wf6KGlesGOZ9gmJzQy+9FFdxIUID1c9Ug== dependencies: "@babel/runtime" "^7.3.1" - jss "10.6.0" + jss "10.8.2" tiny-warning "^1.0.2" jss-plugin-vendor-prefixer@^10.5.1: - version "10.6.0" - resolved "https://registry.yarnpkg.com/jss-plugin-vendor-prefixer/-/jss-plugin-vendor-prefixer-10.6.0.tgz#e1fcd499352846890c38085b11dbd7aa1c4f2c78" - integrity sha512-doJ7MouBXT1lypLLctCwb4nJ6lDYqrTfVS3LtXgox42Xz0gXusXIIDboeh6UwnSmox90QpVnub7au8ybrb0krQ== + version "10.8.2" + resolved "https://registry.yarnpkg.com/jss-plugin-vendor-prefixer/-/jss-plugin-vendor-prefixer-10.8.2.tgz#ebb4a482642f34091e454901e21176441dd5f475" + integrity sha512-DeGv18QsSiYLSVIEB2+l0af6OToUe0JB+trpzUxyqD2QRC/5AzzDrCrYffO5AHZ81QbffYvSN/pkfZaTWpRXlg== dependencies: "@babel/runtime" "^7.3.1" css-vendor "^2.0.8" - jss "10.6.0" + jss "10.8.2" -jss@10.6.0, jss@^10.5.1: - version "10.6.0" - resolved "https://registry.yarnpkg.com/jss/-/jss-10.6.0.tgz#d92ff9d0f214f65ca1718591b68e107be4774149" - integrity sha512-n7SHdCozmxnzYGXBHe0NsO0eUf9TvsHVq2MXvi4JmTn3x5raynodDVE/9VQmBdWFyyj9HpHZ2B4xNZ7MMy7lkw== +jss@10.8.2, jss@^10.5.1: + version "10.8.2" + resolved "https://registry.yarnpkg.com/jss/-/jss-10.8.2.tgz#4b2a30b094b924629a64928236017a52c7c97505" + integrity sha512-FkoUNxI329CKQ9OQC8L72MBF9KPf5q8mIupAJ5twU7G7XREW7ahb+7jFfrjZ4iy1qvhx1HwIWUIvkZBDnKkEdQ== dependencies: "@babel/runtime" "^7.3.1" csstype "^3.0.2" - indefinite-observable "^2.0.1" is-in-browser "^1.1.3" tiny-warning "^1.0.2" @@ -8031,27 +5851,17 @@ jstree-bootstrap-theme@^1.0.1: dependencies: jquery ">=1.9.1" -jstree@^3.3.11: - version "3.3.11" - resolved "https://registry.yarnpkg.com/jstree/-/jstree-3.3.11.tgz#da2f12bcab6af61839586c81db46e8f2e19160aa" - integrity sha512-9ZJKroPjCyjb6JLPuAbBrLJKT6pS1f4m5gkwoEagG5oQWtvzm0IiDsntXTxeFtz7AmqrKfij+gLfF9MgWriNxg== +jstree@^3.3.12: + version "3.3.12" + resolved "https://registry.yarnpkg.com/jstree/-/jstree-3.3.12.tgz#cf206bc85dcf4a4664ed6617eaae3bd5983d8601" + integrity sha512-vHNLWkUr02ZYH7RcIckvhtLUtneWCVEtIKpIp2G9WtRh01ITv18EoNtNQcFG3ozM+oK6wp1Z300gSLXNQWCqGA== dependencies: jquery ">=1.9.1" -jszip@^3.1.3: - version "3.5.0" - resolved "https://registry.yarnpkg.com/jszip/-/jszip-3.5.0.tgz#b4fd1f368245346658e781fec9675802489e15f6" - integrity sha512-WRtu7TPCmYePR1nazfrtuF216cIVon/3GWOvHS9QR5bIwSbnxtdpma6un3jyGGNhHsKCSzn5Ypk+EkDRvTGiFA== - dependencies: - lie "~3.3.0" - pako "~1.0.2" - readable-stream "~2.3.6" - set-immediate-shim "~1.0.1" - -jszip@^3.6.0: - version "3.6.0" - resolved "https://registry.yarnpkg.com/jszip/-/jszip-3.6.0.tgz#839b72812e3f97819cc13ac4134ffced95dd6af9" - integrity sha512-jgnQoG9LKnWO3mnVNBnfhkh0QknICd1FGSrXcgrl67zioyJ4wgx25o9ZqwNtrROSflGBCGYnJfjrIyRIby1OoQ== +jszip@^3.1.3, jszip@^3.7.1: + version "3.7.1" + resolved "https://registry.yarnpkg.com/jszip/-/jszip-3.7.1.tgz#bd63401221c15625a1228c556ca8a68da6fda3d9" + integrity sha512-ghL0tz1XG9ZEmRMcEN2vt7xabrDdqHHeykgARpmZ0BiIctWxM47Vt63ZO2dnp4QYt/xJVLLy5Zv1l/xRdh2byg== dependencies: lie "~3.3.0" pako "~1.0.2" @@ -8076,12 +5886,12 @@ karma-coverage-istanbul-reporter@~3.0.3: istanbul-reports "^3.0.2" minimatch "^3.0.4" -karma-jasmine-html-reporter@^1.5.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/karma-jasmine-html-reporter/-/karma-jasmine-html-reporter-1.6.0.tgz#586e17025a1b4128e9fba55d5f1e8921bfc3bc1e" - integrity sha512-ELO9yf0cNqpzaNLsfFgXd/wxZVYkE2+ECUwhMHUD4PZ17kcsPsYsVyjquiRqyMn2jkd2sHt0IeMyAyq1MC23Fw== +karma-jasmine-html-reporter@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/karma-jasmine-html-reporter/-/karma-jasmine-html-reporter-1.7.0.tgz#52c489a74d760934a1089bfa5ea4a8fcb84cc28b" + integrity sha512-pzum1TL7j90DTE86eFt48/s12hqwQuiD+e5aXx2Dc9wDEn2LfGq6RoAxEZZjFiN0RDSCOnosEKRZWxbQ+iMpQQ== -karma-jasmine@~4.0.0: +karma-jasmine@~4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/karma-jasmine/-/karma-jasmine-4.0.1.tgz#b99e073b6d99a5196fc4bffc121b89313b0abd82" integrity sha512-h8XDAhTiZjJKzfkoO1laMH+zfNlra+dEQHUAjpn5JV1zCPtOIVWGQjLBrqhnzQa/hrU2XrZwSyBa6XjEBzfXzw== @@ -8095,41 +5905,41 @@ karma-source-map-support@1.4.0: dependencies: source-map-support "^0.5.5" -karma@~6.3.2: - version "6.3.2" - resolved "https://registry.yarnpkg.com/karma/-/karma-6.3.2.tgz#24b62fbae3e8b5218cc32a0dac49ad08a541e76d" - integrity sha512-fo4Wt0S99/8vylZMxNj4cBFyOBBnC1bewZ0QOlePij/2SZVWxqbyLeIddY13q6URa2EpLRW8ixvFRUMjkmo1bw== +karma@~6.3.9: + version "6.3.9" + resolved "https://registry.yarnpkg.com/karma/-/karma-6.3.9.tgz#cc309607f0fcdb58a88643184f3e4ba8bff26751" + integrity sha512-E/MqdLM9uVIhfuyVnrhlGBu4miafBdXEAEqCmwdEMh3n17C7UWC/8Kvm3AYKr91gc7scutekZ0xv6rxRaUCtnw== dependencies: body-parser "^1.19.0" braces "^3.0.2" - chokidar "^3.4.2" + chokidar "^3.5.1" colors "^1.4.0" connect "^3.7.0" di "^0.0.1" dom-serialize "^2.2.1" - glob "^7.1.6" - graceful-fs "^4.2.4" + glob "^7.1.7" + graceful-fs "^4.2.6" http-proxy "^1.18.1" - isbinaryfile "^4.0.6" - lodash "^4.17.19" - log4js "^6.2.1" - mime "^2.4.5" + isbinaryfile "^4.0.8" + lodash "^4.17.21" + log4js "^6.3.0" + mime "^2.5.2" minimatch "^3.0.4" qjobs "^1.2.0" range-parser "^1.2.1" rimraf "^3.0.2" - socket.io "^3.1.0" + socket.io "^4.2.0" source-map "^0.6.1" - tmp "0.2.1" - ua-parser-js "^0.7.23" + tmp "^0.2.1" + ua-parser-js "^0.7.30" yargs "^16.1.1" katex@^0.13.0: - version "0.13.18" - resolved "https://registry.yarnpkg.com/katex/-/katex-0.13.18.tgz#ba89e8e4b70cc2325e25e019a62b9fe71e5c2931" - integrity sha512-a3dC4NSVSDU3O1WZbTnOiA8rVNJ2lSiomOl0kmckCIGObccIHXof7gAseIY0o1gjEspe+34ZeSEX2D1ChFKIvA== + version "0.13.24" + resolved "https://registry.yarnpkg.com/katex/-/katex-0.13.24.tgz#fe55455eb455698cb24b911a353d16a3c855d905" + integrity sha512-jZxYuKCma3VS5UuxOx/rFV1QyGSl3Uy/i0kTJF3HgQ5xMinCQVF8Zd4bMY/9aI9b9A2pjIBOsjSSm68ykTAr8w== dependencies: - commander "^6.0.0" + commander "^8.0.0" killable@^1.0.1: version "1.0.1" @@ -8168,9 +5978,9 @@ klaw-sync@^6.0.0: graceful-fs "^4.1.11" klona@^2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/klona/-/klona-2.0.4.tgz#7bb1e3affb0cb8624547ef7e8f6708ea2e39dfc0" - integrity sha512-ZRbnvdg/NxqzC7L9Uyqzf4psi1OM4Cuc+sJAkQPjO6XkQIJTNbfK2Rsmbw8fx1p2mkZdp2FZYo2+LwXYY/uwIA== + version "2.0.5" + resolved "https://registry.yarnpkg.com/klona/-/klona-2.0.5.tgz#d166574d90076395d9963aa7a928fabb8d76afbc" + integrity sha512-pJiBpiXMbt7dkzXe8Ghj/u4FfXOOa98fPW+bihOJ4SjnoijweJrNThJfd3ifXpXhREjpoF2mZVH1GfS9LV3kHQ== leaflet-polylinedecorator@^1.6.0: version "1.6.0" @@ -8211,15 +6021,6 @@ less-loader@10.0.1: dependencies: klona "^2.0.4" -less-loader@7.3.0: - version "7.3.0" - resolved "https://registry.yarnpkg.com/less-loader/-/less-loader-7.3.0.tgz#f9d6d36d18739d642067a05fb5bd70c8c61317e5" - integrity sha512-Mi8915g7NMaLlgi77mgTTQvK022xKRQBIVDSyfl3ErTuBhmZBQab0mjeJjNNqGbdR+qrfTleKXqbGI4uEFavxg== - dependencies: - klona "^2.0.4" - loader-utils "^2.0.0" - schema-utils "^3.0.0" - less@4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/less/-/less-4.1.1.tgz#15bf253a9939791dc690888c3ff424f3e6c7edba" @@ -8237,14 +6038,6 @@ less@4.1.1: needle "^2.5.2" source-map "~0.6.0" -license-webpack-plugin@2.3.11: - version "2.3.11" - resolved "https://registry.yarnpkg.com/license-webpack-plugin/-/license-webpack-plugin-2.3.11.tgz#0d93188a31fce350a44c86212badbaf33dcd29d8" - integrity sha512-0iVGoX5vx0WDy8dmwTTpOOMYiGqILyUbDeVMFH52AjgBlS58lHwOlFMSoqg5nY8Kxl6+FRKyUZY/UdlQaOyqDw== - dependencies: - "@types/webpack-sources" "^0.1.5" - webpack-sources "^1.2.0" - license-webpack-plugin@2.3.20: version "2.3.20" resolved "https://registry.yarnpkg.com/license-webpack-plugin/-/license-webpack-plugin-2.3.20.tgz#f51fb674ca31519dbedbe1c7aabc036e5a7f2858" @@ -8266,21 +6059,16 @@ lilconfig@^2.0.3: integrity sha512-bfTIN7lEsiooCocSISTWXkiWJkRqtL9wYtYy+8EK3Y41qh3mpwPU0ycTOgjdY9ErwXCc8QyrQp82bdL0Xkm9yA== lines-and-columns@^1.1.6: - version "1.1.6" - resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.1.6.tgz#1c00c743b433cd0a4e80758f7b64a57440d9ff00" - integrity sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA= - -loader-runner@^2.4.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-2.4.0.tgz#ed47066bfe534d7e84c4c7b9998c2a75607d9357" - integrity sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw== + version "1.2.4" + resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" + integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== loader-runner@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-4.2.0.tgz#d7022380d66d14c5fb1d496b89864ebcfd478384" integrity sha512-92+huvxMvYlMzMt0iIOukcwYBFpkYJdpl2xsZ7LrlayO7E8SOv+JJUEK17B/dJIHAOLMfh2dZZ/Y18WgmGtYNw== -loader-utils@2.0.0, loader-utils@^2.0.0: +loader-utils@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-2.0.0.tgz#e4cace5b816d425a166b5f097e10cd12b36064b0" integrity sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ== @@ -8289,7 +6077,7 @@ loader-utils@2.0.0, loader-utils@^2.0.0: emojis-list "^3.0.0" json5 "^2.1.2" -loader-utils@^1.1.0, loader-utils@^1.2.3, loader-utils@^1.4.0: +loader-utils@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.4.0.tgz#c579b5e34cb34b1a74edc6c1fb36bfa371d5a613" integrity sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA== @@ -8298,6 +6086,15 @@ loader-utils@^1.1.0, loader-utils@^1.2.3, loader-utils@^1.4.0: emojis-list "^3.0.0" json5 "^1.0.1" +loader-utils@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-2.0.2.tgz#d6e3b4fb81870721ae4e0868ab11dd638368c129" + integrity sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A== + dependencies: + big.js "^5.2.2" + emojis-list "^3.0.0" + json5 "^2.1.2" + locate-path@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" @@ -8338,18 +6135,11 @@ lodash.uniq@^4.5.0: resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M= -lodash@4.17.21, lodash@^4.0.1, lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.21, lodash@~4.17.21: +lodash@4.17.21, lodash@^4.0.1, lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.21, lodash@~4.17.21: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== -log-symbols@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.0.0.tgz#69b3cc46d20f448eccdb75ea1fa733d9e821c920" - integrity sha512-FN8JBzLx6CzeMrB0tg6pqlGU1wCrXW+ZXGH481kfsBqer0hToTIiHdjH4Mq8xJUbvATujKCvaREGWpGUionraA== - dependencies: - chalk "^4.0.0" - log-symbols@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.1.0.tgz#3fbdbb95b4683ac9fc785111e792e558d4abd503" @@ -8358,7 +6148,7 @@ log-symbols@^4.1.0: chalk "^4.1.0" is-unicode-supported "^0.1.0" -log4js@^6.2.1: +log4js@^6.3.0: version "6.3.0" resolved "https://registry.yarnpkg.com/log4js/-/log4js-6.3.0.tgz#10dfafbb434351a3e30277a00b9879446f715bcb" integrity sha512-Mc8jNuSFImQUIateBFwdOQcmC6Q5maU0VVvdC2R6XMb66/VnT+7WS4D/0EeNMZu1YODmJe5NIn2XftCzEocUgw== @@ -8370,11 +6160,11 @@ log4js@^6.2.1: streamroller "^2.2.4" loglevel@^1.6.8: - version "1.7.0" - resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.7.0.tgz#728166855a740d59d38db01cf46f042caa041bb0" - integrity sha512-i2sY04nal5jDcagM3FMfG++T69GEEM8CYuOfeOIvmXzOIcwE9a/CJPR0MFM97pYMj/u10lzz7/zd7+qwhrBTqQ== + version "1.8.0" + resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.8.0.tgz#e7ec73a57e1e7b419cb6c6ac06bf050b67356114" + integrity sha512-G6A/nJLRgWOuuwdNuA6koovfEV1YpqqAG4pRUlFaz3jj2QNZ8M4vBqnVA+HBTmU/AMNUtlOsMmSpF6NyOjztbA== -loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.4.0: +loose-envify@^1.1.0, loose-envify@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== @@ -8389,13 +6179,6 @@ lru-cache@^4.1.5: pseudomap "^1.0.2" yallist "^2.1.2" -lru-cache@^5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" - integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== - dependencies: - yallist "^3.0.2" - lru-cache@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" @@ -8410,7 +6193,7 @@ magic-string@0.25.7, magic-string@^0.25.0: dependencies: sourcemap-codec "^1.4.4" -make-dir@^2.0.0, make-dir@^2.1.0: +make-dir@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-2.1.0.tgz#5f0310e18b8be898cc07009295a30ae41e91e6f5" integrity sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA== @@ -8488,15 +6271,6 @@ material-design-icons@^3.0.1: resolved "https://registry.yarnpkg.com/material-design-icons/-/material-design-icons-3.0.1.tgz#9a71c48747218ebca51e51a66da682038cdcb7bf" integrity sha1-mnHEh0chjrylHlGmbaaCA4zct78= -md5.js@^1.3.4: - version "1.3.5" - resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f" - integrity sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg== - dependencies: - hash-base "^3.0.0" - inherits "^2.0.1" - safe-buffer "^5.1.2" - mdn-data@2.0.14: version "2.0.14" resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.14.tgz#7113fc4281917d63ce29b43446f701e68c25ba50" @@ -8530,14 +6304,6 @@ memory-fs@^0.4.1: errno "^0.1.3" readable-stream "^2.0.1" -memory-fs@^0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.5.0.tgz#324c01288b88652966d161db77838720845a8e3c" - integrity sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA== - dependencies: - errno "^0.1.3" - readable-stream "^2.0.1" - merge-descriptors@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" @@ -8603,15 +6369,7 @@ micromatch@^3.1.10, micromatch@^3.1.4: snapdragon "^0.8.1" to-regex "^3.0.2" -micromatch@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.2.tgz#4fcb0999bf9fbc2fcbdd212f6d629b9a56c39259" - integrity sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q== - dependencies: - braces "^3.0.1" - picomatch "^2.0.5" - -micromatch@^4.0.4: +micromatch@^4.0.2, micromatch@^4.0.4: version "4.0.4" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.4.tgz#896d519dfe9db25fce94ceb7a500919bf881ebf9" integrity sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg== @@ -8619,37 +6377,12 @@ micromatch@^4.0.4: braces "^3.0.1" picomatch "^2.2.3" -miller-rabin@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.1.tgz#f080351c865b0dc562a8462966daa53543c78a4d" - integrity sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA== - dependencies: - bn.js "^4.0.0" - brorand "^1.0.1" - -mime-db@1.44.0: - version "1.44.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.44.0.tgz#fa11c5eb0aca1334b4233cb4d52f10c5a6272f92" - integrity sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg== - -mime-db@1.51.0: +mime-db@1.51.0, "mime-db@>= 1.43.0 < 2": version "1.51.0" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.51.0.tgz#d9ff62451859b18342d960850dc3cfb77e63fb0c" integrity sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g== -"mime-db@>= 1.43.0 < 2": - version "1.45.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.45.0.tgz#cceeda21ccd7c3a745eba2decd55d4b73e7879ea" - integrity sha512-CkqLUxUk15hofLoLyljJSrukZi8mAtgd+yE5uO4tqRZsdsAJKv0O+rFMhVDRJgozy+yG6md5KwuXhD4ocIoP+w== - -mime-types@^2.1.12, mime-types@~2.1.17, mime-types@~2.1.19, mime-types@~2.1.24: - version "2.1.27" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.27.tgz#47949f98e279ea53119f5722e0f34e529bec009f" - integrity sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w== - dependencies: - mime-db "1.44.0" - -mime-types@^2.1.27, mime-types@^2.1.31: +mime-types@^2.1.12, mime-types@^2.1.27, mime-types@^2.1.31, mime-types@~2.1.17, mime-types@~2.1.19, mime-types@~2.1.24: version "2.1.34" resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.34.tgz#5a712f9ec1503511a945803640fafe09d3793c24" integrity sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A== @@ -8661,10 +6394,10 @@ mime@1.6.0, mime@^1.4.1: resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== -mime@^2.4.4, mime@^2.4.5: - version "2.4.6" - resolved "https://registry.yarnpkg.com/mime/-/mime-2.4.6.tgz#e5b407c90db442f2beb5b162373d07b69affa4d1" - integrity sha512-RZKhC3EmpBchfTGBVb8fb+RL2cWyw/32lshnsETttkBAyAUXSGHxbEJWWRXc751DrIxG1q04b8QwMbAwkRPpUA== +mime@^2.4.4, mime@^2.5.2: + version "2.6.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-2.6.0.tgz#a2a682a95cd4d0cb1d6257e28f83da7e35800367" + integrity sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg== mimic-fn@^2.1.0: version "2.1.0" @@ -8676,15 +6409,6 @@ mimic-fn@^3.1.0: resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-3.1.0.tgz#65755145bbf3e36954b949c16450427451d5ca74" integrity sha512-Ysbi9uYW9hFyfrThdDEQuykN4Ey6BuwPD2kpI5ES/nFTDn/98yxYNLZJcgUAKPT/mcrLLKaGzJR9YVxJrIdASQ== -mini-css-extract-plugin@1.3.5: - version "1.3.5" - resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-1.3.5.tgz#252166e78879c106e0130f229d44e0cbdfcebed3" - integrity sha512-tvmzcwqJJXau4OQE5vT72pRT18o2zF+tQJp8CWchqvfQnTlflkzS+dANYcRdyPRWUWRkfmeNTKltx0NZI/b5dQ== - dependencies: - loader-utils "^2.0.0" - schema-utils "^3.0.0" - webpack-sources "^1.1.0" - mini-css-extract-plugin@2.4.2: version "2.4.2" resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-2.4.2.tgz#b3508191ea479388a4715018c99dd3e6dd40d2d2" @@ -8692,16 +6416,11 @@ mini-css-extract-plugin@2.4.2: dependencies: schema-utils "^3.1.0" -minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: +minimalistic-assert@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== -minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" - integrity sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo= - minimatch@3.0.4, minimatch@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" @@ -8722,9 +6441,9 @@ minipass-collect@^1.0.2: minipass "^3.0.0" minipass-fetch@^1.3.0, minipass-fetch@^1.3.2: - version "1.3.3" - resolved "https://registry.yarnpkg.com/minipass-fetch/-/minipass-fetch-1.3.3.tgz#34c7cea038c817a8658461bf35174551dce17a0a" - integrity sha512-akCrLDWfbdAWkMLBxJEeWTdNsjML+dt5YgOI4gJ53vuO0vrmYQkUPxa6j6V65s9CcePIr2SSWqjT2EcrNseryQ== + version "1.4.1" + resolved "https://registry.yarnpkg.com/minipass-fetch/-/minipass-fetch-1.4.1.tgz#d75e0091daac1b0ffd7e9d41629faff7d0c1f1b6" + integrity sha512-CGH1eblLq26Y15+Azk7ey4xh0J/XfJfrCox5LDJiKqI2Q2iwOLOKrlmIaODiSQS8d18jalF6y2K2ePUm0CmShw== dependencies: minipass "^3.1.0" minipass-sized "^1.0.3" @@ -8762,9 +6481,9 @@ minipass-sized@^1.0.3: minipass "^3.0.0" minipass@^3.0.0, minipass@^3.1.0, minipass@^3.1.1, minipass@^3.1.3: - version "3.1.3" - resolved "https://registry.yarnpkg.com/minipass/-/minipass-3.1.3.tgz#7d42ff1f39635482e15f9cdb53184deebd5815fd" - integrity sha512-Mgd2GdMVzY+x3IJ+oHnVM+KG3lA5c8tnabyJKmHSaG2kAGpudxuOf8ToDkhumF7UzME7DecbQE9uOZhNm7PuJg== + version "3.1.5" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-3.1.5.tgz#71f6251b0a33a49c01b3cf97ff77eda030dff732" + integrity sha512-+8NzxD82XQoNKNrl1d/FSi+X8wAEWR+sbYAfIvub4Nz0d22plFG72CEVVaufV8PNf4qSslFTD8VMOxNVhHCjTw== dependencies: yallist "^4.0.0" @@ -8776,22 +6495,6 @@ minizlib@^2.0.0, minizlib@^2.1.1: minipass "^3.0.0" yallist "^4.0.0" -mississippi@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/mississippi/-/mississippi-3.0.0.tgz#ea0a3291f97e0b5e8776b363d5f0a12d94c67022" - integrity sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA== - dependencies: - concat-stream "^1.5.0" - duplexify "^3.4.2" - end-of-stream "^1.1.0" - flush-write-stream "^1.0.0" - from2 "^2.1.0" - parallel-transform "^1.1.0" - pump "^3.0.0" - pumpify "^1.3.3" - stream-each "^1.1.0" - through2 "^2.0.0" - mixin-deep@^1.2.0: version "1.3.2" resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566" @@ -8812,17 +6515,10 @@ mkdirp@^1.0.3, mkdirp@^1.0.4, mkdirp@~1.0.4: resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== -moment-timezone@*: - version "0.5.31" - resolved "https://registry.yarnpkg.com/moment-timezone/-/moment-timezone-0.5.31.tgz#9c40d8c5026f0c7ab46eda3d63e49c155148de05" - integrity sha512-+GgHNg8xRhMXfEbv81iDtrVeTcWt0kWmTEY1XQK14dICTXnWJnT0dxdlPspwqF3keKMVPXwayEsk1DI0AA/jdA== - dependencies: - moment ">= 2.9.0" - -moment-timezone@^0.5.33: - version "0.5.33" - resolved "https://registry.yarnpkg.com/moment-timezone/-/moment-timezone-0.5.33.tgz#b252fd6bb57f341c9b59a5ab61a8e51a73bbd22c" - integrity sha512-PTc2vcT8K9J5/9rDEPe5czSIKgLoGsH8UNpA4qZTVw0Vd/Uz19geE9abbIOQKaAQFcnQ3v5YEXrbSc5BpshH+w== +moment-timezone@*, moment-timezone@^0.5.34: + version "0.5.34" + resolved "https://registry.yarnpkg.com/moment-timezone/-/moment-timezone-0.5.34.tgz#a75938f7476b88f155d3504a9343f7519d9a405c" + integrity sha512-3zAEHh2hKUs3EXLESx/wsgw6IQdusOT8Bxm3D9UrHPQR7zlMmzwybC8zHEM1tQ4LJwP7fcxrWr8tuBg05fFCbg== dependencies: moment ">= 2.9.0" @@ -8831,28 +6527,11 @@ moment-timezone@^0.5.33: resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.1.tgz#b2be769fa31940be9eeea6469c075e35006fa3d3" integrity sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ== -mousetrap@1.6.3: - version "1.6.3" - resolved "https://registry.yarnpkg.com/mousetrap/-/mousetrap-1.6.3.tgz#80fee49665fd478bccf072c9d46bdf1bfed3558a" - integrity sha512-bd+nzwhhs9ifsUrC2tWaSgm24/oo2c83zaRyZQF06hYA6sANfsXHtnZ19AbbbDXCDzeH5nZBSQ4NvCjgD62tJA== - mousetrap@^1.6.0: version "1.6.5" resolved "https://registry.yarnpkg.com/mousetrap/-/mousetrap-1.6.5.tgz#8a766d8c272b08393d5f56074e0b5ec183485bf9" integrity sha512-QNo4kEepaIBwiT8CDhP98umTetp+JNfQYBWvC1pc6/OAibuXtRcxZ58Qz8skvEHYvURne/7R8T5VoOI7rDsEUA== -move-concurrently@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/move-concurrently/-/move-concurrently-1.0.1.tgz#be2c005fda32e0b29af1f05d7c4b33214c701f92" - integrity sha1-viwAX9oy4LKa8fBdfEszIUxwH5I= - dependencies: - aproba "^1.1.1" - copy-concurrently "^1.0.0" - fs-write-stream-atomic "^1.0.8" - mkdirp "^0.5.1" - rimraf "^2.5.4" - run-queue "^1.0.3" - ms@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" @@ -8863,11 +6542,16 @@ ms@2.1.1: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg== -ms@2.1.2, ms@^2.0.0, ms@^2.1.1: +ms@2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== +ms@^2.0.0, ms@^2.1.1: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + multicast-dns-service-types@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz#899f11d9686e5e05cb91b35d5f0e63b773cfc901" @@ -8887,16 +6571,11 @@ mute-stream@0.0.8: integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA== nan@^2.12.1: - version "2.14.1" - resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.1.tgz#d7be34dfa3105b91494c3147089315eff8874b01" - integrity sha512-isWHgVjnFjh2x2yuJ/tj3JbwoHu3UC2dX5G/88Cm24yB6YopVgxvBObDY7n5xW6ExmFhJpSEQqFPvq9zaXc8Jw== + version "2.15.0" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.15.0.tgz#3f34a473ff18e15c1b5626b62903b5ad6e665fee" + integrity sha512-8ZtvEnA2c5aYCZYd1cvgdnU6cqwixRoYg70xPLWUws5ORTa/lnw+u4amixRS/Ac5U5mQVgp9pnlSUnbNWFaWZQ== -nanoid@^3.1.22, nanoid@^3.1.23: - version "3.1.23" - resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.23.tgz#f744086ce7c2bc47ee0a8472574d5c78e4183a81" - integrity sha512-FiB0kzdP0FFVGDKlRLEQ1BgDzU87dy5NnzjeW9YZNt+/c3+q82EQDUwniSAUxp/F0gFNI1ZhKU1FqYsMuqZVnw== - -nanoid@^3.1.30: +nanoid@^3.1.23, nanoid@^3.1.30: version "3.1.30" resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.30.tgz#63f93cc548d2a113dc5dfbc63bfa09e2b9b64362" integrity sha512-zJpuPDwOv8D2zq2WRoMe1HsfZthVewpel9CAvTfc/2mBD1uUT/agc5f7GHGWXlYkFvi1mVxe4IjvP2HNrop7nQ== @@ -8919,9 +6598,9 @@ nanomatch@^1.2.9: to-regex "^3.0.1" needle@^2.5.2: - version "2.6.0" - resolved "https://registry.yarnpkg.com/needle/-/needle-2.6.0.tgz#24dbb55f2509e2324b4a99d61f413982013ccdbe" - integrity sha512-KKYdza4heMsEfSWD7VPUIz3zX2XDwOyX2d+geb4vrERZMT5RMU6ujjaD+I5Yr54uZxQ2w6XRTAhHBbSCyovZBg== + version "2.9.1" + resolved "https://registry.yarnpkg.com/needle/-/needle-2.9.1.tgz#22d1dffbe3490c2b83e301f7709b6736cd8f2684" + integrity sha512-6R9fqJ5Zcmf+uYaFgdIHmLwNldn5HbK8L5ybn7Uz+ylX/rnOsSp1AHcvQSrCaFN+qNM1wpymHqD7mVasEOlHGQ== dependencies: debug "^3.2.6" iconv-lite "^0.4.4" @@ -8932,7 +6611,7 @@ negotiator@0.6.2, negotiator@^0.6.2: resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw== -neo-async@^2.5.0, neo-async@^2.6.1, neo-async@^2.6.2: +neo-async@^2.6.2: version "2.6.2" resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== @@ -8944,12 +6623,12 @@ ngrx-store-freeze@^0.2.4: dependencies: deep-freeze-strict "^1.1.1" -ngx-clipboard@^14.0.1: - version "14.0.1" - resolved "https://registry.yarnpkg.com/ngx-clipboard/-/ngx-clipboard-14.0.1.tgz#fe977ee115f50f6a589487f6f99fa5eef5203763" - integrity sha512-y6fDrvAso1cbM+VvHgB2kJ3dcQ/EBPol33nLaqqKB1jNO/Kd3l17EHdXNW/oKY0wUKCHk7ZCuiinREgUHEYfXg== +ngx-clipboard@^14.0.2: + version "14.0.2" + resolved "https://registry.yarnpkg.com/ngx-clipboard/-/ngx-clipboard-14.0.2.tgz#4098b32499a75a41f8c05991f36d30d2a8ec8122" + integrity sha512-zJaFi09D2bq9X1RYvFixE0AfYOI7E8mUO8S0GXcq76HisuE816HRl+8A46G+NML5GPA3Lr5qaGnQJN533So+8g== dependencies: - ngx-window-token ">=4.0.0" + ngx-window-token ">=4.0.0 <6.0.0" tslib "^2.0.0" ngx-color-picker@^11.0.0: @@ -8959,12 +6638,13 @@ ngx-color-picker@^11.0.0: dependencies: tslib "^2.0.0" -ngx-daterangepicker-material@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/ngx-daterangepicker-material/-/ngx-daterangepicker-material-4.0.1.tgz#788c2e32eb4717629d4a0e60a60bf8d6430d8c13" - integrity sha512-0gY6DGU+dgYdmoAKrIJSB9xnDqBvj91Yis3II/ZJxxMfZVTG4qMMatck6w8FzdU+CYT64ArCq+Uwa6hJRHX6Nw== +ngx-daterangepicker-material@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/ngx-daterangepicker-material/-/ngx-daterangepicker-material-5.0.1.tgz#57403e605b4c317e6f694e3b289732945fcd7e97" + integrity sha512-vbxsiRqyBgXExRBPxuCodLlOOsVEZJ20nTPZks/7z943gZcb2XKwRuQ9hi43MG0xl7RVzDKZdsNKU8bzB86g7g== dependencies: - tslib "^1.10.0" + dayjs "^1.10.4" + tslib "^2.0.0" ngx-drag-drop@^2.0.0: version "2.0.0" @@ -8979,41 +6659,42 @@ ngx-drag-drop@^2.0.0: dependencies: tslib "^1.13.0" -ngx-hm-carousel@^2.0.0-rc.1: - version "2.0.0-rc.1" - resolved "https://registry.yarnpkg.com/ngx-hm-carousel/-/ngx-hm-carousel-2.0.0-rc.1.tgz#0ca7663da21a9ac60470b37d300637c29dc64b3a" - integrity sha512-vEMMFctBpQ+0hiwLo97IVmk39He9Gx2Xp6CudD5K1y4xxsuAkpqsGO5jh3KG3i2kMjP8OZY6plTJwIcATvBmLg== +ngx-hm-carousel@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/ngx-hm-carousel/-/ngx-hm-carousel-2.0.1.tgz#29574c5128b26d8520b1ef6499eec7efca4e403f" + integrity sha512-iZxe1SVDkmXsSdZlU5nOtYV7hZGiRTEOij7Esnmc+PVgmMmIZe784uZv1RM/cKb3+hNesHjJuYyyNDkD+ryANw== dependencies: + "@types/hammerjs" "^2.0.39" hammerjs "^2.0.8" - resize-observer-polyfill "^1.5.1" + tslib "^2.0.0" -ngx-markdown@^11.1.3: - version "11.1.3" - resolved "https://registry.yarnpkg.com/ngx-markdown/-/ngx-markdown-11.1.3.tgz#4d01c2dc425e5a46d1b6aa8517d9a1c1feaa1efd" - integrity sha512-z32q8l76ubrcP62L03mdvrizwueLBHV10LkT8MEDnFcjmY+8J1PytxFJ9EBTJpvc+CaPolgAoi7felN2XJZTSg== +ngx-markdown@^12.0.1: + version "12.0.1" + resolved "https://registry.yarnpkg.com/ngx-markdown/-/ngx-markdown-12.0.1.tgz#94345e99176533c17396f93e97ff5dc172d8ebcc" + integrity sha512-vMp9SyqmVQZCX374MiCV4sRR1SIv5m3xR2HZ39b3+6/BGjAb46mb4wRXKdIxYUoPba7NYZ8GAt5moUCyVZcCyA== dependencies: "@types/marked" "^2.0.0" - emoji-toolkit "^6.0.1" + emoji-toolkit "^6.5.0" katex "^0.13.0" marked "^2.0.0" prismjs "^1.23.0" - tslib "^2.0.0" + tslib "^2.1.0" -ngx-sharebuttons@^8.0.5: - version "8.0.5" - resolved "https://registry.yarnpkg.com/ngx-sharebuttons/-/ngx-sharebuttons-8.0.5.tgz#49481fcb8bf9541747fd72093eca6f4777c1d371" - integrity sha512-LAaZQk1i/yuYkX+SK72OkJBMNmGJ7SS/yoGEIyuUd7r9F9SwLpWfUAjccmtuM0qDzd48h+1CCnPGIB6WYlKY4g== +ngx-sharebuttons@^9.0.0: + version "9.0.0" + resolved "https://registry.yarnpkg.com/ngx-sharebuttons/-/ngx-sharebuttons-9.0.0.tgz#6919ecb2c77ce6165b443cbc7c44884500186173" + integrity sha512-suoDgXnJwn2EHJzFDvm54KUnW6pGq+APC7VT54HNndwp1lcwXj5QbFgB5Vlk4IfN9VIBOE+IAwdFEdxmIK73Og== dependencies: tslib "^2.0.0" -ngx-translate-messageformat-compiler@^4.9.0: - version "4.9.0" - resolved "https://registry.yarnpkg.com/ngx-translate-messageformat-compiler/-/ngx-translate-messageformat-compiler-4.9.0.tgz#00c3d34f7ed2bed6b406acb2e67b7b8989194430" - integrity sha512-Bat3CjtP7SJ8ks9z3GASW/0wjikf/vE9Vqb0H9SmOgP22CNb22K2oMdPacQQOBjy2hRvcVQ+GDqk5oa7MKiw/A== +ngx-translate-messageformat-compiler@^4.11.0: + version "4.11.0" + resolved "https://registry.yarnpkg.com/ngx-translate-messageformat-compiler/-/ngx-translate-messageformat-compiler-4.11.0.tgz#c9b71dd139ba5fcdcd809001e22622de589fd707" + integrity sha512-OdGfWV4fF3DhZqGIHcLmOnQDufugmZ+E90NYr1UPGRZgT10lilr9oLmIrisy3lW4THnZFNo9JXsX7+fX84LbDw== dependencies: tslib "^1.10.0" -ngx-window-token@>=4.0.0: +"ngx-window-token@>=4.0.0 <6.0.0": version "5.0.0" resolved "https://registry.yarnpkg.com/ngx-window-token/-/ngx-window-token-5.0.0.tgz#ca63a25038c9fdd73159857276ff67ec7f5b730b" integrity sha512-DhigCrm9QO8R29lqJYzBC9aaTU0KiWgdnt8RNcTN/DvMaS7shfzAqyvUtxSIm/+JR4gW5JKqR/JODU8760nJMw== @@ -9064,45 +6745,6 @@ node-gyp@^7.1.0: tar "^6.0.2" which "^2.0.2" -node-libs-browser@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.2.1.tgz#b64f513d18338625f90346d27b0d235e631f6425" - integrity sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q== - dependencies: - assert "^1.1.1" - browserify-zlib "^0.2.0" - buffer "^4.3.0" - console-browserify "^1.1.0" - constants-browserify "^1.0.0" - crypto-browserify "^3.11.0" - domain-browser "^1.1.1" - events "^3.0.0" - https-browserify "^1.0.0" - os-browserify "^0.3.0" - path-browserify "0.0.1" - process "^0.11.10" - punycode "^1.2.4" - querystring-es3 "^0.2.0" - readable-stream "^2.3.3" - stream-browserify "^2.0.1" - stream-http "^2.7.2" - string_decoder "^1.0.0" - timers-browserify "^2.0.4" - tty-browserify "0.0.0" - url "^0.11.0" - util "^0.11.0" - vm-browserify "^1.0.1" - -node-releases@^1.1.61: - version "1.1.61" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.61.tgz#707b0fca9ce4e11783612ba4a2fcba09047af16e" - integrity sha512-DD5vebQLg8jLCOzwupn954fbIiZht05DAZs0k2u8NStSe6h9XdsuIQL8hSRKYiU8WUQRznmSDrKGbv3ObOmC7g== - -node-releases@^1.1.71: - version "1.1.72" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.72.tgz#14802ab6b1039a79a0c7d662b610a5bbd76eacbe" - integrity sha512-LLUo+PpH3dU6XizX3iVoubUNheF/owjXCZZ5yACDxNnPtgFuludV1ZL3ayK1kVep42Rmm0+R9/Y60NQbZ2bifw== - node-releases@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.1.tgz#3d1d395f204f1f2f29a54358b9fb678765ad2fc5" @@ -9132,11 +6774,6 @@ normalize-range@^0.1.2: resolved "https://registry.yarnpkg.com/normalize-range/-/normalize-range-0.1.2.tgz#2d10c06bdfd312ea9777695a4d28439456b75942" integrity sha1-LRDAa9/TEuqXd2laTShDlFa3WUI= -normalize-url@^4.5.0: - version "4.5.1" - resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-4.5.1.tgz#0dd90cf1288ee1d1313b87081c9a5932ee48518a" - integrity sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA== - normalize-url@^6.0.1: version "6.1.0" resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-6.1.0.tgz#40d0885b535deffe3f3147bec877d05fe4c5668a" @@ -9161,7 +6798,7 @@ npm-normalize-package-bin@^1.0.1: resolved "https://registry.yarnpkg.com/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz#6e79a41f23fd235c0623218228da7d9c23b8f6e2" integrity sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA== -npm-package-arg@8.1.5: +npm-package-arg@8.1.5, npm-package-arg@^8.0.0, npm-package-arg@^8.0.1, npm-package-arg@^8.1.2: version "8.1.5" resolved "https://registry.yarnpkg.com/npm-package-arg/-/npm-package-arg-8.1.5.tgz#3369b2d5fe8fdc674baa7f1786514ddc15466e44" integrity sha512-LhgZrg0n0VgvzVdSm1oiZworPbTxYHUJCgtsJW8mGvlDpxTM1vSJc3m5QZeUkhAHIzbz3VCHd/R4osi1L1Tg/Q== @@ -9170,24 +6807,6 @@ npm-package-arg@8.1.5: semver "^7.3.4" validate-npm-package-name "^3.0.0" -npm-package-arg@^8.0.0: - version "8.0.1" - resolved "https://registry.yarnpkg.com/npm-package-arg/-/npm-package-arg-8.0.1.tgz#9d76f8d7667b2373ffda60bb801a27ef71e3e270" - integrity sha512-/h5Fm6a/exByzFSTm7jAyHbgOqErl9qSNJDQF32Si/ZzgwT2TERVxRxn3Jurw1wflgyVVAxnFR4fRHPM7y1ClQ== - dependencies: - hosted-git-info "^3.0.2" - semver "^7.0.0" - validate-npm-package-name "^3.0.0" - -npm-package-arg@^8.0.1, npm-package-arg@^8.1.2: - version "8.1.2" - resolved "https://registry.yarnpkg.com/npm-package-arg/-/npm-package-arg-8.1.2.tgz#b868016ae7de5619e729993fbd8d11dc3c52ab62" - integrity sha512-6Eem455JsSMJY6Kpd3EyWE+n5hC+g9bSyHr9K9U2zqZb7+02+hObQ2c0+8iDk/mNF+8r1MhY44WypKJAkySIYA== - dependencies: - hosted-git-info "^4.0.1" - semver "^7.3.4" - validate-npm-package-name "^3.0.0" - npm-packlist@^2.1.4: version "2.2.2" resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-2.2.2.tgz#076b97293fa620f632833186a7a8f65aaa6148c8" @@ -9238,9 +6857,9 @@ npmlog@^4.1.2: set-blocking "~2.0.0" nth-check@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-2.0.0.tgz#1bb4f6dac70072fc313e8c9cd1417b5074c0a125" - integrity sha512-i4sc/Kj8htBrAiH1viZ0TgU8Y5XqCaV/FziYK6TBczxmeKm3AEFWqqF3195yKudrarqy7Zu80Ra5dobFjn9X/Q== + version "2.0.1" + resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-2.0.1.tgz#2efe162f5c3da06a28959fbd3db75dbeea9f0fc2" + integrity sha512-it1vE95zF6dTT9lBsYbxvqh0Soy4SPowchj0UBGj/V6cTPnXXtQOPUbhZ6CmGzAD/rW22LQK6E96pcdJXk4A4w== dependencies: boolbase "^1.0.0" @@ -9259,7 +6878,7 @@ oauth-sign@~0.9.0: resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ== -object-assign@4.x, object-assign@^4, object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1: +object-assign@^4, object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= @@ -9273,18 +6892,13 @@ object-copy@^0.1.0: define-property "^0.2.5" kind-of "^3.0.3" -object-inspect@^1.8.0: - version "1.8.0" - resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.8.0.tgz#df807e5ecf53a609cc6bfe93eac3cc7be5b3a9d0" - integrity sha512-jLdtEOB112fORuypAyl/50VRVIBIdVQOSUUGQHzJ4xBSbit81zRarz7GThkEFZy1RceYrWYcPcBFPQwHyAc1gA== - object-is@^1.0.1: - version "1.1.3" - resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.1.3.tgz#2e3b9e65560137455ee3bd62aec4d90a2ea1cc81" - integrity sha512-teyqLvFWzLkq5B9ki8FVWA902UER2qkxmdA4nLf+wjOLAWgxzCWZNCxpDq9MvE8MmhWNr+I8w3BN49Vx36Y6Xg== + version "1.1.5" + resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.1.5.tgz#b9deeaa5fc7f1846a0faecdceec138e5778f53ac" + integrity sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw== dependencies: + call-bind "^1.0.2" define-properties "^1.1.3" - es-abstract "^1.18.0-next.1" object-keys@^1.0.12, object-keys@^1.1.1: version "1.1.1" @@ -9298,13 +6912,13 @@ object-visit@^1.0.0: dependencies: isobject "^3.0.0" -object.assign@^4.1.0, object.assign@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.1.tgz#303867a666cdd41936ecdedfb1f8f3e32a478cdd" - integrity sha512-VT/cxmx5yaoHSOTSyrCygIDFco+RsibY2NM0a4RdEeY/4KgqezwFtK1yr3U67xYhqJSlASm2pKhLVzPj2lr4bA== +object.assign@^4.1.0: + version "4.1.2" + resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.2.tgz#0ed54a342eceb37b38ff76eb831a0e788cb63940" + integrity sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ== dependencies: + call-bind "^1.0.0" define-properties "^1.1.3" - es-abstract "^1.18.0-next.0" has-symbols "^1.0.1" object-keys "^1.1.1" @@ -9351,14 +6965,6 @@ onetime@^5.1.0: dependencies: mimic-fn "^2.1.0" -open@7.4.0: - version "7.4.0" - resolved "https://registry.yarnpkg.com/open/-/open-7.4.0.tgz#ad95b98f871d9acb0ec8fecc557082cc9986626b" - integrity sha512-PGoBCX/lclIWlpS/R2PQuIR4NJoXh6X5AwVzE7WXnWRGvHg7+4TBCgsujUgiPpm0K1y4qvQeWnCWVTpTKZBtvA== - dependencies: - is-docker "^2.0.0" - is-wsl "^2.1.1" - open@8.2.1: version "8.2.1" resolved "https://registry.yarnpkg.com/open/-/open-8.2.1.tgz#82de42da0ccbf429bc12d099dad2e0975e14e8af" @@ -9383,20 +6989,6 @@ opn@^5.5.0: dependencies: is-wsl "^1.1.0" -ora@5.3.0: - version "5.3.0" - resolved "https://registry.yarnpkg.com/ora/-/ora-5.3.0.tgz#fb832899d3a1372fe71c8b2c534bbfe74961bb6f" - integrity sha512-zAKMgGXUim0Jyd6CXK9lraBnD3H5yPGBPPOkC23a2BG6hsm4Zu6OQSjQuEtV0BHDf4aKHcUFvJiGRrFuW3MG8g== - dependencies: - bl "^4.0.3" - chalk "^4.1.0" - cli-cursor "^3.1.0" - cli-spinners "^2.5.0" - is-interactive "^1.0.0" - log-symbols "^4.0.0" - strip-ansi "^6.0.0" - wcwidth "^1.0.1" - ora@5.4.1, ora@^5.3.0: version "5.4.1" resolved "https://registry.yarnpkg.com/ora/-/ora-5.4.1.tgz#1b2678426af4ac4a509008e5e4ac9e9959db9e18" @@ -9419,11 +7011,6 @@ original@^1.0.0: dependencies: url-parse "^1.4.3" -os-browserify@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.3.0.tgz#854373c7f5c2315914fc9bfc6bd8238fdda1ec27" - integrity sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc= - os-tmpdir@~1.0.1, os-tmpdir@~1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" @@ -9446,14 +7033,7 @@ p-limit@^2.0.0, p-limit@^2.2.0: dependencies: p-try "^2.0.0" -p-limit@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.0.2.tgz#1664e010af3cadc681baafd3e2a437be7b0fb5fe" - integrity sha512-iwqZSOoWIW+Ew4kAGUlN16J4M7OB3ysMLSZtnhmqx7njIHFPlxWBX8xo3lVTyFVq6mI/lL9qt2IsN1sHwaxJkg== - dependencies: - p-try "^2.0.0" - -p-limit@^3.1.0: +p-limit@^3.0.2, p-limit@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== @@ -9523,20 +7103,11 @@ pacote@11.3.5: ssri "^8.0.1" tar "^6.1.0" -pako@^1.0.3, pako@~1.0.2, pako@~1.0.5: +pako@^1.0.3, pako@~1.0.2: version "1.0.11" resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf" integrity sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw== -parallel-transform@^1.1.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/parallel-transform/-/parallel-transform-1.2.0.tgz#9049ca37d6cb2182c3b1d2c720be94d14a5814fc" - integrity sha512-P2vSmIu38uIlvdcU7fDkyrxj33gTUy/ABO5ZUbGowxNCopBq/OoD42bP4UmMrJoPyk4Uqf0mu3mtWBhHCZD8yg== - dependencies: - cyclist "^1.0.1" - inherits "^2.0.3" - readable-stream "^2.1.5" - parent-module@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" @@ -9544,17 +7115,6 @@ parent-module@^1.0.0: dependencies: callsites "^3.0.0" -parse-asn1@^5.0.0, parse-asn1@^5.1.5: - version "5.1.6" - resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.6.tgz#385080a3ec13cb62a62d39409cb3e88844cdaed4" - integrity sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw== - dependencies: - asn1.js "^5.2.0" - browserify-aes "^1.0.0" - evp_bytestokey "^1.0.0" - pbkdf2 "^3.0.3" - safe-buffer "^5.1.1" - parse-json@^5.0.0: version "5.2.0" resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" @@ -9631,11 +7191,6 @@ patch-package@^6.4.7: slash "^2.0.0" tmp "^0.0.33" -path-browserify@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.1.tgz#e6c4ddd7ed3aa27c68a20cc4e50e1a4ee83bbc4a" - integrity sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ== - path-dirname@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0" @@ -9667,9 +7222,9 @@ path-key@^2.0.0, path-key@^2.0.1: integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= path-parse@^1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" - integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw== + version "1.0.7" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" + integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== path-to-regexp@0.1.7: version "0.1.7" @@ -9681,17 +7236,6 @@ path-type@^4.0.0: resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== -pbkdf2@^3.0.3: - version "3.1.1" - resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.1.1.tgz#cb8724b0fada984596856d1a6ebafd3584654b94" - integrity sha512-4Ejy1OPxi9f2tt1rRV7Go7zmfDQ+ZectEQz3VGUQhgq62HtIRPDyG/JtnwIxs6x3uNMwo2V7q1fMvKjb+Tnpqg== - dependencies: - create-hash "^1.1.2" - create-hmac "^1.1.4" - ripemd160 "^2.0.1" - safe-buffer "^5.0.1" - sha.js "^2.4.8" - performance-now@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" @@ -9707,12 +7251,7 @@ picocolors@^1.0.0: resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== -picomatch@^2.0.4, picomatch@^2.0.5, picomatch@^2.2.1: - version "2.2.2" - resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.2.tgz#21f333e9b6b8eaff02468f5146ea406d345f4dad" - integrity sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg== - -picomatch@^2.2.3: +picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3: version "2.3.0" resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.0.tgz#f1f061de8f6a4bf022892e2d128234fb98302972" integrity sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw== @@ -9764,17 +7303,10 @@ pkg-dir@^4.1.0: dependencies: find-up "^4.0.0" -pngjs@^3.3.0: - version "3.4.0" - resolved "https://registry.yarnpkg.com/pngjs/-/pngjs-3.4.0.tgz#99ca7d725965fb655814eaf65f38f12bbdbf555f" - integrity sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w== - -pnp-webpack-plugin@1.6.4: - version "1.6.4" - resolved "https://registry.yarnpkg.com/pnp-webpack-plugin/-/pnp-webpack-plugin-1.6.4.tgz#c9711ac4dc48a685dabafc86f8b6dd9f8df84149" - integrity sha512-7Wjy+9E3WwLOEL30D+m8TSTF7qJJUJLONBnwQp0518siuMxUQUbgZwssaFX+QKlZkjHZcw/IpZCt/H0srrntSg== - dependencies: - ts-pnp "^1.1.6" +pngjs@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/pngjs/-/pngjs-5.0.0.tgz#e79dd2b215767fd9c04561c01236df960bce7fbb" + integrity sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw== polygon-clipping@0.15.3: version "0.15.3" @@ -9860,15 +7392,6 @@ postcss-color-rebeccapurple@^4.0.1: postcss "^7.0.2" postcss-values-parser "^2.0.0" -postcss-colormin@^5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/postcss-colormin/-/postcss-colormin-5.1.1.tgz#834d262f6021f832d9085e355f08ade288a92a1d" - integrity sha512-SyTmqKKN6PyYNeeKEC0hqIP5CDuprO1hHurdW1aezDyfofDUOn7y7MaxcolbsW3oazPwFiGiY30XRiW1V4iZpA== - dependencies: - browserslist "^4.16.0" - colord "^2.0.0" - postcss-value-parser "^4.1.0" - postcss-colormin@^5.2.1: version "5.2.1" resolved "https://registry.yarnpkg.com/postcss-colormin/-/postcss-colormin-5.2.1.tgz#6e444a806fd3c578827dbad022762df19334414d" @@ -9879,13 +7402,6 @@ postcss-colormin@^5.2.1: colord "^2.9.1" postcss-value-parser "^4.1.0" -postcss-convert-values@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/postcss-convert-values/-/postcss-convert-values-5.0.1.tgz#4ec19d6016534e30e3102fdf414e753398645232" - integrity sha512-C3zR1Do2BkKkCgC0g3sF8TS0koF2G+mN8xxayZx3f10cIRmTaAnpgpRQZjNekTZxM2ciSPoh2IWJm0VZx8NoQg== - dependencies: - postcss-value-parser "^4.1.0" - postcss-convert-values@^5.0.2: version "5.0.2" resolved "https://registry.yarnpkg.com/postcss-convert-values/-/postcss-convert-values-5.0.2.tgz#879b849dc3677c7d6bc94b6a2c1a3f0808798059" @@ -9996,15 +7512,6 @@ postcss-image-set-function@^3.0.1: postcss "^7.0.2" postcss-values-parser "^2.0.0" -postcss-import@14.0.0: - version "14.0.0" - resolved "https://registry.yarnpkg.com/postcss-import/-/postcss-import-14.0.0.tgz#3ed1dadac5a16650bde3f4cdea6633b9c3c78296" - integrity sha512-gFDDzXhqr9ELmnLHgCC3TbGfA6Dm/YMb/UN8/f7Uuq4fL7VTk2vOIj6hwINEwbokEmp123bLD7a5m+E+KIetRg== - dependencies: - postcss-value-parser "^4.0.0" - read-cache "^1.0.0" - resolve "^1.1.7" - postcss-import@14.0.2: version "14.0.2" resolved "https://registry.yarnpkg.com/postcss-import/-/postcss-import-14.0.2.tgz#60eff77e6be92e7b67fe469ec797d9424cae1aa1" @@ -10030,17 +7537,6 @@ postcss-lab-function@^2.0.1: postcss "^7.0.2" postcss-values-parser "^2.0.0" -postcss-loader@4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/postcss-loader/-/postcss-loader-4.2.0.tgz#f6993ea3e0f46600fb3ee49bbd010448123a7db4" - integrity sha512-mqgScxHqbiz1yxbnNcPdKYo/6aVt+XExURmEbQlviFVWogDbM4AJ0A/B+ZBpYsJrTRxKw7HyRazg9x0Q9SWwLA== - dependencies: - cosmiconfig "^7.0.0" - klona "^2.0.4" - loader-utils "^2.0.0" - schema-utils "^3.0.0" - semver "^7.3.4" - postcss-loader@6.1.1: version "6.1.1" resolved "https://registry.yarnpkg.com/postcss-loader/-/postcss-loader-6.1.1.tgz#58dd0a3accd9bc87cc52eff75244db578d11301a" @@ -10064,33 +7560,13 @@ postcss-media-minmax@^4.0.0: dependencies: postcss "^7.0.2" -postcss-merge-longhand@^5.0.2: - version "5.0.2" - resolved "https://registry.yarnpkg.com/postcss-merge-longhand/-/postcss-merge-longhand-5.0.2.tgz#277ada51d9a7958e8ef8cf263103c9384b322a41" - integrity sha512-BMlg9AXSI5G9TBT0Lo/H3PfUy63P84rVz3BjCFE9e9Y9RXQZD3+h3YO1kgTNsNJy7bBc1YQp8DmSnwLIW5VPcw== - dependencies: - css-color-names "^1.0.1" - postcss-value-parser "^4.1.0" - stylehacks "^5.0.1" - postcss-merge-longhand@^5.0.4: version "5.0.4" resolved "https://registry.yarnpkg.com/postcss-merge-longhand/-/postcss-merge-longhand-5.0.4.tgz#41f4f3270282ea1a145ece078b7679f0cef21c32" - integrity sha512-2lZrOVD+d81aoYkZDpWu6+3dTAAGkCKbV5DoRhnIR7KOULVrI/R7bcMjhrH9KTRy6iiHKqmtG+n/MMj1WmqHFw== - dependencies: - postcss-value-parser "^4.1.0" - stylehacks "^5.0.1" - -postcss-merge-rules@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/postcss-merge-rules/-/postcss-merge-rules-5.0.1.tgz#4ff61c5089d86845184a0f149e88d687028bef7e" - integrity sha512-UR6R5Ph0c96QB9TMBH3ml8/kvPCThPHepdhRqAbvMRDRHQACPC8iM5NpfIC03+VRMZTGXy4L/BvFzcDFCgb+fA== - dependencies: - browserslist "^4.16.0" - caniuse-api "^3.0.0" - cssnano-utils "^2.0.1" - postcss-selector-parser "^6.0.5" - vendors "^1.0.3" + integrity sha512-2lZrOVD+d81aoYkZDpWu6+3dTAAGkCKbV5DoRhnIR7KOULVrI/R7bcMjhrH9KTRy6iiHKqmtG+n/MMj1WmqHFw== + dependencies: + postcss-value-parser "^4.1.0" + stylehacks "^5.0.1" postcss-merge-rules@^5.0.3: version "5.0.3" @@ -10109,15 +7585,6 @@ postcss-minify-font-values@^5.0.1: dependencies: postcss-value-parser "^4.1.0" -postcss-minify-gradients@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/postcss-minify-gradients/-/postcss-minify-gradients-5.0.1.tgz#2dc79fd1a1afcb72a9e727bc549ce860f93565d2" - integrity sha512-odOwBFAIn2wIv+XYRpoN2hUV3pPQlgbJ10XeXPq8UY2N+9ZG42xu45lTn/g9zZ+d70NKSQD6EOi6UiCMu3FN7g== - dependencies: - cssnano-utils "^2.0.1" - is-color-stop "^1.1.0" - postcss-value-parser "^4.1.0" - postcss-minify-gradients@^5.0.3: version "5.0.3" resolved "https://registry.yarnpkg.com/postcss-minify-gradients/-/postcss-minify-gradients-5.0.3.tgz#f970a11cc71e08e9095e78ec3a6b34b91c19550e" @@ -10127,17 +7594,6 @@ postcss-minify-gradients@^5.0.3: cssnano-utils "^2.0.1" postcss-value-parser "^4.1.0" -postcss-minify-params@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/postcss-minify-params/-/postcss-minify-params-5.0.1.tgz#371153ba164b9d8562842fdcd929c98abd9e5b6c" - integrity sha512-4RUC4k2A/Q9mGco1Z8ODc7h+A0z7L7X2ypO1B6V8057eVK6mZ6xwz6QN64nHuHLbqbclkX1wyzRnIrdZehTEHw== - dependencies: - alphanum-sort "^1.0.2" - browserslist "^4.16.0" - cssnano-utils "^2.0.1" - postcss-value-parser "^4.1.0" - uniqs "^2.0.0" - postcss-minify-params@^5.0.2: version "5.0.2" resolved "https://registry.yarnpkg.com/postcss-minify-params/-/postcss-minify-params-5.0.2.tgz#1b644da903473fbbb18fbe07b8e239883684b85c" @@ -10242,15 +7698,6 @@ postcss-normalize-unicode@^5.0.1: browserslist "^4.16.0" postcss-value-parser "^4.1.0" -postcss-normalize-url@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/postcss-normalize-url/-/postcss-normalize-url-5.0.1.tgz#ffa9fe545935d8b57becbbb7934dd5e245513183" - integrity sha512-hkbG0j58Z1M830/CJ73VsP7gvlG1yF+4y7Fd1w4tD2c7CaA2Psll+pQ6eQhth9y9EaqZSLzamff/D0MZBMbYSg== - dependencies: - is-absolute-url "^3.0.3" - normalize-url "^4.5.0" - postcss-value-parser "^4.1.0" - postcss-normalize-url@^5.0.3: version "5.0.3" resolved "https://registry.yarnpkg.com/postcss-normalize-url/-/postcss-normalize-url-5.0.3.tgz#42eca6ede57fe69075fab0f88ac8e48916ef931c" @@ -10267,14 +7714,6 @@ postcss-normalize-whitespace@^5.0.1: dependencies: postcss-value-parser "^4.1.0" -postcss-ordered-values@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/postcss-ordered-values/-/postcss-ordered-values-5.0.1.tgz#79ef6e2bd267ccad3fc0c4f4a586dfd01c131f64" - integrity sha512-6mkCF5BQ25HvEcDfrMHCLLFHlraBSlOXFnQMHYhSpDO/5jSR1k8LdEXOkv+7+uzW6o6tBYea1Km0wQSRkPJkwA== - dependencies: - cssnano-utils "^2.0.1" - postcss-value-parser "^4.1.0" - postcss-ordered-values@^5.0.2: version "5.0.2" resolved "https://registry.yarnpkg.com/postcss-ordered-values/-/postcss-ordered-values-5.0.2.tgz#1f351426977be00e0f765b3164ad753dac8ed044" @@ -10356,14 +7795,6 @@ postcss-pseudo-class-any-link@^6.0.0: postcss "^7.0.2" postcss-selector-parser "^5.0.0-rc.3" -postcss-reduce-initial@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/postcss-reduce-initial/-/postcss-reduce-initial-5.0.1.tgz#9d6369865b0f6f6f6b165a0ef5dc1a4856c7e946" - integrity sha512-zlCZPKLLTMAqA3ZWH57HlbCjkD55LX9dsRyxlls+wfuRfqCi5mSlZVan0heX5cHr154Dq9AfbH70LyhrSAezJw== - dependencies: - browserslist "^4.16.0" - caniuse-api "^3.0.0" - postcss-reduce-initial@^5.0.2: version "5.0.2" resolved "https://registry.yarnpkg.com/postcss-reduce-initial/-/postcss-reduce-initial-5.0.2.tgz#fa424ce8aa88a89bc0b6d0f94871b24abe94c048" @@ -10412,17 +7843,7 @@ postcss-selector-parser@^5.0.0-rc.3, postcss-selector-parser@^5.0.0-rc.4: indexes-of "^1.0.1" uniq "^1.0.1" -postcss-selector-parser@^6.0.2: - version "6.0.4" - resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.4.tgz#56075a1380a04604c38b063ea7767a129af5c2b3" - integrity sha512-gjMeXBempyInaBqpp8gODmwZ52WaYsVOsfr4L4lDQ7n3ncD6mEyySiDtgzCT+NYC0mmeOLvtsF8iaEf0YT6dBw== - dependencies: - cssesc "^3.0.0" - indexes-of "^1.0.1" - uniq "^1.0.1" - util-deprecate "^1.0.2" - -postcss-selector-parser@^6.0.4, postcss-selector-parser@^6.0.5: +postcss-selector-parser@^6.0.2, postcss-selector-parser@^6.0.4, postcss-selector-parser@^6.0.5: version "6.0.6" resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.6.tgz#2c5bba8174ac2f6981ab631a42ab0ee54af332ea" integrity sha512-9LXrvaaX3+mcv5xkg5kFwqSzSH1JIObIx51PrndZwlmznwXRfxMddDvo9gve3gVR8ZTKgoFDdWkbRFmEhT4PMg== @@ -10430,14 +7851,6 @@ postcss-selector-parser@^6.0.4, postcss-selector-parser@^6.0.5: cssesc "^3.0.0" util-deprecate "^1.0.2" -postcss-svgo@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/postcss-svgo/-/postcss-svgo-5.0.1.tgz#6ed5e01e164e59204978994d844c653a331a8100" - integrity sha512-cD7DFo6tF9i5eWvwtI4irKOHCpmASFS0xvZ5EQIgEdA1AWfM/XiHHY/iss0gcKHhkqwgYmuo2M0KhJLd5Us6mg== - dependencies: - postcss-value-parser "^4.1.0" - svgo "^2.3.0" - postcss-svgo@^5.0.3: version "5.0.3" resolved "https://registry.yarnpkg.com/postcss-svgo/-/postcss-svgo-5.0.3.tgz#d945185756e5dfaae07f9edb0d3cae7ff79f9b30" @@ -10446,15 +7859,6 @@ postcss-svgo@^5.0.3: postcss-value-parser "^4.1.0" svgo "^2.7.0" -postcss-unique-selectors@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/postcss-unique-selectors/-/postcss-unique-selectors-5.0.1.tgz#3be5c1d7363352eff838bd62b0b07a0abad43bfc" - integrity sha512-gwi1NhHV4FMmPn+qwBNuot1sG1t2OmacLQ/AX29lzyggnjd+MnVD5uqQmpXO3J17KGL2WAxQruj1qTd3H0gG/w== - dependencies: - alphanum-sort "^1.0.2" - postcss-selector-parser "^6.0.5" - uniqs "^2.0.0" - postcss-unique-selectors@^5.0.2: version "5.0.2" resolved "https://registry.yarnpkg.com/postcss-unique-selectors/-/postcss-unique-selectors-5.0.2.tgz#5d6893daf534ae52626708e0d62250890108c0c1" @@ -10464,9 +7868,9 @@ postcss-unique-selectors@^5.0.2: postcss-selector-parser "^6.0.5" postcss-value-parser@^4.0.0, postcss-value-parser@^4.0.2, postcss-value-parser@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz#443f6a20ced6481a2bda4fa8532a6e55d789a2cb" - integrity sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ== + version "4.2.0" + resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514" + integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ== postcss-values-parser@^2.0.0, postcss-values-parser@^2.0.1: version "2.0.1" @@ -10477,15 +7881,6 @@ postcss-values-parser@^2.0.0, postcss-values-parser@^2.0.1: indexes-of "^1.0.1" uniq "^1.0.1" -postcss@8.2.14: - version "8.2.14" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.2.14.tgz#dcf313eb8247b3ce8078d048c0e8262ca565ad2b" - integrity sha512-+jD0ZijcvyCqPQo/m/CW0UcARpdFylq04of+Q7RKX6f/Tu+dvpUI/9Sp81+i6/vJThnOBX09Quw0ZLOVwpzX3w== - dependencies: - colorette "^1.2.2" - nanoid "^3.1.22" - source-map "^0.6.1" - postcss@8.3.6: version "8.3.6" resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.3.6.tgz#2730dd76a97969f37f53b9a6096197be311cc4ea" @@ -10495,7 +7890,7 @@ postcss@8.3.6: nanoid "^3.1.23" source-map-js "^0.6.2" -postcss@^7.0.14, postcss@^7.0.17, postcss@^7.0.2, postcss@^7.0.32, postcss@^7.0.5, postcss@^7.0.6: +postcss@^7.0.14, postcss@^7.0.17, postcss@^7.0.2, postcss@^7.0.32, postcss@^7.0.35, postcss@^7.0.5, postcss@^7.0.6: version "7.0.39" resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.39.tgz#9624375d965630e2e1f2c02a935c82a59cb48309" integrity sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA== @@ -10503,24 +7898,6 @@ postcss@^7.0.14, postcss@^7.0.17, postcss@^7.0.2, postcss@^7.0.32, postcss@^7.0. picocolors "^0.2.1" source-map "^0.6.1" -postcss@^7.0.35: - version "7.0.35" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.35.tgz#d2be00b998f7f211d8a276974079f2e92b970e24" - integrity sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg== - dependencies: - chalk "^2.4.2" - source-map "^0.6.1" - supports-color "^6.1.0" - -postcss@^8.1.4: - version "8.3.0" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.3.0.tgz#b1a713f6172ca427e3f05ef1303de8b65683325f" - integrity sha512-+ogXpdAjWGa+fdYY5BQ96V/6tAo+TdSSIMP5huJBIygdWwKtVoB5JWZ7yUd4xZ8r+8Kvvx4nyg/PQ071H4UtcQ== - dependencies: - colorette "^1.2.2" - nanoid "^3.1.23" - source-map-js "^0.6.2" - postcss@^8.2.15, postcss@^8.3.5, postcss@^8.3.7: version "8.4.4" resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.4.tgz#d53d4ec6a75fd62557a66bb41978bf47ff0c2869" @@ -10535,33 +7912,26 @@ postinstall-prepare@^2.0.0: resolved "https://registry.yarnpkg.com/postinstall-prepare/-/postinstall-prepare-2.0.0.tgz#2a6867c1a13a05502aa115d0495efbbd778769cb" integrity sha512-lLFwEKdnGLAaRAm8OpXP6HwrXRW+b8Hh9vRhVHZKmCdobd+D21YM38BCDsi3zrePLSe8Tt0H/mbYkh7/ySQQMg== -prettier@^2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.1.2.tgz#3050700dae2e4c8b67c4c3f666cdb8af405e1ce5" - integrity sha512-16c7K+x4qVlJg9rEbXl7HEGmQyZlG4R9AgP+oHKRMsMsuk8s+ATStlf1NpDqyBI1HpVyfjLOeMhH2LvuNvV5Vg== +prettier@^2.5.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.5.0.tgz#a6370e2d4594e093270419d9cc47f7670488f893" + integrity sha512-FM/zAKgWTxj40rH03VxzIPdXmj39SwSjwG0heUcNFwI+EMZJnY93yAiKXM3dObIKAM5TA88werc8T/EwhB45eg== pretty-bytes@^5.3.0: version "5.6.0" resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-5.6.0.tgz#356256f643804773c82f64723fe78c92c62beaeb" integrity sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg== -prismjs@^1.23.0: - version "1.23.0" - resolved "https://registry.yarnpkg.com/prismjs/-/prismjs-1.23.0.tgz#d3b3967f7d72440690497652a9d40ff046067f33" - integrity sha512-c29LVsqOaLbBHuIbsTxaKENh1N2EQBOHaWv7gkHN4dgRbxSREqDnDbtFJYdpPauS4YCplMSNCABQ6Eeor69bAA== - optionalDependencies: - clipboard "^2.0.0" +prismjs@^1.23.0, prismjs@^1.25.0: + version "1.25.0" + resolved "https://registry.yarnpkg.com/prismjs/-/prismjs-1.25.0.tgz#6f822df1bdad965734b310b315a23315cf999756" + integrity sha512-WCjJHl1KEWbnkQom1+SzftbtXMKQoezOCYs5rECqMN+jP+apI7ftoflyqigqzopSO3hMhTEb0mFClA8lkolgEg== process-nextick-args@~2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== -process@^0.11.10: - version "0.11.10" - resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" - integrity sha1-czIwDoQBYb2j5podHZGn1LwW8YI= - promise-inflight@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3" @@ -10575,7 +7945,7 @@ promise-retry@^2.0.1: err-code "^2.0.2" retry "^0.12.0" -prop-types@^15.5.10, prop-types@^15.6.2, prop-types@^15.7.2: +prop-types@^15.6.2, prop-types@^15.7.2: version "15.7.2" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5" integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ== @@ -10611,11 +7981,11 @@ protractor@~7.0.0: yargs "^15.3.1" proxy-addr@~2.0.5: - version "2.0.6" - resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.6.tgz#fdc2336505447d3f2f2c638ed272caf614bbb2bf" - integrity sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw== + version "2.0.7" + resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" + integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg== dependencies: - forwarded "~0.1.2" + forwarded "0.2.0" ipaddr.js "1.9.1" prr@~1.0.1: @@ -10633,26 +8003,6 @@ psl@^1.1.28: resolved "https://registry.yarnpkg.com/psl/-/psl-1.8.0.tgz#9326f8bcfb013adcc005fdff056acce020e51c24" integrity sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ== -public-encrypt@^4.0.0: - version "4.0.3" - resolved "https://registry.yarnpkg.com/public-encrypt/-/public-encrypt-4.0.3.tgz#4fcc9d77a07e48ba7527e7cbe0de33d0701331e0" - integrity sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q== - dependencies: - bn.js "^4.1.0" - browserify-rsa "^4.0.0" - create-hash "^1.1.0" - parse-asn1 "^5.0.0" - randombytes "^2.0.1" - safe-buffer "^5.1.2" - -pump@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/pump/-/pump-2.0.1.tgz#12399add6e4cf7526d973cbc8b5ce2e2908b3909" - integrity sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA== - dependencies: - end-of-stream "^1.1.0" - once "^1.3.1" - pump@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" @@ -10661,25 +8011,11 @@ pump@^3.0.0: end-of-stream "^1.1.0" once "^1.3.1" -pumpify@^1.3.3: - version "1.5.1" - resolved "https://registry.yarnpkg.com/pumpify/-/pumpify-1.5.1.tgz#36513be246ab27570b1a374a5ce278bfd74370ce" - integrity sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ== - dependencies: - duplexify "^3.6.0" - inherits "^2.0.3" - pump "^2.0.0" - punycode@1.3.2: version "1.3.2" resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" integrity sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0= -punycode@^1.2.4: - version "1.4.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" - integrity sha1-wNWmOycYgArY4esPpSachN1BhF4= - punycode@^2.1.0, punycode@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" @@ -10700,18 +8036,15 @@ qjobs@^1.2.0: resolved "https://registry.yarnpkg.com/qjobs/-/qjobs-1.2.0.tgz#c45e9c61800bd087ef88d7e256423bdd49e5d071" integrity sha512-8YOJEHtxpySA3fFDyCRxA+UUV+fA+rTWnuWvylOK/NCjhY+b4ocCtmu8TtsWb+mYeU+GCHf/S66KZF/AsteKHg== -qrcode@^1.4.4: - version "1.4.4" - resolved "https://registry.yarnpkg.com/qrcode/-/qrcode-1.4.4.tgz#f0c43568a7e7510a55efc3b88d9602f71963ea83" - integrity sha512-oLzEC5+NKFou9P0bMj5+v6Z40evexeE29Z9cummZXZ9QXyMr3lphkURzxjXgPJC5azpxcshoDWV1xE46z+/c3Q== +qrcode@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/qrcode/-/qrcode-1.5.0.tgz#95abb8a91fdafd86f8190f2836abbfc500c72d1b" + integrity sha512-9MgRpgVc+/+47dFvQeD6U2s0Z92EsKzcHogtum4QB+UNd025WOJSHvn/hjk9xmzj7Stj95CyUAs31mrjxliEsQ== dependencies: - buffer "^5.4.3" - buffer-alloc "^1.2.0" - buffer-from "^1.1.1" dijkstrajs "^1.0.1" - isarray "^2.0.1" - pngjs "^3.3.0" - yargs "^13.2.4" + encode-utf8 "^1.0.3" + pngjs "^5.0.0" + yargs "^15.3.1" qs@6.7.0: version "6.7.0" @@ -10723,11 +8056,6 @@ qs@~6.5.2: resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA== -querystring-es3@^0.2.0: - version "0.2.1" - resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73" - integrity sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM= - querystring@0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" @@ -10738,33 +8066,23 @@ querystringify@^2.1.1: resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.2.0.tgz#3345941b4153cb9d082d8eee4cda2016a9aef7f6" integrity sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ== +queue-microtask@^1.2.2: + version "1.2.3" + resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" + integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== + quickselect@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/quickselect/-/quickselect-2.0.0.tgz#f19680a486a5eefb581303e023e98faaf25dd018" integrity sha512-RKJ22hX8mHe3Y6wH/N3wCM6BWtjaxIyyUIkpHOvfFnxdI4yD4tBXEBKSbriGujF6jnSVkJrffuo6vxACiSSxIw== -raf@^3.4.0, raf@^3.4.1: - version "3.4.1" - resolved "https://registry.yarnpkg.com/raf/-/raf-3.4.1.tgz#0742e99a4a6552f445d73e3ee0328af0ff1ede39" - integrity sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA== - dependencies: - performance-now "^2.1.0" - -randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5, randombytes@^2.1.0: +randombytes@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== dependencies: safe-buffer "^5.1.0" -randomfill@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/randomfill/-/randomfill-1.0.4.tgz#c92196fc86ab42be983f1bf31778224931d61458" - integrity sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw== - dependencies: - randombytes "^2.0.5" - safe-buffer "^5.1.0" - range-parser@^1.2.1, range-parser@~1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" @@ -10787,7 +8105,7 @@ raw-body@2.4.0: iconv-lite "0.4.24" unpipe "1.0.0" -raw-loader@4.0.2: +raw-loader@^4.0.2: version "4.0.2" resolved "https://registry.yarnpkg.com/raw-loader/-/raw-loader-4.0.2.tgz#1aac6b7d1ad1501e66efdac1522c73e59a584eb6" integrity sha512-ZnScIV3ag9A4wPX/ZayxL/jZH+euYb6FcUinPcgiQW0+UBtEv0O6Q3lGd3cqJ+GHH+rksEv3Pj99oxJ3u3VIKA== @@ -10803,126 +8121,115 @@ rbush@^3.0.1: quickselect "^2.0.0" rc-align@^4.0.0: - version "4.0.8" - resolved "https://registry.yarnpkg.com/rc-align/-/rc-align-4.0.8.tgz#276c3f5dfadf0de4bb95392cb81568c9e947a668" - integrity sha512-2sRUkmB8z4UEXzaS+lDHzXMoR8HrtKH9nn2yHlHVNyUTnaucjMFbdEoCk+hO1g7cpIgW0MphG8i0EH2scSesfw== + version "4.0.11" + resolved "https://registry.yarnpkg.com/rc-align/-/rc-align-4.0.11.tgz#8198c62db266bc1b8ef05e56c13275bf72628a5e" + integrity sha512-n9mQfIYQbbNTbefyQnRHZPWuTEwG1rY4a9yKlIWHSTbgwI+XUMGRYd0uJ5pE2UbrNX0WvnMBA1zJ3Lrecpra/A== dependencies: "@babel/runtime" "^7.10.1" classnames "2.x" dom-align "^1.7.0" + lodash "^4.17.21" rc-util "^5.3.0" resize-observer-polyfill "^1.5.1" -rc-animate@^3.0.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/rc-animate/-/rc-animate-3.1.1.tgz#defdd863f56816c222534e4dc68feddecd081386" - integrity sha512-8wg2Zg3EETy0k/9kYuis30NJNQg1D6/WSQwnCiz6SvyxQXNet/rVraRz3bPngwY6rcU2nlRvoShiYOorXyF7Sg== +rc-motion@^2.0.0, rc-motion@^2.0.1: + version "2.4.4" + resolved "https://registry.yarnpkg.com/rc-motion/-/rc-motion-2.4.4.tgz#e995d5fa24fc93065c24f714857cf2677d655bb0" + integrity sha512-ms7n1+/TZQBS0Ydd2Q5P4+wJTSOrhIrwNxLXCZpR7Fa3/oac7Yi803HDALc2hLAKaCTQtw9LmQeB58zcwOsqlQ== dependencies: - "@ant-design/css-animation" "^1.7.2" - classnames "^2.2.6" - raf "^3.4.0" - rc-util "^4.15.3" + "@babel/runtime" "^7.11.1" + classnames "^2.2.1" + rc-util "^5.2.1" -rc-motion@^1.0.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/rc-motion/-/rc-motion-1.1.2.tgz#07212f1b96c715b8245ec121339146c4a9b0968c" - integrity sha512-YC/E7SSWKBFakYg4PENhSRWD4ZLDqkI7FKmutJcrMewZ91/ZIWfoZSDvPaBdKO0hsFrrzWepFhXQIq0FNnCMWA== +rc-overflow@^1.0.0: + version "1.2.2" + resolved "https://registry.yarnpkg.com/rc-overflow/-/rc-overflow-1.2.2.tgz#95b0222016c0cdbdc0db85f569c262e7706a5f22" + integrity sha512-X5kj9LDU1ue5wHkqvCprJWLKC+ZLs3p4He/oxjZ1Q4NKaqKBaYf5OdSzRSgh3WH8kSdrfU8LjvlbWnHgJOEkNQ== dependencies: "@babel/runtime" "^7.11.1" classnames "^2.2.1" - raf "^3.4.1" - rc-util "^5.0.6" + rc-resize-observer "^1.0.0" + rc-util "^5.5.1" -rc-select@~10.5.1: - version "10.5.1" - resolved "https://registry.yarnpkg.com/rc-select/-/rc-select-10.5.1.tgz#4d4c5d4f8d2fd3b7e3dccf74e4c43142b2979247" - integrity sha512-fZraoNNhjUmDJccfk6VYgrgHBWFmHWh/NJZh2Xttcm/usOolYI1RjO9ikP4QGhzlJBFtnTLH2pE2nchjn3TCXA== +rc-resize-observer@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/rc-resize-observer/-/rc-resize-observer-1.1.1.tgz#ef666e38065f550730176404bae2ce8ca5fb1ac4" + integrity sha512-5A3B9ha297ItltzXl812WFE36SyRDTNclfrXE3FL1pEwXkBh7iSEzxjzfwsPeMcF9ahy3ZoxLgLuRksXBGGD6A== + dependencies: + "@babel/runtime" "^7.10.1" + classnames "^2.2.1" + rc-util "^5.15.0" + resize-observer-polyfill "^1.5.1" + +rc-select@~13.2.0: + version "13.2.1" + resolved "https://registry.yarnpkg.com/rc-select/-/rc-select-13.2.1.tgz#d69675f8bc72622a8f3bc024fa21bfee8d56257d" + integrity sha512-L2cJFAjVEeDiNVa/dlOVKE79OUb0J7sUBvWN3Viav3XHcjvv9Ovn4D8J9QhBSlDXeGuczZ81CZI3BbdHD25+Gg== dependencies: "@babel/runtime" "^7.10.1" classnames "2.x" - rc-animate "^3.0.0" - rc-trigger "^4.3.0" - rc-util "^5.0.1" - rc-virtual-list "^1.1.2" - warning "^4.0.3" + rc-motion "^2.0.1" + rc-overflow "^1.0.0" + rc-trigger "^5.0.4" + rc-util "^5.9.8" + rc-virtual-list "^3.2.0" -rc-trigger@^4.3.0: - version "4.4.3" - resolved "https://registry.yarnpkg.com/rc-trigger/-/rc-trigger-4.4.3.tgz#ed449cd6cce446555bc57f4394229c5c7154f4b0" - integrity sha512-yq/WyuiPwxd2q6jy+VPyy0GUCRFJ2eFqAaCwPE27AOftXeIupOcJ/2t1wakSq63cfk7qtzev5DKHUAjb8LOJCw== +rc-trigger@^5.0.4: + version "5.2.10" + resolved "https://registry.yarnpkg.com/rc-trigger/-/rc-trigger-5.2.10.tgz#8a0057a940b1b9027eaa33beec8a6ecd85cce2b1" + integrity sha512-FkUf4H9BOFDaIwu42fvRycXMAvkttph9AlbCZXssZDVzz2L+QZ0ERvfB/4nX3ZFPh1Zd+uVGr1DEDeXxq4J1TA== dependencies: "@babel/runtime" "^7.11.2" classnames "^2.2.6" - raf "^3.4.1" rc-align "^4.0.0" - rc-motion "^1.0.0" - rc-util "^5.0.1" - -rc-util@^4.15.3: - version "4.21.1" - resolved "https://registry.yarnpkg.com/rc-util/-/rc-util-4.21.1.tgz#88602d0c3185020aa1053d9a1e70eac161becb05" - integrity sha512-Z+vlkSQVc1l8O2UjR3WQ+XdWlhj5q9BMQNLk2iOBch75CqPfrJyGtcWMcnhRlNuDu0Ndtt4kLVO8JI8BrABobg== - dependencies: - add-dom-event-listener "^1.1.0" - prop-types "^15.5.10" - react-is "^16.12.0" - react-lifecycles-compat "^3.0.4" - shallowequal "^1.1.0" - -rc-util@^5.0.0, rc-util@^5.0.1, rc-util@^5.3.0: - version "5.4.0" - resolved "https://registry.yarnpkg.com/rc-util/-/rc-util-5.4.0.tgz#688eaeecfdae9dae2bfdf10bedbe884591dba004" - integrity sha512-kXDn1JyLJTAWLBFt+fjkTcUtXhxKkipQCobQmxIEVrX62iXgo24z8YKoWehWfMxPZFPE+RXqrmEu9j5kHz/Lrg== - dependencies: - react-is "^16.12.0" - shallowequal "^1.1.0" + rc-motion "^2.0.0" + rc-util "^5.5.0" -rc-util@^5.0.6: - version "5.7.0" - resolved "https://registry.yarnpkg.com/rc-util/-/rc-util-5.7.0.tgz#776b14cf5bbfc24f419fd40c42ffadddda0718fc" - integrity sha512-0hh5XkJ+vBDeMJsHElqT1ijMx+gC3gpClwQ10h/5hccrrgrMx8VUem183KLlH1YrWCfMMPmDXWWNnwsn+p6URw== +rc-util@^5.0.7, rc-util@^5.15.0, rc-util@^5.2.1, rc-util@^5.3.0, rc-util@^5.5.0, rc-util@^5.5.1, rc-util@^5.9.8: + version "5.16.1" + resolved "https://registry.yarnpkg.com/rc-util/-/rc-util-5.16.1.tgz#374db7cb735512f05165ddc3d6b2c61c21b8b4e3" + integrity sha512-kSCyytvdb3aRxQacS/71ta6c+kBWvM1v8/2h9d/HaNWauc3qB8pLnF20PJ8NajkNN8gb+rR1l0eWO+D4Pz+LLQ== dependencies: "@babel/runtime" "^7.12.5" react-is "^16.12.0" shallowequal "^1.1.0" -rc-virtual-list@^1.1.2: - version "1.1.6" - resolved "https://registry.yarnpkg.com/rc-virtual-list/-/rc-virtual-list-1.1.6.tgz#b255baf9aacde149a8893324e6307214094f4c0a" - integrity sha512-u3+izqWL8p8bQy8nYH48qWpiGyxR/ye8D2k0zJlXmfYeL55/xh83YrzHqiDzO78uj0Ewag3nXDA0JTVrYO7ygQ== +rc-virtual-list@^3.2.0: + version "3.4.2" + resolved "https://registry.yarnpkg.com/rc-virtual-list/-/rc-virtual-list-3.4.2.tgz#1078327aa7230b5e456d679ed2ce99f3c036ebd1" + integrity sha512-OyVrrPvvFcHvV0ssz5EDZ+7Rf5qLat/+mmujjchNw5FfbJWNDwkpQ99EcVE6+FtNRmX9wFa1LGNpZLUTvp/4GQ== dependencies: classnames "^2.2.6" - raf "^3.4.1" - rc-util "^5.0.0" + rc-resize-observer "^1.0.0" + rc-util "^5.0.7" -react-ace@^9.1.4: - version "9.1.4" - resolved "https://registry.yarnpkg.com/react-ace/-/react-ace-9.1.4.tgz#7c45c361aa5fe1efa3313fa876bce30aa64a244f" - integrity sha512-4DBWvElbVR3WhsA2HhQ524K9Yoa/J/sjuBV9NUZ+yar3Q4BGJRTnhY6pM0INffH1IkBZHKIOyz34XHjc7RNTpw== +react-ace@^9.5.0: + version "9.5.0" + resolved "https://registry.yarnpkg.com/react-ace/-/react-ace-9.5.0.tgz#b6c32b70d404dd821a7e01accc2d76da667ff1f7" + integrity sha512-4l5FgwGh6K7A0yWVMQlPIXDItM4Q9zzXRqOae8KkCl6MkOob7sC1CzHxZdOGvV+QioKWbX2p5HcdOVUv6cAdSg== dependencies: - ace-builds "^1.4.6" - diff-match-patch "^1.0.4" + ace-builds "^1.4.13" + diff-match-patch "^1.0.5" lodash.get "^4.4.2" lodash.isequal "^4.5.0" prop-types "^15.7.2" -react-dom@^16.13.1: - version "16.13.1" - resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.13.1.tgz#c1bd37331a0486c078ee54c4740720993b2e0e7f" - integrity sha512-81PIMmVLnCNLO/fFOQxdQkvEq/+Hfpv24XNJfpyZhTRfO0QcmQIF/PgCa1zCOj2w1hrn12MFLyaJ/G0+Mxtfag== +react-dom@^17.0.2: + version "17.0.2" + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-17.0.2.tgz#ecffb6845e3ad8dbfcdc498f0d0a939736502c23" + integrity sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA== dependencies: loose-envify "^1.1.0" object-assign "^4.1.1" - prop-types "^15.6.2" - scheduler "^0.19.1" + scheduler "^0.20.2" -react-dropzone@^11.2.0: - version "11.2.0" - resolved "https://registry.yarnpkg.com/react-dropzone/-/react-dropzone-11.2.0.tgz#4e54fa3479e6b6bb93f67914e4a27f1260807fdb" - integrity sha512-S/qaXQHCCg7MVlcrhqd05MLC6DupITLUB0CFn3iCLs6OTjzxdGDF1WTktTe5Jyq8jZdxYfMHNUZOHL0mg+K0Dw== +react-dropzone@^11.4.2: + version "11.4.2" + resolved "https://registry.yarnpkg.com/react-dropzone/-/react-dropzone-11.4.2.tgz#1eb99e9def4cc7520f4f58e85c853ce52c483d56" + integrity sha512-ocYzYn7Qgp0tFc1gQtUTOaHHSzVTwhWHxxY+r7cj2jJTPfMTZB5GWSJHdIVoxsl+EQENpjJ/6Zvcw0BqKZQ+Eg== dependencies: - attr-accept "^2.0.0" - file-selector "^0.1.12" + attr-accept "^2.2.1" + file-selector "^0.2.2" prop-types "^15.7.2" react-is@^16.12.0, react-is@^16.7.0, react-is@^16.8.1: @@ -10935,29 +8242,23 @@ react-is@^16.12.0, react-is@^16.7.0, react-is@^16.8.1: resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0" integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w== -react-lifecycles-compat@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362" - integrity sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA== - react-transition-group@^4.0.0, react-transition-group@^4.4.0: - version "4.4.1" - resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-4.4.1.tgz#63868f9325a38ea5ee9535d828327f85773345c9" - integrity sha512-Djqr7OQ2aPUiYurhPalTrVy9ddmFCCzwhqQmtN+J3+3DzLO209Fdr70QrN8Z3DsglWql6iY1lDWAfpFiBtuKGw== + version "4.4.2" + resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-4.4.2.tgz#8b59a56f09ced7b55cbd53c36768b922890d5470" + integrity sha512-/RNYfRAMlZwDSr6z4zNKV6xu53/e2BuaBbGhbyYIXTrmgu/bGHzmqOs7mJSJBHy9Ud+ApHx3QjrkKSp1pxvlFg== dependencies: "@babel/runtime" "^7.5.5" dom-helpers "^5.0.1" loose-envify "^1.4.0" prop-types "^15.6.2" -react@~16.14.0: - version "16.14.0" - resolved "https://registry.yarnpkg.com/react/-/react-16.14.0.tgz#94d776ddd0aaa37da3eda8fc5b6b18a4c9a3114d" - integrity sha512-0X2CImDkJGApiAlcf0ODKIneSwBPhqJawOa5wCtKbu7ZECrmS26NvtSILynQ66cgkT/RJ4LidJOc3bUESwmU8g== +react@~17.0.2: + version "17.0.2" + resolved "https://registry.yarnpkg.com/react/-/react-17.0.2.tgz#d0b5cc516d29eb3eee383f75b62864cfb6800037" + integrity sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA== dependencies: loose-envify "^1.1.0" object-assign "^4.1.1" - prop-types "^15.6.2" reactcss@^1.2.3: version "1.2.3" @@ -10974,14 +8275,14 @@ read-cache@^1.0.0: pify "^2.3.0" read-package-json-fast@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/read-package-json-fast/-/read-package-json-fast-2.0.2.tgz#2dcb24d9e8dd50fb322042c8c35a954e6cc7ac9e" - integrity sha512-5fyFUyO9B799foVk4n6ylcoAktG/FbE3jwRKxvwaeSrIunaoMc0u81dzXxjeAFKOce7O5KncdfwpGvvs6r5PsQ== + version "2.0.3" + resolved "https://registry.yarnpkg.com/read-package-json-fast/-/read-package-json-fast-2.0.3.tgz#323ca529630da82cb34b36cc0b996693c98c2b83" + integrity sha512-W/BKtbL+dUjTuRL2vziuYhp76s5HZ9qQhd/dKfWIZveD0O40453QNyZhC0e63lqZrAQ4jiOapVoeJ7JrszenQQ== dependencies: json-parse-even-better-errors "^2.3.0" npm-normalize-package-bin "^1.0.1" -"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.3, readable-stream@^2.3.6, readable-stream@~2.3.6: +readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@~2.3.6: version "2.3.7" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== @@ -10994,7 +8295,7 @@ read-package-json-fast@^2.0.1: string_decoder "~1.1.1" util-deprecate "~1.0.1" -readable-stream@^3.0.6, readable-stream@^3.4.0, readable-stream@^3.6.0: +readable-stream@^3.0.6, readable-stream@^3.4.0: version "3.6.0" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== @@ -11012,20 +8313,6 @@ readdirp@^2.2.1: micromatch "^3.1.10" readable-stream "^2.0.2" -readdirp@~3.4.0: - version "3.4.0" - resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.4.0.tgz#9fdccdf9e9155805449221ac645e8303ab5b9ada" - integrity sha512-0xe001vZBnJEK+uKcj8qOhyAKPzIT+gStxWr3LCB0DwcXR5NZJ3IaC+yGnHCYzB/S7ov3m3EEbZI2zeNvX+hGQ== - dependencies: - picomatch "^2.2.1" - -readdirp@~3.5.0: - version "3.5.0" - resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.5.0.tgz#9ba74c019b15d365278d2e91bb8c48d7b4d42c9e" - integrity sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ== - dependencies: - picomatch "^2.2.1" - readdirp@~3.6.0: version "3.6.0" resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" @@ -11038,24 +8325,19 @@ reflect-metadata@^0.1.2: resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.1.13.tgz#67ae3ca57c972a2aa1642b10fe363fe32d49dc08" integrity sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg== -regenerate-unicode-properties@^8.2.0: - version "8.2.0" - resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-8.2.0.tgz#e5de7111d655e7ba60c057dbe9ff37c87e65cdec" - integrity sha512-F9DjY1vKLo/tPePDycuH3dn9H1OTPIkVD9Kz4LODu+F2C75mgjAJ7x/gwy6ZcSNRAAkhNlJSOHRe8k3p+K9WhA== +regenerate-unicode-properties@^9.0.0: + version "9.0.0" + resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-9.0.0.tgz#54d09c7115e1f53dc2314a974b32c1c344efe326" + integrity sha512-3E12UeNSPfjrgwjkR81m5J7Aw/T55Tu7nUyZVQYCKEOs+2dkxEY+DpPtZzO4YruuiPb7NkYLVcyJC4+zCbk5pA== dependencies: - regenerate "^1.4.0" - -regenerate@^1.4.0: - version "1.4.1" - resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.1.tgz#cad92ad8e6b591773485fbe05a485caf4f457e6f" - integrity sha512-j2+C8+NtXQgEKWk49MMP5P/u2GhnahTtVkRIHr5R5lVRlbKvmQ+oS+A5aLKWp2ma5VkT8sh6v+v4hbH0YHR66A== + regenerate "^1.4.2" -regenerator-runtime@0.13.7, regenerator-runtime@^0.13.4: - version "0.13.7" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz#cac2dacc8a1ea675feaabaeb8ae833898ae46f55" - integrity sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew== +regenerate@^1.4.2: + version "1.4.2" + resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.2.tgz#b9346d8827e8f5a32f7ba29637d398b69014848a" + integrity sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A== -regenerator-runtime@0.13.9: +regenerator-runtime@0.13.9, regenerator-runtime@^0.13.4: version "0.13.9" resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz#8925742a98ffd90814988d7566ad30ca3b263b52" integrity sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA== @@ -11081,34 +8363,34 @@ regex-parser@^2.2.11: integrity sha512-jbD/FT0+9MBU2XAZluI7w2OBs1RBi6p9M83nkoZayQXXU9e8Robt69FcZc7wU4eJD/YFTjn1JdCk3rbMJajz8Q== regexp.prototype.flags@^1.2.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.3.0.tgz#7aba89b3c13a64509dabcf3ca8d9fbb9bdf5cb75" - integrity sha512-2+Q0C5g951OlYlJz6yu5/M33IcsESLlLfsyIaLJaG4FA2r4yP8MvVMJUUP/fVBkSpbbbZlS5gynbEWLipiiXiQ== + version "1.3.1" + resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.3.1.tgz#7ef352ae8d159e758c0eadca6f8fcb4eef07be26" + integrity sha512-JiBdRBq91WlY7uRJ0ds7R+dU02i6LKi8r3BuQhNXn+kmeLN+EfHhfjqMRis1zJxnlu88hq/4dx0P2OP3APRTOA== dependencies: + call-bind "^1.0.2" define-properties "^1.1.3" - es-abstract "^1.17.0-next.1" -regexpu-core@^4.7.0, regexpu-core@^4.7.1: - version "4.7.1" - resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-4.7.1.tgz#2dea5a9a07233298fbf0db91fa9abc4c6e0f8ad6" - integrity sha512-ywH2VUraA44DZQuRKzARmw6S66mr48pQVva4LBeRhcOltJ6hExvWly5ZjFLYo67xbIxb6W1q4bAGtgfEl20zfQ== +regexpu-core@^4.7.1: + version "4.8.0" + resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-4.8.0.tgz#e5605ba361b67b1718478501327502f4479a98f0" + integrity sha512-1F6bYsoYiz6is+oz70NWur2Vlh9KWtswuRuzJOfeYUrfPX2o8n74AnUVaOGDbUqVGO9fNHu48/pjJO4sNVwsOg== dependencies: - regenerate "^1.4.0" - regenerate-unicode-properties "^8.2.0" - regjsgen "^0.5.1" - regjsparser "^0.6.4" - unicode-match-property-ecmascript "^1.0.4" - unicode-match-property-value-ecmascript "^1.2.0" + regenerate "^1.4.2" + regenerate-unicode-properties "^9.0.0" + regjsgen "^0.5.2" + regjsparser "^0.7.0" + unicode-match-property-ecmascript "^2.0.0" + unicode-match-property-value-ecmascript "^2.0.0" -regjsgen@^0.5.1: +regjsgen@^0.5.2: version "0.5.2" resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.5.2.tgz#92ff295fb1deecbf6ecdab2543d207e91aa33733" integrity sha512-OFFT3MfrH90xIW8OOSyUrk6QHD5E9JOTeGodiJeBS3J6IwlgzJMNE/1bZklWz5oTg+9dCMyEetclvCVXOPoN3A== -regjsparser@^0.6.4: - version "0.6.4" - resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.6.4.tgz#a769f8684308401a66e9b529d2436ff4d0666272" - integrity sha512-64O87/dPDgfk8/RQqC4gkZoGyyWFIEUTTh80CU6CWuK5vkCGyekIx+oKcEIYtP/RAxSQltCZHCNu/mdd7fqlJw== +regjsparser@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.7.0.tgz#a6b667b54c885e18b52554cb4960ef71187e9968" + integrity sha512-A4pcaORqmNMDVwUjWoTzuhwMGpP+NykpfqAsEgI1FSH/EzC7lrN5TMd+kN8YCovX+jMpu8eaqXgXPCa0g8FQNQ== dependencies: jsesc "~0.5.0" @@ -11118,9 +8400,9 @@ remove-trailing-separator@^1.0.1: integrity sha1-wkvOKig62tW8P1jg1IJJuSN52O8= repeat-element@^1.1.2: - version "1.1.3" - resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.3.tgz#782e0d825c0c5a3bb39731f84efee6b742e6b1ce" - integrity sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g== + version "1.1.4" + resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.4.tgz#be681520847ab58c7568ac75fbfad28ed42d39e9" + integrity sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ== repeat-string@^1.6.1: version "1.6.1" @@ -11211,7 +8493,7 @@ resolve-url@^0.2.1: resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= -resolve@1.20.0, resolve@^1.14.2: +resolve@1.20.0, resolve@^1.1.7, resolve@^1.14.2, resolve@^1.3.2: version "1.20.0" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.20.0.tgz#629a013fb3f70755d6f0b7935cc1c2c5378b1975" integrity sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A== @@ -11219,13 +8501,6 @@ resolve@1.20.0, resolve@^1.14.2: is-core-module "^2.2.0" path-parse "^1.0.6" -resolve@^1.1.7, resolve@^1.3.2: - version "1.17.0" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.17.0.tgz#b25941b54968231cc2d1bb76a79cb7f2c0bf8444" - integrity sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w== - dependencies: - path-parse "^1.0.6" - restore-cursor@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e" @@ -11250,19 +8525,9 @@ reusify@^1.0.4: integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== rfdc@^1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.1.4.tgz#ba72cc1367a0ccd9cf81a870b3b58bd3ad07f8c2" - integrity sha512-5C9HXdzK8EAqN7JDif30jqsBzavB7wLpaubisuQIGHWf2gUXSpzy6ArX/+Da8RjFpagWsCn+pIgxTMAmKw9Zug== - -rgb-regex@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/rgb-regex/-/rgb-regex-1.0.1.tgz#c0e0d6882df0e23be254a475e8edd41915feaeb1" - integrity sha1-wODWiC3w4jviVKR16O3UGRX+rrE= - -rgba-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/rgba-regex/-/rgba-regex-1.0.0.tgz#43374e2e2ca0968b0ef1523460b7d730ff22eeb3" - integrity sha1-QzdOLiyglosO8VI0YLfXMP8i7rM= + version "1.3.0" + resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.3.0.tgz#d0b7c441ab2720d05dc4cf26e01c89631d9da08b" + integrity sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA== rifm@^0.7.0: version "0.7.0" @@ -11271,13 +8536,6 @@ rifm@^0.7.0: dependencies: "@babel/runtime" "^7.3.1" -rimraf@3.0.2, rimraf@^3.0.0, rimraf@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" - integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== - dependencies: - glob "^7.1.3" - rimraf@^2.2.8, rimraf@^2.5.2, rimraf@^2.5.4, rimraf@^2.6.3: version "2.7.1" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" @@ -11285,20 +8543,12 @@ rimraf@^2.2.8, rimraf@^2.5.2, rimraf@^2.5.4, rimraf@^2.6.3: dependencies: glob "^7.1.3" -ripemd160@^2.0.0, ripemd160@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c" - integrity sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA== +rimraf@^3.0.0, rimraf@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" + integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== dependencies: - hash-base "^3.0.0" - inherits "^2.0.1" - -rollup@2.38.4: - version "2.38.4" - resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.38.4.tgz#1b84ea8728c73b1a00a6a6e9c630ec8c3fe48cea" - integrity sha512-B0LcJhjiwKkTl79aGVF/u5KdzsH8IylVfV56Ut6c9ouWLJcUK17T83aZBetNYSnZtXf2OHD4+2PbmRW+Fp5ulg== - optionalDependencies: - fsevents "~2.3.1" + glob "^7.1.3" run-async@^2.4.0: version "2.4.1" @@ -11306,25 +8556,13 @@ run-async@^2.4.0: integrity sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ== run-parallel@^1.1.9: - version "1.1.9" - resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.1.9.tgz#c9dd3a7cf9f4b2c4b6244e173a6ed866e61dd679" - integrity sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q== - -run-queue@^1.0.0, run-queue@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/run-queue/-/run-queue-1.0.3.tgz#e848396f057d223f24386924618e25694161ec47" - integrity sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec= - dependencies: - aproba "^1.1.1" - -rxjs@6.6.3, rxjs@^6.5.3, rxjs@^6.6.0: - version "6.6.3" - resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.3.tgz#8ca84635c4daa900c0d3967a6ee7ac60271ee552" - integrity sha512-trsQc+xYYXZ3urjOiJOuCOa5N3jAZ3eiSpQB5hIT8zGlL2QfnHLJ2r7GMkBGuIausdJN1OneaI6gQlsqNHHmZQ== + version "1.2.0" + resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" + integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== dependencies: - tslib "^1.9.0" + queue-microtask "^1.2.2" -rxjs@6.6.7, rxjs@~6.6.7: +rxjs@6.6.7, rxjs@^6.5.3, rxjs@~6.6.7: version "6.6.7" resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.7.tgz#90ac018acabf491bf65044235d5863c4dab804c9" integrity sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ== @@ -11343,7 +8581,7 @@ safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== -safe-buffer@>=5.1.0, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@~5.2.0: +safe-buffer@>=5.1.0, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.2, safe-buffer@~5.2.0: version "5.2.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== @@ -11360,17 +8598,6 @@ safe-regex@^1.1.0: resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== -sass-loader@10.1.1: - version "10.1.1" - resolved "https://registry.yarnpkg.com/sass-loader/-/sass-loader-10.1.1.tgz#4ddd5a3d7638e7949065dd6e9c7c04037f7e663d" - integrity sha512-W6gVDXAd5hR/WHsPicvZdjAWHBcEJ44UahgxcIE196fW2ong0ZHMPO1kZuI5q0VlvMQZh32gpv69PLWQm70qrw== - dependencies: - klona "^2.0.4" - loader-utils "^2.0.0" - neo-async "^2.6.2" - schema-utils "^3.0.0" - semver "^7.3.2" - sass-loader@12.1.0: version "12.1.0" resolved "https://registry.yarnpkg.com/sass-loader/-/sass-loader-12.1.0.tgz#b73324622231009da6fba61ab76013256380d201" @@ -11379,13 +8606,6 @@ sass-loader@12.1.0: klona "^2.0.4" neo-async "^2.6.2" -sass@1.32.6: - version "1.32.6" - resolved "https://registry.yarnpkg.com/sass/-/sass-1.32.6.tgz#e3646c8325cd97ff75a8a15226007f3ccd221393" - integrity sha512-1bcDHDcSqeFtMr0JXI3xc/CXX6c4p0wHHivJdru8W7waM7a1WjKMm4m/Z5sY7CbVw4Whi2Chpcw6DFfSWwGLzQ== - dependencies: - chokidar ">=2.0.0 <4.0.0" - sass@1.36.0: version "1.36.0" resolved "https://registry.yarnpkg.com/sass/-/sass-1.36.0.tgz#5912ef9d5d16714171ba11cb17edb274c4bbc07e" @@ -11405,10 +8625,10 @@ sax@>=0.6.0, sax@^1.2.4, sax@~1.2.4: resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== -scheduler@^0.19.1: - version "0.19.1" - resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.19.1.tgz#4f3e2ed2c1a7d65681f4c854fa8c5a1ccb40f196" - integrity sha512-n/zwRWRYSUj0/3g/otKDRPMh6qv2SYMWNq85IEa8iZyAv8od9zDYpGSnpBEjNgcMNq6Scbu5KfIPxNF72R/2EA== +scheduler@^0.20.2: + version "0.20.2" + resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.20.2.tgz#4baee39436e34aa93b4874bddcbf0fe8b8b50e91" + integrity sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ== dependencies: loose-envify "^1.1.0" object-assign "^4.1.1" @@ -11438,16 +8658,7 @@ schema-utils@^2.6.5, schema-utils@^2.7.0: ajv "^6.12.4" ajv-keywords "^3.5.2" -schema-utils@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-3.0.0.tgz#67502f6aa2b66a2d4032b4279a2944978a0913ef" - integrity sha512-6D82/xSzO094ajanoOSbe4YvXWMfn2A//8Y1+MUqFAJul5Bs+yn36xbK9OtNDcRVSBJ9jjeoXftM6CfztsjOAA== - dependencies: - "@types/json-schema" "^7.0.6" - ajv "^6.12.5" - ajv-keywords "^3.5.2" - -schema-utils@^3.1.0, schema-utils@^3.1.1: +schema-utils@^3.0.0, schema-utils@^3.1.0, schema-utils@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-3.1.1.tgz#bc74c4b6b6995c1d88f76a8b77bea7219e0c8281" integrity sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw== @@ -11456,21 +8667,26 @@ schema-utils@^3.1.0, schema-utils@^3.1.1: ajv "^6.12.5" ajv-keywords "^3.5.2" -screenfull@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/screenfull/-/screenfull-5.1.0.tgz#85c13c70f4ead4c1b8a935c70010dfdcd2c0e5c8" - integrity sha512-dYaNuOdzr+kc6J6CFcBrzkLCfyGcMg+gWkJ8us93IQ7y1cevhQAugFsaCdMHb6lw8KV3xPzSxzH7zM1dQap9mA== +schema-utils@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-4.0.0.tgz#60331e9e3ae78ec5d16353c467c34b3a0a1d3df7" + integrity sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg== + dependencies: + "@types/json-schema" "^7.0.9" + ajv "^8.8.0" + ajv-formats "^2.1.1" + ajv-keywords "^5.0.0" + +screenfull@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/screenfull/-/screenfull-6.0.0.tgz#6f7f37bfe19c5ee50931ac438c1fe380d5b5ff44" + integrity sha512-LGY0nhNQkC4FX4DT4pZdJ5cZH5EOz9Gfh9KcVMl779pS677k4IV1Wv7sY/CwC9VKFT21fYgCh7zkTVVefi5XKA== select-hose@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/select-hose/-/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca" integrity sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo= -select@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/select/-/select-1.1.2.tgz#0e7350acdec80b1108528786ec1d4418d11b396d" - integrity sha1-DnNQrN7ICxEIUoeG7B1EGNEbOW0= - selenium-webdriver@3.6.0, selenium-webdriver@^3.0.1: version "3.6.0" resolved "https://registry.yarnpkg.com/selenium-webdriver/-/selenium-webdriver-3.6.0.tgz#2ba87a1662c020b8988c981ae62cb2a01298eafc" @@ -11500,21 +8716,14 @@ semver@7.0.0: resolved "https://registry.yarnpkg.com/semver/-/semver-7.0.0.tgz#5f3ca35761e47e05b206c6daff2cf814f0316b8e" integrity sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A== -semver@7.3.4: - version "7.3.4" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.4.tgz#27aaa7d2e4ca76452f98d3add093a72c943edc97" - integrity sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw== - dependencies: - lru-cache "^6.0.0" - -semver@7.3.5, semver@^7.3.4, semver@^7.3.5: +semver@7.3.5, semver@^7.0.0, semver@^7.1.1, semver@^7.3.2, semver@^7.3.4, semver@^7.3.5: version "7.3.5" resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7" integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ== dependencies: lru-cache "^6.0.0" -semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.5.1, semver@^5.6.0: +semver@^5.3.0, semver@^5.5.0, semver@^5.6.0: version "5.7.1" resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== @@ -11524,11 +8733,6 @@ semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.3.0: resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== -semver@^7.0.0, semver@^7.1.1, semver@^7.3.2: - version "7.3.2" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.2.tgz#604962b052b81ed0786aae84389ffba70ffd3938" - integrity sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ== - send@0.17.1: version "0.17.1" resolved "https://registry.yarnpkg.com/send/-/send-0.17.1.tgz#c1d8b059f7900f7466dd4938bdc44e11ddb376c8" @@ -11548,20 +8752,6 @@ send@0.17.1: range-parser "~1.2.1" statuses "~1.5.0" -serialize-javascript@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-4.0.0.tgz#b525e1238489a5ecfc42afacc3fe99e666f4b1aa" - integrity sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw== - dependencies: - randombytes "^2.1.0" - -serialize-javascript@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-5.0.1.tgz#7886ec848049a462467a97d3d918ebb2aaf934f4" - integrity sha512-SaaNal9imEO737H2c05Og0/8LUXG7EnsZyMa8MzkmuHoELfT6txuj0cMqRj6zfPKnmQ1yasR4PCJc8x+M4JSPA== - dependencies: - randombytes "^2.1.0" - serialize-javascript@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.0.tgz#efae5d88f45d7924141da8b5c3a7a7e663fefeb8" @@ -11612,11 +8802,6 @@ set-value@^2.0.0, set-value@^2.0.1: is-plain-object "^2.0.3" split-string "^3.0.1" -setimmediate@^1.0.4: - version "1.0.5" - resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" - integrity sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU= - setprototypeof@1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656" @@ -11627,14 +8812,6 @@ setprototypeof@1.1.1: resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.1.tgz#7e95acb24aa92f5885e0abef5ba131330d4ae683" integrity sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw== -sha.js@^2.4.0, sha.js@^2.4.8: - version "2.4.11" - resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7" - integrity sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ== - dependencies: - inherits "^2.0.1" - safe-buffer "^5.0.1" - shallow-clone@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/shallow-clone/-/shallow-clone-3.0.1.tgz#8f2981ad92531f55035b01fb230769a40e02efa3" @@ -11665,9 +8842,9 @@ sigmund@^1.0.1: integrity sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA= signal-exit@^3.0.0, signal-exit@^3.0.2: - version "3.0.3" - resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c" - integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA== + version "3.0.6" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.6.tgz#24e630c4b0f03fea446a2bd299e62b4a6ca8d0af" + integrity sha512-sDl4qMFpijcGw22U5w63KmD3cZJfBuFlVNbVMKje2keoKML7X2UzWbc4XrmEbDwg0NXJc3yv4/ox7b+JWb57kQ== slash@^2.0.0: version "2.0.0" @@ -11680,9 +8857,9 @@ slash@^3.0.0: integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== smart-buffer@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-4.1.0.tgz#91605c25d91652f4661ea69ccf45f1b331ca21ba" - integrity sha512-iVICrxOzCynf/SNaBQCw34eM9jROU/s5rzIhpOvzhzuYHfJR/DhZfDkXiZSgKXfgv26HT3Yni3AV/DGw0cGnnw== + version "4.2.0" + resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-4.2.0.tgz#6e1d71fa4f18c05f7d0ff216dd16a481d0e8d9ae" + integrity sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg== snapdragon-node@^2.0.1: version "2.1.1" @@ -11714,12 +8891,12 @@ snapdragon@^0.8.1: source-map-resolve "^0.5.0" use "^3.1.0" -socket.io-adapter@~2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/socket.io-adapter/-/socket.io-adapter-2.1.0.tgz#edc5dc36602f2985918d631c1399215e97a1b527" - integrity sha512-+vDov/aTsLjViYTwS9fPy5pEtTkrbEKsw2M+oVSoFGw6OD1IpvlV1VPhUzNbofCQ8oyMbdYJqDtGdmHQK6TdPg== +socket.io-adapter@~2.3.3: + version "2.3.3" + resolved "https://registry.yarnpkg.com/socket.io-adapter/-/socket.io-adapter-2.3.3.tgz#4d6111e4d42e9f7646e365b4f578269821f13486" + integrity sha512-Qd/iwn3VskrpNO60BeRyCyr8ZWw9CPZyitW4AQwmRZ8zCiyDiL+znRnWX6tDHXnWn1sJrM1+b6Mn6wEDJJ4aYQ== -socket.io-parser@~4.0.3: +socket.io-parser@~4.0.4: version "4.0.4" resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-4.0.4.tgz#9ea21b0d61508d18196ef04a2c6b9ab630f4c2b0" integrity sha512-t+b0SS+IxG7Rxzda2EVvyBZbvFPBCjJoyHuE0P//7OAsN23GItzDRdWa6ALxZI/8R5ygK7jAR6t028/z+7295g== @@ -11728,40 +8905,37 @@ socket.io-parser@~4.0.3: component-emitter "~1.3.0" debug "~4.3.1" -socket.io@^3.1.0: - version "3.1.2" - resolved "https://registry.yarnpkg.com/socket.io/-/socket.io-3.1.2.tgz#06e27caa1c4fc9617547acfbb5da9bc1747da39a" - integrity sha512-JubKZnTQ4Z8G4IZWtaAZSiRP3I/inpy8c/Bsx2jrwGrTbKeVU5xd6qkKMHpChYeM3dWZSO0QACiGK+obhBNwYw== +socket.io@^4.2.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/socket.io/-/socket.io-4.4.0.tgz#8140a0db2c22235f88a6dceb867e4d5c9bd70507" + integrity sha512-bnpJxswR9ov0Bw6ilhCvO38/1WPtE3eA2dtxi2Iq4/sFebiDJQzgKNYA7AuVVdGW09nrESXd90NbZqtDd9dzRQ== dependencies: - "@types/cookie" "^0.4.0" - "@types/cors" "^2.8.8" - "@types/node" ">=10.0.0" accepts "~1.3.4" base64id "~2.0.0" - debug "~4.3.1" - engine.io "~4.1.0" - socket.io-adapter "~2.1.0" - socket.io-parser "~4.0.3" + debug "~4.3.2" + engine.io "~6.1.0" + socket.io-adapter "~2.3.3" + socket.io-parser "~4.0.4" sockjs-client@^1.5.0: - version "1.5.1" - resolved "https://registry.yarnpkg.com/sockjs-client/-/sockjs-client-1.5.1.tgz#256908f6d5adfb94dabbdbd02c66362cca0f9ea6" - integrity sha512-VnVAb663fosipI/m6pqRXakEOw7nvd7TUgdr3PlR/8V2I95QIdwT8L4nMxhyU8SmDBHYXU1TOElaKOmKLfYzeQ== + version "1.5.2" + resolved "https://registry.yarnpkg.com/sockjs-client/-/sockjs-client-1.5.2.tgz#4bc48c2da9ce4769f19dc723396b50f5c12330a3" + integrity sha512-ZzRxPBISQE7RpzlH4tKJMQbHM9pabHluk0WBaxAQ+wm/UieeBVBou0p4wVnSQGN9QmpAZygQ0cDIypWuqOFmFQ== dependencies: debug "^3.2.6" eventsource "^1.0.7" faye-websocket "^0.11.3" inherits "^2.0.4" json3 "^3.3.3" - url-parse "^1.5.1" + url-parse "^1.5.3" sockjs@^0.3.21: - version "0.3.21" - resolved "https://registry.yarnpkg.com/sockjs/-/sockjs-0.3.21.tgz#b34ffb98e796930b60a0cfa11904d6a339a7d417" - integrity sha512-DhbPFGpxjc6Z3I+uX07Id5ZO2XwYsWOrYjaSeieES78cq+JaJvVe5q/m1uvjIQhXinhIeCFRH6JgXe+mvVMyXw== + version "0.3.24" + resolved "https://registry.yarnpkg.com/sockjs/-/sockjs-0.3.24.tgz#c9bc8995f33a111bea0395ec30aa3206bdb5ccce" + integrity sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ== dependencies: faye-websocket "^0.11.3" - uuid "^3.4.0" + uuid "^8.3.2" websocket-driver "^0.7.4" socks-proxy-agent@^6.0.0: @@ -11781,7 +8955,7 @@ socks@^2.6.1: ip "^1.1.5" smart-buffer "^4.1.0" -source-list-map@^2.0.0, source-list-map@^2.0.1: +source-list-map@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.1.tgz#3993bd873bfc48479cca9ea3a547835c7c154b34" integrity sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw== @@ -11796,18 +8970,6 @@ source-map-js@^1.0.1: resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.1.tgz#a1741c131e3c77d048252adfa24e23b908670caf" integrity sha512-4+TN2b3tqOCd/kaGRJ/sTYA0tR0mdXx26ipdolxcwtJVqEnqNYvlCAt1q3ypy4QMlYus+Zh34RNtYLoq2oQ4IA== -source-map-loader@1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/source-map-loader/-/source-map-loader-1.1.3.tgz#7dbc2fe7ea09d3e43c51fd9fc478b7f016c1f820" - integrity sha512-6YHeF+XzDOrT/ycFJNI53cgEsp/tHTMl37hi7uVyqFAlTXW109JazaQCkbc+jjoL2637qkH1amLi+JzrIpt5lA== - dependencies: - abab "^2.0.5" - iconv-lite "^0.6.2" - loader-utils "^2.0.0" - schema-utils "^3.0.0" - source-map "^0.6.1" - whatwg-mimetype "^2.3.0" - source-map-loader@3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/source-map-loader/-/source-map-loader-3.0.0.tgz#f2a04ee2808ad01c774dea6b7d2639839f3b3049" @@ -11828,15 +8990,7 @@ source-map-resolve@^0.5.0, source-map-resolve@^0.5.2: source-map-url "^0.4.0" urix "^0.1.0" -source-map-resolve@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.6.0.tgz#3d9df87e236b53f16d01e58150fc7711138e5ed2" - integrity sha512-KXBr9d/fO/bWo97NXsPIAW1bFSBOuCnjbNTBMO7N59hsv5i9yzRDfcYwwt0l04+VqnKC+EwzvJZIP/qkuMgR/w== - dependencies: - atob "^2.1.2" - decode-uri-component "^0.2.0" - -source-map-support@0.5.19, source-map-support@^0.5.17, source-map-support@^0.5.5, source-map-support@~0.5.12, source-map-support@~0.5.19: +source-map-support@0.5.19: version "0.5.19" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.19.tgz#a98b62f86dcaf4f67399648c085291ab9e8fed61" integrity sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw== @@ -11844,25 +8998,25 @@ source-map-support@0.5.19, source-map-support@^0.5.17, source-map-support@^0.5.5 buffer-from "^1.0.0" source-map "^0.6.0" -source-map-support@~0.4.0: - version "0.4.18" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.18.tgz#0286a6de8be42641338594e97ccea75f0a2c585f" - integrity sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA== - dependencies: - source-map "^0.5.6" - -source-map-support@~0.5.20: +source-map-support@^0.5.5, source-map-support@~0.5.19, source-map-support@~0.5.20: version "0.5.21" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== dependencies: - buffer-from "^1.0.0" - source-map "^0.6.0" + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map-support@~0.4.0: + version "0.4.18" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.18.tgz#0286a6de8be42641338594e97ccea75f0a2c585f" + integrity sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA== + dependencies: + source-map "^0.5.6" source-map-url@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" - integrity sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM= + version "0.4.1" + resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.1.tgz#0af66605a745a5a2f91cf1bbf8a7afbc283dec56" + integrity sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw== source-map@0.6.1, source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0, source-map@~0.6.1: version "0.6.1" @@ -11907,13 +9061,6 @@ spdy@^4.0.2: select-hose "^2.0.0" spdy-transport "^3.0.0" -speed-measure-webpack-plugin@1.4.2: - version "1.4.2" - resolved "https://registry.yarnpkg.com/speed-measure-webpack-plugin/-/speed-measure-webpack-plugin-1.4.2.tgz#1608e62d3bdb45f01810010e1b5bfedefedfa58f" - integrity sha512-AtVzD0bnIy2/B0fWqJpJgmhcrfWFhBlduzSo0uwplr/QvB33ZNZj2NEth3NONgdnZJqicK0W0mSxnLSbsVCDbw== - dependencies: - chalk "^4.1.0" - splaytree@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/splaytree/-/splaytree-3.1.0.tgz#17d4a0108a6da3627579690b7b847241e18ddec8" @@ -11956,21 +9103,7 @@ sshpk@^1.7.0: safer-buffer "^2.0.2" tweetnacl "~0.14.0" -ssri@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/ssri/-/ssri-6.0.1.tgz#2a3c41b28dd45b62b63676ecb74001265ae9edd8" - integrity sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA== - dependencies: - figgy-pudding "^3.5.1" - -ssri@^8.0.0: - version "8.0.0" - resolved "https://registry.yarnpkg.com/ssri/-/ssri-8.0.0.tgz#79ca74e21f8ceaeddfcb4b90143c458b8d988808" - integrity sha512-aq/pz989nxVYwn16Tsbj1TqFpD5LLrQxHf5zaHuieFV+R0Bbr4y8qUsOA45hXT/N4/9UNXTarBjnjVmjSOVaAA== - dependencies: - minipass "^3.1.1" - -ssri@^8.0.1: +ssri@^8.0.0, ssri@^8.0.1: version "8.0.1" resolved "https://registry.yarnpkg.com/ssri/-/ssri-8.0.1.tgz#638e4e439e2ffbd2cd289776d5ca457c4f51a2af" integrity sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ== @@ -11995,38 +9128,6 @@ static-extend@^0.1.1: resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= -stream-browserify@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.2.tgz#87521d38a44aa7ee91ce1cd2a47df0cb49dd660b" - integrity sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg== - dependencies: - inherits "~2.0.1" - readable-stream "^2.0.2" - -stream-each@^1.1.0: - version "1.2.3" - resolved "https://registry.yarnpkg.com/stream-each/-/stream-each-1.2.3.tgz#ebe27a0c389b04fbcc233642952e10731afa9bae" - integrity sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw== - dependencies: - end-of-stream "^1.1.0" - stream-shift "^1.0.0" - -stream-http@^2.7.2: - version "2.8.3" - resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.8.3.tgz#b2d242469288a5a27ec4fe8933acf623de6514fc" - integrity sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw== - dependencies: - builtin-status-codes "^3.0.0" - inherits "^2.0.1" - readable-stream "^2.3.6" - to-arraybuffer "^1.0.0" - xtend "^4.0.0" - -stream-shift@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.1.tgz#d7088281559ab2778424279b0877da3c392d5a3d" - integrity sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ== - streamroller@^2.2.4: version "2.2.4" resolved "https://registry.yarnpkg.com/streamroller/-/streamroller-2.2.4.tgz#c198ced42db94086a6193608187ce80a5f2b0e53" @@ -12045,13 +9146,14 @@ string-width@^1.0.1: is-fullwidth-code-point "^1.0.0" strip-ansi "^3.0.0" -"string-width@^1.0.2 || 2": - version "2.1.1" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" - integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== +"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== dependencies: - is-fullwidth-code-point "^2.0.0" - strip-ansi "^4.0.0" + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" string-width@^3.0.0, string-width@^3.1.0: version "3.1.0" @@ -12062,32 +9164,7 @@ string-width@^3.0.0, string-width@^3.1.0: is-fullwidth-code-point "^2.0.0" strip-ansi "^5.1.0" -string-width@^4.1.0, string-width@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.0.tgz#952182c46cc7b2c313d1596e623992bd163b72b5" - integrity sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.0" - -string.prototype.trimend@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz#85812a6b847ac002270f5808146064c995fb6913" - integrity sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g== - dependencies: - define-properties "^1.1.3" - es-abstract "^1.17.5" - -string.prototype.trimstart@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz#14af6d9f34b053f7cfc89b72f8f2ee14b9039a54" - integrity sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw== - dependencies: - define-properties "^1.1.3" - es-abstract "^1.17.5" - -string_decoder@^1.0.0, string_decoder@^1.1.1: +string_decoder@^1.1.1: version "1.3.0" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== @@ -12108,13 +9185,6 @@ strip-ansi@^3.0.0, strip-ansi@^3.0.1: dependencies: ansi-regex "^2.0.0" -strip-ansi@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" - integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8= - dependencies: - ansi-regex "^3.0.0" - strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" @@ -12122,12 +9192,12 @@ strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0: dependencies: ansi-regex "^4.1.0" -strip-ansi@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.0.tgz#0b1571dd7669ccd4f3e06e14ef1eed26225ae532" - integrity sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w== +strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== dependencies: - ansi-regex "^5.0.0" + ansi-regex "^5.0.1" strip-bom@^3.0.0: version "3.0.0" @@ -12139,14 +9209,6 @@ strip-eof@^1.0.0: resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8= -style-loader@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-2.0.0.tgz#9669602fd4690740eaaec137799a03addbbc393c" - integrity sha512-Z0gYUJmzZ6ZdRUqpg1r8GsaFKypE+3xAzuFeMuoHgjc9KZv3wMyCRjQIWEbhoFSq7+7yoHXySDJyyWQaPajeiQ== - dependencies: - loader-utils "^2.0.0" - schema-utils "^3.0.0" - style-loader@3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-3.2.1.tgz#63cb920ec145c8669e9a50e92961452a1ef5dcde" @@ -12160,17 +9222,6 @@ stylehacks@^5.0.1: browserslist "^4.16.0" postcss-selector-parser "^6.0.4" -stylus-loader@4.3.3: - version "4.3.3" - resolved "https://registry.yarnpkg.com/stylus-loader/-/stylus-loader-4.3.3.tgz#381bb6341272ac50bcdfd0b877707eac99b6b757" - integrity sha512-PpWB5PnCXUzW4WMYhCvNzAHJBjIBPMXwsdfkkKuA9W7k8OQFMl/19/AQvaWsxz2IptxUlCseyJ6TY/eEKJ4+UQ== - dependencies: - fast-glob "^3.2.4" - klona "^2.0.4" - loader-utils "^2.0.0" - normalize-path "^3.0.0" - schema-utils "^3.0.0" - stylus-loader@6.1.0: version "6.1.0" resolved "https://registry.yarnpkg.com/stylus-loader/-/stylus-loader-6.1.0.tgz#7a3a719a27cb2b9617896d6da28fda94c3ed9762" @@ -12213,7 +9264,7 @@ supports-color@^6.1.0: dependencies: has-flag "^3.0.0" -supports-color@^7.0.0, supports-color@^7.1.0: +supports-color@^7.1.0: version "7.2.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== @@ -12227,19 +9278,6 @@ supports-color@^8.0.0: dependencies: has-flag "^4.0.0" -svgo@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/svgo/-/svgo-2.3.0.tgz#6b3af81d0cbd1e19c83f5f63cec2cb98c70b5373" - integrity sha512-fz4IKjNO6HDPgIQxu4IxwtubtbSfGEAJUq/IXyTPIkGhWck/faiiwfkvsB8LnBkKLvSoyNNIY6d13lZprJMc9Q== - dependencies: - "@trysound/sax" "0.1.1" - chalk "^4.1.0" - commander "^7.1.0" - css-select "^3.1.2" - css-tree "^1.1.2" - csso "^4.2.0" - stable "^0.1.8" - svgo@^2.7.0: version "2.8.0" resolved "https://registry.yarnpkg.com/svgo/-/svgo-2.8.0.tgz#4ff80cce6710dc2795f0c7c74101e6764cfccd24" @@ -12253,52 +9291,30 @@ svgo@^2.7.0: picocolors "^1.0.0" stable "^0.1.8" -symbol-observable@1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804" - integrity sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ== - symbol-observable@4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-4.0.0.tgz#5b425f192279e87f2f9b937ac8540d1984b39205" integrity sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ== -systemjs@0.21.5: - version "0.21.5" - resolved "https://registry.yarnpkg.com/systemjs/-/systemjs-0.21.5.tgz#2fcef4edfe744003da4787f3f3d45d73f94462d2" - integrity sha512-GWzZhN/x7Fsae2CYkz2GF7OgOS+YDgKulcgd5L1kTogZHMKDrPx5T8zI8I0y5RoU9Dx78Z7j1XMfuFa1thD84A== +systemjs-babel@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/systemjs-babel/-/systemjs-babel-0.3.1.tgz#4b864be909b542fb7a84303f24d0dbdbc35da2e1" + integrity sha512-ggZ+v7RSKmN1OlAd46REpfZJmBTnrBUH1zgHnSalIB0KPepfPXEm1p2auE6v7wCmJl231EyApRxnw6X3SgpQtA== -tapable@^1.0.0, tapable@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.1.3.tgz#a1fccc06b58db61fd7a45da2da44f5f3a3e67ba2" - integrity sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA== +systemjs@6.11.0: + version "6.11.0" + resolved "https://registry.yarnpkg.com/systemjs/-/systemjs-6.11.0.tgz#8df8e74fc05822e6c40170aa409b9ca64833315f" + integrity sha512-7YPIY44j+BoY+E6cGBSw0oCU8SNTTIHKZgftcBdwWkDzs/M86Fdlr21FrzAyph7Zo8r3CFGscyFe4rrBtixrBg== -tapable@^2.1.1: +tapable@^2.1.1, tapable@^2.2.0: version "2.2.1" resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0" integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ== -tapable@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.0.tgz#5c373d281d9c672848213d0e037d1c4165ab426b" - integrity sha512-FBk4IesMV1rBxX2tfiK8RAmogtWn53puLOQlvO8XuwlgxcYbP4mVPS9Ph4aeamSyyVjOl24aYWAuc8U5kCVwMw== - -tar@^6.0.2: - version "6.0.5" - resolved "https://registry.yarnpkg.com/tar/-/tar-6.0.5.tgz#bde815086e10b39f1dcd298e89d596e1535e200f" - integrity sha512-0b4HOimQHj9nXNEAA7zWwMM91Zhhba3pspja6sQbgTpynOJf+bkjBnfybNYzbpLbnwXnbyB4LOREvlyXLkCHSg== - dependencies: - chownr "^2.0.0" - fs-minipass "^2.0.0" - minipass "^3.0.0" - minizlib "^2.1.1" - mkdirp "^1.0.3" - yallist "^4.0.0" - -tar@^6.1.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/tar/-/tar-6.1.0.tgz#d1724e9bcc04b977b18d5c573b333a2207229a83" - integrity sha512-DUCttfhsnLCjwoDoFcI+B2iJgYa93vBnDUATYEeRx6sntCTdN01VnqsIuTlALXla/LWooNg0yEGeB+Y8WdFxGA== +tar@^6.0.2, tar@^6.1.0: + version "6.1.11" + resolved "https://registry.yarnpkg.com/tar/-/tar-6.1.11.tgz#6760a38f003afa1b2ffd0ffe9e9abbd0eab3d621" + integrity sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA== dependencies: chownr "^2.0.0" fs-minipass "^2.0.0" @@ -12307,21 +9323,6 @@ tar@^6.1.0: mkdirp "^1.0.3" yallist "^4.0.0" -terser-webpack-plugin@4.2.3: - version "4.2.3" - resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-4.2.3.tgz#28daef4a83bd17c1db0297070adc07fc8cfc6a9a" - integrity sha512-jTgXh40RnvOrLQNgIkwEKnQ8rmHjHK4u+6UBEi+W+FPmvb+uo+chJXntKe7/3lW5mNysgSWD60KyesnhW8D6MQ== - dependencies: - cacache "^15.0.5" - find-cache-dir "^3.3.1" - jest-worker "^26.5.0" - p-limit "^3.0.2" - schema-utils "^3.0.0" - serialize-javascript "^5.0.1" - source-map "^0.6.1" - terser "^5.3.4" - webpack-sources "^1.4.3" - terser-webpack-plugin@5.1.4: version "5.1.4" resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.1.4.tgz#c369cf8a47aa9922bd0d8a94fe3d3da11a7678a1" @@ -12334,21 +9335,6 @@ terser-webpack-plugin@5.1.4: source-map "^0.6.1" terser "^5.7.0" -terser-webpack-plugin@^1.4.3: - version "1.4.5" - resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-1.4.5.tgz#a217aefaea330e734ffacb6120ec1fa312d6040b" - integrity sha512-04Rfe496lN8EYruwi6oPQkG0vo8C+HT49X687FZnpPF0qMAIHONI6HEXYPKDOE8e5HjXTyKfqRd/agHtH0kOtw== - dependencies: - cacache "^12.0.2" - find-cache-dir "^2.1.0" - is-wsl "^1.1.0" - schema-utils "^1.0.0" - serialize-javascript "^4.0.0" - source-map "^0.6.1" - terser "^4.1.2" - webpack-sources "^1.4.0" - worker-farm "^1.7.0" - terser-webpack-plugin@^5.1.3: version "5.2.5" resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.2.5.tgz#ce65b9880a0c36872555c4874f45bbdb02ee32c9" @@ -12360,15 +9346,6 @@ terser-webpack-plugin@^5.1.3: source-map "^0.6.1" terser "^5.7.2" -terser@5.5.1: - version "5.5.1" - resolved "https://registry.yarnpkg.com/terser/-/terser-5.5.1.tgz#540caa25139d6f496fdea056e414284886fb2289" - integrity sha512-6VGWZNVP2KTUcltUQJ25TtNjx/XgdDsBDKGt8nN0MpydU36LmbPPcMBd2kmtZNNGVVDLg44k7GKeHHj+4zPIBQ== - dependencies: - commander "^2.20.0" - source-map "~0.7.2" - source-map-support "~0.5.19" - terser@5.7.1: version "5.7.1" resolved "https://registry.yarnpkg.com/terser/-/terser-5.7.1.tgz#2dc7a61009b66bb638305cb2a824763b116bf784" @@ -12378,24 +9355,6 @@ terser@5.7.1: source-map "~0.7.2" source-map-support "~0.5.19" -terser@^4.1.2: - version "4.8.0" - resolved "https://registry.yarnpkg.com/terser/-/terser-4.8.0.tgz#63056343d7c70bb29f3af665865a46fe03a0df17" - integrity sha512-EAPipTNeWsb/3wLPeup1tVPaXfIaU68xMnVdPafIL1TV05OhASArYyIfFvnvJCNrR2NIOvDVNNTFRa+Re2MWyw== - dependencies: - commander "^2.20.0" - source-map "~0.6.1" - source-map-support "~0.5.12" - -terser@^5.3.4: - version "5.7.0" - resolved "https://registry.yarnpkg.com/terser/-/terser-5.7.0.tgz#a761eeec206bc87b605ab13029876ead938ae693" - integrity sha512-HP5/9hp2UaZt5fYkuhNBR8YyRcT8juw8+uFbAme53iN9hblvKnLUTKkmwJG6ocWpIKf8UK4DoeWG4ty0J6S6/g== - dependencies: - commander "^2.20.0" - source-map "~0.7.2" - source-map-support "~0.5.19" - terser@^5.7.0, terser@^5.7.2: version "5.10.0" resolved "https://registry.yarnpkg.com/terser/-/terser-5.10.0.tgz#b86390809c0389105eb0a0b62397563096ddafcc" @@ -12405,19 +9364,18 @@ terser@^5.7.0, terser@^5.7.2: source-map "~0.7.2" source-map-support "~0.5.20" +text-segmentation@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/text-segmentation/-/text-segmentation-1.0.2.tgz#1f828fa14aa101c114ded1bda35ba7dcc17c9858" + integrity sha512-uTqvLxdBrVnx/CFQOtnf8tfzSXFm+1Qxau7Xi54j4OPTZokuDOX8qncQzrg2G8ZicAMOM8TgzFAYTb+AqNO4Cw== + dependencies: + utrie "^1.0.1" + text-table@0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= -through2@^2.0.0: - version "2.0.5" - resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd" - integrity sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ== - dependencies: - readable-stream "~2.3.6" - xtend "~4.0.1" - through@X.X.X, through@^2.3.6: version "2.3.8" resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" @@ -12428,23 +9386,11 @@ thunky@^1.0.2: resolved "https://registry.yarnpkg.com/thunky/-/thunky-1.1.0.tgz#5abaf714a9405db0504732bbccd2cedd9ef9537d" integrity sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA== -timers-browserify@^2.0.4: - version "2.0.11" - resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-2.0.11.tgz#800b1f3eee272e5bc53ee465a04d0e804c31211f" - integrity sha512-60aV6sgJ5YEbzUdn9c8kYGIqOubPoUdqQCul3SBAsRCZ40s6Y5cMcrW4dt3/k/EsbLVJNl9n6Vz3fTc+k2GeKQ== - dependencies: - setimmediate "^1.0.4" - timsort@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/timsort/-/timsort-0.3.0.tgz#405411a8e7e6339fe64db9a234de11dc31e02bd4" integrity sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q= -tiny-emitter@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/tiny-emitter/-/tiny-emitter-2.1.0.tgz#1d1a56edfc51c43e863cbb5382a72330e3555423" - integrity sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q== - tiny-warning@^1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/tiny-warning/-/tiny-warning-1.0.3.tgz#94a30db453df4c643d0fd566060d60a875d84754" @@ -12462,13 +9408,6 @@ tmp@0.0.30: dependencies: os-tmpdir "~1.0.1" -tmp@0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.2.1.tgz#8457fc3037dcf4719c251367a1af6500ee1ccf14" - integrity sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ== - dependencies: - rimraf "^3.0.0" - tmp@^0.0.33: version "0.0.33" resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" @@ -12476,10 +9415,12 @@ tmp@^0.0.33: dependencies: os-tmpdir "~1.0.2" -to-arraybuffer@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43" - integrity sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M= +tmp@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.2.1.tgz#8457fc3037dcf4719c251367a1af6500ee1ccf14" + integrity sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ== + dependencies: + rimraf "^3.0.0" to-fast-properties@^2.0.0: version "2.0.0" @@ -12541,61 +9482,53 @@ tree-kill@1.2.2: resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.2.tgz#4ca09a9092c88b73a7cdc5e8a01b507b0790a0cc" integrity sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A== -ts-node@^9.0.0: - version "9.0.0" - resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-9.0.0.tgz#e7699d2a110cc8c0d3b831715e417688683460b3" - integrity sha512-/TqB4SnererCDR/vb4S/QvSZvzQMJN8daAslg7MeaiHvD8rDZsSfXmNeNumyZZzMned72Xoq/isQljYSt8Ynfg== +ts-node@^10.0.0, ts-node@^10.4.0: + version "10.4.0" + resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.4.0.tgz#680f88945885f4e6cf450e7f0d6223dd404895f7" + integrity sha512-g0FlPvvCXSIO1JDF6S232P5jPYqBkRL9qly81ZgAOSU7rwI0stphCgd2kLiCrU9DjQCrJMWEqcNSjQL02s6d8A== dependencies: + "@cspotcode/source-map-support" "0.7.0" + "@tsconfig/node10" "^1.0.7" + "@tsconfig/node12" "^1.0.7" + "@tsconfig/node14" "^1.0.0" + "@tsconfig/node16" "^1.0.2" + acorn "^8.4.1" + acorn-walk "^8.1.1" arg "^4.1.0" + create-require "^1.1.0" diff "^4.0.1" make-error "^1.1.1" - source-map-support "^0.5.17" yn "3.1.1" -ts-pnp@^1.1.6: - version "1.2.0" - resolved "https://registry.yarnpkg.com/ts-pnp/-/ts-pnp-1.2.0.tgz#a500ad084b0798f1c3071af391e65912c86bca92" - integrity sha512-csd+vJOb/gkzvcCHgTGSChYpy5f1/XKNsmvBGO4JXS+z1v2HobugDz4s1IeFXM3wZB44uczs+eazB5Q/ccdhQw== - tsconfig-paths@^3.9.0: - version "3.9.0" - resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.9.0.tgz#098547a6c4448807e8fcb8eae081064ee9a3c90b" - integrity sha512-dRcuzokWhajtZWkQsDVKbWyY+jgcLC5sqJhg2PSgf4ZkH2aHPvaOY8YWGhmjb68b5qqTfasSsDO9k7RUiEmZAw== + version "3.12.0" + resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.12.0.tgz#19769aca6ee8f6a1a341e38c8fa45dd9fb18899b" + integrity sha512-e5adrnOYT6zqVnWqZu7i/BQ3BnhzvGbjEjejFXO20lKIKpwTaupkCPgEfv4GZK1IBciJUEhYs3J3p75FdaTFVg== dependencies: "@types/json5" "^0.0.29" json5 "^1.0.1" minimist "^1.2.0" strip-bom "^3.0.0" -tslib@2.1.0, tslib@~2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.1.0.tgz#da60860f1c2ecaa5703ab7d39bc05b6bf988b97a" - integrity sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A== - tslib@2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.0.tgz#803b8cdab3e12ba581a4ca41c8839bbb0dacb09e" integrity sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg== tslib@^1.10.0, tslib@^1.13.0, tslib@^1.8.1, tslib@^1.9.0: - version "1.14.0" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.0.tgz#d624983f3e2c5e0b55307c3dd6c86acd737622c6" - integrity sha512-+Zw5lu0D9tvBMjGP8LpvMb0u2WW2QV3y+D8mO6J+cNzCYIN4sVy43Bf9vl92nqFahutN0I8zHa7cc4vihIshnw== - -tslib@^2.0.0, tslib@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.0.2.tgz#462295631185db44b21b1ea3615b63cd1c038242" - integrity sha512-wAH28hcEKwna96/UacuWaVspVLkg4x1aDM9JlzqaQTOFczCktkVAb5fmXChgandR1EraDPs2w8P+ozM+oafwxg== + version "1.14.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" + integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== -tslib@^2.1.0, tslib@^2.3.0: +tslib@^2.0.0, tslib@^2.0.3, tslib@^2.1.0, tslib@^2.2.0, tslib@^2.3.0, tslib@^2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01" integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw== -tslib@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.2.0.tgz#fb2c475977e35e241311ede2693cee1ec6698f5c" - integrity sha512-gS9GVHRU+RGn5KQM2rllAlR3dU6m7AcpJKdtH8gFvQiC4Otgk98XnmMU+nZenHt/+VhnBPWwgrJsyrdcw6i23w== +tslib@~2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.1.0.tgz#da60860f1c2ecaa5703ab7d39bc05b6bf988b97a" + integrity sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A== tslint@~6.1.3: version "6.1.3" @@ -12623,11 +9556,6 @@ tsutils@^2.29.0: dependencies: tslib "^1.8.1" -tty-browserify@0.0.0: - version "0.0.0" - resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6" - integrity sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY= - tunnel-agent@^0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" @@ -12645,10 +9573,10 @@ tweetnacl@^0.14.3, tweetnacl@~0.14.0: resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q= -type-fest@^0.11.0: - version "0.11.0" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.11.0.tgz#97abf0872310fed88a5c466b25681576145e33f1" - integrity sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ== +type-fest@^0.21.3: + version "0.21.3" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" + integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== type-is@~1.6.17, type-is@~1.6.18: version "1.6.18" @@ -12658,53 +9586,43 @@ type-is@~1.6.17, type-is@~1.6.18: media-typer "0.3.0" mime-types "~2.1.24" -typedarray@^0.0.6: - version "0.0.6" - resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" - integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= - typeface-roboto@^1.1.13: version "1.1.13" resolved "https://registry.yarnpkg.com/typeface-roboto/-/typeface-roboto-1.1.13.tgz#9c4517cb91e311706c74823e857b4bac9a764ae5" integrity sha512-YXvbd3a1QTREoD+FJoEkl0VQNJoEjewR2H11IjVv4bp6ahuIcw0yyw/3udC4vJkHw3T3cUh85FTg8eWef3pSaw== -typescript@4.1.5: - version "4.1.5" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.1.5.tgz#123a3b214aaff3be32926f0d8f1f6e704eb89a72" - integrity sha512-6OSu9PTIzmn9TCDiovULTnET6BgXtDYL4Gg4szY+cGsc3JP1dQL8qvE8kShTRx1NIw4Q9IBHlwODjkjWEtMUyA== - typescript@4.3.5, typescript@~4.3.5: version "4.3.5" resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.3.5.tgz#4d1c37cc16e893973c45a06886b7113234f119f4" integrity sha512-DqQgihaQ9cUrskJo9kIyW/+g0Vxsk8cDtZ52a3NGh0YNTfpUSArXSohyUGnvbPazEPLu398C0UxmKSOrPumUzA== -ua-parser-js@^0.7.23: - version "0.7.28" - resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.28.tgz#8ba04e653f35ce210239c64661685bf9121dec31" - integrity sha512-6Gurc1n//gjp9eQNXjD9O3M/sMwVtN5S8Lv9bvOYBfKfDNiIIhqiyi01vMBO45u4zkDE420w/e0se7Vs+sIg+g== +ua-parser-js@^0.7.30: + version "0.7.31" + resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.31.tgz#649a656b191dffab4f21d5e053e27ca17cbff5c6" + integrity sha512-qLK/Xe9E2uzmYI3qLeOmI0tEOt+TBBQyUIAh4aAgU05FVYzeZrKUdkAZfBNVGRaHVgV0TDkdEngJSw/SyQchkQ== -unicode-canonical-property-names-ecmascript@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz#2619800c4c825800efdd8343af7dd9933cbe2818" - integrity sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ== +unicode-canonical-property-names-ecmascript@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz#301acdc525631670d39f6146e0e77ff6bbdebddc" + integrity sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ== -unicode-match-property-ecmascript@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz#8ed2a32569961bce9227d09cd3ffbb8fed5f020c" - integrity sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg== +unicode-match-property-ecmascript@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz#54fd16e0ecb167cf04cf1f756bdcc92eba7976c3" + integrity sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q== dependencies: - unicode-canonical-property-names-ecmascript "^1.0.4" - unicode-property-aliases-ecmascript "^1.0.4" + unicode-canonical-property-names-ecmascript "^2.0.0" + unicode-property-aliases-ecmascript "^2.0.0" -unicode-match-property-value-ecmascript@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.2.0.tgz#0d91f600eeeb3096aa962b1d6fc88876e64ea531" - integrity sha512-wjuQHGQVofmSJv1uVISKLE5zO2rNGzM/KCYZch/QQvez7C1hUhBIuZ701fYXExuufJFMPhv2SyL8CyoIfMLbIQ== +unicode-match-property-value-ecmascript@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.0.0.tgz#1a01aa57247c14c568b89775a54938788189a714" + integrity sha512-7Yhkc0Ye+t4PNYzOGKedDhXbYIBe1XEQYQxOPyhcXNMJ0WCABqqj6ckydd6pWRZTHV4GuCPKdBAUiMc60tsKVw== -unicode-property-aliases-ecmascript@^1.0.4: - version "1.1.0" - resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.1.0.tgz#dd57a99f6207bedff4628abefb94c50db941c8f4" - integrity sha512-PqSoPh/pWetQ2phoj5RLiaqIk4kCNwoV3CI+LfGmWLKI3rE3kl1h59XpX2BjgDrmbxD9ARtQobPGU1SguCYuQg== +unicode-property-aliases-ecmascript@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.0.0.tgz#0a36cb9a585c4f6abd51ad1deddb285c165297c8" + integrity sha512-5Zfuy9q/DFr4tfO7ZPeVXb1aPoeQSdeFMLpYuFebehDAhbuevLs5yxSZmIFN1tP5F9Wl4IpJrYojg85/zgyZHQ== union-value@^1.0.0: version "1.0.1" @@ -12721,11 +9639,6 @@ uniq@^1.0.1: resolved "https://registry.yarnpkg.com/uniq/-/uniq-1.0.1.tgz#b31c5ae8254844a3a8281541ce2b04b865a734ff" integrity sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8= -uniqs@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/uniqs/-/uniqs-2.0.0.tgz#ffede4b36b25290696e6e165d4a59edb998e6b02" - integrity sha1-/+3ks2slKQaW5uFl1KWe25mOawI= - unique-filename@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-1.1.1.tgz#1d69769369ada0583103a1e6ae87681b56573230" @@ -12764,9 +9677,9 @@ upath@^1.1.1: integrity sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg== uri-js@^4.2.2: - version "4.4.0" - resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.0.tgz#aa714261de793e8a82347a7bcc9ce74e86f28602" - integrity sha512-B0yRTzYdUCCn9n+F4+Gh4yIDtMQcaJsmYBDsTSG8g/OejKBodLQ2IHfN3bM7jUsRXndopT7OIXWdYqc1fjmV6g== + version "4.4.1" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" + integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== dependencies: punycode "^2.1.0" @@ -12775,18 +9688,10 @@ urix@^0.1.0: resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI= -url-parse@^1.4.3: - version "1.4.7" - resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.4.7.tgz#a8a83535e8c00a316e403a5db4ac1b9b853ae278" - integrity sha512-d3uaVyzDB9tQoSXFvuSUNFibTd9zxd2bkVrDRvF5TmvWWQwqE4lgYJ5m+x1DbecWkw+LK4RNl2CU1hHuOKPVlg== - dependencies: - querystringify "^2.1.1" - requires-port "^1.0.0" - -url-parse@^1.5.1: - version "1.5.1" - resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.5.1.tgz#d5fa9890af8a5e1f274a2c98376510f6425f6e3b" - integrity sha512-HOfCOUJt7iSYzEx/UqgtwKRMC6EU91NFhsCHMv9oM03VJcVo2Qrp8T8kI9D7amFf1cu+/3CEhgb3rF9zL7k85Q== +url-parse@^1.4.3, url-parse@^1.5.3: + version "1.5.3" + resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.5.3.tgz#71c1303d38fb6639ade183c2992c8cc0686df862" + integrity sha512-IIORyIQD9rvj0A4CLWsHkBBJuNqWpFQe224b6j9t/ABmquIS0qDU2pY6kl6AuOrL5OkCXHMCFNe1jBcuAggjvQ== dependencies: querystringify "^2.1.1" requires-port "^1.0.0" @@ -12809,31 +9714,24 @@ util-deprecate@^1.0.1, util-deprecate@^1.0.2, util-deprecate@~1.0.1: resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= -util@0.10.3: - version "0.10.3" - resolved "https://registry.yarnpkg.com/util/-/util-0.10.3.tgz#7afb1afe50805246489e3db7fe0ed379336ac0f9" - integrity sha1-evsa/lCAUkZInj23/g7TeTNqwPk= - dependencies: - inherits "2.0.1" - -util@^0.11.0: - version "0.11.1" - resolved "https://registry.yarnpkg.com/util/-/util-0.11.1.tgz#3236733720ec64bb27f6e26f421aaa2e1b588d61" - integrity sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ== - dependencies: - inherits "2.0.3" - utils-merge@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= -uuid@8.3.2: +utrie@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/utrie/-/utrie-1.0.1.tgz#e155235ebcbddc89ae09261ab6e773ce61401b2f" + integrity sha512-JPaDXF3vzgZxfeEwutdGzlrNoVFL5UvZcbO6Qo9D4GoahrieUPoMU8GCpVpR7MQqcKhmShIh8VlbEN3PLM3EBg== + dependencies: + base64-arraybuffer "^1.0.1" + +uuid@8.3.2, uuid@^8.3.2: version "8.3.2" resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== -uuid@^3.3.2, uuid@^3.4.0: +uuid@^3.3.2: version "3.4.0" resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== @@ -12850,11 +9748,6 @@ vary@^1, vary@~1.1.2: resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= -vendors@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/vendors/-/vendors-1.0.4.tgz#e2b800a53e7a29b93506c3cf41100d16c4c4ad8e" - integrity sha512-/juG65kTL4Cy2su4P8HjtkTxk6VmJDiOPBufWniqQ6wknac6jNiXS9vU+hO3wgusiyqWlzTbVHi0dyJqRONg3w== - verror@1.10.0: version "1.10.0" resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" @@ -12864,41 +9757,11 @@ verror@1.10.0: core-util-is "1.0.2" extsprintf "^1.2.0" -vm-browserify@^1.0.1: - version "1.1.2" - resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-1.1.2.tgz#78641c488b8e6ca91a75f511e7a3b32a86e5dda0" - integrity sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ== - void-elements@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/void-elements/-/void-elements-2.0.1.tgz#c066afb582bb1cb4128d60ea92392e94d5e9dbec" integrity sha1-wGavtYK7HLQSjWDqkjkulNXp2+w= -warning@^4.0.3: - version "4.0.3" - resolved "https://registry.yarnpkg.com/warning/-/warning-4.0.3.tgz#16e9e077eb8a86d6af7d64aa1e05fd85b4678ca3" - integrity sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w== - dependencies: - loose-envify "^1.0.0" - -watchpack-chokidar2@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/watchpack-chokidar2/-/watchpack-chokidar2-2.0.0.tgz#9948a1866cbbd6cb824dea13a7ed691f6c8ddff0" - integrity sha512-9TyfOyN/zLUbA288wZ8IsMZ+6cbzvsNyEzSBp6e/zkifi6xxbl8SmQ/CxQq32k8NNqrdVEVUVSEf56L4rQ/ZxA== - dependencies: - chokidar "^2.1.8" - -watchpack@^1.7.4: - version "1.7.4" - resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.7.4.tgz#6e9da53b3c80bb2d6508188f5b200410866cd30b" - integrity sha512-aWAgTW4MoSJzZPAicljkO1hsi1oKj/RRq/OJQh2PKI2UKL04c2Bs+MBOB+BBABHTXJpf9mCwHN7ANCvYsvY2sg== - dependencies: - graceful-fs "^4.1.2" - neo-async "^2.5.0" - optionalDependencies: - chokidar "^3.4.1" - watchpack-chokidar2 "^2.0.0" - watchpack@^2.2.0, watchpack@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.3.0.tgz#a41bca3da6afaff31e92a433f4c856a0c25ea0c4" @@ -12930,9 +9793,9 @@ webdriver-js-extender@2.1.0: selenium-webdriver "^3.0.1" webdriver-manager@^12.1.7: - version "12.1.7" - resolved "https://registry.yarnpkg.com/webdriver-manager/-/webdriver-manager-12.1.7.tgz#ed4eaee8f906b33c146e869b55e850553a1b1162" - integrity sha512-XINj6b8CYuUYC93SG3xPkxlyUc3IJbD6Vvo75CVGuG9uzsefDzWQrhz0Lq8vbPxtb4d63CZdYophF8k8Or/YiA== + version "12.1.8" + resolved "https://registry.yarnpkg.com/webdriver-manager/-/webdriver-manager-12.1.8.tgz#5e70e73eaaf53a0767d5745270addafbc5905fd4" + integrity sha512-qJR36SXG2VwKugPcdwhaqcLQOD7r8P2Xiv9sfNbfZrKBnX243iAkOueX1yAmeNgIKhJ3YAT/F2gq6IiEZzahsg== dependencies: adm-zip "^0.4.9" chalk "^1.1.1" @@ -12946,17 +9809,6 @@ webdriver-manager@^12.1.7: semver "^5.3.0" xml2js "^0.4.17" -webpack-dev-middleware@3.7.2, webpack-dev-middleware@^3.7.2: - version "3.7.2" - resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-3.7.2.tgz#0019c3db716e3fa5cecbf64f2ab88a74bab331f3" - integrity sha512-1xC42LxbYoqLNAhV6YzTYacicgMZQTqRd27Sim9wn5hJrX3I5nxYy1SxSd4+gjUFsz1dQFj+yEe6zEVmSkeJjw== - dependencies: - memory-fs "^0.4.1" - mime "^2.4.4" - mkdirp "^0.5.1" - range-parser "^1.2.1" - webpack-log "^2.0.0" - webpack-dev-middleware@5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-5.0.0.tgz#0abe825275720e0a339978aea5f0b03b140c1584" @@ -12969,6 +9821,17 @@ webpack-dev-middleware@5.0.0: range-parser "^1.2.1" schema-utils "^3.0.0" +webpack-dev-middleware@^3.7.2: + version "3.7.3" + resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-3.7.3.tgz#0639372b143262e2b84ab95d3b91a7597061c2c5" + integrity sha512-djelc/zGiz9nZj/U7PTBi2ViorGJXEWo/3ltkPbDyxCXhhEXkW0ce99falaok4TPj+AsxLiXJR0EBOb0zh9fKQ== + dependencies: + memory-fs "^0.4.1" + mime "^2.4.4" + mkdirp "^0.5.1" + range-parser "^1.2.1" + webpack-log "^2.0.0" + webpack-dev-server@3.11.2: version "3.11.2" resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-3.11.2.tgz#695ebced76a4929f0d5de7fd73fafe185fe33708" @@ -13016,15 +9879,7 @@ webpack-log@^2.0.0: ansi-colors "^3.0.0" uuid "^3.3.2" -webpack-merge@5.7.3, webpack-merge@^5.7.3: - version "5.7.3" - resolved "https://registry.yarnpkg.com/webpack-merge/-/webpack-merge-5.7.3.tgz#2a0754e1877a25a8bbab3d2475ca70a052708213" - integrity sha512-6/JUQv0ELQ1igjGDzHkXbVDRxkfA57Zw7PfiupdLFJYrgFqY5ZP8xxbpp2lU3EPwYx89ht5Z/aDkD40hFCm5AA== - dependencies: - clone-deep "^4.0.1" - wildcard "^2.0.0" - -webpack-merge@5.8.0: +webpack-merge@5.8.0, webpack-merge@^5.7.3: version "5.8.0" resolved "https://registry.yarnpkg.com/webpack-merge/-/webpack-merge-5.8.0.tgz#2b39dbf22af87776ad744c390223731d30a68f61" integrity sha512-/SaI7xY0831XwP6kzuwhKWVKDP9t1QY1h65lAFLbZqMPIuYcD9QAW4u9STIbU9kaJbPBB/geU/gLr1wDjOhQ+Q== @@ -13032,15 +9887,7 @@ webpack-merge@5.8.0: clone-deep "^4.0.1" wildcard "^2.0.0" -webpack-sources@2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-2.2.0.tgz#058926f39e3d443193b6c31547229806ffd02bac" - integrity sha512-bQsA24JLwcnWGArOKUxYKhX3Mz/nK1Xf6hxullKERyktjNMC4x8koOeaDNTA2fEJ09BdWLbM/iTW0ithREUP0w== - dependencies: - source-list-map "^2.0.1" - source-map "^0.6.1" - -webpack-sources@^1.1.0, webpack-sources@^1.2.0, webpack-sources@^1.3.0, webpack-sources@^1.4.0, webpack-sources@^1.4.1, webpack-sources@^1.4.3: +webpack-sources@^1.2.0, webpack-sources@^1.3.0: version "1.4.3" resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.4.3.tgz#eedd8ec0b928fbf1cbfe994e22d2d890f330a933" integrity sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ== @@ -13060,35 +9907,6 @@ webpack-subresource-integrity@1.5.2: dependencies: webpack-sources "^1.3.0" -webpack@4.44.2: - version "4.44.2" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.44.2.tgz#6bfe2b0af055c8b2d1e90ed2cd9363f841266b72" - integrity sha512-6KJVGlCxYdISyurpQ0IPTklv+DULv05rs2hseIXer6D7KrUicRDLFb4IUM1S6LUAKypPM/nSiVSuv8jHu1m3/Q== - dependencies: - "@webassemblyjs/ast" "1.9.0" - "@webassemblyjs/helper-module-context" "1.9.0" - "@webassemblyjs/wasm-edit" "1.9.0" - "@webassemblyjs/wasm-parser" "1.9.0" - acorn "^6.4.1" - ajv "^6.10.2" - ajv-keywords "^3.4.1" - chrome-trace-event "^1.0.2" - enhanced-resolve "^4.3.0" - eslint-scope "^4.0.3" - json-parse-better-errors "^1.0.2" - loader-runner "^2.4.0" - loader-utils "^1.2.3" - memory-fs "^0.4.1" - micromatch "^3.1.10" - mkdirp "^0.5.3" - neo-async "^2.6.1" - node-libs-browser "^2.2.1" - schema-utils "^1.0.0" - tapable "^1.1.3" - terser-webpack-plugin "^1.4.3" - watchpack "^1.7.4" - webpack-sources "^1.4.1" - webpack@5.50.0: version "5.50.0" resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.50.0.tgz#5562d75902a749eb4d75131f5627eac3a3192527" @@ -13163,11 +9981,6 @@ websocket-extensions@>=0.1.1: resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.4.tgz#7f8473bc839dfd87608adb95d7eb075211578a42" integrity sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg== -whatwg-mimetype@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz#3d4b1e0312d2079879f826aff18dbeeca5960fbf" - integrity sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g== - which-module@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" @@ -13188,31 +10001,17 @@ which@^2.0.2: isexe "^2.0.0" wide-align@^1.1.0: - version "1.1.3" - resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" - integrity sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA== + version "1.1.5" + resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.5.tgz#df1d4c206854369ecf3c9a4898f1b23fbd9d15d3" + integrity sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg== dependencies: - string-width "^1.0.2 || 2" + string-width "^1.0.2 || 2 || 3 || 4" wildcard@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/wildcard/-/wildcard-2.0.0.tgz#a77d20e5200c6faaac979e4b3aadc7b3dd7f8fec" integrity sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw== -worker-farm@^1.7.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/worker-farm/-/worker-farm-1.7.0.tgz#26a94c5391bbca926152002f69b84a4bf772e5a8" - integrity sha512-rvw3QTZc8lAxyVrqcSGVm5yP/IJ2UcB3U0graE3LCFoZ0Yn2x4EoVSqJKdB/T5M+FLcRPjz4TDacRf3OCfNUzw== - dependencies: - errno "~0.1.7" - -worker-plugin@5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/worker-plugin/-/worker-plugin-5.0.0.tgz#113b5fe1f4a5d6a957cecd29915bedafd70bb537" - integrity sha512-AXMUstURCxDD6yGam2r4E34aJg6kW85IiaeX72hi+I1cxyaMUtrvVY6sbfpGKAj5e7f68Acl62BjQF5aOOx2IQ== - dependencies: - loader-utils "^1.1.0" - wrap-ansi@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-5.1.0.tgz#1fd1f67235d5b6d0fee781056001bfb694c03b09" @@ -13246,16 +10045,16 @@ wrappy@1: integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= ws@^6.2.1: - version "6.2.1" - resolved "https://registry.yarnpkg.com/ws/-/ws-6.2.1.tgz#442fdf0a47ed64f59b6a5d8ff130f4748ed524fb" - integrity sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA== + version "6.2.2" + resolved "https://registry.yarnpkg.com/ws/-/ws-6.2.2.tgz#dd5cdbd57a9979916097652d78f1cc5faea0c32e" + integrity sha512-zmhltoSR8u1cnDsD43TX59mzoMZsLKqUweyYBAIvTngR3shc0W6aOZylZmq/7hqyVxPdi+5Ud2QInblgyE72fw== dependencies: async-limiter "~1.0.0" -ws@~7.4.2: - version "7.4.5" - resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.5.tgz#a484dd851e9beb6fdb420027e3885e8ce48986c1" - integrity sha512-xzyu3hFvomRfXKH8vOFMU3OguG6oOvhXMo3xsGy3xWExqaM2dxBbVxuD99O7m3ZUFMvvscsZDqxfgMaRr/Nr1g== +ws@~8.2.3: + version "8.2.3" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.2.3.tgz#63a56456db1b04367d0b721a0b80cae6d8becbba" + integrity sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA== xml2js@^0.4.17: version "0.4.23" @@ -13270,15 +10069,10 @@ xmlbuilder@~11.0.0: resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-11.0.1.tgz#be9bae1c8a046e76b31127726347d0ad7002beb3" integrity sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA== -xtend@^4.0.0, xtend@~4.0.1: - version "4.0.2" - resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" - integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== - y18n@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b" - integrity sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w== + version "4.0.3" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.3.tgz#b5f259c82cd6e336921efd7bfd8bf560de9eeedf" + integrity sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ== y18n@^5.0.5: version "5.0.8" @@ -13290,11 +10084,6 @@ yallist@^2.1.2: resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI= -yallist@^3.0.2: - version "3.1.1" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" - integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== - yallist@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" @@ -13322,11 +10111,16 @@ yargs-parser@^18.1.2: decamelize "^1.2.0" yargs-parser@^20.2.2: - version "20.2.7" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.7.tgz#61df85c113edfb5a7a4e36eb8aa60ef423cbc90a" - integrity sha512-FiNkvbeHzB/syOjIUxFDCnhSfzAL8R5vs40MgLFBorXACCOAEaWu0gRZl14vG8MR9AOJIZbmkjhusqBYZ3HTHw== + version "20.2.9" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" + integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== + +yargs-parser@^21.0.0: + version "21.0.0" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.0.0.tgz#a485d3966be4317426dd56bdb6a30131b281dc55" + integrity sha512-z9kApYUOCwoeZ78rfRYYWdiU/iNL6mwwYlkkZfJoyMR1xps+NEBX5X7XmRpxkZHhXJ6+Ey00IwKxBBSW9FIjyA== -yargs@^13.2.4, yargs@^13.3.2: +yargs@^13.3.2: version "13.3.2" resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.3.2.tgz#ad7ffefec1aa59565ac915f82dccb38a9c31a2dd" integrity sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw== @@ -13373,17 +10167,17 @@ yargs@^16.1.1: yargs-parser "^20.2.2" yargs@^17.0.0: - version "17.2.1" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.2.1.tgz#e2c95b9796a0e1f7f3bf4427863b42e0418191ea" - integrity sha512-XfR8du6ua4K6uLGm5S6fA+FIJom/MdJcFNVY8geLlp2v8GYbOXD4EB1tPNZsRn4vBzKGMgb5DRZMeWuFc2GO8Q== + version "17.3.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.3.0.tgz#295c4ffd0eef148ef3e48f7a2e0f58d0e4f26b1c" + integrity sha512-GQl1pWyDoGptFPJx9b9L6kmR33TGusZvXIZUT+BOz9f7X2L94oeAskFYLEg/FkhV06zZPBYLvLZRWeYId29lew== dependencies: cliui "^7.0.2" escalade "^3.1.1" get-caller-file "^2.0.5" require-directory "^2.1.1" - string-width "^4.2.0" + string-width "^4.2.3" y18n "^5.0.5" - yargs-parser "^20.2.2" + yargs-parser "^21.0.0" yn@3.1.1: version "3.1.1" From a8dad4c6e0c70e2daa72cab7d393cb6683871b74 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Mon, 6 Dec 2021 14:00:21 +0200 Subject: [PATCH 211/432] Improve leaflet-geoman typings --- ui-ngx/src/typings/leaflet-geoman-extend.d.ts | 1493 ++++++++++++++++- ui-ngx/tsconfig.json | 1 - 2 files changed, 1492 insertions(+), 2 deletions(-) diff --git a/ui-ngx/src/typings/leaflet-geoman-extend.d.ts b/ui-ngx/src/typings/leaflet-geoman-extend.d.ts index 7b3378aee3..1a936fe780 100644 --- a/ui-ngx/src/typings/leaflet-geoman-extend.d.ts +++ b/ui-ngx/src/typings/leaflet-geoman-extend.d.ts @@ -14,9 +14,1500 @@ /// limitations under the License. /// +/* tslint:disable:adjacent-overload-signatures unified-signatures */ + import * as L from 'leaflet'; -declare module 'leaflet' { +declare module 'leaflet-pm' { + + /** + * Extends built in leaflet Layer Options. + */ + interface LayerOptions { + pmIgnore?: boolean; + snapIgnore?: boolean; + } + + /** + * Extends built in leaflet Map Options. + */ + interface MapOptions { + pmIgnore?: boolean; + } + + /** + * Extends built in leaflet Map. + */ + interface Map { + pm: PM.PMMap; + } + + /** + * Extends built in leaflet Path. + */ + interface Path { + pm: PM.PMLayer; + } + /** + * Extends built in leaflet ImageOverlay. + */ + interface ImageOverlay { + pm: PM.PMLayer; + } + + /** + * Extends built in leaflet LayerGroup. + */ + interface LayerGroup { + pm: PM.PMLayerGroup; + } + + /** + * Extends built in leaflet Polyline. + */ + interface Polyline { + /** Returns true if Line or Polygon has a self intersection. */ + hasSelfIntersection(): boolean; + } + + /** + * Extends @types/leaflet events... + * + * Todo: This is kind of a mess, and it makes all these event handlers show + * up on Layers and Map. Leaflet itself is based around Evented, and @types/leaflet + * makes this very hard to work around. + * + */ + interface Evented { + /****************************************** + * + * AVAILABLE ON MAP + LAYER, THESE ARE OK ON EVENTED. + * + ********************************************/ + + /** Fired when a layer is removed via Removal Mode. */ + on(type: 'pm:remove', fn: PM.RemoveEventHandler): this; + once(type: 'pm:remove', fn: PM.RemoveEventHandler): this; + off(type: 'pm:remove', fn?: PM.RemoveEventHandler): this; + + /** Fired when the layer being cut. Draw+Edit Mode */ + on(type: 'pm:cut', fn: PM.CutEventHandler): this; + once(type: 'pm:cut', fn: PM.CutEventHandler): this; + off(type: 'pm:cut', fn?: PM.CutEventHandler): this; + + /** Fired when rotation is enabled for a layer. */ + on(type: 'pm:rotateenable', fn: PM.RotateEnableEventHandler): this; + once(type: 'pm:rotateenable', fn: PM.RotateEnableEventHandler): this; + off(type: 'pm:rotateenable', fn?: PM.RotateEnableEventHandler): this; + + /** Fired when rotation is disabled for a layer. */ + on(type: 'pm:rotatedisable', fn: PM.RotateDisableEventHandler): this; + once(type: 'pm:rotatedisable', fn: PM.RotateDisableEventHandler): this; + off(type: 'pm:rotatedisable', fn?: PM.RotateDisableEventHandler): this; + + /** Fired when rotation starts on a layer. */ + on(type: 'pm:rotatestart', fn: PM.RotateStartEventHandler): this; + once(type: 'pm:rotatestart', fn: PM.RotateStartEventHandler): this; + off(type: 'pm:rotatestart', fn?: PM.RotateStartEventHandler): this; + + /** Fired when a layer is rotated. */ + on(type: 'pm:rotate', fn: PM.RotateEventHandler): this; + once(type: 'pm:rotate', fn: PM.RotateEventHandler): this; + off(type: 'pm:rotate', fn?: PM.RotateEventHandler): this; + + /** Fired when rotation ends on a layer. */ + on(type: 'pm:rotateend', fn: PM.RotateEndEventHandler): this; + once(type: 'pm:rotateend', fn: PM.RotateEndEventHandler): this; + off(type: 'pm:rotateend', fn?: PM.RotateEndEventHandler): this; + + /****************************************** + * + * TODO: DRAW/EDIT MODE EVENTS LAYER ONLY + * + ********************************************/ + + /** Fired during a marker move/drag. */ + on(type: 'pm:snapdrag', fn: PM.SnapEventHandler): this; + once(type: 'pm:snapdrag', fn: PM.SnapEventHandler): this; + off(type: 'pm:snapdrag', fn?: PM.SnapEventHandler): this; + + /** Fired when a vertex is snapped. */ + on(type: 'pm:snap', fn: PM.SnapEventHandler): this; + once(type: 'pm:snap', fn: PM.SnapEventHandler): this; + off(type: 'pm:snap', fn?: PM.SnapEventHandler): this; + + /** Fired when a vertex is unsnapped. */ + on(type: 'pm:unsnap', fn: PM.SnapEventHandler): this; + once(type: 'pm:unsnap', fn: PM.SnapEventHandler): this; + off(type: 'pm:unsnap', fn?: PM.SnapEventHandler): this; + + /** Called when the center of a circle is placed/moved. */ + on(type: 'pm:centerplaced', fn: PM.CenterPlacedEventHandler): this; + once(type: 'pm:centerplaced', fn: PM.CenterPlacedEventHandler): this; + off(type: 'pm:centerplaced', fn?: PM.CenterPlacedEventHandler): this; + + /****************************************** + * + * TODO: CUT/EDIT MODE EVENTS LAYER ONLY + * + ********************************************/ + + /** Fired when a layer is edited. */ + on(type: 'pm:edit', fn: PM.EditEventHandler): this; + once(type: 'pm:edit', fn: PM.EditEventHandler): this; + off(type: 'pm:edit', fn?: PM.EditEventHandler): this; + + /****************************************** + * + * TODO: DRAW MODE EVENTS ON MAP ONLY + * + ********************************************/ + + /** Fired when Drawing Mode is toggled. */ + on( + type: 'pm:globaldrawmodetoggled', + fn: PM.GlobalDrawModeToggledEventHandler, + context?: any + ): L.Evented; + once( + type: 'pm:globaldrawmodetoggled', + fn: PM.GlobalDrawModeToggledEventHandler, + context?: any + ): L.Evented; + off( + type: 'pm:globaldrawmodetoggled', + fn?: PM.GlobalDrawModeToggledEventHandler, + context?: any + ): L.Evented; + + /** Called when drawing mode is enabled. Payload includes the shape type and working layer. */ + on( + type: 'pm:drawstart', + fn: PM.DrawStartEventHandler, + context?: any + ): L.Evented; + once( + type: 'pm:drawstart', + fn: PM.DrawStartEventHandler, + context?: any + ): L.Evented; + off( + type: 'pm:drawstart', + fn?: PM.DrawStartEventHandler, + context?: any + ): L.Evented; + + /** Called when drawing mode is disabled. Payload includes the shape type. */ + on( + type: 'pm:drawend', + fn: PM.DrawEndEventHandler, + context?: any + ): L.Evented; + once( + type: 'pm:drawend', + fn: PM.DrawEndEventHandler, + context?: any + ): L.Evented; + off( + type: 'pm:drawend', + fn?: PM.DrawEndEventHandler, + context?: any + ): L.Evented; + + /** Called when drawing mode is disabled. Payload includes the shape type. */ + on(type: 'pm:create', fn: PM.CreateEventHandler, context?: any): L.Evented; + once( + type: 'pm:create', + fn: PM.CreateEventHandler, + context?: any + ): L.Evented; + off( + type: 'pm:create', + fn?: PM.CreateEventHandler, + context?: any + ): L.Evented; + + /****************************************** + * + * TODO: DRAW MODE EVENTS ON LAYER ONLY + * + ********************************************/ + + /** Called when a new vertex is added. */ + on(type: 'pm:vertexadded', fn: PM.VertexAddedEventHandler): this; + once(type: 'pm:vertexadded', fn: PM.VertexAddedEventHandler): this; + off(type: 'pm:vertexadded', fn?: PM.VertexAddedEventHandler): this; + + /****************************************** + * + * TODO: EDIT MODE EVENTS ON LAYER ONLY + * + ********************************************/ + + /** Fired when edit mode is disabled and a layer is edited and its coordinates have changed. */ + on(type: 'pm:update', fn: PM.UpdateEventHandler): this; + once(type: 'pm:update', fn: PM.UpdateEventHandler): this; + off(type: 'pm:update', fn?: PM.UpdateEventHandler): this; + + /** Fired when edit mode on a layer is enabled. */ + on(type: 'pm:enable', fn: PM.EnableEventHandler): this; + once(type: 'pm:enable', fn: PM.EnableEventHandler): this; + off(type: 'pm:enable', fn?: PM.EnableEventHandler): this; + + /** Fired when edit mode on a layer is disabled. */ + on(type: 'pm:disable', fn: PM.DisableEventHandler): this; + once(type: 'pm:disable', fn: PM.DisableEventHandler): this; + off(type: 'pm:disable', fn?: PM.DisableEventHandler): this; + + /** Fired when a vertex is added. */ + on(type: 'pm:vertexadded', fn: PM.VertexAddedEventHandler2): this; + once(type: 'pm:vertexadded', fn: PM.VertexAddedEventHandler2): this; + off(type: 'pm:vertexadded', fn?: PM.VertexAddedEventHandler2): this; + + /** Fired when a vertex is removed. */ + on(type: 'pm:vertexremoved', fn: PM.VertexRemovedEventHandler): this; + once(type: 'pm:vertexremoved', fn: PM.VertexRemovedEventHandler): this; + off(type: 'pm:vertexremoved', fn?: PM.VertexRemovedEventHandler): this; + + /** Fired when a vertex is clicked. */ + on(type: 'pm:vertexclick', fn: PM.VertexClickEventHandler): this; + once(type: 'pm:vertexclick', fn: PM.VertexClickEventHandler): this; + off(type: 'pm:vertexclick', fn?: PM.VertexClickEventHandler): this; + + /** Fired when dragging of a marker which corresponds to a vertex starts. */ + on(type: 'pm:markerdragstart', fn: PM.MarkerDragStartEventHandler): this; + once(type: 'pm:markerdragstart', fn: PM.MarkerDragStartEventHandler): this; + off(type: 'pm:markerdragstart', fn?: PM.MarkerDragStartEventHandler): this; + + /** Fired when dragging a vertex-marker. */ + on(type: 'pm:markerdrag', fn: PM.MarkerDragEventHandler): this; + once(type: 'pm:markerdrag', fn: PM.MarkerDragEventHandler): this; + off(type: 'pm:markerdrag', fn?: PM.MarkerDragEventHandler): this; + + /** Fired when dragging of a vertex-marker ends. */ + on(type: 'pm:markerdragend', fn: PM.MarkerDragEndEventHandler): this; + once(type: 'pm:markerdragend', fn: PM.MarkerDragEndEventHandler): this; + off(type: 'pm:markerdragend', fn?: PM.MarkerDragEndEventHandler): this; + + /** Fired when coords of a layer are reset. E.g. by self-intersection.. */ + on(type: 'pm:layerreset', fn: PM.LayerResetEventHandler): this; + once(type: 'pm:layerreset', fn: PM.LayerResetEventHandler): this; + off(type: 'pm:layerreset', fn?: PM.LayerResetEventHandler): this; + + /** When allowSelfIntersection: false, this event is fired as soon as a self-intersection is detected. */ + on(type: 'pm:intersect', fn: PM.IntersectEventHandler): this; + once(type: 'pm:intersect', fn: PM.IntersectEventHandler): this; + off(type: 'pm:intersect', fn?: PM.IntersectEventHandler): this; + + /****************************************** + * + * TODO: EDIT MODE EVENTS ON MAP ONLY + * + ********************************************/ + + /** Fired when Edit Mode is toggled. */ + on( + type: 'pm:globaleditmodetoggled', + fn: PM.GlobalEditModeToggledEventHandler + ): this; + once( + type: 'pm:globaleditmodetoggled', + fn: PM.GlobalEditModeToggledEventHandler + ): this; + off( + type: 'pm:globaleditmodetoggled', + fn?: PM.GlobalEditModeToggledEventHandler + ): this; + + /****************************************** + * + * TODO: DRAG MODE EVENTS ON MAP ONLY + * + ********************************************/ + + /** Fired when Drag Mode is toggled. */ + on( + type: 'pm:globaldragmodetoggled', + fn: PM.GlobalDragModeToggledEventHandler + ): this; + once( + type: 'pm:globaldragmodetoggled', + fn: PM.GlobalDragModeToggledEventHandler + ): this; + off( + type: 'pm:globaldragmodetoggled', + fn?: PM.GlobalDragModeToggledEventHandler + ): this; + + /****************************************** + * + * TODO: DRAG MODE EVENTS ON LAYER ONLY + * + ********************************************/ + + /** Fired when a layer starts being dragged. */ + on(type: 'pm:dragstart', fn: PM.DragStartEventHandler): this; + once(type: 'pm:dragstart', fn: PM.DragStartEventHandler): this; + off(type: 'pm:dragstart', fn?: PM.DragStartEventHandler): this; + + /** Fired when a layer is dragged. */ + on(type: 'pm:drag', fn: PM.DragEventHandler): this; + once(type: 'pm:drag', fn: PM.DragEventHandler): this; + off(type: 'pm:drag', fn?: PM.DragEventHandler): this; + + /** Fired when a layer stops being dragged. */ + on(type: 'pm:dragend', fn: PM.DragEndEventHandler): this; + once(type: 'pm:dragend', fn: PM.DragEndEventHandler): this; + off(type: 'pm:dragend', fn?: PM.DragEndEventHandler): this; + + /****************************************** + * + * TODO: REMOVE MODE EVENTS ON MAP ONLY + * + ********************************************/ + + /** Fired when Removal Mode is toggled. */ + on( + type: 'pm:globalremovalmodetoggled', + fn: PM.GlobalRemovalModeToggledEventHandler + ): this; + once( + type: 'pm:globalremovalmodetoggled', + fn: PM.GlobalRemovalModeToggledEventHandler + ): this; + off( + type: 'pm:globalremovalmodetoggled', + fn?: PM.GlobalRemovalModeToggledEventHandler + ): this; + + /****************************************** + * + * TODO: CUT MODE EVENTS ON MAP ONLY + * + ********************************************/ + + /** Fired when a layer is removed via Removal Mode. */ + on( + type: 'pm:globalcutmodetoggled', + fn: PM.GlobalCutModeToggledEventHandler + ): this; + once( + type: 'pm:globalcutmodetoggled', + fn: PM.GlobalCutModeToggledEventHandler + ): this; + off( + type: 'pm:globalcutmodetoggled', + fn?: PM.GlobalCutModeToggledEventHandler + ): this; + + /****************************************** + * + * TODO: ROTATE MODE EVENTS ON MAP ONLY + * + ********************************************/ + + /** Fired when Rotate Mode is toggled. */ + on( + type: 'pm:globalrotatemodetoggled', + fn: PM.GlobalRotateModeToggledEventHandler + ): this; + once( + type: 'pm:globalrotatemodetoggled', + fn: PM.GlobalRotateModeToggledEventHandler + ): this; + off( + type: 'pm:globalrotatemodetoggled', + fn?: PM.GlobalRotateModeToggledEventHandler + ): this; + + /****************************************** + * + * TODO: TRANSLATION EVENTS ON MAP ONLY + * + ********************************************/ + + /** Standard Leaflet event. Fired when any layer is removed. */ + on(type: 'pm:langchange', fn: PM.LangChangeEventHandler): this; + once(type: 'pm:langchange', fn: PM.LangChangeEventHandler): this; + off(type: 'pm:langchange', fn?: PM.LangChangeEventHandler): this; + + /****************************************** + * + * TODO: CONTROL EVENTS ON MAP ONLY + * + ********************************************/ + + /** Fired when a Toolbar button is clicked. */ + on(type: 'pm:buttonclick', fn: PM.ButtonClickEventHandler): this; + once(type: 'pm:buttonclick', fn: PM.ButtonClickEventHandler): this; + off(type: 'pm:buttonclick', fn?: PM.ButtonClickEventHandler): this; + + /** Fired when a Toolbar action is clicked. */ + on(type: 'pm:actionclick', fn: PM.ActionClickEventHandler): this; + once(type: 'pm:actionclick', fn: PM.ActionClickEventHandler): this; + off(type: 'pm:actionclick', fn?: PM.ActionClickEventHandler): this; + + /****************************************** + * + * TODO: Keyboard EVENT ON MAP ONLY + * + ********************************************/ + + /** Fired when `keydown` or `keyup` on the document is fired. */ + on(type: 'pm:keyevent', fn: PM.KeyboardKeyEventHandler): this; + once(type: 'pm:keyevent', fn: PM.KeyboardKeyEventHandler): this; + off(type: 'pm:keyevent', fn?: PM.KeyboardKeyEventHandler): this; + } + + namespace PM { + /** Supported shape names. 'ImageOverlay' is in Edit Mode only. Also accepts custom shape name. */ + type SUPPORTED_SHAPES = + | 'Marker' + | 'Circle' + | 'Line' + | 'Rectangle' + | 'Polygon' + | 'Cut' + | 'CircleMarker' + | 'ImageOverlay' + | string; + + /** + * Changes default registration of leaflet-geoman on leaflet layers. + * + * @param optIn - if true, a layers pmIgnore property has to be set to false to get initiated. + */ + function setOptIn(optIn: boolean): void; + + /** + * Enable leaflet-geoman on an ignored layer. + * + * @param layer - re-reads layer.options.pmIgnore to initialize leaflet-geoman. + */ + function reInitLayer(layer: L.Layer): void; + + /** + * PM map interface. + */ + interface PMMap + extends PMDrawMap, + PMEditMap, + PMDragMap, + PMRemoveMap, + PMCutMap, + PMRotateMap { + Toolbar: PMMapToolbar; + + Keyboard: PMMapKeyboard; + + /** Adds the Toolbar to the map. */ + addControls(options?: ToolbarOptions): void; + + /** Toggle the visiblity of the Toolbar. */ + removeControls(): void; + + /** Returns true if the Toolbar is visible on the map. */ + controlsVisible(): boolean; + + /** Toggle the visiblity of the Toolbar. */ + toggleControls(): void; + + setLang( + lang: + | 'cz' + | 'da' + | 'de' + | 'el' + | 'en' + | 'es' + | 'fa' + | 'fr' + | 'hu' + | 'id' + | 'it' + | 'nl' + | 'no' + | 'pl' + | 'pt_br' + | 'ro' + | 'ru' + | 'sv' + | 'tr' + | 'ua' + | 'zh' + | 'zh_tw', + customTranslations?: Translations, + fallbackLanguage?: string + ): void; + + /** Set globalOptions and apply them. */ + setGlobalOptions(options: GlobalOptions): void; + + /** Apply the current globalOptions to all existing layers. */ + applyGlobalOptions(): void; + + /** Returns the globalOptions. */ + getGlobalOptions(): GlobalOptions; + } + + class Translations { + tooltips?: { + placeMarker?: string; + firstVertex?: string; + continueLine?: string; + finishLine?: string; + finishPoly?: string; + finishRect?: string; + startCircle?: string; + finishCircle?: string; + placeCircleMarker?: string; + }; + + actions?: { + finish?: string; + cancel?: string; + removeLastVertex?: string; + }; + + buttonTitles?: { + drawMarkerButton?: string; + drawPolyButton?: string; + drawLineButton?: string; + drawCircleButton?: string; + drawRectButton?: string; + editButton?: string; + dragButton?: string; + cutButton?: string; + deleteButton?: string; + drawCircleMarkerButton?: string; + }; + } + + type ACTION_NAMES = 'cancel' | 'removeLastVertex' | 'finish' | 'finishMode'; + + class Action { + text: string; + onClick?: (e: any) => void; + } + + type TOOLBAR_CONTROL_ORDER = + | 'drawMarker' + | 'drawCircleMarker' + | 'drawPolyline' + | 'drawRectangle' + | 'drawPolygon' + | 'drawCircle' + | 'editMode' + | 'dragMode' + | 'cutPolygon' + | 'removalMode' + | 'rotateMode' + | string; + + interface PMMapToolbar { + /** Pass an array of button names to reorder the buttons in the Toolbar. */ + changeControlOrder(order?: TOOLBAR_CONTROL_ORDER[]): void; + + /** Receive the current order with. */ + getControlOrder(): TOOLBAR_CONTROL_ORDER[]; + + /** The position of a block (draw, edit, custom, options⭐) in the Toolbar can be changed. If not set, the value */ + /** from position of the Toolbar is taken. */ + setBlockPosition( + block: 'draw' | 'edit' | 'custom' | 'options', + position: L.ControlPosition + ): void; + + /** Returns a Object with the positions for all blocks */ + getBlockPositions(): BlockPositions; + + /** To add a custom Control to the Toolbar */ + createCustomControl(options: CustomControlOptions): void; + + /** Creates a copy of a draw Control. Returns the drawInstance and the control. */ + copyDrawControl( + copyInstance: string, + options?: CustomControlOptions + ): void; + + /** Change the actions of an existing button. */ + changeActionsOfControl( + name: string, + actions: (ACTION_NAMES | Action)[] + ): void; + + /** Disable button by control name */ + setButtonDisabled(name: TOOLBAR_CONTROL_ORDER, state: boolean): void; + } + + type KEYBOARD_EVENT_TYPE = 'current' | 'keydown' | 'keyup'; + + interface PMMapKeyboard { + /** Pass an array of button names to reorder the buttons in the Toolbar. */ + getLastKeyEvent(type: KEYBOARD_EVENT_TYPE[]): KeyboardKeyEventHandler; + + /** Returns the current pressed key. [KeyboardEvent.key](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key). */ + getPressedKey(): string; + + /** Returns true if the `Shift` key is currently pressed. */ + isShiftKeyPressed(): boolean; + + /** Returns true if the `Alt` key is currently pressed. */ + isAltKeyPressed(): boolean; + + /** Returns true if the `Ctrl` key is currently pressed. */ + isCtrlKeyPressed(): boolean; + + /** Returns true if the `Meta` key is currently pressed. */ + isMetaKeyPressed(): boolean; + } + + interface Button { + /** Actions */ + actions: (ACTION_NAMES | Action)[]; + + /** Function fired after clicking the control. */ + afterClick: () => void; + + /** CSS class with the Icon. */ + className: string; + + /** If true, other buttons will be disabled on click (default: true) */ + disableOtherButtons: boolean; + + /** Control can be toggled. */ + doToggle: boolean; + + /** Extending Class f. ex. Line, Polygon, ... L.PM.Draw.EXTENDINGCLASS */ + jsClass: string; + + /** Function fired when clicking the control. */ + onClick: () => void; + + position: L.ControlPosition; + + /** Text showing when you hover the control. */ + title: string; + + /** Toggle state true -> enabled, false -> disabled (default: false) */ + toggleStatus: boolean; + + /** Block of the control. 'options' is ⭐ only. */ + tool?: 'draw' | 'edit' | 'custom' | 'options'; + } + + interface CustomControlOptions { + /** Name of the control */ + name: string; + + /** Block of the control. 'options' is ⭐ only. */ + block?: 'draw' | 'edit' | 'custom' | 'options'; + + /** Text showing when you hover the control. */ + title?: string; + + /** CSS class with the Icon. */ + className?: string; + + /** Function fired when clicking the control. */ + onClick?: () => void; + + /** Function fired after clicking the control. */ + afterClick?: () => void; + + /** Actions */ + actions?: (ACTION_NAMES | Action)[]; + + /** Control can be toggled. */ + toggle?: boolean; + + /** Control is disabled. */ + disabled?: boolean; + } + + type PANE = + | 'mapPane' + | 'tilePane' + | 'overlayPane' + | 'shadowPane' + | 'markerPane' + | 'tooltipPane' + | 'popupPane' + | string; + + interface GlobalOptions extends DrawModeOptions, EditModeOptions { + /** Add the created layers to a layergroup instead to the map. */ + layerGroup?: L.Map | L.LayerGroup; + + /** Prioritize the order of snapping. Default: ['Marker','CircleMarker','Circle','Line','Polygon','Rectangle']. */ + snappingOrder: SUPPORTED_SHAPES[]; + + /** Defines in which panes the layers and helper vertices are created. Default: */ + /** { vertexPane: 'markerPane', layerPane: 'overlayPane', markerPane: 'markerPane' } */ + panes: { vertexPane: PANE; layerPane: PANE; markerPane: PANE }; + } + + interface PMDrawMap { + + /** Draw */ + Draw: Draw; + /** Enable Draw Mode with the passed shape. */ + enableDraw(shape: SUPPORTED_SHAPES, options?: DrawModeOptions): void; + + /** Disable all drawing */ + disableDraw(shape?: SUPPORTED_SHAPES): void; + + /** Returns true if global Draw Mode is enabled. false when disabled. */ + globalDrawModeEnabled(): boolean; + + /** Customize the style of the drawn layer. Only for L.Path layers. */ + /** Shapes can be excluded with a ignoreShapes array or merged with the current style with merge: true in optionsModifier. */ + setPathOptions( + options: L.PathOptions, + optionsModifier?: { ignoreShapes?: SUPPORTED_SHAPES[]; merge?: boolean } + ): void; + + /** Returns all Geoman layers on the map as array. Pass true to get a L.FeatureGroup. */ + getGeomanLayers(asFeatureGroup?: boolean): L.FeatureGroup | L.Layer[]; + + /** Returns all Geoman draw layers on the map as array. Pass true to get a L.FeatureGroup. */ + getGeomanDrawLayers(asFeatureGroup?: boolean): L.FeatureGroup | L.Layer[]; + } + + interface PMEditMap { + /** Enables edit mode. The passed options are preserved, even when the mode is enabled via the Toolbar */ + enableGlobalEditMode(options?: EditModeOptions): void; + + /** Disables global edit mode. */ + disableGlobalEditMode(): void; + + /** Toggles global edit mode. */ + toggleGlobalEditMode(options?: EditModeOptions): void; + + /** Returns true if global edit mode is enabled. false when disabled. */ + globalEditModeEnabled(): boolean; + } + + interface PMDragMap { + /** Enables global drag mode. */ + enableGlobalDragMode(): void; + + /** Disables global drag mode. */ + disableGlobalDragMode(): void; + + /** Toggles global drag mode. */ + toggleGlobalDragMode(): void; + + /** Returns true if global drag mode is enabled. false when disabled. */ + globalDragModeEnabled(): boolean; + } + + interface PMRemoveMap { + /** Enables global removal mode. */ + enableGlobalRemovalMode(): void; + + /** Disables global removal mode. */ + disableGlobalRemovalMode(): void; + + /** Toggles global removal mode. */ + toggleGlobalRemovalMode(): void; + + /** Returns true if global removal mode is enabled. false when disabled. */ + globalRemovalModeEnabled(): boolean; + } + + interface PMCutMap { + /** Enables global cut mode. */ + enableGlobalCutMode(options?: CutModeOptions): void; + + /** Disables global cut mode. */ + disableGlobalCutMode(): void; + + /** Toggles global cut mode. */ + toggleGlobalCutMode(options?: CutModeOptions): void; + + /** Returns true if global cut mode is enabled. false when disabled. */ + globalCutModeEnabled(): boolean; + } + + interface PMRotateMap { + /** Enables global rotate mode. */ + enableGlobalRotateMode(): void; + + /** Disables global rotate mode. */ + disableGlobalRotateMode(): void; + + /** Toggles global rotate mode. */ + toggleGlobalRotateMode(): void; + + /** Returns true if global rotate mode is enabled. false when disabled. */ + globalRotateModeEnabled(): boolean; + } + + interface PMRotateLayer { + /** Enables rotate mode on the layer. */ + enableRotate(): void; + + /** Disables rotate mode on the layer. */ + disableRotate(): void; + + /** Toggles rotate mode on the layer. */ + rotateEnabled(): void; + + /** Rotates the layer by x degrees. */ + rotateLayer(degrees: number): void; + + /** Rotates the layer to x degrees. */ + rotateLayerToAngle(degrees: number): void; + + /** Returns the angle of the layer in degrees. */ + getAngle(): number; + } + + interface Draw { + /** Array of available shapes. */ + getShapes(): SUPPORTED_SHAPES[]; + + /** Returns the active shape. */ + getActiveShape(): SUPPORTED_SHAPES; + + /** Set path options */ + setPathOptions(options: L.PathOptions): void; + + /** Set options */ + setOptions(options: DrawModeOptions): void; + + /** Get options */ + getOptions(): DrawModeOptions; + } + + interface CutModeOptions { + allowSelfIntersection?: boolean; + } + + type VertexValidationHandler = (e: { + layer: L.Layer; + marker: L.Marker; + event: any; + }) => boolean; + + interface EditModeOptions { + /** Enable snapping to other layers vertices for precision drawing. Can be disabled by holding the ALT key (default:true). */ + snappable?: boolean; + + /** The distance to another vertex when a snap should happen (default:20). */ + snapDistance?: number; + + /** Allow self intersections (default:true). */ + allowSelfIntersection?: boolean; + + /** Allow self intersections (default:true). */ + allowSelfIntersectionEdit?: boolean; + + /** Disable the removal of markers via right click / vertices via removeVertexOn. (default:false). */ + preventMarkerRemoval?: boolean; + + /** If true, vertex removal that cause a layer to fall below their minimum required vertices will remove the entire layer. */ + /** If false, these vertices can't be removed. Minimum vertices are 2 for Lines and 3 for Polygons (default:true). */ + removeLayerBelowMinVertexCount?: boolean; + + /** Defines which layers should dragged with this layer together. */ + /** true syncs all layers in the same LayerGroup(s) or you pass an `Array` of layers to sync. (default:false). */ + syncLayersOnDrag?: L.Layer[] | boolean; + + /** Edit-Mode for the layer can disabled (`pm.enable()`). (default:true). */ + allowEditing?: boolean; + + /** Removing can be disabled for the layer. (default:true). */ + allowRemoval?: boolean; + + /** Layer can be prevented from cutting. (default:true). */ + allowCutting?: boolean; + + /** Layer can be prevented from rotation. (default:true). */ + allowRotation?: boolean; + + /** Dragging can be disabled for the layer. (default:true). */ + draggable?: boolean; + + /** Leaflet layer event to add a vertex to a Line or Polygon, like dblclick. (default:click). */ + addVertexOn?: + | 'click' + | 'dblclick' + | 'mousedown' + | 'mouseover' + | 'mouseout' + | 'contextmenu'; + + /** A function for validation if a vertex (of a Line / Polygon) is allowed to add. */ + /** It passes a object with `[layer, marker, event}`. For example to check if the layer */ + /** has a certain property or if the `Ctrl` key is pressed. (default:undefined). */ + addVertexValidation?: undefined | VertexValidationHandler; + + /** Leaflet layer event to remove a vertex from a Line or Polygon, like dblclick. (default:contextmenu). */ + removeVertexOn?: + | 'click' + | 'dblclick' + | 'mousedown' + | 'mouseover' + | 'mouseout' + | 'contextmenu'; + + /** A function for validation if a vertex (of a Line / Polygon) is allowed to remove. */ + /** It passes a object with `[layer, marker, event}`. For example to check if the layer has a certain property */ + /** or if the `Ctrl` key is pressed. */ + removeVertexValidation?: undefined | VertexValidationHandler; + + /** A function for validation if a vertex / helper-marker is allowed to move / drag. It passes a object with */ + /** `[layer, marker, event}`. For example to check if the layer has a certain property or if the `Ctrl` key is pressed. */ + moveVertexValidation?: undefined | VertexValidationHandler; + + /** Shows only n markers closest to the cursor. Use -1 for no limit (default:-1). */ + limitMarkersToCount?: number; + + /** Shows markers when under the given zoom level ⭐ */ + limitMarkersToZoom?: number; + + /** Shows only markers in the viewport ⭐ */ + limitMarkersToViewport?: boolean; + + /** Shows markers only after the layer was clicked ⭐ */ + limitMarkersToClick?: boolean; + + /** Pin shared vertices/markers together during edit ⭐ */ + pinning?: boolean; + + /** Hide the middle Markers in edit mode from Polyline and Polygon. */ + hideMiddleMarkers?: boolean; + } + + interface DrawModeOptions { + /** Enable snapping to other layers vertices for precision drawing. Can be disabled by holding the ALT key (default:true). */ + snappable?: boolean; + + /** The distance to another vertex when a snap should happen (default:20). */ + snapDistance?: number; + + /** Allow snapping in the middle of two vertices (middleMarker)(default:false). */ + snapMiddle?: boolean; + + /** Allow snapping between two vertices. (default: true) */ + snapSegment?: boolean; + + /** Require the last point of a shape to be snapped. (default: false). */ + requireSnapToFinish?: boolean; + + /** Show helpful tooltips for your user (default:true). */ + tooltips?: boolean; + + /** Allow self intersections (default:true). */ + allowSelfIntersection?: boolean; + + /** Leaflet path options for the lines between drawn vertices/markers. (default:{color:'red'}). */ + templineStyle?: L.PathOptions; + + /** Leaflet path options for the helper line between last drawn vertex and the cursor. (default:{color:'red',dashArray:[5,5]}). */ + hintlineStyle?: L.PathOptions; + + /** Leaflet path options for the drawn layer (Only for L.Path layers). (default:null). */ + pathOptions?: L.PathOptions; + + /** Leaflet marker options (only for drawing markers). (default:{draggable:true}). */ + markerStyle?: L.MarkerOptions; + + /** Show a marker at the cursor (default:true). */ + cursorMarker?: boolean; + + /** Leaflet layer event to finish the drawn shape (default:null). */ + finishOn?: + | null + | 'click' + | 'dblclick' + | 'mousedown' + | 'mouseover' + | 'mouseout' + | 'contextmenu' + | 'snap'; + + /** Hide the middle Markers in edit mode from Polyline and Polygon. (default:false). */ + hideMiddleMarkers?: boolean; + + /** Set the min radius of a Circle. (default:null). */ + minRadiusCircle?: number; + + /** Set the max radius of a Circle. (default:null). */ + maxRadiusCircle?: number; + + /** Set the min radius of a CircleMarker when editable is active. (default:null). */ + minRadiusCircleMarker?: number; + + /** Set the max radius of a CircleMarker when editable is active. (default:null). */ + maxRadiusCircleMarker?: number; + + /** Makes a CircleMarker editable like a Circle (default:false). */ + editable?: boolean; + + /** Markers and CircleMarkers are editable during the draw-session */ + /** (you can drag them around immediately after drawing them) (default:true). */ + markerEditable?: boolean; + + /** Draw-Mode stays enabled after finishing a layer to immediately draw the next layer. */ + /** Defaults to true for Markers and CircleMarkers and false for all other layers. */ + continueDrawing?: boolean; + + /** Angel of rectangle. */ + rectangleAngle?: number; + + /** Cut-Mode: Only the passed layers can be cut. Cutted layers are removed from the */ + /** Array until no layers are left anymore and cutting is working on all layers again. (Default: []) */ + layersToCut?: L.Layer[]; + } + + /** + * PM toolbar options. + */ + interface ToolbarOptions { + /** Toolbar position. */ + position?: L.ControlPosition; + + /** The position of each block can be customized. If not set, the value from position is taken. */ + positions?: BlockPositions; + + /** Adds button to draw Markers (default:true) */ + drawMarker?: boolean; + + /** Adds button to draw CircleMarkers (default:true) */ + drawCircleMarker?: boolean; + + /** Adds button to draw Line (default:true) */ + drawPolyline?: boolean; + + /** Adds button to draw Rectangle (default:true) */ + drawRectangle?: boolean; + + /** Adds button to draw Polygon (default:true) */ + drawPolygon?: boolean; + + /** Adds button to draw Circle (default:true) */ + drawCircle?: boolean; + + /** Adds button to toggle edit mode for all layers (default:true) */ + editMode?: boolean; + + /** Adds button to toggle drag mode for all layers (default:true) */ + dragMode?: boolean; + + /** Adds button to cut a hole in a polygon or line (default:true) */ + cutPolygon?: boolean; + + /** Adds a button to remove layers (default:true) */ + removalMode?: boolean; + + /** Adds a button to rotate layers (default:true) */ + rotateMode?: boolean; + + /** All buttons will be displayed as one block Customize Controls (default:false) */ + oneBlock?: boolean; + + /** Shows all draw buttons / buttons in the draw block (default:true) */ + drawControls?: boolean; + + /** Shows all edit buttons / buttons in the edit block (default:true) */ + editControls?: boolean; + + /** Shows all buttons in the custom block (default:true) */ + customControls?: boolean; + + /** Shows all options buttons / buttons in the option block ⭐ */ + optionsControls?: boolean; + + /** Adds a button to toggle the Pinning Option ⭐ */ + pinningOption?: boolean; + + /** Adds a button to toggle the Snapping Option ⭐ */ + snappingOption?: boolean; + } + + /** the position of each block. */ + interface BlockPositions { + /** Draw control position (default:''). '' also refers to this position. */ + draw?: L.ControlPosition; + + /** Edit control position (default:''). */ + edit?: L.ControlPosition; + + /** Custom control position (default:''). */ + custom?: L.ControlPosition; + + /** Options control position (default:'') ⭐ */ + options?: L.ControlPosition; + } + + interface PMEditLayer { + /** Enables edit mode. The passed options are preserved, even when the mode is enabled via the Toolbar */ + enable(options?: EditModeOptions): void; + + /** Sets layer options */ + setOptions(options?: EditModeOptions): void; + + /** Gets layer options */ + getOptions(): EditModeOptions; + + /** Disables edit mode. */ + disable(): void; + + /** Toggles edit mode. Passed options are preserved. */ + toggleEdit(options?: EditModeOptions): void; + + /** Returns true if edit mode is enabled. false when disabled. */ + enabled(): boolean; + + /** Returns true if Line or Polygon has a self intersection. */ + hasSelfIntersection(): boolean; + + /** Removes the layer with the same checks as GlobalRemovalMode. */ + remove(): void; + } + + interface PMDragLayer { + /** Enables dragging for the layer. */ + enableLayerDrag(): void; + + /** Disables dragging for the layer. */ + disableLayerDrag(): void; + + /** Returns if the layer is currently dragging. */ + dragging(): boolean; + + /** Returns if drag mode is enabled for the layer. */ + layerDragEnabled(): boolean; + } + + interface PMLayer extends PMRotateLayer, PMEditLayer, PMDragLayer { + /** Get shape of the layer. */ + getShape(): SUPPORTED_SHAPES; + } + + interface PMLayerGroup { + /** Enables edit mode for all child layers. The passed options are preserved, even when the mode is enabled via the Toolbar */ + enable(options?: EditModeOptions): void; + + /** Disable edit mode for all child layers. */ + disable(): void; + + /** Returns if minimum one layer is enabled. */ + enabled(): boolean; + + /** Toggle enable / disable on all layers. */ + toggleEdit(options?: EditModeOptions): void; + + /** Returns the layers of the LayerGroup. `deep=true` return also the children of LayerGroup children. */ + /** `filterGeoman=true` filter out layers that don't have Leaflet-Geoman or temporary stuff. */ + /** `filterGroupsOut=true` does not return the LayerGroup layers self. */ + /** (Default: `deep=false`,`filterGeoman=true`, `filterGroupsOut=true` ) */ + getLayers( + deep?: boolean, + filterGeoman?: boolean, + filterGroupsOut?: boolean + ): L.Layer[]; + + /** Apply Leaflet-Geoman options to all children. The passed options are preserved, even when the mode is enabled via the Toolbar */ + setOptions(options?: EditModeOptions): void; + + /** Returns the options of the LayerGroup. */ + getOptions(): EditModeOptions; + + /** Returns if currently a layer in the LayerGroup is dragging. */ + dragging(): boolean; + } + + namespace Utils { + /** Returns the translation of the passed path. path = json-string f.ex. tooltips.placeMarker */ + function getTranslation(path: string): string; + + /** Returns the middle LatLng between two LatLngs */ + function calcMiddleLatLng( + map: L.Map, + latlng1: L.LatLng, + latlng2: L.LatLng + ): L.LatLng; + + /** Returns all layers that are available for Geoman */ + function findLayers(map: L.Map): L.Layer[]; + + /** Converts a circle into a polygon with default 60 sides. For CRS.Simple maps `withBearing` needs to be false */ + function circleToPolygon( + circle: L.Circle, + sides?: number, + withBearing?: boolean + ): L.Polygon; + + /** Converts a px-radius (CircleMarker) to meter-radius (Circle). */ + /** The center LatLng is needed because the earth has different projections on different places. */ + function pxRadiusToMeterRadius( + radiusInPx: number, + map: L.Map, + center: L.LatLng + ): number; + } + + /** + * DRAW MODE MAP EVENT HANDLERS + */ + + export type GlobalDrawModeToggledEventHandler = (event: { + enabled: boolean; + shape: PM.SUPPORTED_SHAPES; + map: L.Map; + }) => void; + export type DrawStartEventHandler = (e: { + shape: PM.SUPPORTED_SHAPES; + workingLayer: L.Layer; + }) => void; + export type DrawEndEventHandler = (e: { + shape: PM.SUPPORTED_SHAPES; + }) => void; + export type CreateEventHandler = (e: { + shape: PM.SUPPORTED_SHAPES; + layer: L.Layer; + }) => void; + + /** + * DRAW MODE LAYER EVENT HANDLERS + */ + + export type VertexAddedEventHandler = (e: { + shape: PM.SUPPORTED_SHAPES; + workingLayer: L.Layer; + marker: L.Marker; + latlng: L.LatLng; + }) => void; + export type SnapEventHandler = (e: { + shape: PM.SUPPORTED_SHAPES; + distance: number; + layer: L.Layer; + workingLayer: L.Layer; + marker: L.Marker; + layerInteractedWith: L.Layer; + segement: any; + snapLatLng: L.LatLng; + }) => void; + export type CenterPlacedEventHandler = (e: { + shape: PM.SUPPORTED_SHAPES; + workingLayer: L.Layer; + latlng: L.LatLng; + }) => void; + + /** + * EDIT MODE LAYER EVENT HANDLERS + */ + + export type EditEventHandler = (e: { + shape: PM.SUPPORTED_SHAPES; + layer: L.Layer; + }) => void; + export type UpdateEventHandler = (e: { + shape: PM.SUPPORTED_SHAPES; + layer: L.Layer; + }) => void; + export type EnableEventHandler = (e: { + shape: PM.SUPPORTED_SHAPES; + layer: L.Layer; + }) => void; + export type DisableEventHandler = (e: { + shape: PM.SUPPORTED_SHAPES; + layer: L.Layer; + }) => void; + export type VertexAddedEventHandler2 = (e: { + layer: L.Layer; + indexPath: number; + latlng: L.LatLng; + marker: L.Marker; + shape: PM.SUPPORTED_SHAPES; + }) => void; + export type VertexRemovedEventHandler = (e: { + layer: L.Layer; + indexPath: number; + marker: L.Marker; + shape: PM.SUPPORTED_SHAPES; + }) => void; + export type VertexClickEventHandler = (e: { + layer: L.Layer; + indexPath: number; + markerEvent: any; + shape: PM.SUPPORTED_SHAPES; + }) => void; + export type MarkerDragStartEventHandler = (e: { + layer: L.Layer; + indexPath: number; + markerEvent: any; + shape: PM.SUPPORTED_SHAPES; + }) => void; + export type MarkerDragEventHandler = (e: { + layer: L.Layer; + indexPath: number; + markerEvent: any; + shape: PM.SUPPORTED_SHAPES; + }) => void; + export type MarkerDragEndEventHandler = (e: { + layer: L.Layer; + indexPath: number; + markerEvent: any; + shape: PM.SUPPORTED_SHAPES; + intersectionRest: boolean; + }) => void; + export type LayerResetEventHandler = (e: { + layer: L.Layer; + indexPath: number; + markerEvent: any; + shape: PM.SUPPORTED_SHAPES; + }) => void; + export type IntersectEventHandler = (e: { + shape: PM.SUPPORTED_SHAPES; + layer: L.Layer; + intersection: L.LatLng; + }) => void; + + /** + * EDIT MODE MAP EVENT HANDLERS + */ + export type GlobalEditModeToggledEventHandler = (event: { + enabled: boolean; + map: L.Map; + }) => void; + + /** + * DRAG MODE MAP EVENT HANDLERS + */ + export type GlobalDragModeToggledEventHandler = (event: { + enabled: boolean; + map: L.Map; + }) => void; + + /** + * DRAG MODE LAYER EVENT HANDLERS + */ + export type DragStartEventHandler = (e: { + layer: L.Layer; + shape: PM.SUPPORTED_SHAPES; + }) => void; + export type DragEventHandler = (e: { + layer: L.Layer; + containerPoint: any; + latlng: L.LatLng; + layerPoint: L.Point; + originalEvent: any; + shape: PM.SUPPORTED_SHAPES; + }) => void; + export type DragEndEventHandler = (e: { + layer: L.Layer; + shape: PM.SUPPORTED_SHAPES; + }) => void; + + /** + * REMOVE MODE LAYER EVENT HANDLERS + */ + + export type RemoveEventHandler = (e: { + layer: L.Layer; + shape: PM.SUPPORTED_SHAPES; + }) => void; + + /** + * REMOVE MODE MAP EVENT HANDLERS + */ + export type GlobalRemovalModeToggledEventHandler = (e: { + enabled: boolean; + map: L.Map; + }) => void; + + /** + * CUT MODE MAP EVENT HANDLERS + */ + export type GlobalCutModeToggledEventHandler = (e: { + enabled: boolean; + map: L.Map; + }) => void; + export type CutEventHandler = (e: { + layer: L.Layer; + originalLayer: L.Layer; + shape: PM.SUPPORTED_SHAPES; + }) => void; + + /** + * ROTATE MODE LAYER EVENT HANDLERS + */ + export type RotateEnableEventHandler = (e: { + layer: L.Layer; + helpLayer: L.Layer; + }) => void; + export type RotateDisableEventHandler = (e: { layer: L.Layer }) => void; + export type RotateStartEventHandler = (e: { + layer: L.Layer; + helpLayer: L.Layer; + startAngle: number; + originLatLngs: L.LatLng[]; + }) => void; + export type RotateEventHandler = (e: { + layer: L.Layer; + helpLayer: L.Layer; + startAngle: number; + angle: number; + angleDiff: number; + oldLatLngs: L.LatLng[]; + newLatLngs: L.LatLng[]; + }) => void; + export type RotateEndEventHandler = (e: { + layer: L.Layer; + helpLayer: L.Layer; + startAngle: number; + angle: number; + originLatLngs: L.LatLng[]; + newLatLngs: L.LatLng[]; + }) => void; + + /** + * ROTATE MODE MAP EVENT HANDLERS + */ + export type GlobalRotateModeToggledEventHandler = (e: { + enabled: boolean; + map: L.Map; + }) => void; + + /** + * TRANSLATION EVENT HANDLERS + */ + export type LangChangeEventHandler = (e: { + activeLang: string; + oldLang: string; + fallback: string; + translations: PM.Translations; + }) => void; + + /** + * CONTROL MAP EVENT HANDLERS + */ + export type ButtonClickEventHandler = (e: { + btnName: string; + button: PM.Button; + }) => void; + export type ActionClickEventHandler = (e: { + text: string; + action: string; + btnName: string; + button: PM.Button; + }) => void; + + /** + * KEYBOARD EVENT HANDLERS + */ + export type KeyboardKeyEventHandler = (e: { + focusOn: 'document' | 'map'; + eventType: 'keydown' | 'keyup'; + event: any; + }) => void; + } + namespace PM { interface PMMapToolbar { toggleButton( diff --git a/ui-ngx/tsconfig.json b/ui-ngx/tsconfig.json index 2243eae689..9963cadb75 100644 --- a/ui-ngx/tsconfig.json +++ b/ui-ngx/tsconfig.json @@ -23,7 +23,6 @@ "src/typings/jquery.flot.typings.d.ts", "src/typings/jquery.jstree.typings.d.ts", "src/typings/split.js.typings.d.ts", - "node_modules/@geoman-io/leaflet-geoman-free/dist/leaflet-geoman.d.ts", "src/typings/leaflet-geoman-extend.d.ts" ], "paths": { From 73a55a2c34f1d2d818a456669f67eff76781e0ef Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Mon, 6 Dec 2021 16:24:33 +0200 Subject: [PATCH 212/432] Ignore no longer valid messages when processing strategy is completed or timed-out. --- .../actors/ruleChain/DefaultTbContext.java | 10 +++++++ .../RuleChainActorMessageProcessor.java | 28 +++++++++++++++---- .../actors/ruleChain/RuleNodeActor.java | 14 ++++++++-- .../RuleNodeActorMessageProcessor.java | 4 +-- .../actors/shared/ComponentMsgProcessor.java | 12 +++++++- .../service/queue/TbMsgPackCallback.java | 5 ++++ .../queue/TbMsgPackProcessingContext.java | 3 ++ .../thingsboard/server/common/msg/TbMsg.java | 10 ++++++- .../common/msg/queue/TbMsgCallback.java | 14 +++++++++- 9 files changed, 87 insertions(+), 13 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/actors/ruleChain/DefaultTbContext.java b/application/src/main/java/org/thingsboard/server/actors/ruleChain/DefaultTbContext.java index 38d6f4bccb..609c087a51 100644 --- a/application/src/main/java/org/thingsboard/server/actors/ruleChain/DefaultTbContext.java +++ b/application/src/main/java/org/thingsboard/server/actors/ruleChain/DefaultTbContext.java @@ -167,6 +167,11 @@ class DefaultTbContext implements TbContext { } private void enqueue(TopicPartitionInfo tpi, TbMsg tbMsg, Consumer onFailure, Runnable onSuccess) { + if (!tbMsg.isValid()) { + log.trace("[{}] Skip invalid message: {}", getTenantId(), tbMsg); + onFailure.accept(new IllegalArgumentException("Source message is no longer valid!")); + return; + } TransportProtos.ToRuleEngineMsg msg = TransportProtos.ToRuleEngineMsg.newBuilder() .setTenantIdMSB(getTenantId().getId().getMostSignificantBits()) .setTenantIdLSB(getTenantId().getId().getLeastSignificantBits()) @@ -235,6 +240,11 @@ class DefaultTbContext implements TbContext { } private void enqueueForTellNext(TopicPartitionInfo tpi, String queueName, TbMsg source, Set relationTypes, String failureMessage, Runnable onSuccess, Consumer onFailure) { + if (!source.isValid()) { + log.trace("[{}] Skip invalid message: {}", getTenantId(), source); + onFailure.accept(new IllegalArgumentException("Source message is no longer valid!")); + return; + } RuleChainId ruleChainId = nodeCtx.getSelf().getRuleChainId(); RuleNodeId ruleNodeId = nodeCtx.getSelf().getId(); TbMsg tbMsg = TbMsg.newMsg(source, queueName, ruleChainId, ruleNodeId); diff --git a/application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleChainActorMessageProcessor.java b/application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleChainActorMessageProcessor.java index 88a4f6a202..6f6ea8fcec 100644 --- a/application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleChainActorMessageProcessor.java +++ b/application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleChainActorMessageProcessor.java @@ -200,17 +200,20 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor relationTypes, String failureMessage) { try { - checkActive(msg); + checkComponentStateActive(msg); EntityId entityId = msg.getOriginator(); TopicPartitionInfo tpi = systemContext.resolve(ServiceType.TB_RULE_ENGINE, msg.getQueueName(), tenantId, entityId); diff --git a/application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleNodeActor.java b/application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleNodeActor.java index 8fef00c49c..60f462f4d4 100644 --- a/application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleNodeActor.java +++ b/application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleNodeActor.java @@ -27,6 +27,7 @@ import org.thingsboard.server.common.data.id.RuleChainId; import org.thingsboard.server.common.data.id.RuleNodeId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.msg.TbActorMsg; +import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg; import org.thingsboard.server.common.msg.queue.PartitionChangeMsg; @@ -86,12 +87,19 @@ public class RuleNodeActor extends ComponentActor extends Abstract schedulePeriodicMsgWithDelay(context, new StatsPersistTick(), statsPersistFrequency, statsPersistFrequency); } - protected void checkActive(TbMsg tbMsg) throws RuleNodeException { + protected boolean checkMsgValid(TbMsg tbMsg) { + var valid = tbMsg.isValid(); + if (!valid) { + if (log.isTraceEnabled()) { + log.trace("Skip processing of message: {} because it is no longer valid!", tbMsg); + } + } + return valid; + } + + protected void checkComponentStateActive(TbMsg tbMsg) throws RuleNodeException { if (state != ComponentLifecycleState.ACTIVE) { log.debug("Component is not active. Current state [{}] for processor [{}][{}] tenant [{}]", state, entityId.getEntityType(), entityId, tenantId); RuleNodeException ruleNodeException = getInactiveException(); diff --git a/application/src/main/java/org/thingsboard/server/service/queue/TbMsgPackCallback.java b/application/src/main/java/org/thingsboard/server/service/queue/TbMsgPackCallback.java index eff1ecaf86..e3ce0927ef 100644 --- a/application/src/main/java/org/thingsboard/server/service/queue/TbMsgPackCallback.java +++ b/application/src/main/java/org/thingsboard/server/service/queue/TbMsgPackCallback.java @@ -66,6 +66,11 @@ public class TbMsgPackCallback implements TbMsgCallback { ctx.onFailure(tenantId, id, e); } + @Override + public boolean isMsgValid() { + return !ctx.isComplete(); + } + @Override public void onProcessingStart(RuleNodeInfo ruleNodeInfo) { log.trace("[{}] ON PROCESSING START: {}", id, ruleNodeInfo); diff --git a/application/src/main/java/org/thingsboard/server/service/queue/TbMsgPackProcessingContext.java b/application/src/main/java/org/thingsboard/server/service/queue/TbMsgPackProcessingContext.java index d7a064c4ca..62285a411c 100644 --- a/application/src/main/java/org/thingsboard/server/service/queue/TbMsgPackProcessingContext.java +++ b/application/src/main/java/org/thingsboard/server/service/queue/TbMsgPackProcessingContext.java @@ -53,6 +53,8 @@ public class TbMsgPackProcessingContext { private final ConcurrentMap exceptionsMap = new ConcurrentHashMap<>(); private final ConcurrentMap lastRuleNodeMap = new ConcurrentHashMap<>(); + @Getter + private volatile boolean complete = false; public TbMsgPackProcessingContext(String queueName, TbRuleEngineSubmitStrategy submitStrategy) { this.queueName = queueName; @@ -149,6 +151,7 @@ public class TbMsgPackProcessingContext { } public void cleanup() { + complete = true; pendingMap.clear(); successMap.clear(); failedMap.clear(); diff --git a/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsg.java b/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsg.java index 63c148b951..7c77d8a06b 100644 --- a/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsg.java +++ b/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsg.java @@ -269,7 +269,7 @@ public final class TbMsg implements Serializable { } public TbMsgCallback getCallback() { - //May be null in case of deserialization; + // May be null in case of deserialization; if (callback != null) { return callback; } else { @@ -288,4 +288,12 @@ public final class TbMsg implements Serializable { public TbMsgProcessingStackItem popFormStack() { return ctx.pop(); } + + /** + * Checks if the message is still valid for processing. May be invalid if the message pack is timed-out or canceled. + * @return 'true' if message is valid for processing, 'false' otherwise. + */ + public boolean isValid() { + return getCallback().isMsgValid(); + } } diff --git a/common/message/src/main/java/org/thingsboard/server/common/msg/queue/TbMsgCallback.java b/common/message/src/main/java/org/thingsboard/server/common/msg/queue/TbMsgCallback.java index fd62df83c9..2bab1e8340 100644 --- a/common/message/src/main/java/org/thingsboard/server/common/msg/queue/TbMsgCallback.java +++ b/common/message/src/main/java/org/thingsboard/server/common/msg/queue/TbMsgCallback.java @@ -17,6 +17,9 @@ package org.thingsboard.server.common.msg.queue; import org.thingsboard.server.common.data.id.RuleNodeId; +/** + * Should be renamed to TbMsgPackContext, but this can't be changed due to backward-compatibility. + */ public interface TbMsgCallback { TbMsgCallback EMPTY = new TbMsgCallback() { @@ -36,11 +39,20 @@ public interface TbMsgCallback { void onFailure(RuleEngineException e); + /** + * Returns 'true' if rule engine is expecting the message to be processed, 'false' otherwise. + * message may no longer be valid, if the message pack is already expired/canceled/failed. + * + * @return 'true' if rule engine is expecting the message to be processed, 'false' otherwise. + */ + default boolean isMsgValid() { + return true; + } + default void onProcessingStart(RuleNodeInfo ruleNodeInfo) { } default void onProcessingEnd(RuleNodeId ruleNodeId) { } - } From 8065684831045bc183bbc01bbf5f01caa66a73eb Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Tue, 7 Dec 2021 15:52:37 +0200 Subject: [PATCH 213/432] Fix resolve alias filter for query alias types --- ui-ngx/src/app/core/http/entity.service.ts | 24 ++++------------------ 1 file changed, 4 insertions(+), 20 deletions(-) diff --git a/ui-ngx/src/app/core/http/entity.service.ts b/ui-ngx/src/app/core/http/entity.service.ts index 3346d5ce83..2b71df5a0e 100644 --- a/ui-ngx/src/app/core/http/entity.service.ts +++ b/ui-ngx/src/app/core/http/entity.service.ts @@ -906,28 +906,12 @@ export class EntityService { result.entityFilter = deepClone(filter); return of(result); case AliasFilterType.relationsQuery: - result.stateEntity = filter.rootStateEntity; - let rootEntityType; - let rootEntityId; - if (result.stateEntity && stateEntityId) { - rootEntityType = stateEntityId.entityType; - rootEntityId = stateEntityId.id; - } else if (!result.stateEntity) { - rootEntityType = filter.rootEntity.entityType; - rootEntityId = filter.rootEntity.id; - } - if (rootEntityType && rootEntityId) { - const relationQueryRootEntityId = this.resolveAliasEntityId(rootEntityType, rootEntityId); - result.entityFilter = deepClone(filter); - result.entityFilter.rootEntity = relationQueryRootEntityId; - return of(result); - } else { - return of(result); - } case AliasFilterType.assetSearchQuery: case AliasFilterType.deviceSearchQuery: case AliasFilterType.edgeSearchQuery: case AliasFilterType.entityViewSearchQuery: + let rootEntityType; + let rootEntityId; result.stateEntity = filter.rootStateEntity; if (result.stateEntity && stateEntityId) { rootEntityType = stateEntityId.entityType; @@ -937,9 +921,9 @@ export class EntityService { rootEntityId = filter.rootEntity.id; } if (rootEntityType && rootEntityId) { - const searchQueryRootEntityId = this.resolveAliasEntityId(rootEntityType, rootEntityId); + const queryRootEntityId = this.resolveAliasEntityId(rootEntityType, rootEntityId); result.entityFilter = deepClone(filter); - result.entityFilter.rootEntity = searchQueryRootEntityId; + result.entityFilter.rootEntity = queryRootEntityId; return of(result); } else { return of(result); From c628957ec8f4084a0dc089015bd0af5963dca36d Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Tue, 7 Dec 2021 18:44:58 +0200 Subject: [PATCH 214/432] Update ngx-flowchart --- ui-ngx/package.json | 2 +- .../home/pages/rulechain/rulechain-page.component.ts | 2 +- .../modules/home/pages/rulechain/rulechain-page.models.ts | 2 +- .../app/modules/home/pages/rulechain/rulechain.module.ts | 2 +- .../modules/home/pages/rulechain/rulenode.component.ts | 2 +- ui-ngx/src/app/shared/models/rule-node.models.ts | 2 +- ui-ngx/src/app/shared/shared.module.ts | 2 +- ui-ngx/yarn.lock | 8 ++++---- 8 files changed, 11 insertions(+), 11 deletions(-) diff --git a/ui-ngx/package.json b/ui-ngx/package.json index 1256edc46c..adec5e815a 100644 --- a/ui-ngx/package.json +++ b/ui-ngx/package.json @@ -69,7 +69,7 @@ "ngx-color-picker": "^11.0.0", "ngx-daterangepicker-material": "^5.0.1", "ngx-drag-drop": "^2.0.0", - "ngx-flowchart": "git://github.com/thingsboard/ngx-flowchart.git#master", + "ngx-flowchart": "git://github.com/thingsboard/ngx-flowchart.git#release/1.0.0", "ngx-hm-carousel": "^2.0.1", "ngx-markdown": "^12.0.1", "ngx-sharebuttons": "^9.0.0", diff --git a/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.ts b/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.ts index ea9cc54747..cc2c6c903d 100644 --- a/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.ts +++ b/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.ts @@ -50,7 +50,7 @@ import { RuleChainMetaData, ruleChainNodeComponent, RuleChainType } from '@shared/models/rule-chain.models'; -import { FcItemInfo, FlowchartConstants, NgxFlowchartComponent, UserCallbacks } from 'ngx-flowchart/dist/ngx-flowchart'; +import { FcItemInfo, FlowchartConstants, NgxFlowchartComponent, UserCallbacks } from 'ngx-flowchart'; import { FcRuleEdge, FcRuleNode, diff --git a/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.models.ts b/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.models.ts index b6ff534cf6..40a2f4cf28 100644 --- a/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.models.ts +++ b/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.models.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { FcModel } from 'ngx-flowchart/dist/ngx-flowchart'; +import { FcModel } from 'ngx-flowchart'; import { FcRuleEdge, FcRuleNode, FcRuleNodeType } from '@shared/models/rule-node.models'; export interface FcRuleNodeTypeModel extends FcModel { diff --git a/ui-ngx/src/app/modules/home/pages/rulechain/rulechain.module.ts b/ui-ngx/src/app/modules/home/pages/rulechain/rulechain.module.ts index 621149c7a8..95bb4bf3f8 100644 --- a/ui-ngx/src/app/modules/home/pages/rulechain/rulechain.module.ts +++ b/ui-ngx/src/app/modules/home/pages/rulechain/rulechain.module.ts @@ -27,7 +27,7 @@ import { RuleChainPageComponent } from './rulechain-page.component'; import { RuleNodeComponent } from '@home/pages/rulechain/rulenode.component'; -import { FC_NODE_COMPONENT_CONFIG } from 'ngx-flowchart/dist/ngx-flowchart'; +import { FC_NODE_COMPONENT_CONFIG } from 'ngx-flowchart'; import { RuleNodeDetailsComponent } from './rule-node-details.component'; import { RuleNodeLinkComponent } from './rule-node-link.component'; import { LinkLabelsComponent } from '@home/pages/rulechain/link-labels.component'; diff --git a/ui-ngx/src/app/modules/home/pages/rulechain/rulenode.component.ts b/ui-ngx/src/app/modules/home/pages/rulechain/rulenode.component.ts index 03d5d17f55..ce7ff340d5 100644 --- a/ui-ngx/src/app/modules/home/pages/rulechain/rulenode.component.ts +++ b/ui-ngx/src/app/modules/home/pages/rulechain/rulenode.component.ts @@ -16,7 +16,7 @@ import { DomSanitizer, SafeResourceUrl } from '@angular/platform-browser'; import { Component, OnInit } from '@angular/core'; -import { FcNodeComponent } from 'ngx-flowchart/dist/ngx-flowchart'; +import { FcNodeComponent } from 'ngx-flowchart'; import { FcRuleNode, RuleNodeType } from '@shared/models/rule-node.models'; import { Router } from '@angular/router'; import { RuleChainType } from '@app/shared/models/rule-chain.models'; diff --git a/ui-ngx/src/app/shared/models/rule-node.models.ts b/ui-ngx/src/app/shared/models/rule-node.models.ts index 489c6eef10..097f8b2edc 100644 --- a/ui-ngx/src/app/shared/models/rule-node.models.ts +++ b/ui-ngx/src/app/shared/models/rule-node.models.ts @@ -18,7 +18,7 @@ import { BaseData } from '@shared/models/base-data'; import { RuleChainId } from '@shared/models/id/rule-chain-id'; import { RuleNodeId } from '@shared/models/id/rule-node-id'; import { ComponentDescriptor } from '@shared/models/component-descriptor.models'; -import { FcEdge, FcNode } from 'ngx-flowchart/dist/ngx-flowchart'; +import { FcEdge, FcNode } from 'ngx-flowchart'; import { Observable } from 'rxjs'; import { PageComponent } from '@shared/components/page.component'; import { AfterViewInit, EventEmitter, Inject, OnInit, Directive } from '@angular/core'; diff --git a/ui-ngx/src/app/shared/shared.module.ts b/ui-ngx/src/app/shared/shared.module.ts index 50ffdafa65..1f66aedf47 100644 --- a/ui-ngx/src/app/shared/shared.module.ts +++ b/ui-ngx/src/app/shared/shared.module.ts @@ -21,7 +21,7 @@ import { LogoComponent } from '@shared/components/logo.component'; import { TbSnackBarComponent, ToastDirective } from '@shared/components/toast.directive'; import { BreadcrumbComponent } from '@shared/components/breadcrumb.component'; import { FlowInjectionToken, NgxFlowModule } from '@flowjs/ngx-flow'; -import { NgxFlowchartModule } from 'ngx-flowchart/dist/ngx-flowchart'; +import { NgxFlowchartModule } from 'ngx-flowchart'; import Flow from '@flowjs/flow.js'; import { MatAutocompleteModule } from '@angular/material/autocomplete'; diff --git a/ui-ngx/yarn.lock b/ui-ngx/yarn.lock index ba822f9116..f1e5a9abc9 100644 --- a/ui-ngx/yarn.lock +++ b/ui-ngx/yarn.lock @@ -6653,11 +6653,11 @@ ngx-drag-drop@^2.0.0: dependencies: tslib "^1.9.0" -"ngx-flowchart@git://github.com/thingsboard/ngx-flowchart.git#master": - version "0.0.0" - resolved "git://github.com/thingsboard/ngx-flowchart.git#078bfd2cedeeab412dee922e8066a19be6da7278" +"ngx-flowchart@git://github.com/thingsboard/ngx-flowchart.git#release/1.0.0": + version "0.0.1" + resolved "git://github.com/thingsboard/ngx-flowchart.git#aac96f7e0490a386d58864d7819873e7c63cbb48" dependencies: - tslib "^1.13.0" + tslib "^2.2.0" ngx-hm-carousel@^2.0.1: version "2.0.1" From d3c20b2e57494ab5fc828c797359da8d816c7148 Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Tue, 7 Dec 2021 18:50:16 +0200 Subject: [PATCH 215/432] Alarm Query performance improvements --- .../main/data/upgrade/3.3.2/schema_update.sql | 29 ++++++ .../install/ThingsboardInstallService.java | 4 + .../install/SqlDatabaseUpgradeService.java | 22 +++++ .../server/common/data/alarm/EntityAlarm.java | 40 ++++++++ .../data/relation/RelationTypeGroup.java | 1 - .../server/dao/alarm/AlarmDao.java | 5 + .../server/dao/alarm/BaseAlarmService.java | 27 ++--- .../dao/entityview/EntityViewServiceImpl.java | 1 - .../server/dao/model/ModelConstants.java | 1 + .../model/sql/EntityAlarmCompositeKey.java | 42 ++++++++ .../dao/model/sql/EntityAlarmEntity.java | 99 +++++++++++++++++++ .../server/dao/sql/alarm/AlarmRepository.java | 55 ++++------- .../dao/sql/alarm/EntityAlarmRepository.java | 29 ++++++ .../server/dao/sql/alarm/JpaAlarmDao.java | 16 ++- .../query/DefaultAlarmQueryRepository.java | 21 ++-- .../sql/query/DefaultQueryLogComponent.java | 2 +- .../resources/sql/schema-entities-hsql.sql | 12 +++ .../resources/sql/schema-entities-idx.sql | 4 + .../main/resources/sql/schema-entities.sql | 12 +++ .../dao/service/BaseAlarmServiceTest.java | 19 ---- .../resources/sql/hsql/drop-all-tables.sql | 1 + .../resources/sql/psql/drop-all-tables.sql | 1 + .../sql/timescale/drop-all-tables.sql | 1 + 23 files changed, 366 insertions(+), 78 deletions(-) create mode 100644 application/src/main/data/upgrade/3.3.2/schema_update.sql create mode 100644 common/data/src/main/java/org/thingsboard/server/common/data/alarm/EntityAlarm.java create mode 100644 dao/src/main/java/org/thingsboard/server/dao/model/sql/EntityAlarmCompositeKey.java create mode 100644 dao/src/main/java/org/thingsboard/server/dao/model/sql/EntityAlarmEntity.java create mode 100644 dao/src/main/java/org/thingsboard/server/dao/sql/alarm/EntityAlarmRepository.java diff --git a/application/src/main/data/upgrade/3.3.2/schema_update.sql b/application/src/main/data/upgrade/3.3.2/schema_update.sql new file mode 100644 index 0000000000..99d2294129 --- /dev/null +++ b/application/src/main/data/upgrade/3.3.2/schema_update.sql @@ -0,0 +1,29 @@ +-- +-- Copyright © 2016-2021 The Thingsboard Authors +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- + +CREATE TABLE IF NOT EXISTS entity_alarm ( + tenant_id uuid NOT NULL, + entity_id uuid NOT NULL, + created_time bigint NOT NULL, + type varchar(255) NOT NULL, + customer_id uuid, + alarm_id uuid + CONSTRAINT entity_alarm_pkey PRIMARY KEY(entity_id, alarm_id), + CONSTRAINT fk_entity_alarm_id FOREIGN KEY (alarm_id) REFERENCES alarm(id) ON DELETE CASCADE +); + +CREATE INDEX IF NOT EXISTS idx_alarm_tenant_status_created_time ON alarm(tenant_id, status, created_time DESC); +CREATE INDEX IF NOT EXISTS idx_entity_alarm_created_time ON entity_alarm(tenant_id, entity_id, created_time DESC); diff --git a/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java b/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java index ccdac8b363..5b1bee8538 100644 --- a/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java +++ b/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java @@ -210,6 +210,10 @@ public class ThingsboardInstallService { log.info("Upgrading ThingsBoard from version 3.3.0 to 3.3.1 ..."); case "3.3.1": log.info("Upgrading ThingsBoard from version 3.3.1 to 3.3.2 ..."); + break; + case "3.3.2": + log.info("Upgrading ThingsBoard from version 3.3.2 to 3.3.3 ..."); + databaseEntitiesUpgradeService.upgradeDatabase("3.3.2"); log.info("Updating system data..."); systemDataLoaderService.updateSystemWidgets(); break; diff --git a/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java b/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java index fcb9632020..3f9bec2d07 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java @@ -469,6 +469,28 @@ public class SqlDatabaseUpgradeService implements DatabaseEntitiesUpgradeService log.error("Failed updating schema!!!", e); } break; + case "3.3.2": + try (Connection conn = DriverManager.getConnection(dbUrl, dbUserName, dbPassword)) { + log.info("Updating schema ..."); + schemaUpdateFile = Paths.get(installScripts.getDataDir(), "upgrade", "3.3.2", SCHEMA_UPDATE_SQL); + loadSql(schemaUpdateFile, conn); + try { + conn.createStatement().execute("insert into entity_alarm(tenant_id, entity_id, created_time, type, customer_id, alarm_id, status, severity)" + + " select tenant_id, originator_id, created_time, type, customer_id, id, status, severity from alarm;"); + conn.createStatement().execute("insert into entity_alarm(tenant_id, entity_id, created_time, type, customer_id, alarm_id, status, severity)" + + " select a.tenant_id, r.from_id, created_time, type, customer_id, id, status, severity" + + " from alarm a inner join relation r on r.relation_type_group = 'ALARM' and r.relation_type = 'ANY' and a.id = r.to_id ON CONFLICT DO NOTHING;"); + conn.createStatement().execute("delete from relation r where r.relation_type_group = 'ALARM';"); + } catch (Exception e) { + log.error("Failed to update alarm relations!!!", e); + } + log.info("Updating schema settings..."); + conn.createStatement().execute("UPDATE tb_schema_settings SET schema_version = 3003003;"); + log.info("Schema updated."); + } catch (Exception e) { + log.error("Failed updating schema!!!", e); + } + break; default: throw new RuntimeException("Unable to upgrade SQL database, unsupported fromVersion: " + fromVersion); } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/alarm/EntityAlarm.java b/common/data/src/main/java/org/thingsboard/server/common/data/alarm/EntityAlarm.java new file mode 100644 index 0000000000..f6d4a0e2c7 --- /dev/null +++ b/common/data/src/main/java/org/thingsboard/server/common/data/alarm/EntityAlarm.java @@ -0,0 +1,40 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.common.data.alarm; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.thingsboard.server.common.data.HasTenantId; +import org.thingsboard.server.common.data.id.AlarmId; +import org.thingsboard.server.common.data.id.CustomerId; +import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.id.TenantId; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class EntityAlarm implements HasTenantId { + + private TenantId tenantId; + private EntityId entityId; + private long createdTime; + private String alarmType; + + private CustomerId customerId; + private AlarmId alarmId; + +} diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/relation/RelationTypeGroup.java b/common/data/src/main/java/org/thingsboard/server/common/data/relation/RelationTypeGroup.java index c6ca10088d..c35a1dfd1a 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/relation/RelationTypeGroup.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/relation/RelationTypeGroup.java @@ -18,7 +18,6 @@ package org.thingsboard.server.common.data.relation; public enum RelationTypeGroup { COMMON, - ALARM, DASHBOARD, RULE_CHAIN, RULE_NODE, diff --git a/dao/src/main/java/org/thingsboard/server/dao/alarm/AlarmDao.java b/dao/src/main/java/org/thingsboard/server/dao/alarm/AlarmDao.java index 3b10f624d7..8918b7cc1f 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/alarm/AlarmDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/alarm/AlarmDao.java @@ -21,6 +21,7 @@ import org.thingsboard.server.common.data.alarm.AlarmInfo; import org.thingsboard.server.common.data.alarm.AlarmQuery; import org.thingsboard.server.common.data.alarm.AlarmSeverity; import org.thingsboard.server.common.data.alarm.AlarmStatus; +import org.thingsboard.server.common.data.alarm.EntityAlarm; import org.thingsboard.server.common.data.id.AlarmId; import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.EntityId; @@ -32,6 +33,7 @@ import org.thingsboard.server.common.data.query.AlarmDataQuery; import org.thingsboard.server.dao.Dao; import java.util.Collection; +import java.util.List; import java.util.Set; import java.util.UUID; @@ -59,4 +61,7 @@ public interface AlarmDao extends Dao { PageData findAlarmsIdsByEndTsBeforeAndTenantId(Long time, TenantId tenantId, PageLink pageLink); + void createEntityAlarmRecord(EntityAlarm entityAlarm); + + List findEntityAlarmRecords(TenantId tenantId, AlarmId id); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java b/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java index 90d988c20b..64874eff7d 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java @@ -34,6 +34,7 @@ import org.thingsboard.server.common.data.alarm.AlarmQuery; import org.thingsboard.server.common.data.alarm.AlarmSearchStatus; import org.thingsboard.server.common.data.alarm.AlarmSeverity; import org.thingsboard.server.common.data.alarm.AlarmStatus; +import org.thingsboard.server.common.data.alarm.EntityAlarm; import org.thingsboard.server.common.data.exception.ApiUsageLimitsExceededException; import org.thingsboard.server.common.data.id.AlarmId; import org.thingsboard.server.common.data.id.CustomerId; @@ -166,23 +167,24 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ private AlarmOperationResult createAlarm(Alarm alarm) throws InterruptedException, ExecutionException { log.debug("New Alarm : {}", alarm); Alarm saved = alarmDao.save(alarm.getTenantId(), alarm); - List propagatedEntitiesList = createAlarmRelations(saved); + List propagatedEntitiesList = createEntityAlarmRecords(saved); return new AlarmOperationResult(saved, true, true, propagatedEntitiesList); } - private List createAlarmRelations(Alarm alarm) throws InterruptedException, ExecutionException { + private List createEntityAlarmRecords(Alarm alarm) throws InterruptedException, ExecutionException { List propagatedEntitiesList; if (alarm.isPropagate()) { Set parentEntities = getParentEntities(alarm); propagatedEntitiesList = new ArrayList<>(parentEntities.size() + 1); for (EntityId parentId : parentEntities) { propagatedEntitiesList.add(parentId); - createAlarmRelation(alarm.getTenantId(), parentId, alarm.getId()); + createEntityAlarmRecord(alarm.getTenantId(), parentId, alarm); } propagatedEntitiesList.add(alarm.getOriginator()); } else { propagatedEntitiesList = Collections.singletonList(alarm.getOriginator()); } + createEntityAlarmRecord(alarm.getTenantId(), alarm.getOriginator(), alarm); return propagatedEntitiesList; } @@ -221,7 +223,7 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ List propagatedEntitiesList; if (!oldPropagate && newPropagate) { try { - propagatedEntitiesList = createAlarmRelations(result); + propagatedEntitiesList = createEntityAlarmRecords(result); } catch (InterruptedException | ExecutionException e) { log.warn("Failed to update alarm relations [{}]", result, e); throw new RuntimeException(e); @@ -382,17 +384,20 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ private Set getPropagationEntityIds(Alarm alarm) { if (alarm.isPropagate()) { - List relations = relationService.findByTo(alarm.getTenantId(), alarm.getId(), RelationTypeGroup.ALARM); - Set propagationEntityIds = relations.stream().map(EntityRelation::getFrom).collect(Collectors.toSet()); - propagationEntityIds.add(alarm.getOriginator()); - return propagationEntityIds; + List entityAlarms = alarmDao.findEntityAlarmRecords(alarm.getTenantId(), alarm.getId()); + return entityAlarms.stream().map(EntityAlarm::getEntityId).collect(Collectors.toSet()); } else { return Collections.singleton(alarm.getOriginator()); } } - private void createAlarmRelation(TenantId tenantId, EntityId entityId, EntityId alarmId) { - createRelation(tenantId, new EntityRelation(entityId, alarmId, AlarmSearchStatus.ANY.name(), RelationTypeGroup.ALARM)); + private void createEntityAlarmRecord(TenantId tenantId, EntityId entityId, Alarm alarm) { + EntityAlarm entityAlarm = new EntityAlarm(tenantId, entityId, alarm.getCreatedTime(), alarm.getType(), alarm.getCustomerId(), alarm.getId()); + try { + alarmDao.createEntityAlarmRecord(entityAlarm); + } catch (Exception e) { + log.warn("[{}] Failed to create entity alarm record: {}", tenantId, entityAlarm, e); + } } private ListenableFuture getAndUpdate(TenantId tenantId, AlarmId alarmId, Function function) { @@ -402,7 +407,7 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ } private DataValidator alarmDataValidator = - new DataValidator() { + new DataValidator<>() { @Override protected void validateDataImpl(TenantId tenantId, Alarm alarm) { diff --git a/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewServiceImpl.java index 304b04a33d..33ea3d635f 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewServiceImpl.java @@ -44,7 +44,6 @@ import org.thingsboard.server.common.data.id.EntityViewId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; -import org.thingsboard.server.common.data.page.TimePageLink; import org.thingsboard.server.common.data.relation.EntityRelation; import org.thingsboard.server.common.data.relation.EntitySearchDirection; import org.thingsboard.server.common.data.relation.RelationTypeGroup; diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java b/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java index e8e90f2d3c..6f7a3c2567 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java @@ -257,6 +257,7 @@ public class ModelConstants { /** * Cassandra alarm constants. */ + public static final String ENTITY_ALARM_COLUMN_FAMILY_NAME = "entity_alarm"; public static final String ALARM_COLUMN_FAMILY_NAME = "alarm"; public static final String ALARM_TENANT_ID_PROPERTY = TENANT_ID_PROPERTY; public static final String ALARM_CUSTOMER_ID_PROPERTY = CUSTOMER_ID_PROPERTY; diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/EntityAlarmCompositeKey.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/EntityAlarmCompositeKey.java new file mode 100644 index 0000000000..69152418b8 --- /dev/null +++ b/dao/src/main/java/org/thingsboard/server/dao/model/sql/EntityAlarmCompositeKey.java @@ -0,0 +1,42 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.dao.model.sql; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.thingsboard.server.common.data.alarm.EntityAlarm; + +import javax.persistence.Transient; +import java.io.Serializable; +import java.util.UUID; + +@NoArgsConstructor +@AllArgsConstructor +@Data +public class EntityAlarmCompositeKey implements Serializable { + + @Transient + private static final long serialVersionUID = -245388185894468450L; + + private UUID entityId; + private UUID alarmId; + + public EntityAlarmCompositeKey(EntityAlarm entityAlarm) { + this.entityId = entityAlarm.getEntityId().getId(); + this.alarmId = entityAlarm.getAlarmId().getId(); + } +} diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/EntityAlarmEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/EntityAlarmEntity.java new file mode 100644 index 0000000000..50d57cf61c --- /dev/null +++ b/dao/src/main/java/org/thingsboard/server/dao/model/sql/EntityAlarmEntity.java @@ -0,0 +1,99 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.dao.model.sql; + +import lombok.Data; +import org.thingsboard.server.common.data.alarm.EntityAlarm; +import org.thingsboard.server.common.data.id.AlarmId; +import org.thingsboard.server.common.data.id.CustomerId; +import org.thingsboard.server.common.data.id.EntityIdFactory; +import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.dao.model.ToData; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.IdClass; +import javax.persistence.Table; +import java.util.UUID; + +import static org.thingsboard.server.dao.model.ModelConstants.CREATED_TIME_PROPERTY; +import static org.thingsboard.server.dao.model.ModelConstants.CUSTOMER_ID_PROPERTY; +import static org.thingsboard.server.dao.model.ModelConstants.ENTITY_ALARM_COLUMN_FAMILY_NAME; +import static org.thingsboard.server.dao.model.ModelConstants.ENTITY_ID_COLUMN; +import static org.thingsboard.server.dao.model.ModelConstants.ENTITY_TYPE_COLUMN; +import static org.thingsboard.server.dao.model.ModelConstants.TENANT_ID_COLUMN; + +@Data +@Entity +@Table(name = ENTITY_ALARM_COLUMN_FAMILY_NAME) +@IdClass(EntityAlarmCompositeKey.class) +public final class EntityAlarmEntity implements ToData { + + @Column(name = TENANT_ID_COLUMN, columnDefinition = "uuid") + private UUID tenantId; + + @Column(name = ENTITY_TYPE_COLUMN) + private String entityType; + + @Id + @Column(name = ENTITY_ID_COLUMN, columnDefinition = "uuid") + private UUID entityId; + + @Id + @Column(name = "alarm_id", columnDefinition = "uuid") + private UUID alarmId; + + @Column(name = CREATED_TIME_PROPERTY) + private long createdTime; + + @Column(name = "alarm_type") + private String alarmType; + + @Column(name = CUSTOMER_ID_PROPERTY, columnDefinition = "uuid") + private UUID customerId; + + public EntityAlarmEntity() { + super(); + } + + public EntityAlarmEntity(EntityAlarm entityAlarm) { + tenantId = entityAlarm.getTenantId().getId(); + entityId = entityAlarm.getEntityId().getId(); + entityType = entityAlarm.getEntityId().getEntityType().name(); + alarmId = entityAlarm.getAlarmId().getId(); + alarmType = entityAlarm.getAlarmType(); + createdTime = entityAlarm.getCreatedTime(); + if (entityAlarm.getCustomerId() != null) { + customerId = entityAlarm.getCustomerId().getId(); + } + } + + @Override + public EntityAlarm toData() { + EntityAlarm result = new EntityAlarm(); + result.setTenantId(new TenantId(tenantId)); + result.setEntityId(EntityIdFactory.getByTypeAndUuid(entityType, entityId)); + result.setAlarmId(new AlarmId(alarmId)); + result.setAlarmType(alarmType); + result.setCreatedTime(createdTime); + if (customerId != null) { + result.setCustomerId(new CustomerId(customerId)); + } + return result; + } + +} \ No newline at end of file diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/AlarmRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/AlarmRepository.java index a67e29bac0..0152ef058d 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/AlarmRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/AlarmRepository.java @@ -42,47 +42,28 @@ public interface AlarmRepository extends CrudRepository { Pageable pageable); @Query(value = "SELECT new org.thingsboard.server.dao.model.sql.AlarmInfoEntity(a) FROM AlarmEntity a " + - "LEFT JOIN RelationEntity re ON a.id = re.toId " + - "AND re.relationTypeGroup = 'ALARM' " + - "AND re.toType = 'ALARM' " + - "AND re.fromId = :affectedEntityId " + - "AND re.fromType = :affectedEntityType " + + "LEFT JOIN EntityAlarmEntity ea ON a.id = ea.alarmId " + "WHERE a.tenantId = :tenantId " + - "AND (a.originatorId = :affectedEntityId or re.fromId IS NOT NULL) " + - "AND (:startTime IS NULL OR a.createdTime >= :startTime) " + - "AND (:endTime IS NULL OR a.createdTime <= :endTime) " + + "AND ea.tenantId = :tenantId " + + "AND ea.entityId = :affectedEntityId " + + "AND ea.entityType = :affectedEntityType " + + "AND (:startTime IS NULL OR (a.createdTime >= :startTime AND ea.createdTime >= :startTime)) " + + "AND (:endTime IS NULL OR (a.createdTime <= :endTime AND ea.createdTime <= :endTime)) " + "AND ((:alarmStatuses) IS NULL OR a.status in (:alarmStatuses)) " + "AND (LOWER(a.type) LIKE LOWER(CONCAT('%', :searchText, '%')) " + " OR LOWER(a.severity) LIKE LOWER(CONCAT('%', :searchText, '%')) " + " OR LOWER(a.status) LIKE LOWER(CONCAT('%', :searchText, '%'))) " , countQuery = "" + - "SELECT count(a) + " + //alarms with relations only - " (SELECT count(a) FROM AlarmEntity a " + //alarms WITHOUT any relations - " LEFT JOIN RelationEntity re ON a.id = re.toId " + - " AND re.relationTypeGroup = 'ALARM' " + - " AND re.toType = 'ALARM' " + - " AND re.fromId = :affectedEntityId " + - " AND re.fromType = :affectedEntityType " + - " WHERE a.tenantId = :tenantId " + - " AND (a.originatorId = :affectedEntityId) " + - " AND (re.fromId IS NULL) " + //anti join - " AND (:startTime IS NULL OR a.createdTime >= :startTime) " + - " AND (:endTime IS NULL OR a.createdTime <= :endTime) " + - " AND ((:alarmStatuses) IS NULL OR a.status in (:alarmStatuses)) " + - " AND (LOWER(a.type) LIKE LOWER(CONCAT('%', :searchText, '%')) " + - " OR LOWER(a.severity) LIKE LOWER(CONCAT('%', :searchText, '%')) " + - " OR LOWER(a.status) LIKE LOWER(CONCAT('%', :searchText, '%'))) " + - " )" + + "SELECT count(a) " + //alarms with relations only "FROM AlarmEntity a " + - "INNER JOIN RelationEntity re ON a.id = re.toId " + - "AND re.relationTypeGroup = 'ALARM' " + - "AND re.toType = 'ALARM' " + - "AND re.fromId = :affectedEntityId " + - "AND re.fromType = :affectedEntityType " + + "LEFT JOIN EntityAlarmEntity ea ON a.id = ea.alarmId " + "WHERE a.tenantId = :tenantId " + - "AND (:startTime IS NULL OR a.createdTime >= :startTime) " + - "AND (:endTime IS NULL OR a.createdTime <= :endTime) " + + "AND ea.tenantId = :tenantId " + + "AND ea.entityId = :affectedEntityId " + + "AND ea.entityType = :affectedEntityType " + + "AND (:startTime IS NULL OR (a.createdTime >= :startTime AND ea.createdTime >= :startTime)) " + + "AND (:endTime IS NULL OR (a.createdTime <= :endTime AND ea.createdTime <= :endTime)) " + "AND ((:alarmStatuses) IS NULL OR a.status in (:alarmStatuses)) " + "AND (LOWER(a.type) LIKE LOWER(CONCAT('%', :searchText, '%')) " + " OR LOWER(a.severity) LIKE LOWER(CONCAT('%', :searchText, '%')) " + @@ -149,13 +130,11 @@ public interface AlarmRepository extends CrudRepository { Pageable pageable); @Query(value = "SELECT a.severity FROM AlarmEntity a " + - "LEFT JOIN RelationEntity re ON a.id = re.toId " + - "AND re.relationTypeGroup = 'ALARM' " + - "AND re.toType = 'ALARM' " + - "AND re.fromId = :affectedEntityId " + - "AND re.fromType = :affectedEntityType " + + "LEFT JOIN EntityAlarmEntity ea ON a.id = ea.alarmId " + "WHERE a.tenantId = :tenantId " + - "AND (a.originatorId = :affectedEntityId or re.fromId IS NOT NULL) " + + "AND ea.tenantId = :tenantId " + + "AND ea.entityId = :affectedEntityId " + + "AND ea.entityType = :affectedEntityType " + "AND ((:alarmStatuses) IS NULL OR a.status in (:alarmStatuses))") Set findAlarmSeverities(@Param("tenantId") UUID tenantId, @Param("affectedEntityId") UUID affectedEntityId, diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/EntityAlarmRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/EntityAlarmRepository.java new file mode 100644 index 0000000000..ad67e9ba1d --- /dev/null +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/EntityAlarmRepository.java @@ -0,0 +1,29 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.dao.sql.alarm; + +import org.springframework.data.repository.CrudRepository; +import org.thingsboard.server.dao.model.sql.EntityAlarmCompositeKey; +import org.thingsboard.server.dao.model.sql.EntityAlarmEntity; + +import java.util.List; +import java.util.UUID; + +public interface EntityAlarmRepository extends CrudRepository { + + List findAllByAlarmId(UUID alarmId); + +} diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/JpaAlarmDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/JpaAlarmDao.java index 3216a23eee..73e7a39b9a 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/JpaAlarmDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/JpaAlarmDao.java @@ -26,6 +26,7 @@ import org.thingsboard.server.common.data.alarm.AlarmInfo; import org.thingsboard.server.common.data.alarm.AlarmQuery; import org.thingsboard.server.common.data.alarm.AlarmSeverity; import org.thingsboard.server.common.data.alarm.AlarmStatus; +import org.thingsboard.server.common.data.alarm.EntityAlarm; import org.thingsboard.server.common.data.id.AlarmId; import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.EntityId; @@ -37,6 +38,7 @@ import org.thingsboard.server.common.data.query.AlarmDataQuery; import org.thingsboard.server.dao.DaoUtil; import org.thingsboard.server.dao.alarm.AlarmDao; import org.thingsboard.server.dao.model.sql.AlarmEntity; +import org.thingsboard.server.dao.model.sql.EntityAlarmEntity; import org.thingsboard.server.dao.relation.RelationDao; import org.thingsboard.server.dao.sql.JpaAbstractDao; import org.thingsboard.server.dao.sql.query.AlarmQueryRepository; @@ -62,7 +64,7 @@ public class JpaAlarmDao extends JpaAbstractDao implements A private AlarmQueryRepository alarmQueryRepository; @Autowired - private RelationDao relationDao; + private EntityAlarmRepository entityAlarmRepository; @Override protected Class getEntityClass() { @@ -169,4 +171,16 @@ public class JpaAlarmDao extends JpaAbstractDao implements A return DaoUtil.pageToPageData(alarmRepository.findAlarmsIdsByEndTsBeforeAndTenantId(time, tenantId.getId(), DaoUtil.toPageable(pageLink))) .mapData(AlarmId::new); } + + @Override + public void createEntityAlarmRecord(EntityAlarm entityAlarm) { + log.debug("Saving entity {}", entityAlarm); + entityAlarmRepository.save(new EntityAlarmEntity(entityAlarm)); + } + + @Override + public List findEntityAlarmRecords(TenantId tenantId, AlarmId id) { + log.trace("[{}] Try to find entity alarm records using [{}]", tenantId, id); + return DaoUtil.convertDataList(entityAlarmRepository.findAllByAlarmId(id.getId())); + } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/query/DefaultAlarmQueryRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/query/DefaultAlarmQueryRepository.java index 400b12fcab..3fee0f6bef 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/query/DefaultAlarmQueryRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/query/DefaultAlarmQueryRepository.java @@ -105,7 +105,7 @@ public class DefaultAlarmQueryRepository implements AlarmQueryRepository { " a.propagate_relation_types as propagate_relation_types, " + " a.type as type," + SELECT_ORIGINATOR_NAME + ", "; - private static final String JOIN_RELATIONS = "left join relation r on r.relation_type_group = 'ALARM' and r.relation_type = 'ANY' and a.id = r.to_id and r.from_id in (:entity_ids)"; + private static final String JOIN_ENTITY_ALARMS = "inner join entity_alarm ea on a.id = ea.alarm_id"; protected final NamedParameterJdbcTemplate jdbcTemplate; private final TransactionTemplate transactionTemplate; @@ -132,8 +132,8 @@ public class DefaultAlarmQueryRepository implements AlarmQueryRepository { StringBuilder joinPart = new StringBuilder(); boolean addAnd = false; if (pageLink.isSearchPropagatedAlarms()) { - selectPart.append(" CASE WHEN r.from_id IS NULL THEN a.originator_id ELSE r.from_id END as entity_id "); - fromPart.append(JOIN_RELATIONS); + selectPart.append(" ea.entity_id as entity_id "); + fromPart.append(JOIN_ENTITY_ALARMS); wherePart.append(buildPermissionsQuery(tenantId, customerId, ctx)); addAnd = true; } else { @@ -145,7 +145,7 @@ public class DefaultAlarmQueryRepository implements AlarmQueryRepository { sortPart.append(alarmFieldColumnMap.getOrDefault(sortOrderKey, sortOrderKey)) .append(" ").append(sortOrder.getDirection().name()); if (pageLink.isSearchPropagatedAlarms()) { - wherePart.append(" and (a.originator_id in (:entity_ids) or r.from_id IS NOT NULL)"); + wherePart.append(" and ea.entity_id in (:entity_ids)"); } else { addAndIfNeeded(wherePart, addAnd); addAnd = true; @@ -166,7 +166,7 @@ public class DefaultAlarmQueryRepository implements AlarmQueryRepository { } joinPart.append(" as e(id, priority)) e "); if (pageLink.isSearchPropagatedAlarms()) { - joinPart.append("on (r.from_id IS NULL and a.originator_id = e.id) or (r.from_id IS NOT NULL and r.from_id = e.id)"); + joinPart.append("on ea.entity_id = e.id"); } else { joinPart.append("on a.originator_id = e.id"); } @@ -188,6 +188,9 @@ public class DefaultAlarmQueryRepository implements AlarmQueryRepository { addAnd = true; ctx.addLongParameter("startTime", startTs); wherePart.append("a.created_time >= :startTime"); + if (pageLink.isSearchPropagatedAlarms()) { + wherePart.append(" and ea.created_time >= :startTime"); + } } if (endTs > 0) { @@ -195,6 +198,9 @@ public class DefaultAlarmQueryRepository implements AlarmQueryRepository { addAnd = true; ctx.addLongParameter("endTime", endTs); wherePart.append("a.created_time <= :endTime"); + if (pageLink.isSearchPropagatedAlarms()) { + wherePart.append(" and ea.created_time <= :endTime"); + } } if (pageLink.getTypeList() != null && !pageLink.getTypeList().isEmpty()) { @@ -202,6 +208,9 @@ public class DefaultAlarmQueryRepository implements AlarmQueryRepository { addAnd = true; ctx.addStringListParameter("alarmTypes", pageLink.getTypeList()); wherePart.append("a.type in (:alarmTypes)"); + if (pageLink.isSearchPropagatedAlarms()) { + wherePart.append(" and ea.alarm_type in (:alarmTypes)"); + } } if (pageLink.getSeverityList() != null && !pageLink.getSeverityList().isEmpty()) { @@ -279,7 +288,7 @@ public class DefaultAlarmQueryRepository implements AlarmQueryRepository { private String buildPermissionsQuery(TenantId tenantId, CustomerId customerId, QueryContext ctx) { StringBuilder permissionsQuery = new StringBuilder(); ctx.addUuidParameter("permissions_tenant_id", tenantId.getId()); - permissionsQuery.append(" a.tenant_id = :permissions_tenant_id "); + permissionsQuery.append(" a.tenant_id = :permissions_tenant_id and ea.tenant_id = :permissions_tenant_id "); /* No need to check the customer id, because we already use entity id list that passed security check when we were evaluating the data query. */ diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/query/DefaultQueryLogComponent.java b/dao/src/main/java/org/thingsboard/server/dao/sql/query/DefaultQueryLogComponent.java index 89bf4d1ac1..737c148d49 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/query/DefaultQueryLogComponent.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/query/DefaultQueryLogComponent.java @@ -33,7 +33,7 @@ public class DefaultQueryLogComponent implements QueryLogComponent { @Override public void logQuery(QueryContext ctx, String query, long duration) { if (logSqlQueries && duration > logQueriesThreshold) { - log.info("QUERY: {} took {}ms", query, duration); + log.info("QUERY: {} took {} ms", query, duration); Arrays.asList(ctx.getParameterNames()).forEach(param -> log.info("QUERY PARAM: {} -> {}", param, ctx.getValue(param))); } } diff --git a/dao/src/main/resources/sql/schema-entities-hsql.sql b/dao/src/main/resources/sql/schema-entities-hsql.sql index e58ca10459..c5931a8964 100644 --- a/dao/src/main/resources/sql/schema-entities-hsql.sql +++ b/dao/src/main/resources/sql/schema-entities-hsql.sql @@ -43,6 +43,18 @@ CREATE TABLE IF NOT EXISTS alarm ( type varchar(255) ); +CREATE TABLE IF NOT EXISTS entity_alarm ( + tenant_id uuid NOT NULL, + entity_type varchar(32), + entity_id uuid NOT NULL, + created_time bigint NOT NULL, + alarm_type varchar(255) NOT NULL, + customer_id uuid, + alarm_id uuid, + CONSTRAINT entity_alarm_pkey PRIMARY KEY(entity_id, alarm_id), + CONSTRAINT fk_entity_alarm_id FOREIGN KEY (alarm_id) REFERENCES alarm(id) ON DELETE CASCADE +); + CREATE TABLE IF NOT EXISTS asset ( id uuid NOT NULL CONSTRAINT asset_pkey PRIMARY KEY, created_time bigint NOT NULL, diff --git a/dao/src/main/resources/sql/schema-entities-idx.sql b/dao/src/main/resources/sql/schema-entities-idx.sql index 78b1eda905..1238b5ee12 100644 --- a/dao/src/main/resources/sql/schema-entities-idx.sql +++ b/dao/src/main/resources/sql/schema-entities-idx.sql @@ -20,8 +20,12 @@ CREATE INDEX IF NOT EXISTS idx_alarm_originator_created_time ON alarm(originator CREATE INDEX IF NOT EXISTS idx_alarm_tenant_created_time ON alarm(tenant_id, created_time DESC); +CREATE INDEX IF NOT EXISTS idx_alarm_tenant_status_created_time ON alarm(tenant_id, status, created_time DESC); + CREATE INDEX IF NOT EXISTS idx_alarm_tenant_alarm_type_created_time ON alarm(tenant_id, type, created_time DESC); +CREATE INDEX IF NOT EXISTS idx_entity_alarm_created_time ON entity_alarm(tenant_id, entity_id, created_time DESC); + CREATE INDEX IF NOT EXISTS idx_relation_to_id ON relation(relation_type_group, to_type, to_id); CREATE INDEX IF NOT EXISTS idx_relation_from_id ON relation(relation_type_group, from_type, from_id); diff --git a/dao/src/main/resources/sql/schema-entities.sql b/dao/src/main/resources/sql/schema-entities.sql index 69760c377a..de27c8d554 100644 --- a/dao/src/main/resources/sql/schema-entities.sql +++ b/dao/src/main/resources/sql/schema-entities.sql @@ -58,6 +58,18 @@ CREATE TABLE IF NOT EXISTS alarm ( type varchar(255) ); +CREATE TABLE IF NOT EXISTS entity_alarm ( + tenant_id uuid NOT NULL, + entity_type varchar(32), + entity_id uuid NOT NULL, + created_time bigint NOT NULL, + alarm_type varchar(255) NOT NULL, + customer_id uuid, + alarm_id uuid, + CONSTRAINT entity_alarm_pkey PRIMARY KEY(entity_id, alarm_id), + CONSTRAINT fk_entity_alarm_id FOREIGN KEY (alarm_id) REFERENCES alarm(id) ON DELETE CASCADE +); + CREATE TABLE IF NOT EXISTS asset ( id uuid NOT NULL CONSTRAINT asset_pkey PRIMARY KEY, created_time bigint NOT NULL, diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseAlarmServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseAlarmServiceTest.java index a798133ad4..2d3f21545f 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseAlarmServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseAlarmServiceTest.java @@ -612,16 +612,6 @@ public abstract class BaseAlarmServiceTest extends AbstractServiceTest { Assert.assertEquals(1, alarms.getData().size()); Assert.assertEquals(created, alarms.getData().get(0)); - List toAlarmRelations = relationService.findByTo(tenantId, created.getId(), RelationTypeGroup.ALARM); - Assert.assertEquals(1, toAlarmRelations.size()); - - List fromChildRelations = relationService.findByFrom(tenantId, childId, RelationTypeGroup.ALARM); - Assert.assertEquals(0, fromChildRelations.size()); - - List fromParentRelations = relationService.findByFrom(tenantId, parentId, RelationTypeGroup.ALARM); - Assert.assertEquals(1, fromParentRelations.size()); - - Assert.assertTrue("Alarm was not deleted when expected", alarmService.deleteAlarm(tenantId, created.getId()).isSuccessful()); Alarm fetched = alarmService.findAlarmByIdAsync(tenantId, created.getId()).get(); @@ -647,14 +637,5 @@ public abstract class BaseAlarmServiceTest extends AbstractServiceTest { Assert.assertNotNull(alarms.getData()); Assert.assertEquals(0, alarms.getData().size()); - toAlarmRelations = relationService.findByTo(tenantId, created.getId(), RelationTypeGroup.ALARM); - Assert.assertEquals(0, toAlarmRelations.size()); - - fromChildRelations = relationService.findByFrom(tenantId, childId, RelationTypeGroup.ALARM); - Assert.assertEquals(0, fromChildRelations.size()); - - fromParentRelations = relationService.findByFrom(tenantId, childId, RelationTypeGroup.ALARM); - Assert.assertEquals(0, fromParentRelations.size()); - } } diff --git a/dao/src/test/resources/sql/hsql/drop-all-tables.sql b/dao/src/test/resources/sql/hsql/drop-all-tables.sql index 2cd7e26b48..095a38533e 100644 --- a/dao/src/test/resources/sql/hsql/drop-all-tables.sql +++ b/dao/src/test/resources/sql/hsql/drop-all-tables.sql @@ -1,4 +1,5 @@ DROP TABLE IF EXISTS admin_settings; +DROP TABLE IF EXISTS entity_alarm; DROP TABLE IF EXISTS alarm; DROP TABLE IF EXISTS asset; DROP TABLE IF EXISTS audit_log; diff --git a/dao/src/test/resources/sql/psql/drop-all-tables.sql b/dao/src/test/resources/sql/psql/drop-all-tables.sql index 0a71953032..3d1d38a0e7 100644 --- a/dao/src/test/resources/sql/psql/drop-all-tables.sql +++ b/dao/src/test/resources/sql/psql/drop-all-tables.sql @@ -1,4 +1,5 @@ DROP TABLE IF EXISTS admin_settings; +DROP TABLE IF EXISTS entity_alarm; DROP TABLE IF EXISTS alarm; DROP TABLE IF EXISTS asset; DROP TABLE IF EXISTS audit_log; diff --git a/dao/src/test/resources/sql/timescale/drop-all-tables.sql b/dao/src/test/resources/sql/timescale/drop-all-tables.sql index 53da64aff2..f113ec5277 100644 --- a/dao/src/test/resources/sql/timescale/drop-all-tables.sql +++ b/dao/src/test/resources/sql/timescale/drop-all-tables.sql @@ -1,4 +1,5 @@ DROP TABLE IF EXISTS admin_settings; +DROP TABLE IF EXISTS entity_alarm; DROP TABLE IF EXISTS alarm; DROP TABLE IF EXISTS asset; DROP TABLE IF EXISTS audit_log; From dffa84483e63fbc25e43c21ea78caa19ac43c50a Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Wed, 8 Dec 2021 10:50:45 +0200 Subject: [PATCH 216/432] Fixed tests --- .../rules/flow/AbstractRuleEngineFlowIntegrationTest.java | 2 ++ .../lifecycle/AbstractRuleEngineLifecycleIntegrationTest.java | 1 + 2 files changed, 3 insertions(+) diff --git a/application/src/test/java/org/thingsboard/server/rules/flow/AbstractRuleEngineFlowIntegrationTest.java b/application/src/test/java/org/thingsboard/server/rules/flow/AbstractRuleEngineFlowIntegrationTest.java index 90a0404751..eb79bc9d35 100644 --- a/application/src/test/java/org/thingsboard/server/rules/flow/AbstractRuleEngineFlowIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/rules/flow/AbstractRuleEngineFlowIntegrationTest.java @@ -144,6 +144,7 @@ public abstract class AbstractRuleEngineFlowIntegrationTest extends AbstractRule Thread.sleep(1000); TbMsgCallback tbMsgCallback = Mockito.mock(TbMsgCallback.class); + Mockito.when(tbMsgCallback.isMsgValid()).thenReturn(true); TbMsg tbMsg = TbMsg.newMsg("CUSTOM", device.getId(), new TbMsgMetaData(), "{}", tbMsgCallback); QueueToRuleEngineMsg qMsg = new QueueToRuleEngineMsg(savedTenant.getId(), tbMsg, null, null); // Pushing Message to the system @@ -256,6 +257,7 @@ public abstract class AbstractRuleEngineFlowIntegrationTest extends AbstractRule Thread.sleep(1000); TbMsgCallback tbMsgCallback = Mockito.mock(TbMsgCallback.class); + Mockito.when(tbMsgCallback.isMsgValid()).thenReturn(true); TbMsg tbMsg = TbMsg.newMsg("CUSTOM", device.getId(), new TbMsgMetaData(), "{}", tbMsgCallback); QueueToRuleEngineMsg qMsg = new QueueToRuleEngineMsg(savedTenant.getId(), tbMsg, null, null); // Pushing Message to the system diff --git a/application/src/test/java/org/thingsboard/server/rules/lifecycle/AbstractRuleEngineLifecycleIntegrationTest.java b/application/src/test/java/org/thingsboard/server/rules/lifecycle/AbstractRuleEngineLifecycleIntegrationTest.java index cfa546cc11..62b2034b79 100644 --- a/application/src/test/java/org/thingsboard/server/rules/lifecycle/AbstractRuleEngineLifecycleIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/rules/lifecycle/AbstractRuleEngineLifecycleIntegrationTest.java @@ -135,6 +135,7 @@ public abstract class AbstractRuleEngineLifecycleIntegrationTest extends Abstrac Thread.sleep(1000); TbMsgCallback tbMsgCallback = Mockito.mock(TbMsgCallback.class); + Mockito.when(tbMsgCallback.isMsgValid()).thenReturn(true); TbMsg tbMsg = TbMsg.newMsg("CUSTOM", device.getId(), new TbMsgMetaData(), "{}", tbMsgCallback); QueueToRuleEngineMsg qMsg = new QueueToRuleEngineMsg(savedTenant.getId(), tbMsg, null, null); // Pushing Message to the system From d6e18d05cd46d1ad407979878009446b66d42696 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Wed, 8 Dec 2021 15:35:59 +0200 Subject: [PATCH 217/432] Introduce Flow rule node type. Add rile node UIs for RuleChain input/output. Remove rule chain connection metadata. --- .../AnnotationComponentDiscoveryService.java | 27 ++-- .../common/data/plugin/ComponentType.java | 2 +- .../rule/engine/api/NodeDefinition.java | 1 + .../thingsboard/rule/engine/api/RuleNode.java | 2 + .../rule/engine/flow/TbAckNode.java | 2 +- .../rule/engine/flow/TbCheckpointNode.java | 2 +- .../engine/flow/TbRuleChainInputNode.java | 8 +- .../engine/flow/TbRuleChainOutputNode.java | 6 +- .../static/rulenode/rulenode-core-config.js | 96 +++++++++++- .../src/app/core/http/rule-chain.service.ts | 83 ++-------- .../import-export/import-export.service.ts | 9 +- .../home/pages/edge/edge-routing.module.ts | 8 +- .../add-rule-node-link-dialog.component.html | 3 +- .../pages/rulechain/link-labels.component.ts | 74 ++++++--- .../pages/rulechain/rule-node-colors.scss | 2 +- .../rulechain/rule-node-config.component.ts | 9 ++ .../rule-node-details.component.html | 20 +-- .../rulechain/rule-node-details.component.ts | 62 ++------ .../rulechain/rule-node-link.component.html | 1 + .../rulechain/rule-node-link.component.ts | 3 + .../rulechain/rulechain-page.component.html | 3 +- .../rulechain/rulechain-page.component.scss | 2 +- .../rulechain/rulechain-page.component.ts | 147 +++++------------- .../rulechain/rulechain-routing.module.ts | 12 +- .../pages/rulechain/rulenode.component.html | 4 +- .../pages/rulechain/rulenode.component.ts | 43 ++++- .../models/component-descriptor.models.ts | 3 +- .../app/shared/models/rule-chain.models.ts | 33 +--- .../src/app/shared/models/rule-node.models.ts | 23 ++- .../assets/locale/locale.constant-en_US.json | 2 + 30 files changed, 339 insertions(+), 353 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/component/AnnotationComponentDiscoveryService.java b/application/src/main/java/org/thingsboard/server/service/component/AnnotationComponentDiscoveryService.java index 00a5bca503..eaacde0874 100644 --- a/application/src/main/java/org/thingsboard/server/service/component/AnnotationComponentDiscoveryService.java +++ b/application/src/main/java/org/thingsboard/server/service/component/AnnotationComponentDiscoveryService.java @@ -152,24 +152,14 @@ public class AnnotationComponentDiscoveryService implements ComponentDiscoverySe try { scannedComponent.setType(type); Class clazz = Class.forName(clazzName); - switch (type) { - case ENRICHMENT: - case FILTER: - case TRANSFORMATION: - case ACTION: - case EXTERNAL: - RuleNode ruleNodeAnnotation = clazz.getAnnotation(RuleNode.class); - scannedComponent.setName(ruleNodeAnnotation.name()); - scannedComponent.setScope(ruleNodeAnnotation.scope()); - NodeDefinition nodeDefinition = prepareNodeDefinition(ruleNodeAnnotation); - ObjectNode configurationDescriptor = mapper.createObjectNode(); - JsonNode node = mapper.valueToTree(nodeDefinition); - configurationDescriptor.set("nodeDefinition", node); - scannedComponent.setConfigurationDescriptor(configurationDescriptor); - break; - default: - throw new RuntimeException(type + " is not supported yet!"); - } + RuleNode ruleNodeAnnotation = clazz.getAnnotation(RuleNode.class); + scannedComponent.setName(ruleNodeAnnotation.name()); + scannedComponent.setScope(ruleNodeAnnotation.scope()); + NodeDefinition nodeDefinition = prepareNodeDefinition(ruleNodeAnnotation); + ObjectNode configurationDescriptor = mapper.createObjectNode(); + JsonNode node = mapper.valueToTree(nodeDefinition); + configurationDescriptor.set("nodeDefinition", node); + scannedComponent.setConfigurationDescriptor(configurationDescriptor); scannedComponent.setClazz(clazzName); log.info("Processing scanned component: {}", scannedComponent); } catch (Exception e) { @@ -200,6 +190,7 @@ public class AnnotationComponentDiscoveryService implements ComponentDiscoverySe nodeDefinition.setOutEnabled(nodeAnnotation.outEnabled()); nodeDefinition.setRelationTypes(getRelationTypesWithFailureRelation(nodeAnnotation)); nodeDefinition.setCustomRelations(nodeAnnotation.customRelations()); + nodeDefinition.setRuleChainNode(nodeAnnotation.ruleChainNode()); Class configClazz = nodeAnnotation.configClazz(); NodeConfiguration config = configClazz.getDeclaredConstructor().newInstance(); NodeConfiguration defaultConfiguration = config.defaultConfiguration(); diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/plugin/ComponentType.java b/common/data/src/main/java/org/thingsboard/server/common/data/plugin/ComponentType.java index 26c61a03bf..cdb45538ea 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/plugin/ComponentType.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/plugin/ComponentType.java @@ -20,6 +20,6 @@ package org.thingsboard.server.common.data.plugin; */ public enum ComponentType { - ENRICHMENT, FILTER, TRANSFORMATION, ACTION, EXTERNAL + ENRICHMENT, FILTER, TRANSFORMATION, ACTION, EXTERNAL, FLOW } diff --git a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/NodeDefinition.java b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/NodeDefinition.java index 531ac61a2c..5933b1bf18 100644 --- a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/NodeDefinition.java +++ b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/NodeDefinition.java @@ -27,6 +27,7 @@ public class NodeDefinition { private boolean outEnabled; String[] relationTypes; boolean customRelations; + boolean ruleChainNode; JsonNode defaultConfiguration; String[] uiResources; String configDirective; diff --git a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/RuleNode.java b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/RuleNode.java index 53b52491da..7a0f99e2d0 100644 --- a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/RuleNode.java +++ b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/RuleNode.java @@ -58,6 +58,8 @@ public @interface RuleNode { boolean customRelations() default false; + boolean ruleChainNode() default false; + RuleChainType[] ruleChainTypes() default {RuleChainType.CORE, RuleChainType.EDGE}; } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbAckNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbAckNode.java index e10a20232d..850eed19bf 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbAckNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbAckNode.java @@ -28,7 +28,7 @@ import org.thingsboard.server.common.msg.TbMsg; @Slf4j @RuleNode( - type = ComponentType.ACTION, + type = ComponentType.FLOW, name = "acknowledge", configClazz = EmptyNodeConfiguration.class, nodeDescription = "Acknowledges the incoming message", diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbCheckpointNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbCheckpointNode.java index cc3944452a..4f3bc327ec 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbCheckpointNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbCheckpointNode.java @@ -31,7 +31,7 @@ import static org.thingsboard.common.util.DonAsynchron.withCallback; @Slf4j @RuleNode( - type = ComponentType.ACTION, + type = ComponentType.FLOW, name = "checkpoint", configClazz = TbCheckpointNodeConfiguration.class, nodeDescription = "transfers the message to another queue", diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbRuleChainInputNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbRuleChainInputNode.java index c30dac406c..a1e1e31954 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbRuleChainInputNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbRuleChainInputNode.java @@ -33,14 +33,18 @@ import java.util.UUID; @Slf4j @RuleNode( - type = ComponentType.ACTION, - name = "rule chain input", + type = ComponentType.FLOW, + name = "rule chain", configClazz = TbRuleChainInputNodeConfiguration.class, nodeDescription = "transfers the message to another rule chain", nodeDetails = "Allows to nest the rule chain similar to single rule node. " + "The incoming message is forwarded to the input node of the specified target rule chain. " + "The target rule chain may produce multiple labeled outputs. " + "You may use the outputs to forward the results of processing to other rule nodes.", + uiResources = {"static/rulenode/rulenode-core-config.js"}, + configDirective = "tbFlowNodeRuleChainInputConfig", + relationTypes = {}, + ruleChainNode = true, customRelations = true ) public class TbRuleChainInputNode implements TbNode { diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbRuleChainOutputNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbRuleChainOutputNode.java index b09f1bbca5..f5f75f1275 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbRuleChainOutputNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbRuleChainOutputNode.java @@ -28,14 +28,16 @@ import org.thingsboard.server.common.msg.TbMsg; @Slf4j @RuleNode( - type = ComponentType.ACTION, - name = "rule chain output", + type = ComponentType.FLOW, + name = "output", configClazz = TbRuleChainOutputNodeConfiguration.class, nodeDescription = "transfers the message to the caller rule chain", nodeDetails = "Produces output of the rule chain processing. " + "The output is forwarded to the caller rule chain, as an output of the corresponding \"input\" rule node. " + "The rule node configuration contains the \"label\" parameter. " + "This parameter corresponds to the relation type of the output message, and it is used to forward messages to other rule nodes in the caller rule chain. ", + uiResources = {"static/rulenode/rulenode-core-config.js"}, + configDirective = "tbFlowNodeRuleChainOutputConfig", outEnabled = false ) public class TbRuleChainOutputNode implements TbNode { diff --git a/rule-engine/rule-engine-components/src/main/resources/public/static/rulenode/rulenode-core-config.js b/rule-engine/rule-engine-components/src/main/resources/public/static/rulenode/rulenode-core-config.js index 8236c14be8..702fdabe6f 100644 --- a/rule-engine/rule-engine-components/src/main/resources/public/static/rulenode/rulenode-core-config.js +++ b/rule-engine/rule-engine-components/src/main/resources/public/static/rulenode/rulenode-core-config.js @@ -3691,6 +3691,91 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImpo }] }] }); +class RuleChainInputComponent extends RuleNodeConfigurationComponent { + constructor(store, fb) { + super(store); + this.store = store; + this.fb = fb; + this.entityType = EntityType; + } + configForm() { + return this.ruleChainInputConfigForm; + } + onConfigurationSet(configuration) { + this.ruleChainInputConfigForm = this.fb.group({ + ruleChainId: [configuration ? configuration.ruleChainId : null, [Validators.required]] + }); + } +} +RuleChainInputComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RuleChainInputComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); +RuleChainInputComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: RuleChainInputComponent, selector: "tb-flow-node-rule-chain-input-config", usesInheritance: true, ngImport: i0, template: "
\n \n \n
\n", components: [{ type: i8$3.EntityAutocompleteComponent, selector: "tb-entity-autocomplete", inputs: ["entityType", "entitySubtype", "excludeEntityIds", "labelText", "requiredText", "required", "disabled"], outputs: ["entityChanged"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }] }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RuleChainInputComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-flow-node-rule-chain-input-config', + templateUrl: './rule-chain-input.component.html', + styleUrls: [] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); + +class RuleChainOutputComponent extends RuleNodeConfigurationComponent { + constructor(store, fb) { + super(store); + this.store = store; + this.fb = fb; + } + configForm() { + return this.ruleChainOutputConfigForm; + } + onConfigurationSet(configuration) { + this.ruleChainOutputConfigForm = this.fb.group({ + label: [configuration ? configuration.label : null, [Validators.required]] + }); + } +} +RuleChainOutputComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RuleChainOutputComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); +RuleChainOutputComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: RuleChainOutputComponent, selector: "tb-flow-node-rule-chain-output-config", usesInheritance: true, ngImport: i0, template: "
\n \n tb.rulenode.label\n \n \n {{ 'tb.rulenode.label-required' | translate }}\n \n \n
\n", components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.MatError, selector: "mat-error", inputs: ["id"] }], pipes: { "translate": i4.TranslatePipe } }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RuleChainOutputComponent, decorators: [{ + type: Component, + args: [{ + selector: 'tb-flow-node-rule-chain-output-config', + templateUrl: './rule-chain-output.component.html', + styleUrls: [] + }] + }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); + +class RuleNodeCoreConfigFlowModule { +} +RuleNodeCoreConfigFlowModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RuleNodeCoreConfigFlowModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); +RuleNodeCoreConfigFlowModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RuleNodeCoreConfigFlowModule, declarations: [RuleChainInputComponent, + RuleChainOutputComponent], imports: [CommonModule, + SharedModule, + RulenodeCoreConfigCommonModule], exports: [RuleChainInputComponent, + RuleChainOutputComponent] }); +RuleNodeCoreConfigFlowModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RuleNodeCoreConfigFlowModule, imports: [[ + CommonModule, + SharedModule, + RulenodeCoreConfigCommonModule + ]] }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RuleNodeCoreConfigFlowModule, decorators: [{ + type: NgModule, + args: [{ + declarations: [ + RuleChainInputComponent, + RuleChainOutputComponent + ], + imports: [ + CommonModule, + SharedModule, + RulenodeCoreConfigCommonModule + ], + exports: [ + RuleChainInputComponent, + RuleChainOutputComponent + ] + }] + }] }); + function addRuleNodeCoreLocaleEnglish(translate) { const enUS = { tb: { @@ -4105,7 +4190,9 @@ function addRuleNodeCoreLocaleEnglish(translate) { 'for value from message body', 'alarm-severity-pattern-hint': 'Hint: use ${metadataKey} ' + 'for value from metadata, $[messageKey] ' + - 'for value from message body. Alarm severity should be system (CRITICAL, MAJOR etc.)' + 'for value from message body. Alarm severity should be system (CRITICAL, MAJOR etc.)', + label: 'Label', + 'label-required': 'Label is required' }, 'key-val': { key: 'Key', @@ -4134,6 +4221,7 @@ RuleNodeCoreConfigModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0" RuleNodeCoreConfigFilterModule, RulenodeCoreConfigEnrichmentModule, RulenodeCoreConfigTransformModule, + RuleNodeCoreConfigFlowModule, EmptyConfigComponent] }); RuleNodeCoreConfigModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RuleNodeCoreConfigModule, imports: [[ CommonModule, @@ -4141,7 +4229,8 @@ RuleNodeCoreConfigModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0" ], RuleNodeCoreConfigActionModule, RuleNodeCoreConfigFilterModule, RulenodeCoreConfigEnrichmentModule, - RulenodeCoreConfigTransformModule] }); + RulenodeCoreConfigTransformModule, + RuleNodeCoreConfigFlowModule] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RuleNodeCoreConfigModule, decorators: [{ type: NgModule, args: [{ @@ -4157,6 +4246,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImpo RuleNodeCoreConfigFilterModule, RulenodeCoreConfigEnrichmentModule, RulenodeCoreConfigTransformModule, + RuleNodeCoreConfigFlowModule, EmptyConfigComponent ] }] @@ -4170,5 +4260,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImpo * Generated bundle index. Do not edit. */ -export { AssignCustomerConfigComponent, AttributesConfigComponent, AzureIotHubConfigComponent, CalculateDeltaConfigComponent, ChangeOriginatorConfigComponent, CheckAlarmStatusComponent, CheckMessageConfigComponent, CheckPointConfigComponent, CheckRelationConfigComponent, ClearAlarmConfigComponent, CreateAlarmConfigComponent, CreateRelationConfigComponent, CredentialsConfigComponent, CustomerAttributesConfigComponent, DeleteRelationConfigComponent, DeviceAttributesConfigComponent, DeviceProfileConfigComponent, DeviceRelationsQueryConfigComponent, EmptyConfigComponent, EntityDetailsConfigComponent, GeneratorConfigComponent, GetTelemetryFromDatabaseConfigComponent, GpsGeoActionConfigComponent, GpsGeoFilterConfigComponent, KafkaConfigComponent, KvMapConfigComponent, LogConfigComponent, MessageTypeConfigComponent, MessageTypesConfigComponent, MqttConfigComponent, MsgCountConfigComponent, MsgDelayConfigComponent, OriginatorAttributesConfigComponent, OriginatorFieldsConfigComponent, OriginatorTypeConfigComponent, PubSubConfigComponent, PushToCloudConfigComponent, PushToEdgeConfigComponent, RabbitMqConfigComponent, RelatedAttributesConfigComponent, RelationsQueryConfigComponent, RestApiCallConfigComponent, RpcReplyConfigComponent, RpcRequestConfigComponent, RuleNodeCoreConfigActionModule, RuleNodeCoreConfigFilterModule, RuleNodeCoreConfigModule, RulenodeCoreConfigCommonModule, RulenodeCoreConfigEnrichmentModule, RulenodeCoreConfigTransformModule, SafeHtmlPipe, SaveToCustomTableConfigComponent, ScriptConfigComponent, SendEmailConfigComponent, SendSmsConfigComponent, SnsConfigComponent, SqsConfigComponent, SwitchConfigComponent, TenantAttributesConfigComponent, TimeseriesConfigComponent, ToEmailConfigComponent, TransformScriptConfigComponent, UnassignCustomerConfigComponent }; +export { AssignCustomerConfigComponent, AttributesConfigComponent, AzureIotHubConfigComponent, CalculateDeltaConfigComponent, ChangeOriginatorConfigComponent, CheckAlarmStatusComponent, CheckMessageConfigComponent, CheckPointConfigComponent, CheckRelationConfigComponent, ClearAlarmConfigComponent, CreateAlarmConfigComponent, CreateRelationConfigComponent, CredentialsConfigComponent, CustomerAttributesConfigComponent, DeleteRelationConfigComponent, DeviceAttributesConfigComponent, DeviceProfileConfigComponent, DeviceRelationsQueryConfigComponent, EmptyConfigComponent, EntityDetailsConfigComponent, GeneratorConfigComponent, GetTelemetryFromDatabaseConfigComponent, GpsGeoActionConfigComponent, GpsGeoFilterConfigComponent, KafkaConfigComponent, KvMapConfigComponent, LogConfigComponent, MessageTypeConfigComponent, MessageTypesConfigComponent, MqttConfigComponent, MsgCountConfigComponent, MsgDelayConfigComponent, OriginatorAttributesConfigComponent, OriginatorFieldsConfigComponent, OriginatorTypeConfigComponent, PubSubConfigComponent, PushToCloudConfigComponent, PushToEdgeConfigComponent, RabbitMqConfigComponent, RelatedAttributesConfigComponent, RelationsQueryConfigComponent, RestApiCallConfigComponent, RpcReplyConfigComponent, RpcRequestConfigComponent, RuleChainInputComponent, RuleChainOutputComponent, RuleNodeCoreConfigActionModule, RuleNodeCoreConfigFilterModule, RuleNodeCoreConfigFlowModule, RuleNodeCoreConfigModule, RulenodeCoreConfigCommonModule, RulenodeCoreConfigEnrichmentModule, RulenodeCoreConfigTransformModule, SafeHtmlPipe, SaveToCustomTableConfigComponent, ScriptConfigComponent, SendEmailConfigComponent, SendSmsConfigComponent, SnsConfigComponent, SqsConfigComponent, SwitchConfigComponent, TenantAttributesConfigComponent, TimeseriesConfigComponent, ToEmailConfigComponent, TransformScriptConfigComponent, UnassignCustomerConfigComponent }; //# sourceMappingURL=rulenode-core-config.js.map diff --git a/ui-ngx/src/app/core/http/rule-chain.service.ts b/ui-ngx/src/app/core/http/rule-chain.service.ts index 0e11c51fcb..3fa9168d5f 100644 --- a/ui-ngx/src/app/core/http/rule-chain.service.ts +++ b/ui-ngx/src/app/core/http/rule-chain.service.ts @@ -21,11 +21,8 @@ import { HttpClient } from '@angular/common/http'; import { PageLink } from '@shared/models/page/page-link'; import { PageData } from '@shared/models/page/page-data'; import { - ResolvedRuleChainMetaData, RuleChain, - RuleChainConnectionInfo, RuleChainMetaData, - ruleChainNodeComponent, RuleChainType, ruleNodeTypeComponentTypes, unknownNodeComponent @@ -34,14 +31,13 @@ import { ComponentDescriptorService } from './component-descriptor.service'; import { IRuleNodeConfigurationComponent, LinkLabel, - RuleNodeComponentDescriptor, + RuleNodeComponentDescriptor, RuleNodeConfiguration, TestScriptInputParams, TestScriptResult } from '@app/shared/models/rule-node.models'; import { ResourcesService } from '../services/resources.service'; import { catchError, map, mergeMap } from 'rxjs/operators'; import { TranslateService } from '@ngx-translate/core'; -import { EntityType } from '@shared/models/entity-type.models'; import { deepClone, snakeCase } from '@core/utils'; import { DebugRuleNodeEventBody } from '@app/shared/models/event.models'; import { Edge } from '@shared/models/edge.models'; @@ -63,7 +59,8 @@ export class RuleChainService { private translate: TranslateService ) { } - public getRuleChains(pageLink: PageLink, type: RuleChainType = RuleChainType.CORE, config?: RequestConfig): Observable> { + public getRuleChains(pageLink: PageLink, type: RuleChainType = RuleChainType.CORE, + config?: RequestConfig): Observable> { return this.http.get>(`/api/ruleChains${pageLink.toQuery()}&type=${type}`, defaultHttpOptionsFromConfig(config)); } @@ -72,6 +69,10 @@ export class RuleChainService { return this.http.get(`/api/ruleChain/${ruleChainId}`, defaultHttpOptionsFromConfig(config)); } + public getRuleChainOutputLabels(ruleChainId: string, config?: RequestConfig): Observable> { + return this.http.get>(`/api/ruleChain/${ruleChainId}/output/labels`, defaultHttpOptionsFromConfig(config)); + } + public createDefaultRuleChain(ruleChainName: string, config?: RequestConfig): Observable { return this.http.post('/api/ruleChain/device/default', { name: ruleChainName @@ -94,32 +95,10 @@ export class RuleChainService { return this.http.get(`/api/ruleChain/${ruleChainId}/metadata`, defaultHttpOptionsFromConfig(config)); } - public getResolvedRuleChainMetadata(ruleChainId: string, config?: RequestConfig): Observable { - return this.getRuleChainMetadata(ruleChainId, config).pipe( - mergeMap((ruleChainMetaData) => this.resolveRuleChainMetadata(ruleChainMetaData)) - ); - } - public saveRuleChainMetadata(ruleChainMetaData: RuleChainMetaData, config?: RequestConfig): Observable { return this.http.post('/api/ruleChain/metadata', ruleChainMetaData, defaultHttpOptionsFromConfig(config)); } - public saveAndGetResolvedRuleChainMetadata(ruleChainMetaData: RuleChainMetaData, - config?: RequestConfig): Observable { - return this.saveRuleChainMetadata(ruleChainMetaData, config).pipe( - mergeMap((savedRuleChainMetaData) => this.resolveRuleChainMetadata(savedRuleChainMetaData)) - ); - } - - public resolveRuleChainMetadata(ruleChainMetaData: RuleChainMetaData): Observable { - return this.resolveTargetRuleChains(ruleChainMetaData.ruleChainConnections).pipe( - map((targetRuleChainsMap) => { - const resolvedRuleChainMetadata: ResolvedRuleChainMetaData = {...ruleChainMetaData, targetRuleChainsMap}; - return resolvedRuleChainMetadata; - }) - ); - } - public getRuleNodeComponents(modulesMap: IModulesMap, ruleChainType: RuleChainType, config?: RequestConfig): Observable> { if (this.ruleNodeComponentsMap.get(ruleChainType)) { @@ -130,7 +109,6 @@ export class RuleChainService { return this.resolveRuleNodeComponentsUiResources(components, modulesMap).pipe( map((ruleNodeComponents) => { this.ruleNodeComponentsMap.set(ruleChainType, ruleNodeComponents); - this.ruleNodeComponentsMap.get(ruleChainType).push(ruleChainNodeComponent); this.ruleNodeComponentsMap.get(ruleChainType).sort( (comp1, comp2) => { let result = comp1.type.toString().localeCompare(comp2.type.toString()); @@ -180,6 +158,14 @@ export class RuleChainService { return component.configurationDescriptor.nodeDefinition.customRelations; } + public ruleNodeSourceRuleChainId(component: RuleNodeComponentDescriptor, config: RuleNodeConfiguration): string { + if (component.configurationDescriptor.nodeDefinition.ruleChainNode) { + return config?.ruleChainId; + } else { + return null; + } + } + public getLatestRuleNodeDebugInput(ruleNodeId: string, config?: RequestConfig): Observable { return this.http.get(`/api/ruleNode/${ruleNodeId}/debugIn`, defaultHttpOptionsFromConfig(config)); } @@ -188,26 +174,6 @@ export class RuleChainService { return this.http.post('/api/ruleChain/testScript', inputParams, defaultHttpOptionsFromConfig(config)); } - private resolveTargetRuleChains(ruleChainConnections: Array): Observable<{[ruleChainId: string]: RuleChain}> { - if (ruleChainConnections && ruleChainConnections.length) { - const tasks: Observable[] = []; - ruleChainConnections.forEach((connection) => { - tasks.push(this.resolveRuleChain(connection.targetRuleChainId.id)); - }); - return forkJoin(tasks).pipe( - map((ruleChains) => { - const ruleChainsMap: {[ruleChainId: string]: RuleChain} = {}; - ruleChains.forEach((ruleChain) => { - ruleChainsMap[ruleChain.id.id] = ruleChain; - }); - return ruleChainsMap; - }) - ); - } else { - return of({} as {[ruleChainId: string]: RuleChain}); - } - } - private loadRuleNodeComponents(ruleChainType: RuleChainType, config?: RequestConfig): Observable> { return this.componentDescriptorService.getComponentDescriptorsByTypes(ruleNodeTypeComponentTypes, ruleChainType, config).pipe( map((components) => { @@ -228,7 +194,7 @@ export class RuleChainService { tasks.push(this.resolveRuleNodeComponentUiResources(component, modulesMap)); }); return forkJoin(tasks).pipe( - catchError((err) => { + catchError(() => { return of(components); }) ); @@ -268,7 +234,7 @@ export class RuleChainService { )); } return forkJoin(tasks).pipe( - map((res) => { + map(() => { return component; }), catchError(() => { @@ -281,21 +247,6 @@ export class RuleChainService { } } - private resolveRuleChain(ruleChainId: string): Observable { - return this.getRuleChain(ruleChainId, {ignoreErrors: true}).pipe( - map(ruleChain => ruleChain), - catchError((err) => { - const ruleChain = { - id: { - entityType: EntityType.RULE_CHAIN, - id: ruleChainId - } - } as RuleChain; - return of(ruleChain); - }) - ); - } - public getEdgeRuleChains(edgeId: string, pageLink: PageLink, config?: RequestConfig): Observable> { return this.http.get>(`/api/edge/${edgeId}/ruleChains${pageLink.toQuery()}`, defaultHttpOptionsFromConfig(config)); diff --git a/ui-ngx/src/app/modules/home/components/import-export/import-export.service.ts b/ui-ngx/src/app/modules/home/components/import-export/import-export.service.ts index 61cc7ae478..20e21f0aad 100644 --- a/ui-ngx/src/app/modules/home/components/import-export/import-export.service.ts +++ b/ui-ngx/src/app/modules/home/components/import-export/import-export.service.ts @@ -423,7 +423,7 @@ export class ImportExportService { public importRuleChain(expectedRuleChainType: RuleChainType): Observable { return this.openImportDialog('rulechain.import', 'rulechain.rulechain-file').pipe( - mergeMap((ruleChainImport: RuleChainImport) => { + map((ruleChainImport: RuleChainImport) => { if (!this.validateImportedRuleChain(ruleChainImport)) { this.store.dispatch(new ActionNotificationShow( {message: this.translate.instant('rulechain.invalid-rulechain-file-error'), @@ -435,12 +435,7 @@ export class ImportExportService { type: 'error'})); throw new Error('Invalid rule chain type'); } else { - return this.ruleChainService.resolveRuleChainMetadata(ruleChainImport.metadata).pipe( - map((resolvedMetadata) => { - ruleChainImport.resolvedMetadata = resolvedMetadata; - return ruleChainImport; - }) - ); + return ruleChainImport; } }), catchError((err) => { diff --git a/ui-ngx/src/app/modules/home/pages/edge/edge-routing.module.ts b/ui-ngx/src/app/modules/home/pages/edge/edge-routing.module.ts index 4ffa51a6bd..32147ff475 100644 --- a/ui-ngx/src/app/modules/home/pages/edge/edge-routing.module.ts +++ b/ui-ngx/src/app/modules/home/pages/edge/edge-routing.module.ts @@ -18,7 +18,7 @@ import { NgModule } from '@angular/core'; import { RouterModule, Routes } from '@angular/router'; import { EntitiesTableComponent } from '@home/components/entity/entities-table.component'; import { Authority } from '@shared/models/authority.enum'; -import { EdgesTableConfigResolver } from '@home/pages/edge/edges-table-config.resolver' +import { EdgesTableConfigResolver } from '@home/pages/edge/edges-table-config.resolver'; import { AssetsTableConfigResolver } from '@home/pages/asset/assets-table-config.resolver'; import { DevicesTableConfigResolver } from '@home/pages/device/devices-table-config.resolver'; import { EntityViewsTableConfigResolver } from '@home/pages/entity-view/entity-views-table-config.resolver'; @@ -32,7 +32,7 @@ import { ConfirmOnExitGuard } from '@core/guards/confirm-on-exit.guard'; import { RuleChainType } from '@shared/models/rule-chain.models'; import { importRuleChainBreadcumbLabelFunction, - ResolvedRuleChainMetaDataResolver, + RuleChainMetaDataResolver, ruleChainBreadcumbLabelFunction, RuleChainImportGuard, RuleChainResolver, @@ -181,7 +181,7 @@ const routes: Routes = [ }, resolve: { ruleChain: RuleChainResolver, - ruleChainMetaData: ResolvedRuleChainMetaDataResolver, + ruleChainMetaData: RuleChainMetaDataResolver, ruleNodeComponents: RuleNodeComponentsResolver, tooltipster: TooltipsterResolver } @@ -243,7 +243,7 @@ const routes: Routes = [ }, resolve: { ruleChain: RuleChainResolver, - ruleChainMetaData: ResolvedRuleChainMetaDataResolver, + ruleChainMetaData: RuleChainMetaDataResolver, ruleNodeComponents: RuleNodeComponentsResolver, tooltipster: TooltipsterResolver } diff --git a/ui-ngx/src/app/modules/home/pages/rulechain/add-rule-node-link-dialog.component.html b/ui-ngx/src/app/modules/home/pages/rulechain/add-rule-node-link-dialog.component.html index 3ae5bfeb1c..05aafce2c5 100644 --- a/ui-ngx/src/app/modules/home/pages/rulechain/add-rule-node-link-dialog.component.html +++ b/ui-ngx/src/app/modules/home/pages/rulechain/add-rule-node-link-dialog.component.html @@ -34,7 +34,8 @@ required formControlName="link" [allowedLabels]="labels" - [allowCustom]="allowCustomLabels"> + [allowCustom]="allowCustomLabels" + [sourceRuleChainId]="sourceRuleChainId">
diff --git a/ui-ngx/src/app/modules/home/pages/rulechain/link-labels.component.ts b/ui-ngx/src/app/modules/home/pages/rulechain/link-labels.component.ts index acfca56c16..66be6c0f51 100644 --- a/ui-ngx/src/app/modules/home/pages/rulechain/link-labels.component.ts +++ b/ui-ngx/src/app/modules/home/pages/rulechain/link-labels.component.ts @@ -25,7 +25,8 @@ import { MatAutocomplete, MatAutocompleteSelectedEvent } from '@angular/material import { MatChipInputEvent, MatChipList } from '@angular/material/chips'; import { TranslateService } from '@ngx-translate/core'; import { COMMA, ENTER, SEMICOLON } from '@angular/cdk/keycodes'; -import { map, mergeMap, share, startWith } from 'rxjs/operators'; +import { catchError, map, mergeMap, share, startWith } from 'rxjs/operators'; +import { RuleChainService } from '@core/http/rule-chain.service'; @Component({ selector: 'tb-link-labels', @@ -68,6 +69,9 @@ export class LinkLabelsComponent implements ControlValueAccessor, OnInit, OnChan @Input() allowedLabels: {[label: string]: LinkLabel}; + @Input() + sourceRuleChainId: string; + linksFormGroup: FormGroup; modelValue: Array; @@ -86,7 +90,8 @@ export class LinkLabelsComponent implements ControlValueAccessor, OnInit, OnChan constructor(private fb: FormBuilder, public truncate: TruncatePipe, - public translate: TranslateService) { + public translate: TranslateService, + private ruleChainService: RuleChainService) { this.linksFormGroup = this.fb.group({ label: [null] }); @@ -115,7 +120,7 @@ export class LinkLabelsComponent implements ControlValueAccessor, OnInit, OnChan for (const propName of Object.keys(changes)) { const change = changes[propName]; if (change.currentValue !== change.previousValue) { - if (['allowCustom', 'allowedLabels'].includes(propName)) { + if (['allowCustom', 'allowedLabels', 'sourceRuleChainId'].includes(propName)) { reloadLabels = true; } } @@ -139,25 +144,50 @@ export class LinkLabelsComponent implements ControlValueAccessor, OnInit, OnChan this.labelsList.length = 0; this.labels.length = 0; this.modelValue = value; - for (const label of Object.keys(this.allowedLabels)) { - this.labelsList.push({name: this.allowedLabels[label].name, value: this.allowedLabels[label].value}); - } - if (value) { - value.forEach((label) => { - if (this.allowedLabels[label]) { - this.labels.push(deepClone(this.allowedLabels[label])); - } else { - this.labels.push({ - name: label, - value: label - }); - } - }); - } - if (this.chipList && this.required) { - this.chipList.errorState = this.labels.length ? false : true; + this.prepareLabelsList().subscribe((labelsList) => { + this.labelsList = labelsList; + if (value) { + value.forEach((label) => { + if (this.allowedLabels[label]) { + this.labels.push(deepClone(this.allowedLabels[label])); + } else { + this.labels.push({ + name: label, + value: label + }); + } + }); + } + if (this.chipList && this.required) { + this.chipList.errorState = !this.labels.length; + } + this.linksFormGroup.get('label').patchValue('', {emitEvent: true}); + }); + } + + prepareLabelsList(): Observable> { + const labelsList: Array = []; + if (this.sourceRuleChainId) { + return this.ruleChainService.getRuleChainOutputLabels(this.sourceRuleChainId, {ignoreErrors: true}).pipe( + map((labels) => { + for (const label of labels) { + labelsList.push({ + name: label, + value: label + }); + } + return labelsList; + }), + catchError(() => { + return of(labelsList); + }) + ); + } else { + for (const label of Object.keys(this.allowedLabels)) { + labelsList.push({name: this.allowedLabels[label].name, value: this.allowedLabels[label].value}); + } + return of(labelsList); } - this.linksFormGroup.get('label').patchValue('', {emitEvent: true}); } displayLabelFn(label?: LinkLabel): string | undefined { @@ -165,7 +195,7 @@ export class LinkLabelsComponent implements ControlValueAccessor, OnInit, OnChan } textIsNotEmpty(text: string): boolean { - return (text && text != null && text.length > 0) ? true : false; + return (text && text.length > 0); } createLinkLabel($event: Event, value: string) { diff --git a/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-colors.scss b/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-colors.scss index a0896dbacd..07f2b66d50 100644 --- a/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-colors.scss +++ b/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-colors.scss @@ -34,7 +34,7 @@ background-color: #fbc766; } - &.tb-rule-chain-type { + &.tb-flow-type { background-color: #d6c4f1; } diff --git a/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-config.component.ts b/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-config.component.ts index f709da687f..8fd4778abe 100644 --- a/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-config.component.ts +++ b/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-config.component.ts @@ -37,6 +37,7 @@ import { coerceBooleanProperty } from '@angular/cdk/coercion'; import { TranslateService } from '@ngx-translate/core'; import { JsonObjectEditComponent } from '@shared/components/json-object-edit.component'; import { deepClone } from '@core/utils'; +import { RuleChainType } from '@shared/models/rule-chain.models'; @Component({ selector: 'tb-rule-node-config', @@ -69,6 +70,12 @@ export class RuleNodeConfigComponent implements ControlValueAccessor, OnInit, On @Input() ruleNodeId: string; + @Input() + ruleChainId: string; + + @Input() + ruleChainType: RuleChainType; + nodeDefinitionValue: RuleNodeDefinition; @Input() @@ -186,6 +193,8 @@ export class RuleNodeConfigComponent implements ControlValueAccessor, OnInit, On this.definedConfigComponentRef = this.definedConfigContainer.createComponent(factory); this.definedConfigComponent = this.definedConfigComponentRef.instance; this.definedConfigComponent.ruleNodeId = this.ruleNodeId; + this.definedConfigComponent.ruleChainId = this.ruleChainId; + this.definedConfigComponent.ruleChainType = this.ruleChainType; this.definedConfigComponent.configuration = this.configuration; this.changeSubscription = this.definedConfigComponent.configurationChanged.subscribe((configuration) => { this.updateModel(configuration); diff --git a/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-details.component.html b/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-details.component.html index 451b8ad8ee..e390175682 100644 --- a/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-details.component.html +++ b/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-details.component.html @@ -15,7 +15,7 @@ limitations under the License. --> -
+
-
+
rulenode.name @@ -43,6 +43,8 @@
@@ -52,19 +54,5 @@
-
- - -
- - rulenode.description - - -
-
diff --git a/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-details.component.ts b/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-details.component.ts index 4627b2a06b..861f6123e1 100644 --- a/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-details.component.ts +++ b/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-details.component.ts @@ -75,28 +75,16 @@ export class RuleNodeDetailsComponent extends PageComponent implements OnInit, O this.ruleNodeFormSubscription = null; } if (this.ruleNode) { - if (this.ruleNode.component.type !== RuleNodeType.RULE_CHAIN) { - - this.ruleNodeFormGroup = this.fb.group({ - name: [this.ruleNode.name, [Validators.required, Validators.pattern('(.|\\s)*\\S(.|\\s)*'), Validators.maxLength(255)]], - debugMode: [this.ruleNode.debugMode, []], - configuration: [this.ruleNode.configuration, [Validators.required]], - additionalInfo: this.fb.group( - { - description: [this.ruleNode.additionalInfo ? this.ruleNode.additionalInfo.description : ''], - } - ) - }); - } else { - this.ruleNodeFormGroup = this.fb.group({ - targetRuleChainId: [this.ruleNode.targetRuleChainId, [Validators.required]], - additionalInfo: this.fb.group( - { - description: [this.ruleNode.additionalInfo ? this.ruleNode.additionalInfo.description : ''], - } - ) - }); - } + this.ruleNodeFormGroup = this.fb.group({ + name: [this.ruleNode.name, [Validators.required, Validators.pattern('(.|\\s)*\\S(.|\\s)*'), Validators.maxLength(255)]], + debugMode: [this.ruleNode.debugMode, []], + configuration: [this.ruleNode.configuration, [Validators.required]], + additionalInfo: this.fb.group( + { + description: [this.ruleNode.additionalInfo ? this.ruleNode.additionalInfo.description : ''], + } + ) + }); this.ruleNodeFormSubscription = this.ruleNodeFormGroup.valueChanges.subscribe(() => { this.updateRuleNode(); }); @@ -107,23 +95,8 @@ export class RuleNodeDetailsComponent extends PageComponent implements OnInit, O private updateRuleNode() { const formValue = this.ruleNodeFormGroup.value || {}; - - if (this.ruleNode.component.type === RuleNodeType.RULE_CHAIN) { - const targetRuleChainId: string = formValue.targetRuleChainId; - if (this.ruleNode.targetRuleChainId !== targetRuleChainId && targetRuleChainId) { - this.ruleChainService.getRuleChain(targetRuleChainId).subscribe( - (ruleChain) => { - this.ruleNode.name = ruleChain.name; - Object.assign(this.ruleNode, formValue); - } - ); - } else { - Object.assign(this.ruleNode, formValue); - } - } else { - formValue.name = formValue.name.trim(); - Object.assign(this.ruleNode, formValue); - } + formValue.name = formValue.name.trim(); + Object.assign(this.ruleNode, formValue); } ngOnInit(): void { @@ -141,20 +114,19 @@ export class RuleNodeDetailsComponent extends PageComponent implements OnInit, O } validate() { - if (this.ruleNode.component.type !== RuleNodeType.RULE_CHAIN) { - this.ruleNodeConfigComponent.validate(); - } + this.ruleNodeConfigComponent.validate(); } openRuleChain($event: Event) { if ($event) { $event.stopPropagation(); } - if (this.ruleNode.targetRuleChainId) { + const ruleChainId = this.ruleNodeFormGroup.get('configuration')?.value?.ruleChainId; + if (ruleChainId) { if (this.ruleChainType === RuleChainType.EDGE) { - this.router.navigateByUrl(`/edgeManagement/ruleChains/${this.ruleNode.targetRuleChainId}`); + this.router.navigateByUrl(`/edgeManagement/ruleChains/${ruleChainId}`); } else { - this.router.navigateByUrl(`/ruleChains/${this.ruleNode.targetRuleChainId}`); + this.router.navigateByUrl(`/ruleChains/${ruleChainId}`); } } } diff --git a/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-link.component.html b/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-link.component.html index 564017b7c9..7a62dd7105 100644 --- a/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-link.component.html +++ b/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-link.component.html @@ -22,6 +22,7 @@ formControlName="labels" [allowedLabels]="allowedLabels" [allowCustom]="allowCustom" + [sourceRuleChainId]="sourceRuleChainId" >
diff --git a/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-link.component.ts b/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-link.component.ts index 8ca7cf190b..7c14097979 100644 --- a/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-link.component.ts +++ b/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-link.component.ts @@ -57,6 +57,9 @@ export class RuleNodeLinkComponent implements ControlValueAccessor, OnInit { @Input() allowedLabels: {[label: string]: LinkLabel}; + @Input() + sourceRuleChainId: string; + ruleNodeLinkFormGroup: FormGroup; modelValue: FcRuleEdge; diff --git a/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.html b/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.html index 997cfb3cd5..1daaab95da 100644 --- a/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.html +++ b/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.html @@ -158,7 +158,8 @@ #tbRuleNodeLink [(ngModel)]="editingRuleNodeLink" [allowedLabels]="editingRuleNodeLinkLabels" - [allowCustom]="editingRuleNodeAllowCustomLabels"> + [allowCustom]="editingRuleNodeAllowCustomLabels" + [sourceRuleChainId]="editingRuleNodeSourceRuleChainId"> diff --git a/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.scss b/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.scss index aab0c4d127..24b1ecc9b0 100644 --- a/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.scss +++ b/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.scss @@ -184,7 +184,7 @@ display: block; position: absolute; top: 11px; - right: -12px; + right: 10px; border: 1px solid #FFFFFF; border-radius: 4px; line-height: 18px; diff --git a/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.ts b/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.ts index cc2c6c903d..8784716861 100644 --- a/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.ts +++ b/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.ts @@ -43,12 +43,10 @@ import { ActivatedRoute, Router } from '@angular/router'; import { inputNodeComponent, NodeConnectionInfo, - ResolvedRuleChainMetaData, RuleChain, - RuleChainConnectionInfo, RuleChainImport, RuleChainMetaData, - ruleChainNodeComponent, RuleChainType + RuleChainType } from '@shared/models/rule-chain.models'; import { FcItemInfo, FlowchartConstants, NgxFlowchartComponent, UserCallbacks } from 'ngx-flowchart'; import { @@ -75,7 +73,6 @@ import { DialogComponent } from '@shared/components/dialog.component'; import { MatMenuTrigger } from '@angular/material/menu'; import { ItemBufferService, RuleNodeConnection } from '@core/services/item-buffer.service'; import { Hotkey } from 'angular2-hotkeys'; -import { EntityType } from '@shared/models/entity-type.models'; import { DebugEventType, EventType } from '@shared/models/event.models'; import Timeout = NodeJS.Timeout; @@ -130,6 +127,7 @@ export class RuleChainPageComponent extends PageComponent editingRuleNodeIndex = -1; editingRuleNodeAllowCustomLabels = false; editingRuleNodeLinkLabels: {[label: string]: LinkLabel}; + editingRuleNodeSourceRuleChainId: string; @ViewChild('tbRuleNode') ruleNodeComponent: RuleNodeDetailsComponent; @ViewChild('tbRuleNodeLink') ruleNodeLinkComponent: RuleNodeLinkComponent; @@ -147,7 +145,7 @@ export class RuleChainPageComponent extends PageComponent ruleNodeTypeSearch = ''; ruleChain: RuleChain; - ruleChainMetaData: ResolvedRuleChainMetaData; + ruleChainMetaData: RuleChainMetaData; ruleChainModel: FcRuleNodeModel = { nodes: [], @@ -179,16 +177,11 @@ export class RuleChainPageComponent extends PageComponent createEdge: (event, edge: FcRuleEdge) => { const sourceNode = this.ruleChainCanvas.modelService.nodes.getNodeByConnectorId(edge.source) as FcRuleNode; if (sourceNode.component.type === RuleNodeType.INPUT) { - const destNode = this.ruleChainCanvas.modelService.nodes.getNodeByConnectorId(edge.destination) as FcRuleNode; - if (destNode.component.type === RuleNodeType.RULE_CHAIN) { - return NEVER; - } else { - const found = this.ruleChainModel.edges.find(theEdge => theEdge.source === (this.inputConnectorId + '')); - if (found) { - this.ruleChainCanvas.modelService.edges.delete(found); - } - return of(edge); + const found = this.ruleChainModel.edges.find(theEdge => theEdge.source === (this.inputConnectorId + '')); + if (found) { + this.ruleChainCanvas.modelService.edges.delete(found); } + return of(edge); } else { if (edge.label) { if (!edge.labels) { @@ -198,8 +191,9 @@ export class RuleChainPageComponent extends PageComponent } else { const labels = this.ruleChainService.getRuleNodeSupportedLinks(sourceNode.component); const allowCustomLabels = this.ruleChainService.ruleNodeAllowCustomLinks(sourceNode.component); + const sourceRuleChainId = this.ruleChainService.ruleNodeSourceRuleChainId(sourceNode.component, sourceNode.configuration); this.enableHotKeys = false; - return this.addRuleNodeLink(edge, labels, allowCustomLabels).pipe( + return this.addRuleNodeLink(edge, labels, allowCustomLabels, sourceRuleChainId).pipe( tap(() => { this.enableHotKeys = true; }), @@ -294,7 +288,7 @@ export class RuleChainPageComponent extends PageComponent if (this.isImport) { const ruleChainImport: RuleChainImport = this.itembuffer.getRuleChainImport(); this.ruleChain = ruleChainImport.ruleChain; - this.ruleChainMetaData = ruleChainImport.resolvedMetadata; + this.ruleChainMetaData = ruleChainImport.metadata; } else { this.ruleChain = this.route.snapshot.data.ruleChain; this.ruleChainMetaData = this.route.snapshot.data.ruleChainMetaData; @@ -601,63 +595,6 @@ export class RuleChainPageComponent extends PageComponent } }); } - if (this.ruleChainMetaData.ruleChainConnections) { - const ruleChainsMap = this.ruleChainMetaData.targetRuleChainsMap; - const ruleChainNodesMap: {[ruleChainNodeId: string]: FcRuleNode} = {}; - const ruleChainEdgeMap: {[edgeKey: string]: FcRuleEdge} = {}; - this.ruleChainMetaData.ruleChainConnections.forEach((ruleChainConnection) => { - const ruleChain = ruleChainsMap[ruleChainConnection.targetRuleChainId.id]; - if (ruleChainConnection.additionalInfo && ruleChainConnection.additionalInfo.ruleChainNodeId) { - let ruleChainNode = ruleChainNodesMap[ruleChainConnection.additionalInfo.ruleChainNodeId]; - if (!ruleChainNode) { - ruleChainNode = { - id: 'rule-chain-node-' + this.nextNodeID++, - name: ruleChain.name ? ruleChain.name : 'Unresolved', - targetRuleChainId: ruleChain.name ? ruleChainConnection.targetRuleChainId.id : null, - error: ruleChain.name ? undefined : this.translate.instant('rulenode.invalid-target-rulechain'), - additionalInfo: ruleChainConnection.additionalInfo, - x: Math.round(ruleChainConnection.additionalInfo.layoutX), - y: Math.round(ruleChainConnection.additionalInfo.layoutY), - component: ruleChainNodeComponent, - nodeClass: ruleNodeTypeDescriptors.get(RuleNodeType.RULE_CHAIN).nodeClass, - icon: ruleNodeTypeDescriptors.get(RuleNodeType.RULE_CHAIN).icon, - connectors: [ - { - type: FlowchartConstants.leftConnectorType, - id: (this.nextConnectorID++) + '' - } - ], - ruleChainType: this.ruleChainType - }; - ruleChainNodesMap[ruleChainConnection.additionalInfo.ruleChainNodeId] = ruleChainNode; - this.ruleChainModel.nodes.push(ruleChainNode); - } - const sourceNode = nodes[ruleChainConnection.fromIndex]; - if (sourceNode) { - const connectors = sourceNode.connectors.filter(connector => connector.type === FlowchartConstants.rightConnectorType); - if (connectors && connectors.length) { - const sourceId = connectors[0].id; - const destId = ruleChainNode.connectors[0].id; - const edgeKey = sourceId + '_' + destId; - let ruleChainEdge = ruleChainEdgeMap[edgeKey]; - if (!ruleChainEdge) { - ruleChainEdge = { - source: sourceId, - destination: destId, - label: ruleChainConnection.type, - labels: [ruleChainConnection.type] - }; - ruleChainEdgeMap[edgeKey] = ruleChainEdge; - this.ruleChainModel.edges.push(ruleChainEdge); - } else { - ruleChainEdge.label += ' / ' + ruleChainConnection.type; - ruleChainEdge.labels.push(ruleChainConnection.type); - } - } - } - } - }); - } if (this.ruleChainCanvas) { this.ruleChainCanvas.adjustCanvasSize(true); } @@ -918,6 +855,8 @@ export class RuleChainPageComponent extends PageComponent this.editingRuleNode = null; this.editingRuleNodeLinkLabels = this.ruleChainService.getRuleNodeSupportedLinks(sourceNode.component); this.editingRuleNodeAllowCustomLabels = this.ruleChainService.ruleNodeAllowCustomLinks(sourceNode.component); + this.editingRuleNodeSourceRuleChainId = + this.ruleChainService.ruleNodeSourceRuleChainId(sourceNode.component, sourceNode.configuration); this.isEditingRuleNodeLink = true; this.editingRuleNodeLinkIndex = this.ruleChainModel.edges.indexOf(edge); this.editingRuleNodeLink = deepClone(edge); @@ -1093,7 +1032,7 @@ export class RuleChainPageComponent extends PageComponent const type = ruleNodeTypeDescriptors.get(ruleNodeType); this.displayTooltip(event, '
' + - '
' + + '
' + '
' + this.translate.instant(type.name) + '
' + '
' + this.translate.instant(type.details) + '
' + '
' + @@ -1104,7 +1043,7 @@ export class RuleChainPageComponent extends PageComponent displayLibNodeDescriptionTooltip(event: MouseEvent, node: FcRuleNodeType) { this.displayTooltip(event, '
' + - '
' + + '
' + '
' + node.component.name + '
' + '
' + node.component.configurationDescriptor.nodeDefinition.description + '
' + '
' + node.component.configurationDescriptor.nodeDefinition.details + '
' + @@ -1129,7 +1068,7 @@ export class RuleChainPageComponent extends PageComponent } } let tooltipContent = '
' + - '
' + + '
' + '
' + name + '
' + '
' + desc + '
'; if (details) { @@ -1189,7 +1128,7 @@ export class RuleChainPageComponent extends PageComponent resetDebugModeInAllNodes() { let changed = false; this.ruleChainModel.nodes.forEach((node) => { - if (node.component.type !== RuleNodeType.INPUT && node.component.type !== RuleNodeType.RULE_CHAIN) { + if (node.component.type !== RuleNodeType.INPUT) { changed = changed || node.debugMode; node.debugMode = false; } @@ -1223,12 +1162,11 @@ export class RuleChainPageComponent extends PageComponent const ruleChainMetaData: RuleChainMetaData = { ruleChainId: this.ruleChain.id, nodes: [], - connections: [], - ruleChainConnections: [] + connections: [] }; const nodes: FcRuleNode[] = []; this.ruleChainModel.nodes.forEach((node) => { - if (node.component.type !== RuleNodeType.INPUT && node.component.type !== RuleNodeType.RULE_CHAIN) { + if (node.component.type !== RuleNodeType.INPUT) { const ruleNode: RuleNode = { id: node.ruleNodeId, type: node.component.clazz, @@ -1253,35 +1191,19 @@ export class RuleChainPageComponent extends PageComponent const destNode = this.ruleChainCanvas.modelService.nodes.getNodeByConnectorId(edge.destination); if (sourceNode.component.type !== RuleNodeType.INPUT) { const fromIndex = nodes.indexOf(sourceNode); - if (destNode.component.type === RuleNodeType.RULE_CHAIN) { - const ruleChainConnection = { - fromIndex, - targetRuleChainId: {entityType: EntityType.RULE_CHAIN, id: destNode.targetRuleChainId}, - additionalInfo: destNode.additionalInfo ? destNode.additionalInfo : {} - } as RuleChainConnectionInfo; - ruleChainConnection.additionalInfo.layoutX = Math.round(destNode.x); - ruleChainConnection.additionalInfo.layoutY = Math.round(destNode.y); - ruleChainConnection.additionalInfo.ruleChainNodeId = destNode.id; - edge.labels.forEach((label) => { - const newRuleChainConnection = deepClone(ruleChainConnection); - newRuleChainConnection.type = label; - ruleChainMetaData.ruleChainConnections.push(newRuleChainConnection); - }); - } else { - const toIndex = nodes.indexOf(destNode); - const nodeConnection = { - fromIndex, - toIndex - } as NodeConnectionInfo; - edge.labels.forEach((label) => { - const newNodeConnection = deepClone(nodeConnection); - newNodeConnection.type = label; - ruleChainMetaData.connections.push(newNodeConnection); - }); - } + const toIndex = nodes.indexOf(destNode); + const nodeConnection = { + fromIndex, + toIndex + } as NodeConnectionInfo; + edge.labels.forEach((label) => { + const newNodeConnection = deepClone(nodeConnection); + newNodeConnection.type = label; + ruleChainMetaData.connections.push(newNodeConnection); + }); } }); - this.ruleChainService.saveAndGetResolvedRuleChainMetadata(ruleChainMetaData).subscribe((savedRuleChainMetaData) => { + this.ruleChainService.saveRuleChainMetadata(ruleChainMetaData).subscribe((savedRuleChainMetaData) => { this.ruleChainMetaData = savedRuleChainMetaData; if (this.isImport) { this.isDirtyValue = false; @@ -1346,7 +1268,8 @@ export class RuleChainPageComponent extends PageComponent ); } - addRuleNodeLink(link: FcRuleEdge, labels: {[label: string]: LinkLabel}, allowCustomLabels: boolean): Observable { + addRuleNodeLink(link: FcRuleEdge, labels: {[label: string]: LinkLabel}, + allowCustomLabels: boolean, sourceRuleChainId: string): Observable { return this.dialog.open(AddRuleNodeLinkDialogComponent, { disableClose: true, @@ -1354,7 +1277,8 @@ export class RuleChainPageComponent extends PageComponent data: { link, labels, - allowCustomLabels + allowCustomLabels, + sourceRuleChainId } }).afterClosed(); } @@ -1384,7 +1308,7 @@ export class RuleChainPageComponent extends PageComponent } ); const content = '
' + - '
' + + '
' + '
' + node.error + '
' + '
' + '
'; @@ -1452,6 +1376,7 @@ export interface AddRuleNodeLinkDialogData { link: FcRuleEdge; labels: {[label: string]: LinkLabel}; allowCustomLabels: boolean; + sourceRuleChainId: string; } @Component({ @@ -1468,6 +1393,7 @@ export class AddRuleNodeLinkDialogComponent extends DialogComponent { } @Injectable() -export class ResolvedRuleChainMetaDataResolver implements Resolve { +export class RuleChainMetaDataResolver implements Resolve { constructor(private ruleChainService: RuleChainService) { } - resolve(route: ActivatedRouteSnapshot): Observable { + resolve(route: ActivatedRouteSnapshot): Observable { const ruleChainId = route.params.ruleChainId; - return this.ruleChainService.getResolvedRuleChainMetadata(ruleChainId); + return this.ruleChainService.getRuleChainMetadata(ruleChainId); } } @@ -160,7 +160,7 @@ const routes: Routes = [ }, resolve: { ruleChain: RuleChainResolver, - ruleChainMetaData: ResolvedRuleChainMetaDataResolver, + ruleChainMetaData: RuleChainMetaDataResolver, ruleNodeComponents: RuleNodeComponentsResolver, tooltipster: TooltipsterResolver } @@ -196,7 +196,7 @@ const routes: Routes = [ providers: [ RuleChainsTableConfigResolver, RuleChainResolver, - ResolvedRuleChainMetaDataResolver, + RuleChainMetaDataResolver, RuleNodeComponentsResolver, TooltipsterResolver, RuleChainImportGuard diff --git a/ui-ngx/src/app/modules/home/pages/rulechain/rulenode.component.html b/ui-ngx/src/app/modules/home/pages/rulechain/rulenode.component.html index da53c21a08..3de5679cc5 100644 --- a/ui-ngx/src/app/modules/home/pages/rulechain/rulenode.component.html +++ b/ui-ngx/src/app/modules/home/pages/rulechain/rulenode.component.html @@ -59,8 +59,8 @@ ×
-
-
+
+
diff --git a/ui-ngx/src/app/modules/home/pages/rulechain/rulenode.component.ts b/ui-ngx/src/app/modules/home/pages/rulechain/rulenode.component.ts index ce7ff340d5..6825f7b5ff 100644 --- a/ui-ngx/src/app/modules/home/pages/rulechain/rulenode.component.ts +++ b/ui-ngx/src/app/modules/home/pages/rulechain/rulenode.component.ts @@ -20,6 +20,7 @@ import { FcNodeComponent } from 'ngx-flowchart'; import { FcRuleNode, RuleNodeType } from '@shared/models/rule-node.models'; import { Router } from '@angular/router'; import { RuleChainType } from '@app/shared/models/rule-chain.models'; +import { TranslateService } from '@ngx-translate/core'; @Component({ // tslint:disable-next-line:component-selector @@ -33,6 +34,7 @@ export class RuleNodeComponent extends FcNodeComponent implements OnInit { RuleNodeType = RuleNodeType; constructor(private sanitizer: DomSanitizer, + private translate: TranslateService, private router: Router) { super(); } @@ -48,13 +50,48 @@ export class RuleNodeComponent extends FcNodeComponent implements OnInit { if ($event) { $event.stopPropagation(); } - if (node.targetRuleChainId) { + if (node.configuration?.ruleChainId) { if (node.ruleChainType === RuleChainType.EDGE) { - this.router.navigateByUrl(`/edgeManagement/ruleChains/${node.targetRuleChainId}`); + this.router.navigateByUrl(`/edgeManagement/ruleChains/${node.configuration?.ruleChainId}`); } else { - this.router.navigateByUrl(`/ruleChains/${node.targetRuleChainId}`); + this.router.navigateByUrl(`/ruleChains/${node.configuration?.ruleChainId}`); } } } + + displayOpenRuleChainTooltip($event: MouseEvent, node: FcRuleNode) { + if ($event) { + $event.stopPropagation(); + } + this.userNodeCallbacks.mouseLeave($event, node); + const tooltipContent = '
' + + '
' + + '
' + this.translate.instant('rulechain.open-rulechain') + '
'; + const element = $($event.target); + element.tooltipster( + { + theme: 'tooltipster-shadow', + delay: 100, + trigger: 'custom', + triggerOpen: { + click: false, + tap: false + }, + triggerClose: { + click: true, + tap: true, + scroll: true, + mouseleave: true + }, + side: 'top', + distance: 12, + trackOrigin: true + } + ); + const tooltip = element.tooltipster('instance'); + const contentElement = $(tooltipContent); + tooltip.content(contentElement); + tooltip.open(); + } } diff --git a/ui-ngx/src/app/shared/models/component-descriptor.models.ts b/ui-ngx/src/app/shared/models/component-descriptor.models.ts index e266113848..068a902b18 100644 --- a/ui-ngx/src/app/shared/models/component-descriptor.models.ts +++ b/ui-ngx/src/app/shared/models/component-descriptor.models.ts @@ -21,7 +21,8 @@ export enum ComponentType { FILTER = 'FILTER', TRANSFORMATION = 'TRANSFORMATION', ACTION = 'ACTION', - EXTERNAL = 'EXTERNAL' + EXTERNAL = 'EXTERNAL', + FLOW = 'FLOW' } export enum ComponentScope { diff --git a/ui-ngx/src/app/shared/models/rule-chain.models.ts b/ui-ngx/src/app/shared/models/rule-chain.models.ts index 925ad0b432..61f70bfcb6 100644 --- a/ui-ngx/src/app/shared/models/rule-chain.models.ts +++ b/ui-ngx/src/app/shared/models/rule-chain.models.ts @@ -38,17 +38,11 @@ export interface RuleChainMetaData { firstNodeIndex?: number; nodes: Array; connections: Array; - ruleChainConnections: Array; -} - -export interface ResolvedRuleChainMetaData extends RuleChainMetaData { - targetRuleChainsMap: {[ruleChainId: string]: RuleChain}; } export interface RuleChainImport { ruleChain: RuleChain; metadata: RuleChainMetaData; - resolvedMetadata?: ResolvedRuleChainMetaData; } export interface NodeConnectionInfo { @@ -57,39 +51,16 @@ export interface NodeConnectionInfo { type: string; } -export interface RuleChainConnectionInfo { - fromIndex: number; - targetRuleChainId: RuleChainId; - additionalInfo: any; - type: string; -} - export const ruleNodeTypeComponentTypes: ComponentType[] = [ ComponentType.FILTER, ComponentType.ENRICHMENT, ComponentType.TRANSFORMATION, ComponentType.ACTION, - ComponentType.EXTERNAL + ComponentType.EXTERNAL, + ComponentType.FLOW ]; -export const ruleChainNodeComponent: RuleNodeComponentDescriptor = { - type: RuleNodeType.RULE_CHAIN, - name: 'rule chain', - clazz: 'tb.internal.RuleChain', - configurationDescriptor: { - nodeDefinition: { - description: '', - details: 'Forwards incoming messages to specified Rule Chain', - inEnabled: true, - outEnabled: false, - relationTypes: [], - customRelations: false, - defaultConfiguration: {} - } - } -}; - export const unknownNodeComponent: RuleNodeComponentDescriptor = { type: RuleNodeType.UNKNOWN, name: 'unknown', diff --git a/ui-ngx/src/app/shared/models/rule-node.models.ts b/ui-ngx/src/app/shared/models/rule-node.models.ts index 097f8b2edc..ce2563826f 100644 --- a/ui-ngx/src/app/shared/models/rule-node.models.ts +++ b/ui-ngx/src/app/shared/models/rule-node.models.ts @@ -52,6 +52,7 @@ export interface RuleNodeDefinition { outEnabled: boolean; relationTypes: string[]; customRelations: boolean; + ruleChainNode?: boolean; defaultConfiguration: RuleNodeConfiguration; icon?: string; iconUrl?: string; @@ -67,6 +68,8 @@ export interface RuleNodeConfigurationDescriptor { export interface IRuleNodeConfigurationComponent { ruleNodeId: string; + ruleChainId: string; + ruleChainType: RuleChainType; configuration: RuleNodeConfiguration; configurationChanged: Observable; validate(); @@ -74,11 +77,16 @@ export interface IRuleNodeConfigurationComponent { } @Directive() +// tslint:disable-next-line:directive-class-suffix export abstract class RuleNodeConfigurationComponent extends PageComponent implements IRuleNodeConfigurationComponent, OnInit, AfterViewInit { ruleNodeId: string; + ruleChainId: string; + + ruleChainType: RuleChainType; + configurationValue: RuleNodeConfiguration; private configurationSet = false; @@ -184,7 +192,7 @@ export enum RuleNodeType { TRANSFORMATION = 'TRANSFORMATION', ACTION = 'ACTION', EXTERNAL = 'EXTERNAL', - RULE_CHAIN = 'RULE_CHAIN', + FLOW = 'FLOW', UNKNOWN = 'UNKNOWN', INPUT = 'INPUT' } @@ -195,7 +203,7 @@ export const ruleNodeTypesLibrary = [ RuleNodeType.TRANSFORMATION, RuleNodeType.ACTION, RuleNodeType.EXTERNAL, - RuleNodeType.RULE_CHAIN, + RuleNodeType.FLOW, ]; export interface RuleNodeTypeDescriptor { @@ -260,12 +268,12 @@ export const ruleNodeTypeDescriptors = new Map Date: Wed, 8 Dec 2021 15:57:52 +0200 Subject: [PATCH 218/432] Removed TODO --- .../org/thingsboard/server/controller/RuleChainController.java | 1 - 1 file changed, 1 deletion(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java b/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java index 9122990339..5357daacce 100644 --- a/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java +++ b/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java @@ -361,7 +361,6 @@ public class RuleChainController extends BaseController { @ApiParam(value = "A JSON value representing the rule chain metadata.") @RequestBody RuleChainMetaData ruleChainMetaData, @ApiParam(value = "Update related rule nodes.") - //TODO: change default value to "false" before merge @RequestParam(value = "updateRelated", required = false, defaultValue = "true") boolean updateRelated ) throws ThingsboardException { try { From b5da8752c57b7c716c1d884f44d6c8c9add3097e Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Wed, 8 Dec 2021 16:23:54 +0200 Subject: [PATCH 219/432] Use output rule node name instead of label --- .../controller/RuleChainController.java | 4 --- .../rule/DefaultTbRuleChainService.java | 29 ++++++--------- .../data/rule/RuleNodeUpdateResult.java | 3 +- .../server/dao/rule/BaseRuleChainService.java | 4 +-- .../engine/flow/TbRuleChainOutputNode.java | 11 +++--- .../TbRuleChainOutputNodeConfiguration.java | 35 ------------------- .../static/rulenode/rulenode-core-config.js | 9 ++--- 7 files changed, 21 insertions(+), 74 deletions(-) delete mode 100644 rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbRuleChainOutputNodeConfiguration.java diff --git a/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java b/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java index 5357daacce..85f469a6c9 100644 --- a/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java +++ b/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java @@ -36,10 +36,7 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestController; -import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.rule.engine.api.ScriptEngine; -import org.thingsboard.rule.engine.flow.TbRuleChainOutputNode; -import org.thingsboard.rule.engine.flow.TbRuleChainOutputNodeConfiguration; import org.thingsboard.server.actors.ActorSystemContext; import org.thingsboard.server.actors.tenant.DebugTbRateLimits; import org.thingsboard.server.common.data.DataConstants; @@ -71,7 +68,6 @@ import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsgDataType; import org.thingsboard.server.common.msg.TbMsgMetaData; import org.thingsboard.server.dao.event.EventService; -import org.thingsboard.server.dao.rule.RuleChainService; import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.service.install.InstallScripts; import org.thingsboard.server.service.rule.TbRuleChainService; diff --git a/application/src/main/java/org/thingsboard/server/service/rule/DefaultTbRuleChainService.java b/application/src/main/java/org/thingsboard/server/service/rule/DefaultTbRuleChainService.java index e6d1ba1d8a..ff2599c0ff 100644 --- a/application/src/main/java/org/thingsboard/server/service/rule/DefaultTbRuleChainService.java +++ b/application/src/main/java/org/thingsboard/server/service/rule/DefaultTbRuleChainService.java @@ -23,7 +23,6 @@ import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.rule.engine.flow.TbRuleChainInputNode; import org.thingsboard.rule.engine.flow.TbRuleChainInputNodeConfiguration; import org.thingsboard.rule.engine.flow.TbRuleChainOutputNode; -import org.thingsboard.rule.engine.flow.TbRuleChainOutputNodeConfiguration; import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.data.id.RuleChainId; import org.thingsboard.server.common.data.id.RuleNodeId; @@ -65,14 +64,7 @@ public class DefaultTbRuleChainService implements TbRuleChainService { Set outputLabels = new TreeSet<>(); for (RuleNode ruleNode : metaData.getNodes()) { if (isOutputRuleNode(ruleNode)) { - try { - var configuration = JacksonUtil.treeToValue(ruleNode.getConfiguration(), TbRuleChainOutputNodeConfiguration.class); - if (StringUtils.isNotEmpty(configuration.getLabel())) { - outputLabels.add(configuration.getLabel()); - } - } catch (Exception e) { - log.warn("[{}][{}] Failed to decode rule node configuration", tenantId, ruleChainId, e); - } + outputLabels.add(ruleNode.getName()); } } return outputLabels; @@ -130,16 +122,15 @@ public class DefaultTbRuleChainService implements TbRuleChainService { Set confusedLabels = new HashSet<>(); Map updatedLabels = new HashMap<>(); for (RuleNodeUpdateResult update : result.getUpdatedRuleNodes()) { - var node = update.getNewRuleNode(); - if (isOutputRuleNode(node)) { + var oldNode = update.getOldRuleNode(); + var newNode = update.getNewRuleNode(); + if (isOutputRuleNode(newNode)) { try { - TbRuleChainOutputNodeConfiguration oldConf = JacksonUtil.treeToValue(update.getOldConfiguration(), TbRuleChainOutputNodeConfiguration.class); - TbRuleChainOutputNodeConfiguration newConf = JacksonUtil.treeToValue(node.getConfiguration(), TbRuleChainOutputNodeConfiguration.class); - oldLabels.add(oldConf.getLabel()); - newLabels.add(newConf.getLabel()); - if (!oldConf.getLabel().equals(newConf.getLabel())) { - String oldLabel = oldConf.getLabel(); - String newLabel = newConf.getLabel(); + oldLabels.add(oldNode.getName()); + newLabels.add(newNode.getName()); + if (!oldNode.getName().equals(newNode.getName())) { + String oldLabel = oldNode.getName(); + String newLabel = newNode.getName(); if (updatedLabels.containsKey(oldLabel) && !updatedLabels.get(oldLabel).equals(newLabel)) { confusedLabels.add(oldLabel); log.warn("[{}][{}] Can't automatically rename the label from [{}] to [{}] due to conflict [{}]", tenantId, ruleChainId, oldLabel, newLabel, updatedLabels.get(oldLabel)); @@ -149,7 +140,7 @@ public class DefaultTbRuleChainService implements TbRuleChainService { } } catch (Exception e) { - log.warn("[{}][{}][{}] Failed to decode rule node configuration", tenantId, ruleChainId, node.getId(), e); + log.warn("[{}][{}][{}] Failed to decode rule node configuration", tenantId, ruleChainId, newNode.getId(), e); } } } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleNodeUpdateResult.java b/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleNodeUpdateResult.java index a279533138..02f68ea5c2 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleNodeUpdateResult.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleNodeUpdateResult.java @@ -27,6 +27,7 @@ import java.util.Map; @Data public class RuleNodeUpdateResult { - private final JsonNode oldConfiguration; + private final RuleNode oldRuleNode; private final RuleNode newRuleNode; + } diff --git a/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java b/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java index e1aaa31d3c..33ef74db65 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java @@ -172,10 +172,10 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC newRuleNode = ruleChainMetaData.getNodes().get(index); toAddOrUpdate.add(newRuleNode); } else { - updatedRuleNodes.add(new RuleNodeUpdateResult(existingNode.getConfiguration(), null)); + updatedRuleNodes.add(new RuleNodeUpdateResult(existingNode, null)); toDelete.add(existingNode); } - updatedRuleNodes.add(new RuleNodeUpdateResult(existingNode.getConfiguration(), newRuleNode)); + updatedRuleNodes.add(new RuleNodeUpdateResult(existingNode, newRuleNode)); } if (nodes != null) { for (RuleNode node : toAddOrUpdate) { diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbRuleChainOutputNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbRuleChainOutputNode.java index f5f75f1275..59ddc1c096 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbRuleChainOutputNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbRuleChainOutputNode.java @@ -16,6 +16,7 @@ package org.thingsboard.rule.engine.flow; import lombok.extern.slf4j.Slf4j; +import org.thingsboard.rule.engine.api.EmptyNodeConfiguration; import org.thingsboard.rule.engine.api.RuleNode; import org.thingsboard.rule.engine.api.TbContext; import org.thingsboard.rule.engine.api.TbNode; @@ -30,28 +31,24 @@ import org.thingsboard.server.common.msg.TbMsg; @RuleNode( type = ComponentType.FLOW, name = "output", - configClazz = TbRuleChainOutputNodeConfiguration.class, + configClazz = EmptyNodeConfiguration.class, nodeDescription = "transfers the message to the caller rule chain", nodeDetails = "Produces output of the rule chain processing. " + "The output is forwarded to the caller rule chain, as an output of the corresponding \"input\" rule node. " + - "The rule node configuration contains the \"label\" parameter. " + - "This parameter corresponds to the relation type of the output message, and it is used to forward messages to other rule nodes in the caller rule chain. ", + "The output rule node name corresponds to the relation type of the output message, and it is used to forward messages to other rule nodes in the caller rule chain. ", uiResources = {"static/rulenode/rulenode-core-config.js"}, configDirective = "tbFlowNodeRuleChainOutputConfig", outEnabled = false ) public class TbRuleChainOutputNode implements TbNode { - private TbRuleChainOutputNodeConfiguration config; - @Override public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException { - this.config = TbNodeUtils.convert(configuration, TbRuleChainOutputNodeConfiguration.class); } @Override public void onMsg(TbContext ctx, TbMsg msg) { - ctx.output(msg, config.getLabel()); + ctx.output(msg, ctx.getSelf().getName()); } @Override diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbRuleChainOutputNodeConfiguration.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbRuleChainOutputNodeConfiguration.java deleted file mode 100644 index 8d220530c3..0000000000 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbRuleChainOutputNodeConfiguration.java +++ /dev/null @@ -1,35 +0,0 @@ -/** - * Copyright © 2016-2021 The Thingsboard Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.thingsboard.rule.engine.flow; - -import lombok.Data; -import org.thingsboard.rule.engine.api.NodeConfiguration; -import org.thingsboard.rule.engine.api.TbRelationTypes; -import org.thingsboard.server.common.data.DataConstants; - -@Data -public class TbRuleChainOutputNodeConfiguration implements NodeConfiguration { - - private String label; - - @Override - public TbRuleChainOutputNodeConfiguration defaultConfiguration() { - var result = new TbRuleChainOutputNodeConfiguration(); - result.setLabel(TbRelationTypes.SUCCESS); - return result; - } - -} diff --git a/rule-engine/rule-engine-components/src/main/resources/public/static/rulenode/rulenode-core-config.js b/rule-engine/rule-engine-components/src/main/resources/public/static/rulenode/rulenode-core-config.js index 702fdabe6f..54fbc87f07 100644 --- a/rule-engine/rule-engine-components/src/main/resources/public/static/rulenode/rulenode-core-config.js +++ b/rule-engine/rule-engine-components/src/main/resources/public/static/rulenode/rulenode-core-config.js @@ -3728,13 +3728,11 @@ class RuleChainOutputComponent extends RuleNodeConfigurationComponent { return this.ruleChainOutputConfigForm; } onConfigurationSet(configuration) { - this.ruleChainOutputConfigForm = this.fb.group({ - label: [configuration ? configuration.label : null, [Validators.required]] - }); + this.ruleChainOutputConfigForm = this.fb.group({}); } } RuleChainOutputComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RuleChainOutputComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); -RuleChainOutputComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: RuleChainOutputComponent, selector: "tb-flow-node-rule-chain-output-config", usesInheritance: true, ngImport: i0, template: "
\n \n tb.rulenode.label\n \n \n {{ 'tb.rulenode.label-required' | translate }}\n \n \n
\n", components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.MatError, selector: "mat-error", inputs: ["id"] }], pipes: { "translate": i4.TranslatePipe } }); +RuleChainOutputComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: RuleChainOutputComponent, selector: "tb-flow-node-rule-chain-output-config", usesInheritance: true, ngImport: i0, template: "
\n
\n
\n", directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }], pipes: { "translate": i4.TranslatePipe } }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RuleChainOutputComponent, decorators: [{ type: Component, args: [{ @@ -4191,8 +4189,7 @@ function addRuleNodeCoreLocaleEnglish(translate) { 'alarm-severity-pattern-hint': 'Hint: use ${metadataKey} ' + 'for value from metadata, $[messageKey] ' + 'for value from message body. Alarm severity should be system (CRITICAL, MAJOR etc.)', - label: 'Label', - 'label-required': 'Label is required' + 'output-node-name-hint': 'The rule node name corresponds to the relation type of the output message, and it is used to forward messages to other rule nodes in the caller rule chain.' }, 'key-val': { key: 'Key', From 54486049f41f1964897cf2d8077e1a5ddcb160fd Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Wed, 8 Dec 2021 16:38:07 +0200 Subject: [PATCH 220/432] Notifications on related rule chain upates --- .../controller/RuleChainController.java | 24 ++++++++++++++----- .../rule/DefaultTbRuleChainService.java | 17 ++++++------- .../service/rule/TbRuleChainService.java | 4 ++-- 3 files changed, 29 insertions(+), 16 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java b/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java index 85f469a6c9..2f9e325c8f 100644 --- a/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java +++ b/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java @@ -77,6 +77,8 @@ import org.thingsboard.server.service.security.permission.Operation; import org.thingsboard.server.service.security.permission.Resource; import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; @@ -373,23 +375,33 @@ public class RuleChainController extends BaseController { RuleChainUpdateResult result = ruleChainService.saveRuleChainMetaData(tenantId, ruleChainMetaData); checkNotNull(result.isSuccess() ? true : null); + List updatedRuleChains; if (updateRelated && result.isSuccess()) { - tbRuleChainService.updateRelatedRuleChains(tenantId, ruleChainMetaData.getRuleChainId(), result); + updatedRuleChains = tbRuleChainService.updateRelatedRuleChains(tenantId, ruleChainMetaData.getRuleChainId(), result); + } else { + updatedRuleChains = Collections.emptyList(); } RuleChainMetaData savedRuleChainMetaData = checkNotNull(ruleChainService.loadRuleChainMetaData(tenantId, ruleChainMetaData.getRuleChainId())); if (RuleChainType.CORE.equals(ruleChain.getType())) { tbClusterService.broadcastEntityStateChangeEvent(ruleChain.getTenantId(), ruleChain.getId(), ComponentLifecycleEvent.UPDATED); + updatedRuleChains.forEach(updatedRuleChain -> { + tbClusterService.broadcastEntityStateChangeEvent(updatedRuleChain.getTenantId(), updatedRuleChain.getId(), ComponentLifecycleEvent.UPDATED); + }); } - logEntityAction(ruleChain.getId(), ruleChain, - null, - ActionType.UPDATED, null, ruleChainMetaData); + logEntityAction(ruleChain.getId(), ruleChain, null, ActionType.UPDATED, null, ruleChainMetaData); + for (RuleChain updatedRuleChain : updatedRuleChains) { + RuleChainMetaData updatedRuleChainMetaData = checkNotNull(ruleChainService.loadRuleChainMetaData(tenantId, updatedRuleChain.getId())); + logEntityAction(updatedRuleChain.getId(), updatedRuleChain, null, ActionType.UPDATED, null, updatedRuleChainMetaData); + } if (RuleChainType.EDGE.equals(ruleChain.getType())) { - sendEntityNotificationMsg(ruleChain.getTenantId(), - ruleChain.getId(), EdgeEventActionType.UPDATED); + sendEntityNotificationMsg(ruleChain.getTenantId(), ruleChain.getId(), EdgeEventActionType.UPDATED); + updatedRuleChains.forEach(updatedRuleChain -> { + sendEntityNotificationMsg(updatedRuleChain.getTenantId(), updatedRuleChain.getId(), EdgeEventActionType.UPDATED); + }); } return savedRuleChainMetaData; diff --git a/application/src/main/java/org/thingsboard/server/service/rule/DefaultTbRuleChainService.java b/application/src/main/java/org/thingsboard/server/service/rule/DefaultTbRuleChainService.java index ff2599c0ff..14f56d1f6b 100644 --- a/application/src/main/java/org/thingsboard/server/service/rule/DefaultTbRuleChainService.java +++ b/application/src/main/java/org/thingsboard/server/service/rule/DefaultTbRuleChainService.java @@ -15,7 +15,6 @@ */ package org.thingsboard.server.service.rule; -import com.fasterxml.jackson.core.JsonProcessingException; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; @@ -23,7 +22,6 @@ import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.rule.engine.flow.TbRuleChainInputNode; import org.thingsboard.rule.engine.flow.TbRuleChainInputNodeConfiguration; import org.thingsboard.rule.engine.flow.TbRuleChainOutputNode; -import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.data.id.RuleChainId; import org.thingsboard.server.common.data.id.RuleNodeId; import org.thingsboard.server.common.data.id.TenantId; @@ -37,9 +35,7 @@ import org.thingsboard.server.common.data.rule.RuleNodeUpdateResult; import org.thingsboard.server.dao.relation.RelationService; import org.thingsboard.server.dao.rule.RuleChainService; import org.thingsboard.server.queue.util.TbCoreComponent; -import org.thingsboard.server.service.security.permission.Operation; -import java.util.ArrayList; import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; @@ -111,10 +107,11 @@ public class DefaultTbRuleChainService implements TbRuleChainService { } @Override - public void updateRelatedRuleChains(TenantId tenantId, RuleChainId ruleChainId, RuleChainUpdateResult result) { + public List updateRelatedRuleChains(TenantId tenantId, RuleChainId ruleChainId, RuleChainUpdateResult result) { + Set ruleChainIds = new HashSet<>(); log.debug("[{}][{}] Going to update links in related rule chains", tenantId, ruleChainId); if (result.getUpdatedRuleNodes() == null || result.getUpdatedRuleNodes().isEmpty()) { - return; + return null; } Set oldLabels = new HashSet<>(); @@ -149,19 +146,23 @@ public class DefaultTbRuleChainService implements TbRuleChainService { // Remove all output labels that are renamed but still present in the rule chain; newLabels.forEach(updatedLabels::remove); if (!oldLabels.equals(newLabels)) { - updateRelatedRuleChains(tenantId, ruleChainId, updatedLabels); + ruleChainIds.addAll(updateRelatedRuleChains(tenantId, ruleChainId, updatedLabels)); } + return ruleChainIds.stream().map(id -> ruleChainService.findRuleChainById(tenantId, id)).collect(Collectors.toList()); } - public void updateRelatedRuleChains(TenantId tenantId, RuleChainId ruleChainId, Map labelsMap) { + public Set updateRelatedRuleChains(TenantId tenantId, RuleChainId ruleChainId, Map labelsMap) { + Set updatedRuleChains = new HashSet<>(); List usageList = getOutputLabelUsage(tenantId, ruleChainId); for (RuleChainOutputLabelsUsage usage : usageList) { labelsMap.forEach((oldLabel, newLabel) -> { if (usage.getLabels().contains(oldLabel)) { + updatedRuleChains.add(usage.getRuleChainId()); renameOutgoingLinks(tenantId, usage.getRuleNodeId(), oldLabel, newLabel); } }); } + return updatedRuleChains; } private void renameOutgoingLinks(TenantId tenantId, RuleNodeId ruleNodeId, String oldLabel, String newLabel) { diff --git a/application/src/main/java/org/thingsboard/server/service/rule/TbRuleChainService.java b/application/src/main/java/org/thingsboard/server/service/rule/TbRuleChainService.java index d08f234d8e..ff2d738f9c 100644 --- a/application/src/main/java/org/thingsboard/server/service/rule/TbRuleChainService.java +++ b/application/src/main/java/org/thingsboard/server/service/rule/TbRuleChainService.java @@ -15,9 +15,9 @@ */ package org.thingsboard.server.service.rule; -import com.fasterxml.jackson.core.JsonProcessingException; import org.thingsboard.server.common.data.id.RuleChainId; import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.rule.RuleChain; import org.thingsboard.server.common.data.rule.RuleChainOutputLabelsUsage; import org.thingsboard.server.common.data.rule.RuleChainUpdateResult; @@ -30,5 +30,5 @@ public interface TbRuleChainService { List getOutputLabelUsage(TenantId tenantId, RuleChainId ruleChainId); - void updateRelatedRuleChains(TenantId tenantId, RuleChainId ruleChainId, RuleChainUpdateResult result); + List updateRelatedRuleChains(TenantId tenantId, RuleChainId ruleChainId, RuleChainUpdateResult result); } From c150352ecd22d3fe8149e8b59330000545a822fe Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Wed, 8 Dec 2021 18:38:46 +0200 Subject: [PATCH 221/432] Save RuleChain MetaData method fix --- .../server/service/rule/DefaultTbRuleChainService.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/application/src/main/java/org/thingsboard/server/service/rule/DefaultTbRuleChainService.java b/application/src/main/java/org/thingsboard/server/service/rule/DefaultTbRuleChainService.java index 14f56d1f6b..e9795ce15f 100644 --- a/application/src/main/java/org/thingsboard/server/service/rule/DefaultTbRuleChainService.java +++ b/application/src/main/java/org/thingsboard/server/service/rule/DefaultTbRuleChainService.java @@ -36,6 +36,7 @@ import org.thingsboard.server.dao.relation.RelationService; import org.thingsboard.server.dao.rule.RuleChainService; import org.thingsboard.server.queue.util.TbCoreComponent; +import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; @@ -111,7 +112,7 @@ public class DefaultTbRuleChainService implements TbRuleChainService { Set ruleChainIds = new HashSet<>(); log.debug("[{}][{}] Going to update links in related rule chains", tenantId, ruleChainId); if (result.getUpdatedRuleNodes() == null || result.getUpdatedRuleNodes().isEmpty()) { - return null; + return Collections.emptyList(); } Set oldLabels = new HashSet<>(); From 1d8256b4194647fa09a0d12c4dfa2993ea086324 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Wed, 8 Dec 2021 19:13:51 +0200 Subject: [PATCH 222/432] Fix sql upgrade scripts --- application/src/main/data/upgrade/3.3.2/schema_update.sql | 4 ++-- .../server/service/install/SqlDatabaseUpgradeService.java | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/application/src/main/data/upgrade/3.3.2/schema_update.sql b/application/src/main/data/upgrade/3.3.2/schema_update.sql index 99d2294129..fff08f734c 100644 --- a/application/src/main/data/upgrade/3.3.2/schema_update.sql +++ b/application/src/main/data/upgrade/3.3.2/schema_update.sql @@ -20,8 +20,8 @@ CREATE TABLE IF NOT EXISTS entity_alarm ( created_time bigint NOT NULL, type varchar(255) NOT NULL, customer_id uuid, - alarm_id uuid - CONSTRAINT entity_alarm_pkey PRIMARY KEY(entity_id, alarm_id), + alarm_id uuid, + CONSTRAINT entity_alarm_pkey PRIMARY KEY (entity_id, alarm_id), CONSTRAINT fk_entity_alarm_id FOREIGN KEY (alarm_id) REFERENCES alarm(id) ON DELETE CASCADE ); diff --git a/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java b/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java index 3f9bec2d07..cf34a31006 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java @@ -475,10 +475,10 @@ public class SqlDatabaseUpgradeService implements DatabaseEntitiesUpgradeService schemaUpdateFile = Paths.get(installScripts.getDataDir(), "upgrade", "3.3.2", SCHEMA_UPDATE_SQL); loadSql(schemaUpdateFile, conn); try { - conn.createStatement().execute("insert into entity_alarm(tenant_id, entity_id, created_time, type, customer_id, alarm_id, status, severity)" + - " select tenant_id, originator_id, created_time, type, customer_id, id, status, severity from alarm;"); - conn.createStatement().execute("insert into entity_alarm(tenant_id, entity_id, created_time, type, customer_id, alarm_id, status, severity)" + - " select a.tenant_id, r.from_id, created_time, type, customer_id, id, status, severity" + + conn.createStatement().execute("insert into entity_alarm(tenant_id, entity_id, created_time, type, customer_id, alarm_id)" + + " select tenant_id, originator_id, created_time, type, customer_id, id from alarm;"); + conn.createStatement().execute("insert into entity_alarm(tenant_id, entity_id, created_time, type, customer_id, alarm_id)" + + " select a.tenant_id, r.from_id, created_time, type, customer_id, id" + " from alarm a inner join relation r on r.relation_type_group = 'ALARM' and r.relation_type = 'ANY' and a.id = r.to_id ON CONFLICT DO NOTHING;"); conn.createStatement().execute("delete from relation r where r.relation_type_group = 'ALARM';"); } catch (Exception e) { From 8c7f90b74ceab1281547e20d2cc8f86f13d32a4a Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Wed, 8 Dec 2021 19:39:36 +0200 Subject: [PATCH 223/432] Fix upgrade --- application/src/main/data/upgrade/3.3.2/schema_update.sql | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/application/src/main/data/upgrade/3.3.2/schema_update.sql b/application/src/main/data/upgrade/3.3.2/schema_update.sql index fff08f734c..73e708bf74 100644 --- a/application/src/main/data/upgrade/3.3.2/schema_update.sql +++ b/application/src/main/data/upgrade/3.3.2/schema_update.sql @@ -16,12 +16,13 @@ CREATE TABLE IF NOT EXISTS entity_alarm ( tenant_id uuid NOT NULL, + entity_type varchar(32), entity_id uuid NOT NULL, created_time bigint NOT NULL, - type varchar(255) NOT NULL, + alarm_type varchar(255) NOT NULL, customer_id uuid, alarm_id uuid, - CONSTRAINT entity_alarm_pkey PRIMARY KEY (entity_id, alarm_id), + CONSTRAINT entity_alarm_pkey PRIMARY KEY(entity_id, alarm_id), CONSTRAINT fk_entity_alarm_id FOREIGN KEY (alarm_id) REFERENCES alarm(id) ON DELETE CASCADE ); From eebce55d5a16221356b71430a66e3655bda2b039 Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Thu, 9 Dec 2021 15:12:03 +0200 Subject: [PATCH 224/432] Improved upgrade script performance --- .../main/data/upgrade/3.3.2/schema_update.sql | 42 +++++- .../install/SqlDatabaseUpgradeService.java | 28 ++-- .../update/DefaultDataUpdateService.java | 126 +++++++++--------- .../server/dao/alarm/AlarmService.java | 2 + .../server/dao/entity/EntityService.java | 2 - .../server/dao/alarm/AlarmDao.java | 2 + .../server/dao/alarm/BaseAlarmService.java | 6 +- .../dao/entity/AbstractEntityService.java | 8 ++ .../server/dao/entity/BaseEntityService.java | 5 - .../dao/relation/BaseRelationService.java | 5 +- .../server/dao/relation/RelationDao.java | 2 +- .../server/dao/rule/BaseRuleChainService.java | 2 - .../dao/sql/alarm/EntityAlarmRepository.java | 3 + .../server/dao/sql/alarm/JpaAlarmDao.java | 6 + .../dao/sql/relation/JpaRelationDao.java | 4 +- .../dao/sql/relation/RelationRepository.java | 12 +- .../main/resources/sql/schema-entities.sql | 2 +- 17 files changed, 156 insertions(+), 101 deletions(-) diff --git a/application/src/main/data/upgrade/3.3.2/schema_update.sql b/application/src/main/data/upgrade/3.3.2/schema_update.sql index 73e708bf74..9a8c30ab63 100644 --- a/application/src/main/data/upgrade/3.3.2/schema_update.sql +++ b/application/src/main/data/upgrade/3.3.2/schema_update.sql @@ -22,9 +22,49 @@ CREATE TABLE IF NOT EXISTS entity_alarm ( alarm_type varchar(255) NOT NULL, customer_id uuid, alarm_id uuid, - CONSTRAINT entity_alarm_pkey PRIMARY KEY(entity_id, alarm_id), + CONSTRAINT entity_alarm_pkey PRIMARY KEY (entity_id, alarm_id), CONSTRAINT fk_entity_alarm_id FOREIGN KEY (alarm_id) REFERENCES alarm(id) ON DELETE CASCADE ); CREATE INDEX IF NOT EXISTS idx_alarm_tenant_status_created_time ON alarm(tenant_id, status, created_time DESC); CREATE INDEX IF NOT EXISTS idx_entity_alarm_created_time ON entity_alarm(tenant_id, entity_id, created_time DESC); + +INSERT INTO entity_alarm(tenant_id, entity_type, entity_id, created_time, alarm_type, customer_id, alarm_id) +SELECT tenant_id, + CASE + WHEN originator_type = 0 THEN 'TENANT' + WHEN originator_type = 1 THEN 'CUSTOMER' + WHEN originator_type = 2 THEN 'USER' + WHEN originator_type = 3 THEN 'DASHBOARD' + WHEN originator_type = 4 THEN 'ASSET' + WHEN originator_type = 5 THEN 'DEVICE' + WHEN originator_type = 6 THEN 'ALARM' + WHEN originator_type = 7 THEN 'RULE_CHAIN' + WHEN originator_type = 8 THEN 'RULE_NODE' + WHEN originator_type = 9 THEN 'ENTITY_VIEW' + WHEN originator_type = 10 THEN 'WIDGETS_BUNDLE' + WHEN originator_type = 11 THEN 'WIDGET_TYPE' + WHEN originator_type = 12 THEN 'TENANT_PROFILE' + WHEN originator_type = 13 THEN 'DEVICE_PROFILE' + WHEN originator_type = 14 THEN 'API_USAGE_STATE' + WHEN originator_type = 15 THEN 'TB_RESOURCE' + WHEN originator_type = 16 THEN 'OTA_PACKAGE' + WHEN originator_type = 17 THEN 'EDGE' + WHEN originator_type = 18 THEN 'RPC' + else 'UNKNOWN' + END, + originator_id, + created_time, + type, + customer_id, + id +FROM alarm +ON CONFLICT DO NOTHING; + +INSERT INTO entity_alarm(tenant_id, entity_type, entity_id, created_time, alarm_type, customer_id, alarm_id) +SELECT a.tenant_id, r.from_type, r.from_id, created_time, type, customer_id, id +FROM alarm a + INNER JOIN relation r ON r.relation_type_group = 'ALARM' and r.relation_type = 'ANY' and a.id = r.to_id +ON CONFLICT DO NOTHING; + +DELETE FROM relation r WHERE r.relation_type_group = 'ALARM'; \ No newline at end of file diff --git a/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java b/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java index cf34a31006..27e8375dc8 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java @@ -43,6 +43,7 @@ import java.sql.SQLSyntaxErrorException; import java.sql.SQLWarning; import java.sql.Statement; import java.util.List; +import java.util.concurrent.TimeUnit; import static org.thingsboard.server.service.install.DatabaseHelper.ADDITIONAL_INFO; import static org.thingsboard.server.service.install.DatabaseHelper.ASSIGNED_CUSTOMERS; @@ -474,16 +475,6 @@ public class SqlDatabaseUpgradeService implements DatabaseEntitiesUpgradeService log.info("Updating schema ..."); schemaUpdateFile = Paths.get(installScripts.getDataDir(), "upgrade", "3.3.2", SCHEMA_UPDATE_SQL); loadSql(schemaUpdateFile, conn); - try { - conn.createStatement().execute("insert into entity_alarm(tenant_id, entity_id, created_time, type, customer_id, alarm_id)" + - " select tenant_id, originator_id, created_time, type, customer_id, id from alarm;"); - conn.createStatement().execute("insert into entity_alarm(tenant_id, entity_id, created_time, type, customer_id, alarm_id)" + - " select a.tenant_id, r.from_id, created_time, type, customer_id, id" + - " from alarm a inner join relation r on r.relation_type_group = 'ALARM' and r.relation_type = 'ANY' and a.id = r.to_id ON CONFLICT DO NOTHING;"); - conn.createStatement().execute("delete from relation r where r.relation_type_group = 'ALARM';"); - } catch (Exception e) { - log.error("Failed to update alarm relations!!!", e); - } log.info("Updating schema settings..."); conn.createStatement().execute("UPDATE tb_schema_settings SET schema_version = 3003003;"); log.info("Schema updated."); @@ -498,10 +489,25 @@ public class SqlDatabaseUpgradeService implements DatabaseEntitiesUpgradeService private void loadSql(Path sqlFile, Connection conn) throws Exception { String sql = new String(Files.readAllBytes(sqlFile), Charset.forName("UTF-8")); - conn.createStatement().execute(sql); //NOSONAR, ignoring because method used to execute thingsboard database upgrade script + Statement st = conn.createStatement(); + st.setQueryTimeout((int) TimeUnit.HOURS.toSeconds(3)); + st.execute(sql);//NOSONAR, ignoring because method used to execute thingsboard database upgrade script + printWarnings(st); Thread.sleep(5000); } + protected void printWarnings(Statement statement) throws SQLException { + SQLWarning warnings = statement.getWarnings(); + if (warnings != null) { + log.info("{}", warnings.getMessage()); + SQLWarning nextWarning = warnings.getNextWarning(); + while (nextWarning != null) { + log.info("{}", nextWarning.getMessage()); + nextWarning = nextWarning.getNextWarning(); + } + } + } + protected boolean isOldSchema(Connection conn, long fromVersion) { boolean isOldSchema = true; try { diff --git a/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java b/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java index e244a0f0b0..de8216a4ab 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java @@ -139,7 +139,7 @@ public class DefaultDataUpdateService implements DataUpdateService { break; case "3.3.2": log.info("Updating data from version 3.3.2 to 3.3.3 ..."); - nestedRuleNodeUpdater.updateEntities(null); + updateNestedRuleChains(); break; default: throw new RuntimeException("Unable to update data, unsupported fromVersion: " + fromVersion); @@ -225,73 +225,73 @@ public class DefaultDataUpdateService implements DataUpdateService { } }; - private final PaginatedUpdater nestedRuleNodeUpdater = - new PaginatedUpdater<>() { - - @Override - protected String getName() { - return "Tenants nested rule chain updater"; - } - - @Override - protected boolean forceReportTotal() { - return true; - } - - @Override - protected PageData findEntities(String region, PageLink pageLink) { - return tenantService.findTenants(pageLink); - } - - @Override - protected void updateEntity(Tenant tenant) { + private void updateNestedRuleChains() { + try { + var packSize = 1024; + var updated = 0; + boolean hasNext = true; + while (hasNext) { + List relations = relationService.findRuleNodeToRuleChainRelations(TenantId.SYS_TENANT_ID, RuleChainType.CORE, packSize); + hasNext = relations.size() == packSize; + for (EntityRelation relation : relations) { try { - var tenantId = tenant.getId(); - var packSize = 1024; - boolean hasNext = true; - while (hasNext) { - List relations = relationService.findRuleNodeToRuleChainRelations(tenantId, RuleChainType.CORE, packSize); - hasNext = relations.size() == packSize; - for (EntityRelation relation : relations) { - - RuleNode sourceNode = ruleChainService.findRuleNodeById(tenantId, new RuleNodeId(relation.getFrom().getId())); - RuleChainId sourceRuleChainId = sourceNode.getRuleChainId(); - RuleChain targetRuleChain = ruleChainService.findRuleChainById(tenantId, new RuleChainId(relation.getTo().getId())); - RuleNode targetNode = new RuleNode(); - targetNode.setName(targetRuleChain.getName()); - targetNode.setRuleChainId(sourceRuleChainId); - targetNode.setType(TbRuleChainInputNode.class.getName()); - TbRuleChainInputNodeConfiguration configuration = new TbRuleChainInputNodeConfiguration(); - configuration.setRuleChainId(targetRuleChain.getId().toString()); - targetNode.setConfiguration(JacksonUtil.valueToTree(configuration)); - targetNode.setAdditionalInfo(relation.getAdditionalInfo()); - targetNode.setDebugMode(false); - targetNode = ruleChainService.saveRuleNode(tenantId, targetNode); - - EntityRelation sourceRuleChainToRuleNode = new EntityRelation(); - sourceRuleChainToRuleNode.setFrom(sourceRuleChainId); - sourceRuleChainToRuleNode.setTo(targetNode.getId()); - sourceRuleChainToRuleNode.setType(EntityRelation.CONTAINS_TYPE); - sourceRuleChainToRuleNode.setTypeGroup(RelationTypeGroup.RULE_CHAIN); - relationService.saveRelation(tenantId, sourceRuleChainToRuleNode); - - EntityRelation sourceRuleNodeToTargetRuleNode = new EntityRelation(); - sourceRuleNodeToTargetRuleNode.setFrom(sourceNode.getId()); - sourceRuleNodeToTargetRuleNode.setTo(targetNode.getId()); - sourceRuleNodeToTargetRuleNode.setType(relation.getType()); - sourceRuleNodeToTargetRuleNode.setTypeGroup(RelationTypeGroup.RULE_NODE); - sourceRuleNodeToTargetRuleNode.setAdditionalInfo(relation.getAdditionalInfo()); - relationService.saveRelation(tenantId, sourceRuleNodeToTargetRuleNode); - - //Delete old relation - relationService.deleteRelation(tenantId, relation); - } + RuleNodeId sourceNodeId = new RuleNodeId(relation.getFrom().getId()); + RuleNode sourceNode = ruleChainService.findRuleNodeById(TenantId.SYS_TENANT_ID, sourceNodeId); + if (sourceNode == null) { + log.info("Skip processing of relation for non existing source rule node: [{}]", sourceNodeId); + relationService.deleteRelation(TenantId.SYS_TENANT_ID, relation); + continue; + } + RuleChainId sourceRuleChainId = sourceNode.getRuleChainId(); + RuleChainId targetRuleChainId = new RuleChainId(relation.getTo().getId()); + RuleChain targetRuleChain = ruleChainService.findRuleChainById(TenantId.SYS_TENANT_ID, targetRuleChainId); + if (targetRuleChain == null) { + log.info("Skip processing of relation for non existing target rule chain: [{}]", targetRuleChainId); + relationService.deleteRelation(TenantId.SYS_TENANT_ID, relation); + continue; } + TenantId tenantId = targetRuleChain.getTenantId(); + RuleNode targetNode = new RuleNode(); + targetNode.setName(targetRuleChain.getName()); + targetNode.setRuleChainId(sourceRuleChainId); + targetNode.setType(TbRuleChainInputNode.class.getName()); + TbRuleChainInputNodeConfiguration configuration = new TbRuleChainInputNodeConfiguration(); + configuration.setRuleChainId(targetRuleChain.getId().toString()); + targetNode.setConfiguration(JacksonUtil.valueToTree(configuration)); + targetNode.setAdditionalInfo(relation.getAdditionalInfo()); + targetNode.setDebugMode(false); + targetNode = ruleChainService.saveRuleNode(tenantId, targetNode); + + EntityRelation sourceRuleChainToRuleNode = new EntityRelation(); + sourceRuleChainToRuleNode.setFrom(sourceRuleChainId); + sourceRuleChainToRuleNode.setTo(targetNode.getId()); + sourceRuleChainToRuleNode.setType(EntityRelation.CONTAINS_TYPE); + sourceRuleChainToRuleNode.setTypeGroup(RelationTypeGroup.RULE_CHAIN); + relationService.saveRelation(tenantId, sourceRuleChainToRuleNode); + + EntityRelation sourceRuleNodeToTargetRuleNode = new EntityRelation(); + sourceRuleNodeToTargetRuleNode.setFrom(sourceNode.getId()); + sourceRuleNodeToTargetRuleNode.setTo(targetNode.getId()); + sourceRuleNodeToTargetRuleNode.setType(relation.getType()); + sourceRuleNodeToTargetRuleNode.setTypeGroup(RelationTypeGroup.RULE_NODE); + sourceRuleNodeToTargetRuleNode.setAdditionalInfo(relation.getAdditionalInfo()); + relationService.saveRelation(tenantId, sourceRuleNodeToTargetRuleNode); + + //Delete old relation + relationService.deleteRelation(tenantId, relation); + updated++; } catch (Exception e) { - log.error("Unable to update Tenant", e); + log.info("Failed to update RuleNodeToRuleChainRelation: {}", relation, e); } } - }; + if (updated > 0) { + log.info("RuleNodeToRuleChainRelations: {} entities updated so far...", updated); + } + } + } catch (Exception e) { + log.error("Unable to update Tenant", e); + } + } private final PaginatedUpdater tenantsDefaultEdgeRuleChainUpdater = new PaginatedUpdater<>() { diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/alarm/AlarmService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/alarm/AlarmService.java index c0cddd9337..c175503d19 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/alarm/AlarmService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/alarm/AlarmService.java @@ -63,4 +63,6 @@ public interface AlarmService { PageData findAlarmDataByQueryForEntities(TenantId tenantId, CustomerId customerId, AlarmDataQuery query, Collection orderedEntityIds); + + void deleteEntityAlarmRelations(TenantId tenantId, EntityId entityId); } diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/entity/EntityService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/entity/EntityService.java index e6a9538e54..52fed96493 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/entity/EntityService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/entity/EntityService.java @@ -30,8 +30,6 @@ public interface EntityService { CustomerId fetchEntityCustomerId(TenantId tenantId, EntityId entityId); - void deleteEntityRelations(TenantId tenantId, EntityId entityId); - long countEntitiesByQuery(TenantId tenantId, CustomerId customerId, EntityCountQuery query); PageData findEntityDataByQuery(TenantId tenantId, CustomerId customerId, EntityDataQuery query); diff --git a/dao/src/main/java/org/thingsboard/server/dao/alarm/AlarmDao.java b/dao/src/main/java/org/thingsboard/server/dao/alarm/AlarmDao.java index 8918b7cc1f..d7fe41e8c7 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/alarm/AlarmDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/alarm/AlarmDao.java @@ -64,4 +64,6 @@ public interface AlarmDao extends Dao { void createEntityAlarmRecord(EntityAlarm entityAlarm); List findEntityAlarmRecords(TenantId tenantId, AlarmId id); + + void deleteEntityAlarmRecords(TenantId tenantId, EntityId entityId); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java b/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java index 64874eff7d..eb6d5c778e 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java @@ -46,7 +46,6 @@ import org.thingsboard.server.common.data.query.AlarmDataQuery; import org.thingsboard.server.common.data.relation.EntityRelation; import org.thingsboard.server.common.data.relation.EntityRelationsQuery; import org.thingsboard.server.common.data.relation.EntitySearchDirection; -import org.thingsboard.server.common.data.relation.RelationTypeGroup; import org.thingsboard.server.common.data.relation.RelationsSearchParameters; import org.thingsboard.server.dao.entity.AbstractEntityService; import org.thingsboard.server.dao.entity.EntityService; @@ -350,6 +349,11 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ return alarmSeverities.stream().min(AlarmSeverity::compareTo).orElse(null); } + @Override + public void deleteEntityAlarmRelations(TenantId tenantId, EntityId entityId) { + alarmDao.deleteEntityAlarmRecords(tenantId, entityId); + } + private Alarm merge(Alarm existing, Alarm alarm) { if (alarm.getStartTs() > existing.getEndTs()) { existing.setEndTs(alarm.getStartTs()); diff --git a/dao/src/main/java/org/thingsboard/server/dao/entity/AbstractEntityService.java b/dao/src/main/java/org/thingsboard/server/dao/entity/AbstractEntityService.java index 4d2a299576..970712fc19 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/entity/AbstractEntityService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/entity/AbstractEntityService.java @@ -18,12 +18,14 @@ package org.thingsboard.server.dao.entity; import lombok.extern.slf4j.Slf4j; import org.hibernate.exception.ConstraintViolationException; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Lazy; import org.thingsboard.server.common.data.EntityView; import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.relation.EntityRelation; import org.thingsboard.server.common.data.relation.RelationTypeGroup; +import org.thingsboard.server.dao.alarm.AlarmService; import org.thingsboard.server.dao.edge.EdgeService; import org.thingsboard.server.dao.entityview.EntityViewService; import org.thingsboard.server.dao.exception.DataValidationException; @@ -41,6 +43,10 @@ public abstract class AbstractEntityService { @Autowired protected RelationService relationService; + @Lazy + @Autowired + protected AlarmService alarmService; + @Autowired protected EntityViewService entityViewService; @@ -60,6 +66,8 @@ public abstract class AbstractEntityService { protected void deleteEntityRelations(TenantId tenantId, EntityId entityId) { log.trace("Executing deleteEntityRelations [{}]", entityId); relationService.deleteEntityRelations(tenantId, entityId); + log.trace("Executing deleteEntityAlarms [{}]", entityId); + alarmService.deleteEntityAlarmRelations(tenantId, entityId); } protected Optional extractConstraintViolationException(Exception t) { diff --git a/dao/src/main/java/org/thingsboard/server/dao/entity/BaseEntityService.java b/dao/src/main/java/org/thingsboard/server/dao/entity/BaseEntityService.java index 7686d9ec21..06e19a7730 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/entity/BaseEntityService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/entity/BaseEntityService.java @@ -104,11 +104,6 @@ public class BaseEntityService extends AbstractEntityService implements EntitySe @Autowired private OtaPackageService otaPackageService; - @Override - public void deleteEntityRelations(TenantId tenantId, EntityId entityId) { - super.deleteEntityRelations(tenantId, entityId); - } - @Override public long countEntitiesByQuery(TenantId tenantId, CustomerId customerId, EntityCountQuery query) { log.trace("Executing countEntitiesByQuery, tenantId [{}], customerId [{}], query [{}]", tenantId, customerId, query); diff --git a/dao/src/main/java/org/thingsboard/server/dao/relation/BaseRelationService.java b/dao/src/main/java/org/thingsboard/server/dao/relation/BaseRelationService.java index 1e1d0eee18..996c0801ff 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/relation/BaseRelationService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/relation/BaseRelationService.java @@ -563,10 +563,9 @@ public class BaseRelationService implements RelationService { @Override public List findRuleNodeToRuleChainRelations(TenantId tenantId, RuleChainType ruleChainType, int limit) { - log.trace("Executing findRuleNodeToRuleChainRelations, tenantId [{}] and limit {}", - tenantId, limit); + log.trace("Executing findRuleNodeToRuleChainRelations, tenantId [{}], ruleChainType {} and limit {}", tenantId, ruleChainType, limit); validateId(tenantId, "Invalid tenant id: " + tenantId); - return relationDao.findRuleNodeToRuleChainRelations(tenantId, ruleChainType, limit); + return relationDao.findRuleNodeToRuleChainRelations(ruleChainType, limit); } protected void validate(EntityRelation relation) { diff --git a/dao/src/main/java/org/thingsboard/server/dao/relation/RelationDao.java b/dao/src/main/java/org/thingsboard/server/dao/relation/RelationDao.java index efb516af3e..85d333b04a 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/relation/RelationDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/relation/RelationDao.java @@ -61,5 +61,5 @@ public interface RelationDao { ListenableFuture deleteOutboundRelationsAsync(TenantId tenantId, EntityId entity); - List findRuleNodeToRuleChainRelations(TenantId tenantId, RuleChainType ruleChainType, int limit); + List findRuleNodeToRuleChainRelations(RuleChainType ruleChainType, int limit); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java b/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java index 33ef74db65..6b990a7c6c 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java @@ -28,7 +28,6 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.BaseData; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.Tenant; @@ -48,7 +47,6 @@ import org.thingsboard.server.common.data.rule.RuleChainConnectionInfo; import org.thingsboard.server.common.data.rule.RuleChainData; import org.thingsboard.server.common.data.rule.RuleChainImportResult; import org.thingsboard.server.common.data.rule.RuleChainMetaData; -import org.thingsboard.server.common.data.rule.RuleChainOutputLabelsUsage; import org.thingsboard.server.common.data.rule.RuleChainType; import org.thingsboard.server.common.data.rule.RuleChainUpdateResult; import org.thingsboard.server.common.data.rule.RuleNode; diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/EntityAlarmRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/EntityAlarmRepository.java index ad67e9ba1d..852b0d2ce6 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/EntityAlarmRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/EntityAlarmRepository.java @@ -16,6 +16,7 @@ package org.thingsboard.server.dao.sql.alarm; import org.springframework.data.repository.CrudRepository; +import org.springframework.transaction.annotation.Transactional; import org.thingsboard.server.dao.model.sql.EntityAlarmCompositeKey; import org.thingsboard.server.dao.model.sql.EntityAlarmEntity; @@ -26,4 +27,6 @@ public interface EntityAlarmRepository extends CrudRepository findAllByAlarmId(UUID alarmId); + @Transactional + void deleteByEntityId(UUID id); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/JpaAlarmDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/JpaAlarmDao.java index 73e7a39b9a..eaed0480c4 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/JpaAlarmDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/JpaAlarmDao.java @@ -183,4 +183,10 @@ public class JpaAlarmDao extends JpaAbstractDao implements A log.trace("[{}] Try to find entity alarm records using [{}]", tenantId, id); return DaoUtil.convertDataList(entityAlarmRepository.findAllByAlarmId(id.getId())); } + + @Override + public void deleteEntityAlarmRecords(TenantId tenantId, EntityId entityId) { + log.trace("[{}] Try to delete entity alarm records using [{}]", tenantId, entityId); + entityAlarmRepository.deleteByEntityId(entityId.getId()); + } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/relation/JpaRelationDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/relation/JpaRelationDao.java index 5291da6669..4b021114f7 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/relation/JpaRelationDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/relation/JpaRelationDao.java @@ -199,8 +199,8 @@ public class JpaRelationDao extends JpaAbstractDaoListeningExecutorService imple } @Override - public List findRuleNodeToRuleChainRelations(TenantId tenantId, RuleChainType ruleChainType, int limit) { - return DaoUtil.convertDataList(relationRepository.findRuleNodeToRuleChainRelations(tenantId.getId(), ruleChainType, PageRequest.of(0, limit))); + public List findRuleNodeToRuleChainRelations(RuleChainType ruleChainType, int limit) { + return DaoUtil.convertDataList(relationRepository.findRuleNodeToRuleChainRelations(ruleChainType, PageRequest.of(0, limit))); } private Specification getEntityFieldsSpec(EntityId from, String relationType, RelationTypeGroup typeGroup, EntityType childType) { diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/relation/RelationRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/relation/RelationRepository.java index 28b125ac3c..65c888f39e 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/relation/RelationRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/relation/RelationRepository.java @@ -58,15 +58,9 @@ public interface RelationRepository String fromType); @Query("SELECT r FROM RelationEntity r WHERE " + - "r.fromId in (SELECT id from RuleNodeEntity where ruleChainId in " + - "(SELECT id from RuleChainEntity where tenantId = :tenantId and type = :ruleChainType ))" + - "AND r.fromType = 'RULE_NODE' " + - "AND r.toType = 'RULE_CHAIN' " + - "AND r.relationTypeGroup = 'RULE_NODE'") - List findRuleNodeToRuleChainRelations( - @Param("tenantId") UUID tenantId, - @Param("ruleChainType") RuleChainType ruleChainType, - Pageable page); + "r.relationTypeGroup = 'RULE_NODE' AND r.toType = 'RULE_CHAIN' " + + "AND r.toId in (SELECT id from RuleChainEntity where type = :ruleChainType )") + List findRuleNodeToRuleChainRelations(@Param("ruleChainType") RuleChainType ruleChainType, Pageable page); @Transactional S save(S entity); diff --git a/dao/src/main/resources/sql/schema-entities.sql b/dao/src/main/resources/sql/schema-entities.sql index de27c8d554..4fc5fbaebc 100644 --- a/dao/src/main/resources/sql/schema-entities.sql +++ b/dao/src/main/resources/sql/schema-entities.sql @@ -66,7 +66,7 @@ CREATE TABLE IF NOT EXISTS entity_alarm ( alarm_type varchar(255) NOT NULL, customer_id uuid, alarm_id uuid, - CONSTRAINT entity_alarm_pkey PRIMARY KEY(entity_id, alarm_id), + CONSTRAINT entity_alarm_pkey PRIMARY KEY (entity_id, alarm_id), CONSTRAINT fk_entity_alarm_id FOREIGN KEY (alarm_id) REFERENCES alarm(id) ON DELETE CASCADE ); From a5b747107b1d852e1344af9697cbc24991fc3caa Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Thu, 9 Dec 2021 18:46:35 +0200 Subject: [PATCH 225/432] UI: Create nested rule chain from selected region --- ...ate-nested-rulechain-dialog.component.html | 65 ++++ .../rulechain/rulechain-page.component.scss | 2 +- .../rulechain/rulechain-page.component.ts | 298 +++++++++++++++++- .../home/pages/rulechain/rulechain.module.ts | 5 +- ui-ngx/src/app/shared/models/constants.ts | 3 +- .../src/app/shared/models/rule-node.models.ts | 8 +- .../assets/locale/locale.constant-en_US.json | 1 + 7 files changed, 375 insertions(+), 7 deletions(-) create mode 100644 ui-ngx/src/app/modules/home/pages/rulechain/create-nested-rulechain-dialog.component.html diff --git a/ui-ngx/src/app/modules/home/pages/rulechain/create-nested-rulechain-dialog.component.html b/ui-ngx/src/app/modules/home/pages/rulechain/create-nested-rulechain-dialog.component.html new file mode 100644 index 0000000000..a8e719dbab --- /dev/null +++ b/ui-ngx/src/app/modules/home/pages/rulechain/create-nested-rulechain-dialog.component.html @@ -0,0 +1,65 @@ + +
+ +

rulenode.create-nested-rulechain

+ + +
+ + +
+ +
+ + rulechain.name + + + {{ 'rulechain.name-required' | translate }} + + + {{ 'rulechain.name-max-length' | translate }} + + +
+ + rulechain.description + + +
+
+ +
+
+ + +
+ diff --git a/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.scss b/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.scss index 24b1ecc9b0..a05c80bb04 100644 --- a/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.scss +++ b/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.scss @@ -325,7 +325,7 @@ } .tb-rule-chain-context-menu { - min-width: 256px; + min-width: 320px; max-height: 404px; border-radius: 8px; margin-left: -20px; diff --git a/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.ts b/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.ts index 8784716861..b240fc104b 100644 --- a/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.ts +++ b/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.ts @@ -54,7 +54,7 @@ import { FcRuleNode, FcRuleNodeType, getRuleNodeHelpLink, - LinkLabel, + LinkLabel, outputNodeClazz, ruleChainNodeClazz, RuleNode, RuleNodeComponentDescriptor, RuleNodeType, @@ -405,6 +405,17 @@ export class RuleChainPageComponent extends PageComponent }, ['INPUT', 'SELECT', 'TEXTAREA'], this.translate.instant('rulenode.delete-selected-objects')) ); + this.hotKeys.push( + new Hotkey('ctrl+r', (event: KeyboardEvent) => { + if (this.enableHotKeys && this.canCreateNestedRuleChain()) { + event.preventDefault(); + this.createNestedRuleChain(); + return false; + } + return true; + }, ['INPUT', 'SELECT', 'TEXTAREA'], + this.translate.instant('rulenode.create-nested-rulechain')) + ); } } @@ -684,6 +695,19 @@ export class RuleChainPageComponent extends PageComponent shortcut: 'Esc' } ); + if (this.canCreateNestedRuleChain()) { + contextInfo.menuItems.push( + { + action: () => { + this.createNestedRuleChain(); + }, + enabled: true, + value: 'rulenode.create-nested-rulechain', + icon: 'settings_ethernet', + shortcut: 'M-R' + } + ); + } contextInfo.menuItems.push( { action: () => { @@ -818,6 +842,208 @@ export class RuleChainPageComponent extends PageComponent return contextInfo; } + private canCreateNestedRuleChain(): boolean { + const selectedNodes = this.ruleChainCanvas.modelService.nodes.getSelectedNodes(); + const selectedEdges = this.ruleChainCanvas.modelService.edges.getSelectedEdges(); + if (selectedNodes.length > 1) { + const toIndexSet = new Set(); + selectedEdges.forEach((edge: FcRuleEdge) => { + const sourceNode = this.ruleChainCanvas.modelService.nodes.getNodeByConnectorId(edge.source); + const destNode = this.ruleChainCanvas.modelService.nodes.getNodeByConnectorId(edge.destination); + const fromIndex = selectedNodes.indexOf(sourceNode); + const toIndex = selectedNodes.indexOf(destNode); + if (fromIndex > -1 && toIndex > -1) { + toIndexSet.add(toIndex); + } + }); + const noInputNodes = selectedNodes.filter((node, index) => !toIndexSet.has(index)); + return noInputNodes.filter((node: FcRuleNode) => node.component.configurationDescriptor.nodeDefinition.inEnabled).length <= 1; + } + return false; + } + + private createNestedRuleChain() { + const selectedNodes = this.ruleChainCanvas.modelService.nodes.getSelectedNodes(); + const selectedEdges = this.ruleChainCanvas.modelService.edges.getSelectedEdges(); + this.dialog.open(CreateNestedRuleChainDialogComponent, { + disableClose: true, + panelClass: ['tb-dialog', 'tb-fullscreen-dialog'], + data: { + ruleChainType: this.ruleChainType + } + }).afterClosed().subscribe((ruleChain) => { + if (ruleChain) { + this.ruleChainCanvas.modelService.deselectAll(); + const ruleChainMetaData: RuleChainMetaData = { + ruleChainId: ruleChain.id, + nodes: [], + connections: [] + }; + let outputEdges: FcRuleEdge[] = []; + let minX: number = null; + let maxX = 0; + let minY = null; + let maxY = 0; + + selectedNodes.forEach((node: FcRuleNode) => { + const ruleNode: RuleNode = { + type: node.component.clazz, + name: node.name, + configuration: deepClone(node.configuration), + additionalInfo: node.additionalInfo ? deepClone(node.additionalInfo) : {}, + debugMode: node.debugMode + }; + if (minX === null) { + minX = node.x; + } else { + minX = Math.min(minX, node.x); + } + if (minY === null) { + minY = node.y; + } else { + minY = Math.min(minY, node.y); + } + maxX = Math.max(maxX, node.x); + maxY = Math.max(maxY, node.y); + ruleNode.additionalInfo.layoutX = Math.round(node.x); + ruleNode.additionalInfo.layoutY = Math.round(node.y); + ruleChainMetaData.nodes.push(ruleNode); + const outputConnectors = this.ruleChainCanvas.modelService.nodes.getConnectorsByType(node, FlowchartConstants.rightConnectorType); + outputConnectors.forEach(connector => { + const nodeOutputEdges = this.ruleChainCanvas.modelService.model.edges.filter(edge => edge.source === connector.id); + const outerEdges = nodeOutputEdges.filter(edge => { + const destNode = this.ruleChainCanvas.modelService.nodes.getNodeByConnectorId(edge.destination); + return selectedNodes.indexOf(destNode) === -1; + }); + outputEdges = outputEdges.concat(outerEdges); + }); + }); + const toIndexSet = new Set(); + selectedEdges.forEach((edge: FcRuleEdge) => { + const sourceNode = this.ruleChainCanvas.modelService.nodes.getNodeByConnectorId(edge.source); + const destNode = this.ruleChainCanvas.modelService.nodes.getNodeByConnectorId(edge.destination); + if (sourceNode.component.type !== RuleNodeType.INPUT) { + const fromIndex = selectedNodes.indexOf(sourceNode); + const toIndex = selectedNodes.indexOf(destNode); + if (fromIndex > -1 && toIndex > -1) { + const nodeConnection = { + fromIndex, + toIndex + } as NodeConnectionInfo; + edge.labels.forEach((label) => { + const newNodeConnection = deepClone(nodeConnection); + newNodeConnection.type = label; + ruleChainMetaData.connections.push(newNodeConnection); + }); + toIndexSet.add(toIndex); + } + } + }); + const noInputNodes = selectedNodes.filter((node, index) => !toIndexSet.has(index)); + const possibleInputNodes = noInputNodes.filter((node: FcRuleNode) => + node.component.configurationDescriptor.nodeDefinition.inEnabled); + let inputEdges: FcRuleEdge[] = []; + if (possibleInputNodes.length) { + const firstNode = possibleInputNodes[0]; + const inputConnectors = this.ruleChainCanvas.modelService.nodes + .getConnectorsByType(firstNode, FlowchartConstants.leftConnectorType); + if (inputConnectors.length) { + const inputConnector = inputConnectors[0]; + const nodeInputEdges = this.ruleChainCanvas.modelService.model.edges.filter(edge => edge.destination === inputConnector.id); + inputEdges = inputEdges.concat(nodeInputEdges); + } + ruleChainMetaData.firstNodeIndex = selectedNodes.indexOf(firstNode); + } + outputEdges.forEach((outputEdge) => { + const sourceNode = this.ruleChainCanvas.modelService.nodes.getNodeByConnectorId(outputEdge.source); + const destNode = this.ruleChainCanvas.modelService.nodes.getNodeByConnectorId(outputEdge.destination); + const outputNode: RuleNode = { + type: outputNodeClazz, + name: outputEdge.label, + configuration: {}, + additionalInfo: {}, + debugMode: false + }; + outputNode.additionalInfo.layoutX = Math.round(destNode.x); + outputNode.additionalInfo.layoutY = Math.round(destNode.y); + ruleChainMetaData.nodes.push(outputNode); + const fromIndex = selectedNodes.indexOf(sourceNode); + const toIndex = ruleChainMetaData.nodes.length - 1; + const nodeConnection = { + fromIndex, + toIndex + } as NodeConnectionInfo; + outputEdge.labels.forEach((label) => { + const newNodeConnection = deepClone(nodeConnection); + newNodeConnection.type = label; + ruleChainMetaData.connections.push(newNodeConnection); + }); + }); + const deltaX = Math.round(minX - 375); + const deltaY = Math.round(minY - 150); + ruleChainMetaData.nodes.forEach((node) => { + node.additionalInfo.layoutX -= deltaX; + node.additionalInfo.layoutY -= deltaY; + }); + this.ruleChainService.saveRuleChainMetadata(ruleChainMetaData).subscribe(() => { + const component = this.ruleChainService.getRuleNodeComponentByClazz(this.ruleChainType, ruleChainNodeClazz); + const descriptor = ruleNodeTypeDescriptors.get(component.type); + let icon = descriptor.icon; + let iconUrl = null; + if (component.configurationDescriptor.nodeDefinition.icon) { + icon = component.configurationDescriptor.nodeDefinition.icon; + } + if (component.configurationDescriptor.nodeDefinition.iconUrl) { + iconUrl = component.configurationDescriptor.nodeDefinition.iconUrl; + } + const ruleChainNodeX = (minX + maxX) / 2; + const ruleChainNodeY = (minY + maxY) / 2; + const ruleChainInputId = (this.nextConnectorID++) + ''; + const ruleChainOutputId = (this.nextConnectorID++) + ''; + const ruleChainNode: FcRuleNode = { + name: ruleChain.name, + component, + id: 'rule-chain-node-' + this.nextNodeID++, + configuration: { + ruleChainId: ruleChain.id.id + }, + debugMode: false, + x: Math.round(ruleChainNodeX), + y: Math.round(ruleChainNodeY), + nodeClass: descriptor.nodeClass, + icon, + iconUrl, + ruleChainType: this.ruleChainType, + connectors: [ + { + type: FlowchartConstants.leftConnectorType, + id: ruleChainInputId + }, + { + type: FlowchartConstants.rightConnectorType, + id: ruleChainOutputId + } + ] + }; + this.ruleChainModel.nodes.push(ruleChainNode); + inputEdges.forEach((inputEdge) => { + inputEdge.destination = ruleChainInputId; + }); + outputEdges.forEach((outputEdge) => { + outputEdge.source = ruleChainOutputId; + outputEdge.labels = [outputEdge.label]; + }); + selectedNodes.forEach((node) => { + this.ruleChainCanvas.modelService.nodes.delete(node); + }); + this.onModelChanged(); + this.updateRuleNodesHighlight(); + }); + } + }); + } + onModelChanged() { this.isDirtyValue = true; this.validate(); @@ -1498,3 +1724,73 @@ export class AddRuleNodeDialogComponent extends DialogComponent + implements OnInit, ErrorStateMatcher { + + createNestedRuleChainFormGroup: FormGroup; + + submitted = false; + + constructor(protected store: Store, + protected router: Router, + @Inject(MAT_DIALOG_DATA) public data: CreateNestedRuleChainDialogData, + @SkipSelf() private errorStateMatcher: ErrorStateMatcher, + private fb: FormBuilder, + private ruleChainService: RuleChainService, + public dialogRef: MatDialogRef) { + super(store, router, dialogRef); + + } + + ngOnInit(): void { + this.createNestedRuleChainFormGroup = this.fb.group( + { + name: ['', [Validators.required, Validators.maxLength(255)]], + additionalInfo: this.fb.group( + { + description: [''], + } + ) + } + ); + } + + isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean { + const originalErrorState = this.errorStateMatcher.isErrorState(control, form); + const customErrorState = !!(control && control.invalid && this.submitted); + return originalErrorState || customErrorState; + } + + cancel(): void { + this.dialogRef.close(null); + } + + add(): void { + this.submitted = true; + const ruleChain = { + name: this.createNestedRuleChainFormGroup.get('name').value, + debugMode: false, + type: this.data.ruleChainType, + additionalInfo: { + description: this.createNestedRuleChainFormGroup.get('additionalInfo').get('description').value + } + } as RuleChain; + this.ruleChainService.saveRuleChain(ruleChain).subscribe( + (savedRuleChain) => { + this.dialogRef.close(savedRuleChain); + } + ); + } +} + diff --git a/ui-ngx/src/app/modules/home/pages/rulechain/rulechain.module.ts b/ui-ngx/src/app/modules/home/pages/rulechain/rulechain.module.ts index 95bb4bf3f8..73df594f89 100644 --- a/ui-ngx/src/app/modules/home/pages/rulechain/rulechain.module.ts +++ b/ui-ngx/src/app/modules/home/pages/rulechain/rulechain.module.ts @@ -23,7 +23,7 @@ import { HomeComponentsModule } from '@modules/home/components/home-components.m import { RuleChainTabsComponent } from '@home/pages/rulechain/rulechain-tabs.component'; import { AddRuleNodeDialogComponent, - AddRuleNodeLinkDialogComponent, + AddRuleNodeLinkDialogComponent, CreateNestedRuleChainDialogComponent, RuleChainPageComponent } from './rulechain-page.component'; import { RuleNodeComponent } from '@home/pages/rulechain/rulenode.component'; @@ -44,7 +44,8 @@ import { RuleNodeConfigComponent } from './rule-node-config.component'; LinkLabelsComponent, RuleNodeLinkComponent, AddRuleNodeLinkDialogComponent, - AddRuleNodeDialogComponent + AddRuleNodeDialogComponent, + CreateNestedRuleChainDialogComponent ], providers: [ { diff --git a/ui-ngx/src/app/shared/models/constants.ts b/ui-ngx/src/app/shared/models/constants.ts index b30ed084ab..9bf120f8b7 100644 --- a/ui-ngx/src/app/shared/models/constants.ts +++ b/ui-ngx/src/app/shared/models/constants.ts @@ -100,7 +100,8 @@ export const HelpLinks = { ruleNodeSaveAttributes: helpBaseUrl + '/docs/user-guide/rule-engine-2-0/action-nodes/#save-attributes-node', ruleNodeSaveTimeseries: helpBaseUrl + '/docs/user-guide/rule-engine-2-0/action-nodes/#save-timeseries-node', ruleNodeSaveToCustomTable: helpBaseUrl + '/docs/user-guide/rule-engine-2-0/action-nodes/#save-to-custom-table', - ruleNodeRuleChain: helpBaseUrl + '/docs/user-guide/ui/rule-chains/', + ruleNodeRuleChain: helpBaseUrl + '/docs/user-guide/rule-engine-2-0/flow-nodes/#rule-chain-node', + ruleNodeOutputNode: helpBaseUrl + '/docs/user-guide/rule-engine-2-0/flow-nodes/#output-node', ruleNodeAwsSns: helpBaseUrl + '/docs/user-guide/rule-engine-2-0/external-nodes/#aws-sns-node', ruleNodeAwsSqs: helpBaseUrl + '/docs/user-guide/rule-engine-2-0/external-nodes/#aws-sqs-node', ruleNodeKafka: helpBaseUrl + '/docs/user-guide/rule-engine-2-0/external-nodes/#kafka-node', diff --git a/ui-ngx/src/app/shared/models/rule-node.models.ts b/ui-ngx/src/app/shared/models/rule-node.models.ts index ce2563826f..f30574ce7b 100644 --- a/ui-ngx/src/app/shared/models/rule-node.models.ts +++ b/ui-ngx/src/app/shared/models/rule-node.models.ts @@ -394,6 +394,9 @@ export const messageTypeNames = new Map( ] ); +export const ruleChainNodeClazz = 'org.thingsboard.rule.engine.flow.TbRuleChainInputNode'; +export const outputNodeClazz = 'org.thingsboard.rule.engine.flow.TbRuleChainOutputNode'; + const ruleNodeClazzHelpLinkMap = { 'org.thingsboard.rule.engine.filter.TbCheckRelationNode': 'ruleNodeCheckRelation', 'org.thingsboard.rule.engine.filter.TbCheckMessageNode': 'ruleNodeCheckExistenceFields', @@ -431,7 +434,6 @@ const ruleNodeClazzHelpLinkMap = { 'org.thingsboard.rule.engine.telemetry.TbMsgAttributesNode': 'ruleNodeSaveAttributes', 'org.thingsboard.rule.engine.telemetry.TbMsgTimeseriesNode': 'ruleNodeSaveTimeseries', 'org.thingsboard.rule.engine.action.TbSaveToCustomCassandraTableNode': 'ruleNodeSaveToCustomTable', - 'tb.internal.RuleChain': 'ruleNodeRuleChain', 'org.thingsboard.rule.engine.aws.sns.TbSnsNode': 'ruleNodeAwsSns', 'org.thingsboard.rule.engine.aws.sqs.TbSqsNode': 'ruleNodeAwsSqs', 'org.thingsboard.rule.engine.kafka.TbKafkaNode': 'ruleNodeKafka', @@ -442,7 +444,9 @@ const ruleNodeClazzHelpLinkMap = { 'org.thingsboard.rule.engine.mail.TbSendEmailNode': 'ruleNodeSendEmail', 'org.thingsboard.rule.engine.sms.TbSendSmsNode': 'ruleNodeSendSms', 'org.thingsboard.rule.engine.edge.TbMsgPushToCloudNode': 'ruleNodePushToCloud', - 'org.thingsboard.rule.engine.edge.TbMsgPushToEdgeNode': 'ruleNodePushToEdge' + 'org.thingsboard.rule.engine.edge.TbMsgPushToEdgeNode': 'ruleNodePushToEdge', + 'org.thingsboard.rule.engine.flow.TbRuleChainInputNode': 'ruleNodeRuleChain', + 'org.thingsboard.rule.engine.flow.TbRuleChainOutputNode': 'ruleNodeOutputNode', }; export function getRuleNodeHelpLink(component: RuleNodeComponentDescriptor): string { diff --git a/ui-ngx/src/assets/locale/locale.constant-en_US.json b/ui-ngx/src/assets/locale/locale.constant-en_US.json index 05e2039633..3982bfedda 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -2587,6 +2587,7 @@ "deselect-all-objects": "Deselect all nodes and connections", "delete-selected-objects": "Delete selected nodes and connections", "delete-selected": "Delete selected", + "create-nested-rulechain": "Create nested rule chain", "select-all": "Select all", "copy-selected": "Copy selected", "deselect-all": "Deselect all", From 6d97d9466fc4463a4117e38ac93ece7c7e066bbf Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Thu, 9 Dec 2021 18:54:52 +0200 Subject: [PATCH 226/432] Update rule nodes UI --- .../resources/public/static/rulenode/rulenode-core-config.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/rule-engine/rule-engine-components/src/main/resources/public/static/rulenode/rulenode-core-config.js b/rule-engine/rule-engine-components/src/main/resources/public/static/rulenode/rulenode-core-config.js index 54fbc87f07..ae61853e4b 100644 --- a/rule-engine/rule-engine-components/src/main/resources/public/static/rulenode/rulenode-core-config.js +++ b/rule-engine/rule-engine-components/src/main/resources/public/static/rulenode/rulenode-core-config.js @@ -204,6 +204,7 @@ var EntityDetailsField; EntityDetailsField["TITLE"] = "TITLE"; EntityDetailsField["COUNTRY"] = "COUNTRY"; EntityDetailsField["STATE"] = "STATE"; + EntityDetailsField["CITY"] = "CITY"; EntityDetailsField["ZIP"] = "ZIP"; EntityDetailsField["ADDRESS"] = "ADDRESS"; EntityDetailsField["ADDRESS2"] = "ADDRESS2"; @@ -215,6 +216,7 @@ const entityDetailsTranslations = new Map([ [EntityDetailsField.TITLE, 'tb.rulenode.entity-details-title'], [EntityDetailsField.COUNTRY, 'tb.rulenode.entity-details-country'], [EntityDetailsField.STATE, 'tb.rulenode.entity-details-state'], + [EntityDetailsField.CITY, 'tb.rulenode.entity-details-city'], [EntityDetailsField.ZIP, 'tb.rulenode.entity-details-zip'], [EntityDetailsField.ADDRESS, 'tb.rulenode.entity-details-address'], [EntityDetailsField.ADDRESS2, 'tb.rulenode.entity-details-address2'], @@ -4105,6 +4107,7 @@ function addRuleNodeCoreLocaleEnglish(translate) { 'entity-details-title': 'Title', 'entity-details-country': 'Country', 'entity-details-state': 'State', + 'entity-details-city': 'City', 'entity-details-zip': 'Zip', 'entity-details-address': 'Address', 'entity-details-address2': 'Address2', From 112e50c33122fb7512c6f08a7cdb308e329dd0f9 Mon Sep 17 00:00:00 2001 From: Chantsova Ekaterina Date: Fri, 10 Dec 2021 11:29:38 +0200 Subject: [PATCH 227/432] Modules map: mat-datetimepicker added --- ui-ngx/src/app/modules/common/modules-map.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ui-ngx/src/app/modules/common/modules-map.ts b/ui-ngx/src/app/modules/common/modules-map.ts index 8404a03aa0..32934b0273 100644 --- a/ui-ngx/src/app/modules/common/modules-map.ts +++ b/ui-ngx/src/app/modules/common/modules-map.ts @@ -72,6 +72,7 @@ import * as NgrxStore from '@ngrx/store'; import * as RxJs from 'rxjs'; import * as RxJsOperators from 'rxjs/operators'; import * as TranslateCore from '@ngx-translate/core'; +import * as MatDateTimePicker from '@mat-datetimepicker/core'; import * as _moment from 'moment'; import * as TbCore from '@core/public-api'; @@ -348,6 +349,7 @@ class ModulesMap implements IModulesMap { rxjs: RxJs, 'rxjs/operators': RxJsOperators, '@ngx-translate/core': TranslateCore, + '@mat-datetimepicker/core': MatDateTimePicker, moment: _moment, '@core/public-api': TbCore, From 26034e7047099313e29b38288eabbbae5627cbe1 Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Fri, 10 Dec 2021 12:42:27 +0200 Subject: [PATCH 228/432] added ability to send lwm2m model updates after sleeping --- .../server/client/LwM2mClientContextImpl.java | 4 + .../downlink/DownlinkRequestCallback.java | 4 +- .../lwm2m/server/model/LwM2MModelConfig.java | 92 +++++++ .../server/model/LwM2MModelConfigService.java | 29 +++ .../model/LwM2MModelConfigServiceImpl.java | 235 ++++++++++++++++++ .../store/TbDummyLwM2MModelConfigStore.java | 38 +++ .../server/store/TbLwM2MModelConfigStore.java | 28 +++ .../server/store/TbLwM2mStoreFactory.java | 5 + .../store/TbRedisLwM2MModelConfigStore.java | 79 ++++++ .../uplink/DefaultLwM2MUplinkMsgHandler.java | 104 +++----- .../common/util/CollectionsUtil.java | 37 +++ .../thingsboard/common/util/JacksonUtil.java | 8 + 12 files changed, 595 insertions(+), 68 deletions(-) create mode 100644 common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/model/LwM2MModelConfig.java create mode 100644 common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/model/LwM2MModelConfigService.java create mode 100644 common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/model/LwM2MModelConfigServiceImpl.java create mode 100644 common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbDummyLwM2MModelConfigStore.java create mode 100644 common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2MModelConfigStore.java create mode 100644 common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbRedisLwM2MModelConfigStore.java create mode 100644 common/util/src/main/java/org/thingsboard/common/util/CollectionsUtil.java diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java index e2b05847f7..246444ddaa 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java @@ -41,6 +41,7 @@ import org.thingsboard.server.transport.lwm2m.secure.TbLwM2MSecurityInfo; import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportContext; import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil; import org.thingsboard.server.transport.lwm2m.server.LwM2mVersionedModelProvider; +import org.thingsboard.server.transport.lwm2m.server.model.LwM2MModelConfigService; import org.thingsboard.server.transport.lwm2m.server.ota.LwM2MOtaUpdateService; import org.thingsboard.server.transport.lwm2m.server.session.LwM2MSessionManager; import org.thingsboard.server.transport.lwm2m.server.store.TbLwM2MClientStore; @@ -76,6 +77,7 @@ public class LwM2mClientContextImpl implements LwM2mClientContext { private final LwM2MSessionManager sessionManager; private final TransportDeviceProfileCache deviceProfileCache; private final LwM2mVersionedModelProvider modelProvider; + private final LwM2MModelConfigService modelConfigService; @Autowired @Lazy @@ -259,6 +261,7 @@ public class LwM2mClientContextImpl implements LwM2mClientContext { // TODO: change tests to use new certificate. // this.securityStore.remove(client.getEndpoint(), registration.getId()); clientStore.remove(client.getEndpoint()); + modelConfigService.removeUpdates(client.getEndpoint()); UUID profileId = client.getProfileId(); if (profileId != null) { Optional otherClients = lwM2mClientsByRegistrationId.values().stream().filter(e -> e.getProfileId().equals(profileId)).findFirst(); @@ -333,6 +336,7 @@ public class LwM2mClientContextImpl implements LwM2mClientContext { if (LwM2MClientState.REGISTERED.equals(lwM2MClient.getState())) { PowerMode powerMode = getPowerMode(lwM2MClient); if (PowerMode.PSM.equals(powerMode) || PowerMode.E_DRX.equals(powerMode)) { + modelConfigService.sendUpdates(lwM2MClient); defaultLwM2MUplinkMsgHandler.initAttributes(lwM2MClient); TransportProtos.TransportToDeviceActorMsg persistentRpcRequestMsg = TransportProtos.TransportToDeviceActorMsg .newBuilder() diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DownlinkRequestCallback.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DownlinkRequestCallback.java index 8912c51960..40cf896f55 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DownlinkRequestCallback.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DownlinkRequestCallback.java @@ -17,9 +17,9 @@ package org.thingsboard.server.transport.lwm2m.server.downlink; public interface DownlinkRequestCallback { - default boolean onSent(R request){ + default boolean onSent(R request) { return true; - }; + } void onSuccess(R request, T response); diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/model/LwM2MModelConfig.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/model/LwM2MModelConfig.java new file mode 100644 index 0000000000..5c0acc150c --- /dev/null +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/model/LwM2MModelConfig.java @@ -0,0 +1,92 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.transport.lwm2m.server.model; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.ToString; +import lombok.extern.slf4j.Slf4j; +import org.thingsboard.server.common.data.device.data.lwm2m.ObjectAttributes; + +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +import static org.thingsboard.common.util.CollectionsUtil.diffSets; + +@Data +@NoArgsConstructor +@ToString(exclude = "toCancelRead") +@Slf4j +public class LwM2MModelConfig { + private String endpoint; + private Map attributesToAdd; + private Set attributesToRemove; + private Set toObserve; + private Set toCancelObserve; + private Set toRead; + @JsonIgnore + private Set toCancelRead; + + public LwM2MModelConfig(String endpoint) { + this.endpoint = endpoint; + this.attributesToAdd = new ConcurrentHashMap<>(); + this.attributesToRemove = ConcurrentHashMap.newKeySet(); + this.toObserve = ConcurrentHashMap.newKeySet(); + this.toCancelObserve = ConcurrentHashMap.newKeySet(); + this.toRead = ConcurrentHashMap.newKeySet(); + this.toCancelRead = new HashSet<>(); + } + + public void merge(LwM2MModelConfig modelConfig) { + if (modelConfig.isEmpty() && modelConfig.getToCancelRead().isEmpty()) { + return; + } + + modelConfig.getAttributesToAdd().forEach((k, v) -> { + if (this.attributesToRemove.contains(k)) { + this.attributesToRemove.remove(k); + } else { + this.attributesToAdd.put(k, v); + } + }); + + modelConfig.getAttributesToRemove().forEach(k -> { + if (this.attributesToAdd.containsKey(k)) { + this.attributesToRemove.remove(k); + } else { + this.attributesToRemove.add(k); + } + }); + + this.toObserve.addAll(diffSets(this.toCancelObserve, modelConfig.getToObserve())); + this.toCancelObserve.addAll(diffSets(this.toObserve, modelConfig.getToCancelObserve())); + + this.toObserve.removeAll(modelConfig.getToCancelObserve()); + this.toCancelObserve.removeAll(modelConfig.getToObserve()); + + this.toRead.removeAll(modelConfig.getToObserve()); + this.toRead.removeAll(modelConfig.getToCancelRead()); + this.toRead.addAll(modelConfig.getToRead()); + } + + @JsonIgnore + public boolean isEmpty() { + return attributesToAdd.isEmpty() && toObserve.isEmpty() && toCancelObserve.isEmpty() && toRead.isEmpty(); + } +} diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/model/LwM2MModelConfigService.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/model/LwM2MModelConfigService.java new file mode 100644 index 0000000000..9670b7791b --- /dev/null +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/model/LwM2MModelConfigService.java @@ -0,0 +1,29 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.transport.lwm2m.server.model; + +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; + +public interface LwM2MModelConfigService { + + void sendUpdates(LwM2mClient lwM2mClient); + + void sendUpdates(LwM2mClient lwM2mClient, LwM2MModelConfig modelConfig); + + void persistUpdates(String endpoint); + + void removeUpdates(String endpoint); +} diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/model/LwM2MModelConfigServiceImpl.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/model/LwM2MModelConfigServiceImpl.java new file mode 100644 index 0000000000..9f0a84cbce --- /dev/null +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/model/LwM2MModelConfigServiceImpl.java @@ -0,0 +1,235 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.transport.lwm2m.server.model; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Service; +import org.thingsboard.server.common.data.device.data.lwm2m.ObjectAttributes; +import org.thingsboard.server.queue.util.AfterStartUp; +import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientContext; +import org.thingsboard.server.transport.lwm2m.server.downlink.DownlinkRequestCallback; +import org.thingsboard.server.transport.lwm2m.server.downlink.LwM2mDownlinkMsgHandler; +import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MCancelObserveCallback; +import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MCancelObserveRequest; +import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MObserveCallback; +import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MObserveRequest; +import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MReadCallback; +import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MReadRequest; +import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MWriteAttributesCallback; +import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MWriteAttributesRequest; +import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService; +import org.thingsboard.server.transport.lwm2m.server.store.TbLwM2MModelConfigStore; +import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler; + +import javax.annotation.PreDestroy; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.TimeoutException; +import java.util.stream.Collectors; + +@Slf4j +@Service +@TbLwM2mTransportComponent +public class LwM2MModelConfigServiceImpl implements LwM2MModelConfigService { + + @Autowired + private TbLwM2MModelConfigStore modelStore; + + @Autowired + @Lazy + private LwM2mDownlinkMsgHandler downlinkMsgHandler; + @Autowired + @Lazy + private LwM2mUplinkMsgHandler uplinkMsgHandler; + @Autowired + @Lazy + private LwM2mClientContext clientContext; + + @Autowired + private LwM2MTelemetryLogService logService; + + private ConcurrentMap currentModelConfigs; + + @AfterStartUp(order = Integer.MAX_VALUE - 1) + private void init() { + List models = modelStore.getAll(); + log.debug("Fetched model configs: {}", models); + currentModelConfigs = models.stream() + .collect(Collectors.toConcurrentMap(LwM2MModelConfig::getEndpoint, m -> m)); + } + + @Override + public void sendUpdates(LwM2mClient lwM2mClient) { + LwM2MModelConfig modelConfig = currentModelConfigs.get(lwM2mClient.getEndpoint()); + if (modelConfig == null || modelConfig.isEmpty()) { + return; + } + + doSend(lwM2mClient, modelConfig); + } + + public void sendUpdates(LwM2mClient lwM2mClient, LwM2MModelConfig newModelConfig) { + String endpoint = lwM2mClient.getEndpoint(); + LwM2MModelConfig modelConfig = currentModelConfigs.get(endpoint); + if (modelConfig == null || modelConfig.isEmpty()) { + modelConfig = newModelConfig; + currentModelConfigs.put(endpoint, modelConfig); + } else { + modelConfig.merge(newModelConfig); + } + + if (lwM2mClient.isAsleep()) { + modelStore.put(modelConfig); + } else { + doSend(lwM2mClient, modelConfig); + } + } + + private void doSend(LwM2mClient lwM2mClient, LwM2MModelConfig modelConfig) { + log.trace("Send LwM2M Model updates: [{}]", modelConfig); + + String endpoint = lwM2mClient.getEndpoint(); + + Map attrToAdd = modelConfig.getAttributesToAdd(); + attrToAdd.forEach((id, attributes) -> { + TbLwM2MWriteAttributesRequest request = TbLwM2MWriteAttributesRequest.builder().versionedId(id) + .attributes(attributes) + .timeout(clientContext.getRequestTimeout(lwM2mClient)).build(); + downlinkMsgHandler.sendWriteAttributesRequest(lwM2mClient, request, + createDownlinkProxyCallback(() -> { + attrToAdd.remove(id); + if (modelConfig.isEmpty()) { + modelStore.remove(endpoint); + } + }, new TbLwM2MWriteAttributesCallback(logService, lwM2mClient, id)) + ); + }); + + Set attrToRemove = modelConfig.getAttributesToRemove(); + attrToRemove.forEach((id) -> { + TbLwM2MWriteAttributesRequest request = TbLwM2MWriteAttributesRequest.builder().versionedId(id) + .attributes(new ObjectAttributes()) + .timeout(clientContext.getRequestTimeout(lwM2mClient)).build(); + downlinkMsgHandler.sendWriteAttributesRequest(lwM2mClient, request, + createDownlinkProxyCallback(() -> { + attrToRemove.remove(id); + if (modelConfig.isEmpty()) { + modelStore.remove(endpoint); + } + }, new TbLwM2MWriteAttributesCallback(logService, lwM2mClient, id)) + ); + }); + + Set toRead = modelConfig.getToRead(); + toRead.forEach(id -> { + TbLwM2MReadRequest request = TbLwM2MReadRequest.builder().versionedId(id) + .timeout(clientContext.getRequestTimeout(lwM2mClient)).build(); + downlinkMsgHandler.sendReadRequest(lwM2mClient, request, + createDownlinkProxyCallback(() -> { + toRead.remove(id); + if (modelConfig.isEmpty()) { + modelStore.remove(endpoint); + } + }, new TbLwM2MReadCallback(uplinkMsgHandler, logService, lwM2mClient, id)) + ); + }); + + Set toObserve = modelConfig.getToObserve(); + toObserve.forEach(id -> { + TbLwM2MObserveRequest request = TbLwM2MObserveRequest.builder().versionedId(id) + .timeout(clientContext.getRequestTimeout(lwM2mClient)).build(); + downlinkMsgHandler.sendObserveRequest(lwM2mClient, request, + createDownlinkProxyCallback(() -> { + toObserve.remove(id); + if (modelConfig.isEmpty()) { + modelStore.remove(endpoint); + } + }, new TbLwM2MObserveCallback(uplinkMsgHandler, logService, lwM2mClient, id)) + ); + }); + + Set toCancelObserve = modelConfig.getToCancelObserve(); + toCancelObserve.forEach(id -> { + TbLwM2MCancelObserveRequest request = TbLwM2MCancelObserveRequest.builder().versionedId(id) + .timeout(clientContext.getRequestTimeout(lwM2mClient)).build(); + downlinkMsgHandler.sendCancelObserveRequest(lwM2mClient, request, + createDownlinkProxyCallback(() -> { + toCancelObserve.remove(id); + if (modelConfig.isEmpty()) { + modelStore.remove(endpoint); + } + }, new TbLwM2MCancelObserveCallback(logService, lwM2mClient, id)) + ); + }); + } + + private DownlinkRequestCallback createDownlinkProxyCallback(Runnable processRemove, DownlinkRequestCallback callback) { + return new DownlinkRequestCallback<>() { + @Override + public void onSuccess(R request, T response) { + processRemove.run(); + callback.onSuccess(request, response); + } + + @Override + public void onValidationError(String params, String msg) { + processRemove.run(); + callback.onValidationError(params, msg); + } + + @Override + public void onError(String params, Exception e) { + try { + if (e instanceof TimeoutException) { + return; + } + processRemove.run(); + } finally { + callback.onError(params, e); + } + } + + }; + } + + @Override + public void persistUpdates(String endpoint) { + LwM2MModelConfig modelConfig = currentModelConfigs.get(endpoint); + if (modelConfig != null && !modelConfig.isEmpty()) { + modelStore.put(modelConfig); + } + } + + @Override + public void removeUpdates(String endpoint) { + currentModelConfigs.remove(endpoint); + } + + @PreDestroy + private void destroy() { + currentModelConfigs.values().forEach(model -> { + if (model != null && !model.isEmpty()) { + modelStore.put(model); + } + }); + } +} diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbDummyLwM2MModelConfigStore.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbDummyLwM2MModelConfigStore.java new file mode 100644 index 0000000000..06e55ca629 --- /dev/null +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbDummyLwM2MModelConfigStore.java @@ -0,0 +1,38 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.transport.lwm2m.server.store; + +import org.thingsboard.server.transport.lwm2m.server.model.LwM2MModelConfig; + +import java.util.Collections; +import java.util.List; + +public class TbDummyLwM2MModelConfigStore implements TbLwM2MModelConfigStore { + @Override + public List getAll() { + return Collections.emptyList(); + } + + @Override + public void put(LwM2MModelConfig modelConfig) { + + } + + @Override + public void remove(String endpoint) { + + } +} diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2MModelConfigStore.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2MModelConfigStore.java new file mode 100644 index 0000000000..74d7566279 --- /dev/null +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2MModelConfigStore.java @@ -0,0 +1,28 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.transport.lwm2m.server.store; + +import org.thingsboard.server.transport.lwm2m.server.model.LwM2MModelConfig; + +import java.util.List; + +public interface TbLwM2MModelConfigStore { + List getAll(); + + void put(LwM2MModelConfig modelConfig); + + void remove(String endpoint); +} diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mStoreFactory.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mStoreFactory.java index 9156d73181..de2f0c8de0 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mStoreFactory.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mStoreFactory.java @@ -62,6 +62,11 @@ public class TbLwM2mStoreFactory { return isRedis() ? new TbRedisLwM2MClientStore(getConnectionFactory()) : new TbDummyLwM2MClientStore(); } + @Bean + private TbLwM2MModelConfigStore modelConfigStore() { + return isRedis() ? new TbRedisLwM2MModelConfigStore(getConnectionFactory()) : new TbDummyLwM2MModelConfigStore(); + } + @Bean private TbLwM2MClientOtaInfoStore otaStore() { return isRedis() ? new TbLwM2mRedisClientOtaInfoStore(getConnectionFactory()) : new TbDummyLwM2MClientOtaInfoStore(); diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbRedisLwM2MModelConfigStore.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbRedisLwM2MModelConfigStore.java new file mode 100644 index 0000000000..9cf016f7ba --- /dev/null +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbRedisLwM2MModelConfigStore.java @@ -0,0 +1,79 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.transport.lwm2m.server.store; + +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.data.redis.connection.RedisClusterConnection; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.core.Cursor; +import org.springframework.data.redis.core.ScanOptions; +import org.thingsboard.common.util.JacksonUtil; +import org.thingsboard.server.transport.lwm2m.server.model.LwM2MModelConfig; + +import java.util.ArrayList; +import java.util.List; + +@Slf4j +@AllArgsConstructor +public class TbRedisLwM2MModelConfigStore implements TbLwM2MModelConfigStore { + private static final String MODEL_EP = "MODEL#EP#"; + private final RedisConnectionFactory connectionFactory; + + @Override + public List getAll() { + try (var connection = connectionFactory.getConnection()) { + List configs = new ArrayList<>(); + ScanOptions scanOptions = ScanOptions.scanOptions().count(100).match(MODEL_EP + "*").build(); + List> scans = new ArrayList<>(); + if (connection instanceof RedisClusterConnection) { + ((RedisClusterConnection) connection).clusterGetNodes().forEach(node -> { + scans.add(((RedisClusterConnection) connection).scan(node, scanOptions)); + }); + } else { + scans.add(connection.scan(scanOptions)); + } + + scans.forEach(scan -> { + scan.forEachRemaining(key -> { + byte[] element = connection.get(key); + configs.add(JacksonUtil.fromBytes(element, LwM2MModelConfig.class)); + }); + }); + return configs; + } + } + + @Override + public void put(LwM2MModelConfig modelConfig) { + byte[] clientSerialized = JacksonUtil.writeValueAsBytes(modelConfig); + try (var connection = connectionFactory.getConnection()) { + connection.getSet(getKey(modelConfig.getEndpoint()), clientSerialized); + } + } + + @Override + public void remove(String endpoint) { + try (var connection = connectionFactory.getConnection()) { + connection.del(getKey(endpoint)); + } + } + + private byte[] getKey(String endpoint) { + return (MODEL_EP + endpoint).getBytes(); + } + +} diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/DefaultLwM2MUplinkMsgHandler.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/DefaultLwM2MUplinkMsgHandler.java index 7a2d27d548..3b1aeeb5b1 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/DefaultLwM2MUplinkMsgHandler.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/DefaultLwM2MUplinkMsgHandler.java @@ -83,6 +83,8 @@ import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MReadRequest import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MWriteAttributesCallback; import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MWriteAttributesRequest; import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService; +import org.thingsboard.server.transport.lwm2m.server.model.LwM2MModelConfig; +import org.thingsboard.server.transport.lwm2m.server.model.LwM2MModelConfigService; import org.thingsboard.server.transport.lwm2m.server.ota.LwM2MOtaUpdateService; import org.thingsboard.server.transport.lwm2m.server.session.LwM2MSessionManager; import org.thingsboard.server.transport.lwm2m.server.store.TbLwM2MDtlsSessionStore; @@ -106,6 +108,7 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; +import static org.thingsboard.common.util.CollectionsUtil.diffSets; import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPARATOR_PATH; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LWM2M_ERROR; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LWM2M_INFO; @@ -147,6 +150,7 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl private final LwM2mVersionedModelProvider modelProvider; private final RegistrationStore registrationStore; private final TbLwM2mSecurityStore securityStore; + private final LwM2MModelConfigService modelConfigService; public DefaultLwM2MUplinkMsgHandler(TransportService transportService, LwM2MTransportServerConfig config, @@ -161,7 +165,8 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl TbLwM2MDtlsSessionStore sessionStore, LwM2mVersionedModelProvider modelProvider, RegistrationStore registrationStore, - TbLwM2mSecurityStore securityStore) { + TbLwM2mSecurityStore securityStore, + LwM2MModelConfigService modelConfigService) { this.transportService = transportService; this.sessionManager = sessionManager; this.attributesService = attributesService; @@ -176,6 +181,7 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl this.modelProvider = modelProvider; this.registrationStore = registrationStore; this.securityStore = securityStore; + this.modelConfigService = modelConfigService; } @PostConstruct @@ -757,7 +763,6 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl private void onDeviceProfileUpdate(List clients, DeviceProfile deviceProfile) { var oldProfile = clientContext.getProfile(deviceProfile.getUuidId()); if (clientContext.profileUpdate(deviceProfile) != null) { - // #1 TelemetryMappingConfiguration oldTelemetryParams = oldProfile.getObserveAttr(); Set attributeSetOld = oldTelemetryParams.getAttribute(); Set telemetrySetOld = oldTelemetryParams.getTelemetry(); @@ -777,46 +782,42 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl Set observeToRemove = diffSets(observeNew, observeOld); Set newObjectsToRead = new HashSet<>(); + Set newObjectsToCancelRead = new HashSet<>(); - // #3.1 if (!attributeSetOld.equals(attributeSetNew)) { newObjectsToRead.addAll(diffSets(attributeSetOld, attributeSetNew)); + newObjectsToCancelRead.addAll(diffSets(attributeSetNew, attributeSetOld)); + } - // #3.2 if (!telemetrySetOld.equals(telemetrySetNew)) { newObjectsToRead.addAll(diffSets(telemetrySetOld, telemetrySetNew)); + newObjectsToCancelRead.addAll(diffSets(telemetrySetNew, telemetrySetOld)); } - // #3.3 if (!keyNameOld.equals(keyNameNew)) { ParametersAnalyzeResult keyNameChange = this.getAnalyzerKeyName(keyNameOld, keyNameNew); newObjectsToRead.addAll(keyNameChange.getPathPostParametersAdd()); } - // #3.4, #6 - if (!attributeLwm2mOld.equals(attributeLwm2mNew)) { - this.compareAndSendWriteAttributes(clients, attributeLwm2mOld, attributeLwm2mNew); - } + ParametersAnalyzeResult analyzerParameters = getAttributesAnalyzer(attributeLwm2mOld, attributeLwm2mNew); - // #4.1 add - if (!newObjectsToRead.isEmpty()) { - Set newObjectsToReadButNotNewInObserve = diffSets(observeToAdd, newObjectsToRead); - // update value in Resources - for (String versionedId : newObjectsToReadButNotNewInObserve) { - clients.forEach(client -> sendReadRequest(client, versionedId)); - } - } + clients.forEach(client -> { + LwM2MModelConfig modelConfig = new LwM2MModelConfig(client.getEndpoint()); + modelConfig.getToRead().addAll(diffSets(observeToAdd, newObjectsToRead)); + modelConfig.getToCancelRead().addAll(newObjectsToCancelRead); + modelConfig.getToCancelObserve().addAll(observeToRemove); + modelConfig.getToObserve().addAll(observeToAdd); - // Calculating difference between old and new flags. - if (!observeToAdd.isEmpty()) { - for (String targetId : observeToAdd) { - clients.forEach(client -> sendObserveRequest(client, targetId)); - } - } - if (!observeToRemove.isEmpty()) { - for (String targetId : observeToRemove) { - clients.forEach(client -> sendCancelObserveRequest(targetId, client)); - } - } + Set clientObjects = clientContext.getSupportedIdVerInClient(client); + Set pathToAdd = analyzerParameters.getPathPostParametersAdd().stream().filter(target -> clientObjects.contains("/" + target.split(LWM2M_SEPARATOR_PATH)[1])) + .collect(Collectors.toUnmodifiableSet()); + modelConfig.getAttributesToAdd().putAll(pathToAdd.stream().collect(Collectors.toMap(t -> t, attributeLwm2mNew::get))); + + Set pathToRemove = analyzerParameters.getPathPostParametersDel().stream().filter(target -> clientObjects.contains("/" + target.split(LWM2M_SEPARATOR_PATH)[1])) + .collect(Collectors.toUnmodifiableSet()); + modelConfig.getAttributesToRemove().addAll(pathToRemove); + + modelConfigService.sendUpdates(client, modelConfig); + }); // update value in fwInfo OtherConfiguration newLwM2mSettings = newProfile.getClientLwM2mSettings(); @@ -835,13 +836,6 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl } } - /** - * Returns new set with elements that are present in set B(new) but absent in set A(old). - */ - private static Set diffSets(Set a, Set b) { - return b.stream().filter(p -> !a.contains(p)).collect(Collectors.toSet()); - } - private ParametersAnalyzeResult getAnalyzerKeyName(Map keyNameOld, Map keyNameNew) { ParametersAnalyzeResult analyzerParameters = new ParametersAnalyzeResult(); Set paths = keyNameNew.entrySet() @@ -852,14 +846,10 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl return analyzerParameters; } - /** - * #6.1 - send update WriteAttribute - * #6.2 - send empty WriteAttribute - */ - private void compareAndSendWriteAttributes(List clients, Map lwm2mAttributesOld, Map lwm2mAttributesNew) { + private ParametersAnalyzeResult getAttributesAnalyzer(Map attributeLwm2mOld, Map attributeLwm2mNew) { ParametersAnalyzeResult analyzerParameters = new ParametersAnalyzeResult(); - Set pathOld = lwm2mAttributesOld.keySet(); - Set pathNew = lwm2mAttributesNew.keySet(); + Set pathOld = attributeLwm2mOld.keySet(); + Set pathNew = attributeLwm2mNew.keySet(); analyzerParameters.setPathPostParametersAdd(pathNew .stream().filter(p -> !pathOld.contains(p)).collect(Collectors.toSet())); analyzerParameters.setPathPostParametersDel(pathOld @@ -867,31 +857,13 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl Set pathCommon = pathNew .stream().filter(pathOld::contains).collect(Collectors.toSet()); Set pathCommonChange = pathCommon - .stream().filter(p -> !lwm2mAttributesOld.get(p).equals(lwm2mAttributesNew.get(p))).collect(Collectors.toSet()); + .stream().filter(p -> !attributeLwm2mOld.get(p).equals(attributeLwm2mNew.get(p))).collect(Collectors.toSet()); analyzerParameters.getPathPostParametersAdd().addAll(pathCommonChange); - // #6 - // #6.2 - if (analyzerParameters.getPathPostParametersAdd().size() > 0) { - clients.forEach(client -> { - Set clientObjects = clientContext.getSupportedIdVerInClient(client); - Set pathSend = analyzerParameters.getPathPostParametersAdd().stream().filter(target -> clientObjects.contains("/" + target.split(LWM2M_SEPARATOR_PATH)[1])) - .collect(Collectors.toUnmodifiableSet()); - if (!pathSend.isEmpty()) { - pathSend.forEach(target -> sendWriteAttributesRequest(client, target, lwm2mAttributesNew.get(target))); - } - }); - } - // #6.2 - if (analyzerParameters.getPathPostParametersDel().size() > 0) { - clients.forEach(client -> { - Set clientObjects = clientContext.getSupportedIdVerInClient(client); - Set pathSend = analyzerParameters.getPathPostParametersDel().stream().filter(target -> clientObjects.contains("/" + target.split(LWM2M_SEPARATOR_PATH)[1])) - .collect(Collectors.toUnmodifiableSet()); - if (!pathSend.isEmpty()) { - pathSend.forEach(target -> sendWriteAttributesRequest(client, target, new ObjectAttributes())); - } - }); - } + return analyzerParameters; + } + + private void compareAndSetWriteAttributes(LwM2mClient client, ParametersAnalyzeResult analyzerParameters, Map lwm2mAttributesNew, LwM2MModelConfig modelConfig) { + } /** diff --git a/common/util/src/main/java/org/thingsboard/common/util/CollectionsUtil.java b/common/util/src/main/java/org/thingsboard/common/util/CollectionsUtil.java new file mode 100644 index 0000000000..8a2228e554 --- /dev/null +++ b/common/util/src/main/java/org/thingsboard/common/util/CollectionsUtil.java @@ -0,0 +1,37 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.common.util; + +import java.util.Collection; +import java.util.Set; +import java.util.stream.Collectors; + +public class CollectionsUtil { + public static boolean isEmpty(Collection collection) { + return collection == null || collection.isEmpty(); + } + + public static boolean isNotEmpty(Collection collection) { + return !isEmpty(collection); + } + + /** + * Returns new set with elements that are present in set B(new) but absent in set A(old). + */ + public static Set diffSets(Set a, Set b) { + return b.stream().filter(p -> !a.contains(p)).collect(Collectors.toSet()); + } +} diff --git a/common/util/src/main/java/org/thingsboard/common/util/JacksonUtil.java b/common/util/src/main/java/org/thingsboard/common/util/JacksonUtil.java index da50963bd4..6e8e5610eb 100644 --- a/common/util/src/main/java/org/thingsboard/common/util/JacksonUtil.java +++ b/common/util/src/main/java/org/thingsboard/common/util/JacksonUtil.java @@ -123,4 +123,12 @@ public class JacksonUtil { return OBJECT_MAPPER.treeToValue(tree, type); } + public static byte[] writeValueAsBytes(T value) { + try { + return OBJECT_MAPPER.writeValueAsBytes(value); + } catch (JsonProcessingException e) { + throw new IllegalArgumentException("The given Json object value: " + + value + " cannot be transformed to a String", e); + } + } } From 80a782145222b9a8ae91acff4003e2731a7e5053 Mon Sep 17 00:00:00 2001 From: desoliture Date: Wed, 8 Dec 2021 17:58:14 +0200 Subject: [PATCH 229/432] fix "password is empty" on only-white-spaces password --- .../service/security/auth/rest/RestLoginProcessingFilter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/src/main/java/org/thingsboard/server/service/security/auth/rest/RestLoginProcessingFilter.java b/application/src/main/java/org/thingsboard/server/service/security/auth/rest/RestLoginProcessingFilter.java index 76c0cd7a87..f9dbac87e9 100644 --- a/application/src/main/java/org/thingsboard/server/service/security/auth/rest/RestLoginProcessingFilter.java +++ b/application/src/main/java/org/thingsboard/server/service/security/auth/rest/RestLoginProcessingFilter.java @@ -73,7 +73,7 @@ public class RestLoginProcessingFilter extends AbstractAuthenticationProcessingF throw new AuthenticationServiceException("Invalid login request payload"); } - if (StringUtils.isBlank(loginRequest.getUsername()) || StringUtils.isBlank(loginRequest.getPassword())) { + if (StringUtils.isBlank(loginRequest.getUsername()) || StringUtils.isEmpty(loginRequest.getPassword())) { throw new AuthenticationServiceException("Username or Password not provided"); } From 409fddc2e89a26eeebc75a9bf9aad718e9e0db35 Mon Sep 17 00:00:00 2001 From: desoliture Date: Fri, 10 Dec 2021 18:05:20 +0200 Subject: [PATCH 230/432] add password policy for white-spaces --- .../service/security/system/DefaultSystemSecurityService.java | 4 ++++ .../server/common/data/security/model/UserPasswordPolicy.java | 2 ++ 2 files changed, 6 insertions(+) diff --git a/application/src/main/java/org/thingsboard/server/service/security/system/DefaultSystemSecurityService.java b/application/src/main/java/org/thingsboard/server/service/security/system/DefaultSystemSecurityService.java index 5db9509a77..26f6dbab65 100644 --- a/application/src/main/java/org/thingsboard/server/service/security/system/DefaultSystemSecurityService.java +++ b/application/src/main/java/org/thingsboard/server/service/security/system/DefaultSystemSecurityService.java @@ -27,6 +27,7 @@ import org.passay.PasswordData; import org.passay.PasswordValidator; import org.passay.Rule; import org.passay.RuleResult; +import org.passay.WhitespaceRule; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cache.annotation.CacheEvict; import org.springframework.cache.annotation.Cacheable; @@ -174,6 +175,9 @@ public class DefaultSystemSecurityService implements SystemSecurityService { if (isPositiveInteger(passwordPolicy.getMinimumSpecialCharacters())) { passwordRules.add(new CharacterRule(EnglishCharacterData.Special, passwordPolicy.getMinimumSpecialCharacters())); } + if (!passwordPolicy.getAllowWhitespaces()) { + passwordRules.add(new WhitespaceRule()); + } PasswordValidator validator = new PasswordValidator(passwordRules); PasswordData passwordData = new PasswordData(password); RuleResult result = validator.validate(passwordData); diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/security/model/UserPasswordPolicy.java b/common/data/src/main/java/org/thingsboard/server/common/data/security/model/UserPasswordPolicy.java index 28bdae82c3..8648f9839f 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/security/model/UserPasswordPolicy.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/security/model/UserPasswordPolicy.java @@ -35,6 +35,8 @@ public class UserPasswordPolicy implements Serializable { private Integer minimumDigits; @ApiModelProperty(position = 1, value = "Minimum number of special in the password." ) private Integer minimumSpecialCharacters; + @ApiModelProperty(position = 1, value = "Allow white-spaces") + private Boolean allowWhitespaces; @ApiModelProperty(position = 1, value = "Password expiration period (days). Force expiration of the password." ) private Integer passwordExpirationPeriodDays; From 8392075168622a6c34e2b054bba1c502e65cfe9e Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Mon, 13 Dec 2021 09:08:19 +0200 Subject: [PATCH 231/432] log4j-api and log4j-to-slf4j upgrade to 2.15 on dependency management --- pom.xml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/pom.xml b/pom.xml index ab92c575fd..33b531579a 100755 --- a/pom.xml +++ b/pom.xml @@ -47,6 +47,7 @@ 3.3.0 0.7.0 1.7.32 + 2.15.0 1.2.6 0.10 4.10.0 @@ -1492,6 +1493,16 @@ jul-to-slf4j ${slf4j.version} + + org.apache.logging.log4j + log4j-api + ${log4j.version} + + + org.apache.logging.log4j + log4j-to-slf4j + ${log4j.version} + ch.qos.logback logback-core From 2b06d15f3f066f63eabbacfc30c487af4a508ebd Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Mon, 13 Dec 2021 09:34:47 +0200 Subject: [PATCH 232/432] log4j-core defined to 2.15 on dependency management, but not used at this moment, just to be sure that no vulnerability brought by third-party. see https://github.com/advisories/GHSA-jfh8-c2jp-5v3q --- pom.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pom.xml b/pom.xml index 33b531579a..705a7f5602 100755 --- a/pom.xml +++ b/pom.xml @@ -1498,6 +1498,11 @@ log4j-api ${log4j.version} + + org.apache.logging.log4j + log4j-core + ${log4j.version} + org.apache.logging.log4j log4j-to-slf4j From 38b08ff76956a7867bdfbbef08bbea7d51127648 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Mon, 13 Dec 2021 12:58:09 +0200 Subject: [PATCH 233/432] Update grpc and netty versions to proper handle native windows ssl libraries --- pom.xml | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/pom.xml b/pom.xml index 705a7f5602..8730be5bee 100755 --- a/pom.xml +++ b/pom.xml @@ -75,11 +75,11 @@ 4.2.0 3.5.5 3.17.2 - 1.38.0 + 1.42.1 1.18.18 1.2.4 - 4.1.67.Final - 2.0.40.Final + 4.1.71.Final + 2.0.46.Final 1.7.0 4.8.0 2.19.1 @@ -1239,7 +1239,12 @@ io.netty netty-tcnative-boringssl-static - ${netty-tcnative-boringssl-static.version} + ${netty-tcnative.version} + + + io.netty + netty-tcnative-classes + ${netty-tcnative.version} io.netty From 34b4aeac4933e825b3ea1149356fce8c10bc6f46 Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Mon, 13 Dec 2021 15:52:48 +0200 Subject: [PATCH 234/432] added code defaults sql.remove_null_chars=true (same as thingsboard.yaml) to simplify test setup --- .../server/dao/sql/attributes/AttributeKvInsertRepository.java | 2 +- .../server/dao/sqlts/insert/AbstractInsertRepository.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/attributes/AttributeKvInsertRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/attributes/AttributeKvInsertRepository.java index 84688be9c9..8390860826 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/attributes/AttributeKvInsertRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/attributes/AttributeKvInsertRepository.java @@ -56,7 +56,7 @@ public abstract class AttributeKvInsertRepository { @Autowired private TransactionTemplate transactionTemplate; - @Value("${sql.remove_null_chars}") + @Value("${sql.remove_null_chars:true}") private boolean removeNullChars; protected void saveOrUpdate(List entities) { diff --git a/dao/src/main/java/org/thingsboard/server/dao/sqlts/insert/AbstractInsertRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sqlts/insert/AbstractInsertRepository.java index 77c59c5f21..490293860c 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sqlts/insert/AbstractInsertRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sqlts/insert/AbstractInsertRepository.java @@ -29,7 +29,7 @@ public abstract class AbstractInsertRepository { private static final ThreadLocal PATTERN_THREAD_LOCAL = ThreadLocal.withInitial(() -> Pattern.compile(String.valueOf(Character.MIN_VALUE))); private static final String EMPTY_STR = ""; - @Value("${sql.remove_null_chars}") + @Value("${sql.remove_null_chars:true}") private boolean removeNullChars; @Autowired From 1678e14d4f10bc29fbaca307c122a0572dda2f13 Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Mon, 13 Dec 2021 15:54:28 +0200 Subject: [PATCH 235/432] tests: verify that all tenants deleted before delete default tenant profile (abstract web test) --- .../server/controller/AbstractWebTest.java | 27 ++++++++++++++++--- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/application/src/test/java/org/thingsboard/server/controller/AbstractWebTest.java b/application/src/test/java/org/thingsboard/server/controller/AbstractWebTest.java index 1a6027350c..5944cad7b3 100644 --- a/application/src/test/java/org/thingsboard/server/controller/AbstractWebTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/AbstractWebTest.java @@ -22,7 +22,6 @@ import io.jsonwebtoken.Claims; import io.jsonwebtoken.Header; import io.jsonwebtoken.Jwt; import io.jsonwebtoken.Jwts; -import lombok.Getter; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.RandomStringUtils; import org.apache.commons.lang3.StringUtils; @@ -59,20 +58,20 @@ import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.device.profile.DefaultDeviceProfileConfiguration; import org.thingsboard.server.common.data.device.profile.DefaultDeviceProfileTransportConfiguration; import org.thingsboard.server.common.data.device.profile.DeviceProfileData; -import org.thingsboard.server.common.data.edge.Edge; import org.thingsboard.server.common.data.device.profile.DeviceProfileTransportConfiguration; import org.thingsboard.server.common.data.device.profile.MqttDeviceProfileTransportConfiguration; import org.thingsboard.server.common.data.device.profile.MqttTopics; import org.thingsboard.server.common.data.device.profile.ProtoTransportPayloadConfiguration; import org.thingsboard.server.common.data.device.profile.TransportPayloadTypeConfiguration; +import org.thingsboard.server.common.data.edge.Edge; import org.thingsboard.server.common.data.id.HasId; import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.page.TimePageLink; import org.thingsboard.server.common.data.security.Authority; import org.thingsboard.server.config.ThingsboardSecurityConfiguration; import org.thingsboard.server.dao.tenant.TenantProfileService; -import org.thingsboard.server.queue.memory.InMemoryStorage; import org.thingsboard.server.service.mail.TestMailService; import org.thingsboard.server.service.security.auth.jwt.RefreshTokenRequest; import org.thingsboard.server.service.security.auth.rest.LoginRequest; @@ -83,6 +82,7 @@ import java.util.Arrays; import java.util.Comparator; import java.util.List; +import static org.assertj.core.api.Assertions.assertThat; import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.asyncDispatch; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; @@ -95,7 +95,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. import static org.springframework.test.web.servlet.setup.MockMvcBuilders.webAppContextSetup; @Slf4j -public abstract class AbstractWebTest extends AbstractInMemoryStorageTest{ +public abstract class AbstractWebTest extends AbstractInMemoryStorageTest { protected ObjectMapper mapper = new ObjectMapper(); @@ -214,11 +214,29 @@ public abstract class AbstractWebTest extends AbstractInMemoryStorageTest{ doDelete("/api/tenant/" + tenantId.getId().toString()) .andExpect(status().isOk()); + verifyNoTenantsLeft(); + tenantProfileService.deleteTenantProfiles(TenantId.SYS_TENANT_ID); log.info("Executed web test teardown"); } + void verifyNoTenantsLeft() throws Exception { + List loadedTenants = new ArrayList<>(); + PageLink pageLink = new PageLink(10); + PageData pageData; + do { + pageData = doGetTypedWithPageLink("/api/tenants?", new TypeReference>() { + }, pageLink); + loadedTenants.addAll(pageData.getData()); + if (pageData.hasNext()) { + pageLink = pageLink.nextPageLink(); + } + } while (pageData.hasNext()); + + assertThat(loadedTenants).as("All tenants expected to be deleted, but some tenants left in the database").isEmpty(); + } + protected void loginSysAdmin() throws Exception { login(SYS_ADMIN_EMAIL, SYS_ADMIN_PASSWORD); } @@ -580,6 +598,7 @@ public abstract class AbstractWebTest extends AbstractInMemoryStorageTest{ protected Edge constructEdge(String name, String type) { return constructEdge(tenantId, name, type); } + protected Edge constructEdge(TenantId tenantId, String name, String type) { Edge edge = new Edge(); edge.setTenantId(tenantId); From 4f4e75f942d58efc90744c9724f9bfbcf6fc2bac Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Mon, 13 Dec 2021 15:55:51 +0200 Subject: [PATCH 236/432] tests: fixed coap integration tests lifecycle (can not delete default tenant profile after test) --- ...AttributesRequestProtoIntegrationTest.java | 12 +++++------ ...actCoapAttributesProtoIntegrationTest.java | 11 +++++----- ...actCoapTimeseriesProtoIntegrationTest.java | 20 +++++++++---------- 3 files changed, 21 insertions(+), 22 deletions(-) diff --git a/application/src/test/java/org/thingsboard/server/transport/coap/attributes/request/AbstractCoapAttributesRequestProtoIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/coap/attributes/request/AbstractCoapAttributesRequestProtoIntegrationTest.java index b5534cba80..a8277fe0c7 100644 --- a/application/src/test/java/org/thingsboard/server/transport/coap/attributes/request/AbstractCoapAttributesRequestProtoIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/coap/attributes/request/AbstractCoapAttributesRequestProtoIntegrationTest.java @@ -24,7 +24,7 @@ import lombok.extern.slf4j.Slf4j; import org.eclipse.californium.core.CoapResponse; import org.eclipse.californium.core.coap.CoAP; import org.eclipse.californium.core.coap.MediaTypeRegistry; -import org.junit.After; +import org.junit.Before; import org.junit.Test; import org.thingsboard.server.common.data.CoapDeviceType; import org.thingsboard.server.common.data.DeviceProfileProvisionType; @@ -70,15 +70,15 @@ public abstract class AbstractCoapAttributesRequestProtoIntegrationTest extends " }\n" + "}"; - @After - public void afterTest() throws Exception { - processAfterTest(); + @Before + @Override + public void beforeTest() throws Exception { + processBeforeTest("Test Request attribute values from the server proto", CoapDeviceType.DEFAULT, + TransportPayloadType.PROTOBUF, null, ATTRIBUTES_SCHEMA_STR, null, null, null, null, DeviceProfileProvisionType.DISABLED); } @Test public void testRequestAttributesValuesFromTheServer() throws Exception { - super.processBeforeTest("Test Request attribute values from the server proto", CoapDeviceType.DEFAULT, - TransportPayloadType.PROTOBUF, null, ATTRIBUTES_SCHEMA_STR, null, null, null, null, DeviceProfileProvisionType.DISABLED); processTestRequestAttributesValuesFromTheServer(); } diff --git a/application/src/test/java/org/thingsboard/server/transport/coap/telemetry/attributes/AbstractCoapAttributesProtoIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/coap/telemetry/attributes/AbstractCoapAttributesProtoIntegrationTest.java index b3e9ea4ef6..4ed46b5e76 100644 --- a/application/src/test/java/org/thingsboard/server/transport/coap/telemetry/attributes/AbstractCoapAttributesProtoIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/coap/telemetry/attributes/AbstractCoapAttributesProtoIntegrationTest.java @@ -20,7 +20,7 @@ import com.google.protobuf.Descriptors; import com.google.protobuf.DynamicMessage; import com.squareup.wire.schema.internal.parser.ProtoFileElement; import lombok.extern.slf4j.Slf4j; -import org.junit.After; +import org.junit.Before; import org.junit.Test; import org.thingsboard.server.common.data.CoapDeviceType; import org.thingsboard.server.common.data.TransportPayloadType; @@ -39,14 +39,14 @@ import static org.junit.Assert.assertTrue; @Slf4j public abstract class AbstractCoapAttributesProtoIntegrationTest extends AbstractCoapAttributesIntegrationTest { - @After - public void afterTest() throws Exception { - processAfterTest(); + @Before + @Override + public void beforeTest() throws Exception { + processBeforeTest("Test Post Attributes device Proto", CoapDeviceType.DEFAULT, TransportPayloadType.PROTOBUF); } @Test public void testPushAttributes() throws Exception { - super.processBeforeTest("Test Post Attributes device Proto", CoapDeviceType.DEFAULT, TransportPayloadType.PROTOBUF); DeviceProfileTransportConfiguration transportConfiguration = deviceProfile.getProfileData().getTransportConfiguration(); assertTrue(transportConfiguration instanceof CoapDeviceProfileTransportConfiguration); CoapDeviceProfileTransportConfiguration coapTransportConfiguration = (CoapDeviceProfileTransportConfiguration) transportConfiguration; @@ -90,7 +90,6 @@ public abstract class AbstractCoapAttributesProtoIntegrationTest extends Abstrac @Test public void testPushAttributesWithExplicitPresenceProtoKeys() throws Exception { - super.processBeforeTest("Test Post Attributes device Proto", CoapDeviceType.DEFAULT, TransportPayloadType.PROTOBUF); DeviceProfileTransportConfiguration transportConfiguration = deviceProfile.getProfileData().getTransportConfiguration(); assertTrue(transportConfiguration instanceof CoapDeviceProfileTransportConfiguration); CoapDeviceProfileTransportConfiguration coapTransportConfiguration = (CoapDeviceProfileTransportConfiguration) transportConfiguration; diff --git a/application/src/test/java/org/thingsboard/server/transport/coap/telemetry/timeseries/AbstractCoapTimeseriesProtoIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/coap/telemetry/timeseries/AbstractCoapTimeseriesProtoIntegrationTest.java index 699ba1e24d..612867636c 100644 --- a/application/src/test/java/org/thingsboard/server/transport/coap/telemetry/timeseries/AbstractCoapTimeseriesProtoIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/coap/telemetry/timeseries/AbstractCoapTimeseriesProtoIntegrationTest.java @@ -20,7 +20,7 @@ import com.google.protobuf.Descriptors; import com.google.protobuf.DynamicMessage; import com.squareup.wire.schema.internal.parser.ProtoFileElement; import lombok.extern.slf4j.Slf4j; -import org.junit.After; +import org.junit.Before; import org.junit.Test; import org.thingsboard.server.common.data.CoapDeviceType; import org.thingsboard.server.common.data.DeviceProfileProvisionType; @@ -33,7 +33,6 @@ import org.thingsboard.server.common.data.device.profile.ProtoTransportPayloadCo import org.thingsboard.server.common.data.device.profile.TransportPayloadTypeConfiguration; import java.util.Arrays; -import java.util.Collections; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; @@ -41,14 +40,15 @@ import static org.junit.Assert.assertTrue; @Slf4j public abstract class AbstractCoapTimeseriesProtoIntegrationTest extends AbstractCoapTimeseriesIntegrationTest { - @After - public void afterTest() throws Exception { - processAfterTest(); + @Before + @Override + public void beforeTest() throws Exception { + //do nothing, processBeforeTest will be invoked in particular test methods with different parameters } @Test public void testPushTelemetry() throws Exception { - super.processBeforeTest("Test Post Telemetry device proto payload", CoapDeviceType.DEFAULT, TransportPayloadType.PROTOBUF); + processBeforeTest("Test Post Telemetry device proto payload", CoapDeviceType.DEFAULT, TransportPayloadType.PROTOBUF); DeviceProfileTransportConfiguration transportConfiguration = deviceProfile.getProfileData().getTransportConfiguration(); assertTrue(transportConfiguration instanceof CoapDeviceProfileTransportConfiguration); CoapDeviceProfileTransportConfiguration coapDeviceProfileTransportConfiguration = (CoapDeviceProfileTransportConfiguration) transportConfiguration; @@ -117,7 +117,7 @@ public abstract class AbstractCoapTimeseriesProtoIntegrationTest extends Abstrac " }\n" + " }\n" + "}"; - super.processBeforeTest("Test Post Telemetry device proto payload", CoapDeviceType.DEFAULT, TransportPayloadType.PROTOBUF, schemaStr, null, null, null, null, null, DeviceProfileProvisionType.DISABLED); + processBeforeTest("Test Post Telemetry device proto payload", CoapDeviceType.DEFAULT, TransportPayloadType.PROTOBUF, schemaStr, null, null, null, null, null, DeviceProfileProvisionType.DISABLED); DeviceProfileTransportConfiguration transportConfiguration = deviceProfile.getProfileData().getTransportConfiguration(); assertTrue(transportConfiguration instanceof CoapDeviceProfileTransportConfiguration); CoapDeviceProfileTransportConfiguration coapDeviceProfileTransportConfiguration = (CoapDeviceProfileTransportConfiguration) transportConfiguration; @@ -167,12 +167,12 @@ public abstract class AbstractCoapTimeseriesProtoIntegrationTest extends Abstrac .setField(postTelemetryMsgDescriptor.findFieldByName("values"), valuesMsg) .build(); - processTestPostTelemetry(postTelemetryMsg.toByteArray(), Arrays.asList("key1", "key2", "key3", "key4", "key5"), true, false); + processTestPostTelemetry(postTelemetryMsg.toByteArray(), Arrays.asList("key1", "key2", "key3", "key4", "key5"), true, false); } @Test public void testPushTelemetryWithExplicitPresenceProtoKeys() throws Exception { - super.processBeforeTest("Test Post Telemetry device proto payload", CoapDeviceType.DEFAULT, TransportPayloadType.PROTOBUF); + processBeforeTest("Test Post Telemetry device proto payload", CoapDeviceType.DEFAULT, TransportPayloadType.PROTOBUF); DeviceProfileTransportConfiguration transportConfiguration = deviceProfile.getProfileData().getTransportConfiguration(); assertTrue(transportConfiguration instanceof CoapDeviceProfileTransportConfiguration); CoapDeviceProfileTransportConfiguration coapDeviceProfileTransportConfiguration = (CoapDeviceProfileTransportConfiguration) transportConfiguration; @@ -239,7 +239,7 @@ public abstract class AbstractCoapTimeseriesProtoIntegrationTest extends Abstrac " }\n" + " }\n" + "}"; - super.processBeforeTest("Test Post Telemetry device proto payload", CoapDeviceType.DEFAULT, TransportPayloadType.PROTOBUF, schemaStr, null, null, null, null, null, DeviceProfileProvisionType.DISABLED); + processBeforeTest("Test Post Telemetry device proto payload", CoapDeviceType.DEFAULT, TransportPayloadType.PROTOBUF, schemaStr, null, null, null, null, null, DeviceProfileProvisionType.DISABLED); DeviceProfileTransportConfiguration transportConfiguration = deviceProfile.getProfileData().getTransportConfiguration(); assertTrue(transportConfiguration instanceof CoapDeviceProfileTransportConfiguration); CoapDeviceProfileTransportConfiguration coapDeviceProfileTransportConfiguration = (CoapDeviceProfileTransportConfiguration) transportConfiguration; From d2ccaa2dd95b90c1635f4614de8e22686112e986 Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Mon, 13 Dec 2021 16:02:05 +0200 Subject: [PATCH 237/432] tests: fixed mqtt integration tests lifecycle (can not delete default tenant profile after test) --- ...actMqttAttributesProtoIntegrationTest.java | 23 +++++++------- ...actMqttTimeseriesProtoIntegrationTest.java | 31 ++++++++++--------- 2 files changed, 28 insertions(+), 26 deletions(-) diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/telemetry/attributes/AbstractMqttAttributesProtoIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/telemetry/attributes/AbstractMqttAttributesProtoIntegrationTest.java index a68ece0df0..48467be27f 100644 --- a/application/src/test/java/org/thingsboard/server/transport/mqtt/telemetry/attributes/AbstractMqttAttributesProtoIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/telemetry/attributes/AbstractMqttAttributesProtoIntegrationTest.java @@ -20,7 +20,7 @@ import com.google.protobuf.Descriptors; import com.google.protobuf.DynamicMessage; import com.squareup.wire.schema.internal.parser.ProtoFileElement; import lombok.extern.slf4j.Slf4j; -import org.junit.After; +import org.junit.Before; import org.junit.Test; import org.thingsboard.server.common.data.TransportPayloadType; import org.thingsboard.server.common.data.device.profile.DeviceProfileTransportConfiguration; @@ -42,27 +42,28 @@ public abstract class AbstractMqttAttributesProtoIntegrationTest extends Abstrac private static final String POST_DATA_ATTRIBUTES_TOPIC = "proto/attributes"; - @After - public void afterTest() throws Exception { - processAfterTest(); + @Before + @Override + public void beforeTest() throws Exception { + //do nothing, processBeforeTest will be invoked in particular test methods with different parameters } @Test public void testPushAttributes() throws Exception { - super.processBeforeTest("Test Post Attributes device", "Test Post Attributes gateway", TransportPayloadType.PROTOBUF, null, POST_DATA_ATTRIBUTES_TOPIC); + processBeforeTest("Test Post Attributes device", "Test Post Attributes gateway", TransportPayloadType.PROTOBUF, null, POST_DATA_ATTRIBUTES_TOPIC); DynamicMessage postAttributesMsg = getDefaultDynamicMessage(); processAttributesTest(POST_DATA_ATTRIBUTES_TOPIC, Arrays.asList("key1", "key2", "key3", "key4", "key5"), postAttributesMsg.toByteArray(), false); } @Test public void testPushAttributesWithEnabledJsonBackwardCompatibility() throws Exception { - super.processBeforeTest("Test Post Attributes device", "Test Post Attributes gateway", TransportPayloadType.PROTOBUF, null, POST_DATA_ATTRIBUTES_TOPIC, true, false); + processBeforeTest("Test Post Attributes device", "Test Post Attributes gateway", TransportPayloadType.PROTOBUF, null, POST_DATA_ATTRIBUTES_TOPIC, true, false); processJsonPayloadAttributesTest(POST_DATA_ATTRIBUTES_TOPIC, Arrays.asList("key1", "key2", "key3", "key4", "key5"), PAYLOAD_VALUES_STR.getBytes()); } @Test public void testPushAttributesWithExplicitPresenceProtoKeys() throws Exception { - super.processBeforeTest("Test Post Attributes device", "Test Post Attributes gateway", TransportPayloadType.PROTOBUF, null, POST_DATA_ATTRIBUTES_TOPIC); + processBeforeTest("Test Post Attributes device", "Test Post Attributes gateway", TransportPayloadType.PROTOBUF, null, POST_DATA_ATTRIBUTES_TOPIC); DynamicSchema attributesSchema = getDynamicSchema(); DynamicMessage.Builder nestedJsonObjectBuilder = attributesSchema.newMessageBuilder("PostAttributes.JsonObject.NestedJsonObject"); @@ -95,27 +96,27 @@ public abstract class AbstractMqttAttributesProtoIntegrationTest extends Abstrac @Test public void testPushAttributesOnShortTopic() throws Exception { - super.processBeforeTest("Test Post Attributes device", "Test Post Attributes gateway", TransportPayloadType.PROTOBUF, null, POST_DATA_ATTRIBUTES_TOPIC); + processBeforeTest("Test Post Attributes device", "Test Post Attributes gateway", TransportPayloadType.PROTOBUF, null, POST_DATA_ATTRIBUTES_TOPIC); DynamicMessage postAttributesMsg = getDefaultDynamicMessage(); processAttributesTest(MqttTopics.DEVICE_ATTRIBUTES_SHORT_TOPIC, Arrays.asList("key1", "key2", "key3", "key4", "key5"), postAttributesMsg.toByteArray(), false); } @Test public void testPushAttributesOnShortJsonTopic() throws Exception { - super.processBeforeTest("Test Post Attributes device", "Test Post Attributes gateway", TransportPayloadType.PROTOBUF, null, POST_DATA_ATTRIBUTES_TOPIC); + processBeforeTest("Test Post Attributes device", "Test Post Attributes gateway", TransportPayloadType.PROTOBUF, null, POST_DATA_ATTRIBUTES_TOPIC); processJsonPayloadAttributesTest(MqttTopics.DEVICE_ATTRIBUTES_SHORT_JSON_TOPIC, Arrays.asList("key1", "key2", "key3", "key4", "key5"), PAYLOAD_VALUES_STR.getBytes()); } @Test public void testPushAttributesOnShortProtoTopic() throws Exception { - super.processBeforeTest("Test Post Attributes device", "Test Post Attributes gateway", TransportPayloadType.PROTOBUF, null, POST_DATA_ATTRIBUTES_TOPIC); + processBeforeTest("Test Post Attributes device", "Test Post Attributes gateway", TransportPayloadType.PROTOBUF, null, POST_DATA_ATTRIBUTES_TOPIC); DynamicMessage postAttributesMsg = getDefaultDynamicMessage(); processAttributesTest(MqttTopics.DEVICE_ATTRIBUTES_SHORT_PROTO_TOPIC, Arrays.asList("key1", "key2", "key3", "key4", "key5"), postAttributesMsg.toByteArray(), false); } @Test public void testPushAttributesGateway() throws Exception { - super.processBeforeTest("Test Post Attributes device", "Test Post Attributes gateway", TransportPayloadType.PROTOBUF, null, null); + processBeforeTest("Test Post Attributes device", "Test Post Attributes gateway", TransportPayloadType.PROTOBUF, null, null); TransportApiProtos.GatewayAttributesMsg.Builder gatewayAttributesMsgProtoBuilder = TransportApiProtos.GatewayAttributesMsg.newBuilder(); List expectedKeys = Arrays.asList("key1", "key2", "key3", "key4", "key5"); String deviceName1 = "Device A"; diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/telemetry/timeseries/AbstractMqttTimeseriesProtoIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/telemetry/timeseries/AbstractMqttTimeseriesProtoIntegrationTest.java index fd6cf9b9ae..6bef6e5fc8 100644 --- a/application/src/test/java/org/thingsboard/server/transport/mqtt/telemetry/timeseries/AbstractMqttTimeseriesProtoIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/telemetry/timeseries/AbstractMqttTimeseriesProtoIntegrationTest.java @@ -21,15 +21,15 @@ import com.google.protobuf.DynamicMessage; import com.squareup.wire.schema.internal.parser.ProtoFileElement; import lombok.extern.slf4j.Slf4j; import org.eclipse.paho.client.mqttv3.MqttAsyncClient; -import org.junit.After; +import org.junit.Before; import org.junit.Test; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.DeviceProfileProvisionType; import org.thingsboard.server.common.data.TransportPayloadType; import org.thingsboard.server.common.data.device.profile.DeviceProfileTransportConfiguration; import org.thingsboard.server.common.data.device.profile.MqttDeviceProfileTransportConfiguration; -import org.thingsboard.server.common.data.device.profile.ProtoTransportPayloadConfiguration; import org.thingsboard.server.common.data.device.profile.MqttTopics; +import org.thingsboard.server.common.data.device.profile.ProtoTransportPayloadConfiguration; import org.thingsboard.server.common.data.device.profile.TransportPayloadTypeConfiguration; import org.thingsboard.server.gen.transport.TransportApiProtos; import org.thingsboard.server.gen.transport.TransportProtos; @@ -45,21 +45,22 @@ public abstract class AbstractMqttTimeseriesProtoIntegrationTest extends Abstrac private static final String POST_DATA_TELEMETRY_TOPIC = "proto/telemetry"; - @After - public void afterTest() throws Exception { - processAfterTest(); + @Before + @Override + public void beforeTest() throws Exception { + //do nothing, processBeforeTest will be invoked in particular test methods with different parameters } @Test public void testPushTelemetry() throws Exception { - super.processBeforeTest("Test Post Telemetry device proto payload", "Test Post Telemetry gateway proto payload", TransportPayloadType.PROTOBUF, POST_DATA_TELEMETRY_TOPIC, null); + processBeforeTest("Test Post Telemetry device proto payload", "Test Post Telemetry gateway proto payload", TransportPayloadType.PROTOBUF, POST_DATA_TELEMETRY_TOPIC, null); DynamicMessage postTelemetryMsg = getDefaultDynamicMessage(); processTelemetryTest(POST_DATA_TELEMETRY_TOPIC, Arrays.asList("key1", "key2", "key3", "key4", "key5"), postTelemetryMsg.toByteArray(), false, false); } @Test public void testPushTelemetryWithEnabledJsonBackwardCompatibility() throws Exception { - super.processBeforeTest("Test Post Telemetry device proto payload", "Test Post Telemetry gateway proto payload", TransportPayloadType.PROTOBUF, POST_DATA_TELEMETRY_TOPIC, null, true, false); + processBeforeTest("Test Post Telemetry device proto payload", "Test Post Telemetry gateway proto payload", TransportPayloadType.PROTOBUF, POST_DATA_TELEMETRY_TOPIC, null, true, false); processJsonPayloadTelemetryTest(POST_DATA_TELEMETRY_TOPIC, Arrays.asList("key1", "key2", "key3", "key4", "key5"), PAYLOAD_VALUES_STR.getBytes(), false); } @@ -90,7 +91,7 @@ public abstract class AbstractMqttTimeseriesProtoIntegrationTest extends Abstrac " }\n" + " }\n" + "}"; - super.processBeforeTest("Test Post Telemetry device proto payload", "Test Post Telemetry gateway proto payload", TransportPayloadType.PROTOBUF, POST_DATA_TELEMETRY_TOPIC, null, schemaStr, null, null, null, null, null, DeviceProfileProvisionType.DISABLED, false, false); + processBeforeTest("Test Post Telemetry device proto payload", "Test Post Telemetry gateway proto payload", TransportPayloadType.PROTOBUF, POST_DATA_TELEMETRY_TOPIC, null, schemaStr, null, null, null, null, null, DeviceProfileProvisionType.DISABLED, false, false); DynamicSchema telemetrySchema = getDynamicSchema(schemaStr); DynamicMessage.Builder nestedJsonObjectBuilder = telemetrySchema.newMessageBuilder("PostTelemetry.JsonObject.NestedJsonObject"); @@ -135,7 +136,7 @@ public abstract class AbstractMqttTimeseriesProtoIntegrationTest extends Abstrac @Test public void testPushTelemetryWithExplicitPresenceProtoKeys() throws Exception { - super.processBeforeTest("Test Post Telemetry device proto payload", "Test Post Telemetry gateway proto payload", TransportPayloadType.PROTOBUF, POST_DATA_TELEMETRY_TOPIC, null); + processBeforeTest("Test Post Telemetry device proto payload", "Test Post Telemetry gateway proto payload", TransportPayloadType.PROTOBUF, POST_DATA_TELEMETRY_TOPIC, null); DynamicSchema telemetrySchema = getDynamicSchema(DEVICE_TELEMETRY_PROTO_SCHEMA); DynamicMessage.Builder nestedJsonObjectBuilder = telemetrySchema.newMessageBuilder("PostTelemetry.JsonObject.NestedJsonObject"); @@ -192,7 +193,7 @@ public abstract class AbstractMqttTimeseriesProtoIntegrationTest extends Abstrac " }\n" + " }\n" + "}"; - super.processBeforeTest("Test Post Telemetry device proto payload", "Test Post Telemetry gateway proto payload", TransportPayloadType.PROTOBUF, POST_DATA_TELEMETRY_TOPIC, null, schemaStr, null, null, null, null, null, DeviceProfileProvisionType.DISABLED, false, false); + processBeforeTest("Test Post Telemetry device proto payload", "Test Post Telemetry gateway proto payload", TransportPayloadType.PROTOBUF, POST_DATA_TELEMETRY_TOPIC, null, schemaStr, null, null, null, null, null, DeviceProfileProvisionType.DISABLED, false, false); DynamicSchema telemetrySchema = getDynamicSchema(schemaStr); DynamicMessage.Builder nestedJsonObjectBuilder = telemetrySchema.newMessageBuilder("PostTelemetry.JsonObject.NestedJsonObject"); @@ -232,27 +233,27 @@ public abstract class AbstractMqttTimeseriesProtoIntegrationTest extends Abstrac @Test public void testPushTelemetryOnShortTopic() throws Exception { - super.processBeforeTest("Test Post Telemetry device proto payload", "Test Post Telemetry gateway proto payload", TransportPayloadType.PROTOBUF, POST_DATA_TELEMETRY_TOPIC, null); + processBeforeTest("Test Post Telemetry device proto payload", "Test Post Telemetry gateway proto payload", TransportPayloadType.PROTOBUF, POST_DATA_TELEMETRY_TOPIC, null); DynamicMessage postTelemetryMsg = getDefaultDynamicMessage(); processTelemetryTest(MqttTopics.DEVICE_TELEMETRY_SHORT_TOPIC, Arrays.asList("key1", "key2", "key3", "key4", "key5"), postTelemetryMsg.toByteArray(), false, false); } @Test public void testPushTelemetryOnShortJsonTopic() throws Exception { - super.processBeforeTest("Test Post Telemetry device proto payload", "Test Post Telemetry gateway proto payload", TransportPayloadType.PROTOBUF, POST_DATA_TELEMETRY_TOPIC, null); + processBeforeTest("Test Post Telemetry device proto payload", "Test Post Telemetry gateway proto payload", TransportPayloadType.PROTOBUF, POST_DATA_TELEMETRY_TOPIC, null); processJsonPayloadTelemetryTest(MqttTopics.DEVICE_TELEMETRY_SHORT_JSON_TOPIC, Arrays.asList("key1", "key2", "key3", "key4", "key5"), PAYLOAD_VALUES_STR.getBytes(), false); } @Test public void testPushTelemetryOnShortProtoTopic() throws Exception { - super.processBeforeTest("Test Post Telemetry device proto payload", "Test Post Telemetry gateway proto payload", TransportPayloadType.PROTOBUF, POST_DATA_TELEMETRY_TOPIC, null); + processBeforeTest("Test Post Telemetry device proto payload", "Test Post Telemetry gateway proto payload", TransportPayloadType.PROTOBUF, POST_DATA_TELEMETRY_TOPIC, null); DynamicMessage postTelemetryMsg = getDefaultDynamicMessage(); processTelemetryTest(MqttTopics.DEVICE_TELEMETRY_SHORT_PROTO_TOPIC, Arrays.asList("key1", "key2", "key3", "key4", "key5"), postTelemetryMsg.toByteArray(), false, false); } @Test public void testPushTelemetryGateway() throws Exception { - super.processBeforeTest("Test Post Telemetry device proto payload", "Test Post Telemetry gateway proto payload", TransportPayloadType.PROTOBUF, null, null, null, null, null, null, null, null, DeviceProfileProvisionType.DISABLED, false, false); + processBeforeTest("Test Post Telemetry device proto payload", "Test Post Telemetry gateway proto payload", TransportPayloadType.PROTOBUF, null, null, null, null, null, null, null, null, DeviceProfileProvisionType.DISABLED, false, false); TransportApiProtos.GatewayTelemetryMsg.Builder gatewayTelemetryMsgProtoBuilder = TransportApiProtos.GatewayTelemetryMsg.newBuilder(); List expectedKeys = Arrays.asList("key1", "key2", "key3", "key4", "key5"); String deviceName1 = "Device A"; @@ -266,7 +267,7 @@ public abstract class AbstractMqttTimeseriesProtoIntegrationTest extends Abstrac @Test public void testGatewayConnect() throws Exception { - super.processBeforeTest("Test Post Telemetry device proto payload", "Test Post Telemetry gateway proto payload", TransportPayloadType.PROTOBUF, POST_DATA_TELEMETRY_TOPIC, null, null, null, null, null, null, null, DeviceProfileProvisionType.DISABLED, false, false); + processBeforeTest("Test Post Telemetry device proto payload", "Test Post Telemetry gateway proto payload", TransportPayloadType.PROTOBUF, POST_DATA_TELEMETRY_TOPIC, null, null, null, null, null, null, null, DeviceProfileProvisionType.DISABLED, false, false); String deviceName = "Device A"; TransportApiProtos.ConnectMsg connectMsgProto = getConnectProto(deviceName); MqttAsyncClient client = getMqttAsyncClient(gatewayAccessToken); From 112882b477dd8d653eeea1ffe1a39da82f958ff4 Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Mon, 13 Dec 2021 16:52:17 +0200 Subject: [PATCH 238/432] tests: fixed user controller tests lifecycle (can not delete default tenant profile after test) --- .../controller/BaseUserControllerTest.java | 174 +++++------------- 1 file changed, 44 insertions(+), 130 deletions(-) diff --git a/application/src/test/java/org/thingsboard/server/controller/BaseUserControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/BaseUserControllerTest.java index e25b5e35ad..652089daeb 100644 --- a/application/src/test/java/org/thingsboard/server/controller/BaseUserControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/BaseUserControllerTest.java @@ -36,6 +36,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; +import static org.assertj.core.api.Assertions.assertThat; import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.is; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header; @@ -50,15 +51,10 @@ public abstract class BaseUserControllerTest extends AbstractControllerTest { public void testSaveUser() throws Exception { loginSysAdmin(); - Tenant tenant = new Tenant(); - tenant.setTitle("My tenant"); - Tenant savedTenant = doPost("/api/tenant", tenant, Tenant.class); - Assert.assertNotNull(savedTenant); - String email = "tenant2@thingsboard.org"; User user = new User(); user.setAuthority(Authority.TENANT_ADMIN); - user.setTenantId(savedTenant.getId()); + user.setTenantId(tenantId); user.setEmail(email); user.setFirstName("Joe"); user.setLastName("Downs"); @@ -100,24 +96,16 @@ public abstract class BaseUserControllerTest extends AbstractControllerTest { loginSysAdmin(); doDelete("/api/user/" + savedUser.getId().getId().toString()) .andExpect(status().isOk()); - - doDelete("/api/tenant/" + savedTenant.getId().getId().toString()) - .andExpect(status().isOk()); } @Test public void testSaveUserWithViolationOfFiledValidation() throws Exception { loginSysAdmin(); - Tenant tenant = new Tenant(); - tenant.setTitle("My tenant"); - Tenant savedTenant = doPost("/api/tenant", tenant, Tenant.class); - Assert.assertNotNull(savedTenant); - String email = "tenant2@thingsboard.org"; User user = new User(); user.setAuthority(Authority.TENANT_ADMIN); - user.setTenantId(savedTenant.getId()); + user.setTenantId(tenantId); user.setEmail(email); user.setFirstName(RandomStringUtils.randomAlphabetic(300)); user.setLastName("Downs"); @@ -130,14 +118,10 @@ public abstract class BaseUserControllerTest extends AbstractControllerTest { @Test public void testUpdateUserFromDifferentTenant() throws Exception { loginSysAdmin(); - Tenant tenant = new Tenant(); - tenant.setTitle("My tenant"); - Tenant savedTenant = doPost("/api/tenant", tenant, Tenant.class); - Assert.assertNotNull(savedTenant); User tenantAdmin = new User(); tenantAdmin.setAuthority(Authority.TENANT_ADMIN); - tenantAdmin.setTenantId(savedTenant.getId()); + tenantAdmin.setTenantId(tenantId); tenantAdmin.setEmail("tenant2@thingsboard.org"); tenantAdmin.setFirstName("Joe"); tenantAdmin.setLastName("Downs"); @@ -147,24 +131,16 @@ public abstract class BaseUserControllerTest extends AbstractControllerTest { doPost("/api/user", tenantAdmin, User.class, status().isForbidden()); deleteDifferentTenant(); - loginSysAdmin(); - doDelete("/api/tenant/" + savedTenant.getId().getId().toString()) - .andExpect(status().isOk()); } @Test public void testResetPassword() throws Exception { loginSysAdmin(); - Tenant tenant = new Tenant(); - tenant.setTitle("My tenant"); - Tenant savedTenant = doPost("/api/tenant", tenant, Tenant.class); - Assert.assertNotNull(savedTenant); - String email = "tenant2@thingsboard.org"; User user = new User(); user.setAuthority(Authority.TENANT_ADMIN); - user.setTenantId(savedTenant.getId()); + user.setTenantId(tenantId); user.setEmail(email); user.setFirstName("Joe"); user.setLastName("Downs"); @@ -205,24 +181,16 @@ public abstract class BaseUserControllerTest extends AbstractControllerTest { loginSysAdmin(); doDelete("/api/user/" + savedUser.getId().getId().toString()) .andExpect(status().isOk()); - - doDelete("/api/tenant/" + savedTenant.getId().getId().toString()) - .andExpect(status().isOk()); } @Test public void testFindUserById() throws Exception { loginSysAdmin(); - Tenant tenant = new Tenant(); - tenant.setTitle("My tenant"); - Tenant savedTenant = doPost("/api/tenant", tenant, Tenant.class); - Assert.assertNotNull(savedTenant); - String email = "tenant2@thingsboard.org"; User user = new User(); user.setAuthority(Authority.TENANT_ADMIN); - user.setTenantId(savedTenant.getId()); + user.setTenantId(tenantId); user.setEmail(email); user.setFirstName("Joe"); user.setLastName("Downs"); @@ -231,24 +199,16 @@ public abstract class BaseUserControllerTest extends AbstractControllerTest { User foundUser = doGet("/api/user/" + savedUser.getId().getId().toString(), User.class); Assert.assertNotNull(foundUser); Assert.assertEquals(savedUser, foundUser); - - doDelete("/api/tenant/" + savedTenant.getId().getId().toString()) - .andExpect(status().isOk()); } @Test public void testSaveUserWithSameEmail() throws Exception { loginSysAdmin(); - Tenant tenant = new Tenant(); - tenant.setTitle("My tenant"); - Tenant savedTenant = doPost("/api/tenant", tenant, Tenant.class); - Assert.assertNotNull(savedTenant); - String email = TENANT_ADMIN_EMAIL; User user = new User(); user.setAuthority(Authority.TENANT_ADMIN); - user.setTenantId(savedTenant.getId()); + user.setTenantId(tenantId); user.setEmail(email); user.setFirstName("Joe"); user.setLastName("Downs"); @@ -256,24 +216,16 @@ public abstract class BaseUserControllerTest extends AbstractControllerTest { doPost("/api/user", user) .andExpect(status().isBadRequest()) .andExpect(statusReason(containsString("User with email '" + email + "' already present in database"))); - - doDelete("/api/tenant/" + savedTenant.getId().getId().toString()) - .andExpect(status().isOk()); } @Test public void testSaveUserWithInvalidEmail() throws Exception { loginSysAdmin(); - Tenant tenant = new Tenant(); - tenant.setTitle("My tenant"); - Tenant savedTenant = doPost("/api/tenant", tenant, Tenant.class); - Assert.assertNotNull(savedTenant); - String email = "tenant_thingsboard.org"; User user = new User(); user.setAuthority(Authority.TENANT_ADMIN); - user.setTenantId(savedTenant.getId()); + user.setTenantId(tenantId); user.setEmail(email); user.setFirstName("Joe"); user.setLastName("Downs"); @@ -281,32 +233,21 @@ public abstract class BaseUserControllerTest extends AbstractControllerTest { doPost("/api/user", user) .andExpect(status().isBadRequest()) .andExpect(statusReason(containsString("Invalid email address format '" + email + "'"))); - - doDelete("/api/tenant/" + savedTenant.getId().getId().toString()) - .andExpect(status().isOk()); } @Test public void testSaveUserWithEmptyEmail() throws Exception { loginSysAdmin(); - Tenant tenant = new Tenant(); - tenant.setTitle("My tenant"); - Tenant savedTenant = doPost("/api/tenant", tenant, Tenant.class); - Assert.assertNotNull(savedTenant); - User user = new User(); user.setAuthority(Authority.TENANT_ADMIN); - user.setTenantId(savedTenant.getId()); + user.setTenantId(tenantId); user.setFirstName("Joe"); user.setLastName("Downs"); doPost("/api/user", user) .andExpect(status().isBadRequest()) .andExpect(statusReason(containsString("User email should be specified"))); - - doDelete("/api/tenant/" + savedTenant.getId().getId().toString()) - .andExpect(status().isOk()); } @Test @@ -328,15 +269,10 @@ public abstract class BaseUserControllerTest extends AbstractControllerTest { public void testDeleteUser() throws Exception { loginSysAdmin(); - Tenant tenant = new Tenant(); - tenant.setTitle("My tenant"); - Tenant savedTenant = doPost("/api/tenant", tenant, Tenant.class); - Assert.assertNotNull(savedTenant); - String email = "tenant2@thingsboard.org"; User user = new User(); user.setAuthority(Authority.TENANT_ADMIN); - user.setTenantId(savedTenant.getId()); + user.setTenantId(tenantId); user.setEmail(email); user.setFirstName("Joe"); user.setLastName("Downs"); @@ -350,17 +286,15 @@ public abstract class BaseUserControllerTest extends AbstractControllerTest { doGet("/api/user/" + savedUser.getId().getId().toString()) .andExpect(status().isNotFound()); - - doDelete("/api/tenant/" + savedTenant.getId().getId().toString()) - .andExpect(status().isOk()); } @Test public void testFindTenantAdmins() throws Exception { loginSysAdmin(); + //here created a new tenant despite already created on AbstractWebTest and then delete the tenant properly on the last line Tenant tenant = new Tenant(); - tenant.setTitle("My tenant"); + tenant.setTitle("My tenant with many admins"); Tenant savedTenant = doPost("/api/tenant", tenant, Tenant.class); Assert.assertNotNull(savedTenant); @@ -380,7 +314,8 @@ public abstract class BaseUserControllerTest extends AbstractControllerTest { PageData pageData = null; do { pageData = doGetTypedWithPageLink("/api/tenant/" + tenantId.getId().toString() + "/users?", - new TypeReference>(){}, pageLink); + new TypeReference>() { + }, pageLink); loadedTenantAdmins.addAll(pageData.getData()); if (pageData.hasNext()) { pageLink = pageLink.nextPageLink(); @@ -390,14 +325,16 @@ public abstract class BaseUserControllerTest extends AbstractControllerTest { Collections.sort(tenantAdmins, idComparator); Collections.sort(loadedTenantAdmins, idComparator); - Assert.assertEquals(tenantAdmins, loadedTenantAdmins); + assertThat(tenantAdmins).as("admins list size").hasSameSizeAs(loadedTenantAdmins); + assertThat(tenantAdmins).as("admins list content").isEqualTo(loadedTenantAdmins); + + doDelete("/api/tenant/" + tenantId.getId().toString()) + .andExpect(status().isOk()); - doDelete("/api/tenant/"+savedTenant.getId().getId().toString()) - .andExpect(status().isOk()); - pageLink = new PageLink(33); - pageData = doGetTypedWithPageLink("/api/tenant/" + tenantId.getId().toString() + "/users?", - new TypeReference>(){}, pageLink); + pageData = doGetTypedWithPageLink("/api/tenant/" + tenantId.getId().toString() + "/users?", + new TypeReference>() { + }, pageLink); Assert.assertFalse(pageData.hasNext()); Assert.assertTrue(pageData.getData().isEmpty()); } @@ -407,13 +344,6 @@ public abstract class BaseUserControllerTest extends AbstractControllerTest { loginSysAdmin(); - Tenant tenant = new Tenant(); - tenant.setTitle("My tenant"); - Tenant savedTenant = doPost("/api/tenant", tenant, Tenant.class); - Assert.assertNotNull(savedTenant); - - TenantId tenantId = savedTenant.getId(); - String email1 = "testEmail1"; List tenantAdminsEmail1 = new ArrayList<>(); @@ -447,7 +377,8 @@ public abstract class BaseUserControllerTest extends AbstractControllerTest { PageData pageData = null; do { pageData = doGetTypedWithPageLink("/api/tenant/" + tenantId.getId().toString() + "/users?", - new TypeReference>(){}, pageLink); + new TypeReference>() { + }, pageLink); loadedTenantAdminsEmail1.addAll(pageData.getData()); if (pageData.hasNext()) { pageLink = pageLink.nextPageLink(); @@ -463,7 +394,8 @@ public abstract class BaseUserControllerTest extends AbstractControllerTest { pageLink = new PageLink(16, 0, email2); do { pageData = doGetTypedWithPageLink("/api/tenant/" + tenantId.getId().toString() + "/users?", - new TypeReference>(){}, pageLink); + new TypeReference>() { + }, pageLink); loadedTenantAdminsEmail2.addAll(pageData.getData()); if (pageData.hasNext()) { pageLink = pageLink.nextPageLink(); @@ -481,8 +413,9 @@ public abstract class BaseUserControllerTest extends AbstractControllerTest { } pageLink = new PageLink(4, 0, email1); - pageData = doGetTypedWithPageLink("/api/tenant/" + tenantId.getId().toString() + "/users?", - new TypeReference>(){}, pageLink); + pageData = doGetTypedWithPageLink("/api/tenant/" + tenantId.getId().toString() + "/users?", + new TypeReference>() { + }, pageLink); Assert.assertFalse(pageData.hasNext()); Assert.assertEquals(0, pageData.getData().size()); @@ -492,25 +425,17 @@ public abstract class BaseUserControllerTest extends AbstractControllerTest { } pageLink = new PageLink(4, 0, email2); - pageData = doGetTypedWithPageLink("/api/tenant/" + tenantId.getId().toString() + "/users?", - new TypeReference>(){}, pageLink); + pageData = doGetTypedWithPageLink("/api/tenant/" + tenantId.getId().toString() + "/users?", + new TypeReference>() { + }, pageLink); Assert.assertFalse(pageData.hasNext()); Assert.assertEquals(0, pageData.getData().size()); - - doDelete("/api/tenant/" + savedTenant.getId().getId().toString()) - .andExpect(status().isOk()); } @Test public void testFindCustomerUsers() throws Exception { - loginSysAdmin(); - Tenant tenant = new Tenant(); - tenant.setTitle("My tenant"); - Tenant savedTenant = doPost("/api/tenant", tenant, Tenant.class); - Assert.assertNotNull(savedTenant); - TenantId tenantId = savedTenant.getId(); User tenantAdmin = new User(); tenantAdmin.setAuthority(Authority.TENANT_ADMIN); tenantAdmin.setTenantId(tenantId); @@ -540,7 +465,8 @@ public abstract class BaseUserControllerTest extends AbstractControllerTest { PageData pageData = null; do { pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/users?", - new TypeReference>(){}, pageLink); + new TypeReference>() { + }, pageLink); loadedCustomerUsers.addAll(pageData.getData()); if (pageData.hasNext()) { pageLink = pageLink.nextPageLink(); @@ -554,23 +480,12 @@ public abstract class BaseUserControllerTest extends AbstractControllerTest { doDelete("/api/customer/" + customerId.getId().toString()) .andExpect(status().isOk()); - - loginSysAdmin(); - - doDelete("/api/tenant/" + savedTenant.getId().getId().toString()) - .andExpect(status().isOk()); } @Test public void testFindCustomerUsersByEmail() throws Exception { - loginSysAdmin(); - Tenant tenant = new Tenant(); - tenant.setTitle("My tenant"); - Tenant savedTenant = doPost("/api/tenant", tenant, Tenant.class); - Assert.assertNotNull(savedTenant); - TenantId tenantId = savedTenant.getId(); User tenantAdmin = new User(); tenantAdmin.setAuthority(Authority.TENANT_ADMIN); tenantAdmin.setTenantId(tenantId); @@ -619,7 +534,8 @@ public abstract class BaseUserControllerTest extends AbstractControllerTest { PageData pageData = null; do { pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/users?", - new TypeReference>(){}, pageLink); + new TypeReference>() { + }, pageLink); loadedCustomerUsersEmail1.addAll(pageData.getData()); if (pageData.hasNext()) { pageLink = pageLink.nextPageLink(); @@ -635,7 +551,8 @@ public abstract class BaseUserControllerTest extends AbstractControllerTest { pageLink = new PageLink(16, 0, email2); do { pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/users?", - new TypeReference>(){}, pageLink); + new TypeReference>() { + }, pageLink); loadedCustomerUsersEmail2.addAll(pageData.getData()); if (pageData.hasNext()) { pageLink = pageLink.nextPageLink(); @@ -653,8 +570,9 @@ public abstract class BaseUserControllerTest extends AbstractControllerTest { } pageLink = new PageLink(4, 0, email1); - pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/users?", - new TypeReference>(){}, pageLink); + pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/users?", + new TypeReference>() { + }, pageLink); Assert.assertFalse(pageData.hasNext()); Assert.assertEquals(0, pageData.getData().size()); @@ -664,18 +582,14 @@ public abstract class BaseUserControllerTest extends AbstractControllerTest { } pageLink = new PageLink(4, 0, email2); - pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/users?", - new TypeReference>(){}, pageLink); + pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/users?", + new TypeReference>() { + }, pageLink); Assert.assertFalse(pageData.hasNext()); Assert.assertEquals(0, pageData.getData().size()); doDelete("/api/customer/" + customerId.getId().toString()) .andExpect(status().isOk()); - - loginSysAdmin(); - - doDelete("/api/tenant/" + savedTenant.getId().getId().toString()) - .andExpect(status().isOk()); } } From 26c62dda7cdd2e19ef20a0339a57354532536f3a Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Mon, 13 Dec 2021 17:25:30 +0200 Subject: [PATCH 239/432] tests: temporary disabled testTimeseriesWithFailures on BaseEdgeTest to unblock the tests transition process --- .../java/org/thingsboard/server/edge/BaseEdgeTest.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/application/src/test/java/org/thingsboard/server/edge/BaseEdgeTest.java b/application/src/test/java/org/thingsboard/server/edge/BaseEdgeTest.java index 2dea0d2811..33bb88c450 100644 --- a/application/src/test/java/org/thingsboard/server/edge/BaseEdgeTest.java +++ b/application/src/test/java/org/thingsboard/server/edge/BaseEdgeTest.java @@ -217,7 +217,14 @@ abstract public class BaseEdgeTest extends AbstractControllerTest { testRpcCall(); - testTimeseriesWithFailures(); + //TODO fix the test with @voba + //2021-12-13 16:59:52,493 [main] WARN o.t.edge.rpc.EdgeGrpcClient - We had reached maximum of termination attempts. Force closing channel + //2021-12-13 16:59:52,501 [grpc-default-executor-1] WARN o.t.edge.rpc.EdgeGrpcClient - We had reached maximum of termination attempts. Force closing channel + //java.lang.AssertionError <3 internal lines> + // at org.thingsboard.server.edge.BaseEdgeTest.testTimeseriesWithFailures(BaseEdgeTest.java:1146) + // at org.thingsboard.server.edge.BaseEdgeTest.test(BaseEdgeTest.java:220) + // + //testTimeseriesWithFailures(); testSendMessagesToCloud(); } From 56cc5a5adbbb77d12c981c1792d54d58087cfa5a Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Mon, 13 Dec 2021 19:30:19 +0200 Subject: [PATCH 240/432] Revert "tests: temporary disabled testTimeseriesWithFailures on BaseEdgeTest to unblock the tests transition process" This reverts commit 26c62dda7cdd2e19ef20a0339a57354532536f3a. --- .../java/org/thingsboard/server/edge/BaseEdgeTest.java | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/application/src/test/java/org/thingsboard/server/edge/BaseEdgeTest.java b/application/src/test/java/org/thingsboard/server/edge/BaseEdgeTest.java index 33bb88c450..2dea0d2811 100644 --- a/application/src/test/java/org/thingsboard/server/edge/BaseEdgeTest.java +++ b/application/src/test/java/org/thingsboard/server/edge/BaseEdgeTest.java @@ -217,14 +217,7 @@ abstract public class BaseEdgeTest extends AbstractControllerTest { testRpcCall(); - //TODO fix the test with @voba - //2021-12-13 16:59:52,493 [main] WARN o.t.edge.rpc.EdgeGrpcClient - We had reached maximum of termination attempts. Force closing channel - //2021-12-13 16:59:52,501 [grpc-default-executor-1] WARN o.t.edge.rpc.EdgeGrpcClient - We had reached maximum of termination attempts. Force closing channel - //java.lang.AssertionError <3 internal lines> - // at org.thingsboard.server.edge.BaseEdgeTest.testTimeseriesWithFailures(BaseEdgeTest.java:1146) - // at org.thingsboard.server.edge.BaseEdgeTest.test(BaseEdgeTest.java:220) - // - //testTimeseriesWithFailures(); + testTimeseriesWithFailures(); testSendMessagesToCloud(); } From e680b33c9c94aa06ea39c0ee6f04939ad0d7e406 Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Mon, 13 Dec 2021 19:40:01 +0200 Subject: [PATCH 241/432] fixed EntityDataAdapter.convertValue that convert "500D" (valid Java number) into "500" as double. --- .../org/thingsboard/server/dao/sql/query/EntityDataAdapter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/query/EntityDataAdapter.java b/dao/src/main/java/org/thingsboard/server/dao/sql/query/EntityDataAdapter.java index 5450c43287..a25a5f6201 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/query/EntityDataAdapter.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/query/EntityDataAdapter.java @@ -83,7 +83,7 @@ public class EntityDataAdapter { if (value != null) { String strVal = value.toString(); // check number - if (NumberUtils.isNumber(strVal)) { + if (strVal.length() > 0 && NumberUtils.isParsable(strVal)) { try { long longVal = Long.parseLong(strVal); return Long.toString(longVal); From 9bc12ab6d7745b3f859845c9955f7dd5aa89640c Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Tue, 14 Dec 2021 10:17:55 +0200 Subject: [PATCH 242/432] Docker linux/arm64 support --- msa/js-executor/docker/Dockerfile | 10 ++- msa/js-executor/install.js | 7 +- msa/js-executor/package.json | 2 +- msa/js-executor/pom.xml | 1 + msa/pom.xml | 63 ++++++++++++- msa/tb-node/pom.xml | 1 + msa/tb/pom.xml | 144 ++++++++++++++++++++++++++++++ msa/transport/coap/pom.xml | 1 + msa/transport/http/pom.xml | 1 + msa/transport/lwm2m/pom.xml | 1 + msa/transport/mqtt/pom.xml | 1 + msa/transport/snmp/pom.xml | 1 + msa/web-ui/docker/Dockerfile | 10 ++- msa/web-ui/install.js | 7 +- msa/web-ui/package.json | 2 +- msa/web-ui/pom.xml | 1 + packaging/js/build.gradle | 65 ++++++++++++-- pom.xml | 5 ++ 18 files changed, 305 insertions(+), 18 deletions(-) diff --git a/msa/js-executor/docker/Dockerfile b/msa/js-executor/docker/Dockerfile index ede28aa4f4..92b2229e79 100644 --- a/msa/js-executor/docker/Dockerfile +++ b/msa/js-executor/docker/Dockerfile @@ -16,13 +16,19 @@ FROM thingsboard/base -COPY start-js-executor.sh ${pkg.name}.deb /tmp/ +ARG TARGETPLATFORM + +COPY start-js-executor.sh ${pkg.name}.deb ${pkg.name}-arm64.deb /tmp/ RUN chmod a+x /tmp/*.sh \ && mv /tmp/start-js-executor.sh /usr/bin -RUN yes | dpkg -i /tmp/${pkg.name}.deb +RUN if [ "$TARGETPLATFORM" = "linux/arm64" ]; \ + then yes | dpkg -i /tmp/${pkg.name}-arm64.deb; \ + else yes | dpkg -i /tmp/${pkg.name}.deb; \ + fi RUN rm /tmp/${pkg.name}.deb +RUN rm /tmp/${pkg.name}-arm64.deb RUN systemctl --no-reload disable --now ${pkg.name}.service > /dev/null 2>&1 || : diff --git a/msa/js-executor/install.js b/msa/js-executor/install.js index d180a5247a..9fe911e7b2 100644 --- a/msa/js-executor/install.js +++ b/msa/js-executor/install.js @@ -21,10 +21,13 @@ let _projectRoot = null; (async() => { - await fse.move(path.join(projectRoot(), 'target', 'thingsboard-js-executor-linux'), + await fse.move(path.join(projectRoot(), 'target', 'thingsboard-js-executor-linux-x64'), path.join(targetPackageDir('linux'), 'bin', 'tb-js-executor'), {overwrite: true}); - await fse.move(path.join(projectRoot(), 'target', 'thingsboard-js-executor-win.exe'), + await fse.move(path.join(projectRoot(), 'target', 'thingsboard-js-executor-linux-arm64'), + path.join(targetPackageDir('linux'), 'bin-arm64', 'tb-js-executor'), + {overwrite: true}); + await fse.move(path.join(projectRoot(), 'target', 'thingsboard-js-executor-win-x64.exe'), path.join(targetPackageDir('windows'), 'bin', 'tb-js-executor.exe'), {overwrite: true}); })(); diff --git a/msa/js-executor/package.json b/msa/js-executor/package.json index 9fe84ffa9f..0e2cee6e54 100644 --- a/msa/js-executor/package.json +++ b/msa/js-executor/package.json @@ -6,7 +6,7 @@ "main": "server.js", "bin": "server.js", "scripts": { - "install": "pkg -t node12-linux-x64,node12-win-x64 --out-path ./target . && node install.js", + "install": "pkg -t node12-linux-x64,node12-linux-arm64,node12-win-x64 --out-path ./target . && node install.js", "test": "echo \"Error: no test specified\" && exit 1", "start": "nodemon server.js", "start-prod": "NODE_ENV=production nodemon server.js" diff --git a/msa/js-executor/pom.xml b/msa/js-executor/pom.xml index 5cabaed58a..16f1f0293b 100644 --- a/msa/js-executor/pom.xml +++ b/msa/js-executor/pom.xml @@ -42,6 +42,7 @@ package ${project.build.directory}/package/linux ${project.build.directory}/package/windows + pre-integration-test diff --git a/msa/pom.xml b/msa/pom.xml index 024607378c..f5dd65b3e0 100644 --- a/msa/pom.xml +++ b/msa/pom.xml @@ -35,6 +35,7 @@ true true 1.4.13 + none @@ -58,8 +59,67 @@ black-box-tests + + push-docker-amd-arm-images + + + push-docker-amd-arm-images + + + + + + org.codehaus.mojo + exec-maven-plugin + + + push-latest-docker-amd-arm-images + ${docker.push-arm-amd-image.phase} + + exec + + + docker + ${project.build.directory} + + buildx + build + -t + ${docker.repo}/${docker.name}:latest + --platform=linux/amd64,linux/arm64 + -o + type=registry + . + + + + + push-version-docker-amd-arm-images + ${docker.push-arm-amd-image.phase} + + exec + + + docker + ${project.build.directory} + + buildx + build + -t + ${docker.repo}/${docker.name}:${project.version} + --platform=linux/amd64,linux/arm64 + -o + type=registry + . + + + + + + + + - @@ -78,5 +138,4 @@ - diff --git a/msa/tb-node/pom.xml b/msa/tb-node/pom.xml index 9cf97b4906..d7d1b41907 100644 --- a/msa/tb-node/pom.xml +++ b/msa/tb-node/pom.xml @@ -38,6 +38,7 @@ tb-node /var/log/${pkg.name} /usr/share/${pkg.name} + pre-integration-test diff --git a/msa/tb/pom.xml b/msa/tb/pom.xml index 841a4edbdf..df00aa3a72 100644 --- a/msa/tb/pom.xml +++ b/msa/tb/pom.xml @@ -355,6 +355,150 @@ + + push-docker-amd-arm-images + + + push-docker-amd-arm-images + + + + + + org.codehaus.mojo + exec-maven-plugin + + + push-latest-docker-amd-arm-tb-images + pre-integration-test + + exec + + + docker + ${project.build.directory}/docker-tb + + buildx + build + -t + ${docker.repo}/${tb.docker.name}:latest + --platform=linux/amd64,linux/arm64 + -o + type=registry + . + + + + + push-version-docker-amd-arm-tb-images + pre-integration-test + + exec + + + docker + ${project.build.directory}/docker-tb + + buildx + build + -t + ${docker.repo}/${tb.docker.name}:${project.version} + --platform=linux/amd64,linux/arm64 + -o + type=registry + . + + + + + push-latest-docker-amd-arm-tb-postgres-images + pre-integration-test + + exec + + + docker + ${project.build.directory}/docker-postgres + + buildx + build + -t + ${docker.repo}/${tb-postgres.docker.name}:latest + --platform=linux/amd64,linux/arm64 + -o + type=registry + . + + + + + push-version-docker-amd-arm-tb-postgres-images + pre-integration-test + + exec + + + docker + ${project.build.directory}/docker-postgres + + buildx + build + -t + ${docker.repo}/${tb-postgres.docker.name}:${project.version} + --platform=linux/amd64,linux/arm64 + -o + type=registry + . + + + + + push-latest-docker-amd-arm-tb-cassandra-images + pre-integration-test + + exec + + + docker + ${project.build.directory}/docker-cassandra + + buildx + build + -t + ${docker.repo}/${tb-cassandra.docker.name}:latest + --platform=linux/amd64,linux/arm64 + -o + type=registry + . + + + + + push-version-docker-amd-arm-tb-cassandra-images + pre-integration-test + + exec + + + docker + ${project.build.directory}/docker-cassandra + + buildx + build + -t + ${docker.repo}/${tb-cassandra.docker.name}:${project.version} + --platform=linux/amd64,linux/arm64 + -o + type=registry + . + + + + + + + + diff --git a/msa/transport/coap/pom.xml b/msa/transport/coap/pom.xml index 34b37c6334..155ceb3af8 100644 --- a/msa/transport/coap/pom.xml +++ b/msa/transport/coap/pom.xml @@ -38,6 +38,7 @@ tb-coap-transport /var/log/${pkg.name} /usr/share/${pkg.name} + pre-integration-test diff --git a/msa/transport/http/pom.xml b/msa/transport/http/pom.xml index 0cc5320250..9af7cc5907 100644 --- a/msa/transport/http/pom.xml +++ b/msa/transport/http/pom.xml @@ -38,6 +38,7 @@ tb-http-transport /var/log/${pkg.name} /usr/share/${pkg.name} + pre-integration-test diff --git a/msa/transport/lwm2m/pom.xml b/msa/transport/lwm2m/pom.xml index 2dd44c4386..a1c3689af5 100644 --- a/msa/transport/lwm2m/pom.xml +++ b/msa/transport/lwm2m/pom.xml @@ -38,6 +38,7 @@ tb-lwm2m-transport /var/log/${pkg.name} /usr/share/${pkg.name} + pre-integration-test diff --git a/msa/transport/mqtt/pom.xml b/msa/transport/mqtt/pom.xml index d483ef42eb..97f6cc4e62 100644 --- a/msa/transport/mqtt/pom.xml +++ b/msa/transport/mqtt/pom.xml @@ -38,6 +38,7 @@ tb-mqtt-transport /var/log/${pkg.name} /usr/share/${pkg.name} + pre-integration-test diff --git a/msa/transport/snmp/pom.xml b/msa/transport/snmp/pom.xml index a30942fe4c..f3776fb8c3 100644 --- a/msa/transport/snmp/pom.xml +++ b/msa/transport/snmp/pom.xml @@ -39,6 +39,7 @@ tb-snmp-transport /var/log/${pkg.name} /usr/share/${pkg.name} + pre-integration-test diff --git a/msa/web-ui/docker/Dockerfile b/msa/web-ui/docker/Dockerfile index 90fbb8d34e..5b4acf9eb3 100644 --- a/msa/web-ui/docker/Dockerfile +++ b/msa/web-ui/docker/Dockerfile @@ -16,13 +16,19 @@ FROM thingsboard/base -COPY start-web-ui.sh ${pkg.name}.deb /tmp/ +ARG TARGETPLATFORM + +COPY start-web-ui.sh ${pkg.name}.deb ${pkg.name}-arm64.deb /tmp/ RUN chmod a+x /tmp/*.sh \ && mv /tmp/start-web-ui.sh /usr/bin -RUN yes | dpkg -i /tmp/${pkg.name}.deb +RUN if [ "$TARGETPLATFORM" = "linux/arm64" ]; \ + then yes | dpkg -i /tmp/${pkg.name}-arm64.deb; \ + else yes | dpkg -i /tmp/${pkg.name}.deb; \ + fi RUN rm /tmp/${pkg.name}.deb +RUN rm /tmp/${pkg.name}-arm64.deb RUN systemctl --no-reload disable --now ${pkg.name}.service > /dev/null 2>&1 || : diff --git a/msa/web-ui/install.js b/msa/web-ui/install.js index 36b2311bb0..f0021d64f7 100644 --- a/msa/web-ui/install.js +++ b/msa/web-ui/install.js @@ -21,10 +21,13 @@ let _projectRoot = null; (async() => { - await fse.move(path.join(projectRoot(), 'target', 'thingsboard-web-ui-linux'), + await fse.move(path.join(projectRoot(), 'target', 'thingsboard-web-ui-linux-x64'), path.join(targetPackageDir('linux'), 'bin', 'tb-web-ui'), {overwrite: true}); - await fse.move(path.join(projectRoot(), 'target', 'thingsboard-web-ui-win.exe'), + await fse.move(path.join(projectRoot(), 'target', 'thingsboard-web-ui-linux-arm64'), + path.join(targetPackageDir('linux'), 'bin-arm64', 'tb-web-ui'), + {overwrite: true}); + await fse.move(path.join(projectRoot(), 'target', 'thingsboard-web-ui-win-x64.exe'), path.join(targetPackageDir('windows'), 'bin', 'tb-web-ui.exe'), {overwrite: true}); })(); diff --git a/msa/web-ui/package.json b/msa/web-ui/package.json index cc98e5f457..9e2075010a 100644 --- a/msa/web-ui/package.json +++ b/msa/web-ui/package.json @@ -6,7 +6,7 @@ "main": "server.js", "bin": "server.js", "scripts": { - "install": "pkg -t node12-linux-x64,node12-win-x64 --out-path ./target . && node install.js", + "install": "pkg -t node12-linux-x64,node12-linux-arm64,node12-win-x64 --out-path ./target . && node install.js", "test": "echo \"Error: no test specified\" && exit 1", "start": "WEB_FOLDER=./target/web nodemon server.js", "start-prod": "NODE_ENV=production nodemon server.js" diff --git a/msa/web-ui/pom.xml b/msa/web-ui/pom.xml index 2b973afaba..bf311df492 100644 --- a/msa/web-ui/pom.xml +++ b/msa/web-ui/pom.xml @@ -44,6 +44,7 @@ package ${project.build.directory}/package/linux ${project.build.directory}/package/windows + pre-integration-test diff --git a/packaging/js/build.gradle b/packaging/js/build.gradle index 929b7ed9d7..df9d86dde7 100644 --- a/packaging/js/build.gradle +++ b/packaging/js/build.gradle @@ -36,12 +36,6 @@ ospackage { user pkgUser permissionGroup pkgUser - // Copy the executable file - from("${buildDir}/package/linux/bin/${pkgName}") { - fileMode 0500 - into "bin" - } - // Copy the init file from("${buildDir}/package/linux/init/template") { fileMode 0500 @@ -78,9 +72,17 @@ buildRpm { preUninstall file("${buildDir}/control/rpm/prerm") postUninstall file("${buildDir}/control/rpm/postrm") + into pkgInstallFolder + user pkgUser permissionGroup pkgUser + // Copy the executable file + from("${buildDir}/package/linux/bin/${pkgName}") { + fileMode 0500 + into "bin" + } + // Copy the system unit files from("${buildDir}/control/template.service") { addParentDirs = false @@ -111,9 +113,58 @@ buildDeb { preUninstall file("${buildDir}/control/deb/prerm") postUninstall file("${buildDir}/control/deb/postrm") + into pkgInstallFolder + + user pkgUser + permissionGroup pkgUser + + // Copy the executable file + from("${buildDir}/package/linux/bin/${pkgName}") { + fileMode 0500 + into "bin" + } + + // Copy the system unit files + from("${buildDir}/control/template.service") { + addParentDirs = false + fileMode 0644 + into "/lib/systemd/system" + rename { String filename -> + "${pkgName}.service" + } + } + + link("/etc/${pkgName}/conf", "${pkgInstallFolder}/conf") +} + +// Same as the buildRpm task +task buildDebArm64(type: Deb) { + + arch = "arm64" + + archiveFileName = "${pkgName}-arm64.deb" + + configurationFile("${pkgInstallFolder}/conf/${pkgName}.conf") + configurationFile("${pkgInstallFolder}/conf/custom-environment-variables.yml") + configurationFile("${pkgInstallFolder}/conf/default.yml") + configurationFile("${pkgInstallFolder}/conf/logger.js") + + preInstall file("${buildDir}/control/deb/preinst") + postInstall file("${buildDir}/control/deb/postinst") + preUninstall file("${buildDir}/control/deb/prerm") + postUninstall file("${buildDir}/control/deb/postrm") + + into pkgInstallFolder + user pkgUser permissionGroup pkgUser + // Copy the executable file + from("${buildDir}/package/linux/bin-arm64/${pkgName}") { + fileMode 0500 + into "bin" + } + // Copy the system unit files from("${buildDir}/control/template.service") { addParentDirs = false @@ -126,3 +177,5 @@ buildDeb { link("/etc/${pkgName}/conf", "${pkgInstallFolder}/conf") } + +buildDeb.finalizedBy buildDebArm64 diff --git a/pom.xml b/pom.xml index 8730be5bee..af4180baab 100755 --- a/pom.xml +++ b/pom.xml @@ -684,6 +684,11 @@ maven-deploy-plugin 3.0.0-M1 + + org.codehaus.mojo + exec-maven-plugin + 3.0.0 + org.apache.maven.plugins maven-dependency-plugin From bbecb26023cb41aa91918cb979fe018da9626460 Mon Sep 17 00:00:00 2001 From: desoliture Date: Tue, 14 Dec 2021 11:35:09 +0200 Subject: [PATCH 243/432] add default value to password rule "allow whitespaces" - true --- .../server/common/data/security/model/UserPasswordPolicy.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/security/model/UserPasswordPolicy.java b/common/data/src/main/java/org/thingsboard/server/common/data/security/model/UserPasswordPolicy.java index 8648f9839f..1e4aeb0055 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/security/model/UserPasswordPolicy.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/security/model/UserPasswordPolicy.java @@ -36,7 +36,7 @@ public class UserPasswordPolicy implements Serializable { @ApiModelProperty(position = 1, value = "Minimum number of special in the password." ) private Integer minimumSpecialCharacters; @ApiModelProperty(position = 1, value = "Allow white-spaces") - private Boolean allowWhitespaces; + private Boolean allowWhitespaces = true; @ApiModelProperty(position = 1, value = "Password expiration period (days). Force expiration of the password." ) private Integer passwordExpirationPeriodDays; From 86ba65f2a4857df5b842fdda98f3c60799971129 Mon Sep 17 00:00:00 2001 From: Kalutka Zhenya Date: Tue, 14 Dec 2021 11:39:25 +0200 Subject: [PATCH 244/432] Added UI for Allow whitespace --- .../modules/home/pages/admin/security-settings.component.html | 3 +++ .../modules/home/pages/admin/security-settings.component.ts | 3 ++- ui-ngx/src/app/shared/models/settings.models.ts | 1 + ui-ngx/src/assets/locale/locale.constant-en_US.json | 1 + 4 files changed, 7 insertions(+), 1 deletion(-) diff --git a/ui-ngx/src/app/modules/home/pages/admin/security-settings.component.html b/ui-ngx/src/app/modules/home/pages/admin/security-settings.component.html index a9051f793b..d3bf5757f1 100644 --- a/ui-ngx/src/app/modules/home/pages/admin/security-settings.component.html +++ b/ui-ngx/src/app/modules/home/pages/admin/security-settings.component.html @@ -139,6 +139,9 @@ {{ 'admin.password-reuse-frequency-days-range' | translate }} + + admin.allow-whitespace +
diff --git a/ui-ngx/src/app/modules/home/pages/admin/security-settings.component.ts b/ui-ngx/src/app/modules/home/pages/admin/security-settings.component.ts index 6824ce8c3e..28051eacd6 100644 --- a/ui-ngx/src/app/modules/home/pages/admin/security-settings.component.ts +++ b/ui-ngx/src/app/modules/home/pages/admin/security-settings.component.ts @@ -63,7 +63,8 @@ export class SecuritySettingsComponent extends PageComponent implements OnInit, minimumDigits: [null, Validators.min(0)], minimumSpecialCharacters: [null, Validators.min(0)], passwordExpirationPeriodDays: [null, Validators.min(0)], - passwordReuseFrequencyDays: [null, Validators.min(0)] + passwordReuseFrequencyDays: [null, Validators.min(0)], + allowWhitespaces: [true] } ) }); diff --git a/ui-ngx/src/app/shared/models/settings.models.ts b/ui-ngx/src/app/shared/models/settings.models.ts index 8b2d4aac78..b130bb6338 100644 --- a/ui-ngx/src/app/shared/models/settings.models.ts +++ b/ui-ngx/src/app/shared/models/settings.models.ts @@ -55,6 +55,7 @@ export interface UserPasswordPolicy { minimumDigits: number; minimumSpecialCharacters: number; passwordExpirationPeriodDays: number; + allowWhitespaces: boolean; } export interface SecuritySettings { diff --git a/ui-ngx/src/assets/locale/locale.constant-en_US.json b/ui-ngx/src/assets/locale/locale.constant-en_US.json index 3ee86c15d6..a2ad663f90 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -152,6 +152,7 @@ "password-expiration-period-days-range": "Password expiration period in days can't be negative", "password-reuse-frequency-days": "Password reuse frequency in days", "password-reuse-frequency-days-range": "Password reuse frequency in days can't be negative", + "allow-whitespace": "Allow whitespace", "general-policy": "General policy", "max-failed-login-attempts": "Maximum number of failed login attempts, before account is locked", "minimum-max-failed-login-attempts-range": "Maximum number of failed login attempts can't be negative", From 4bc2eba8a26f94cd8b01c0fb322c26d34d63f55c Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Tue, 14 Dec 2021 12:31:46 +0200 Subject: [PATCH 245/432] Add important index --- application/src/main/data/upgrade/3.3.2/schema_update.sql | 1 + .../java/org/thingsboard/server/dao/rule/RuleChainDao.java | 1 - .../org/thingsboard/server/dao/sql/rule/JpaRuleChainDao.java | 5 ----- dao/src/main/resources/sql/schema-entities-idx.sql | 2 ++ 4 files changed, 3 insertions(+), 6 deletions(-) diff --git a/application/src/main/data/upgrade/3.3.2/schema_update.sql b/application/src/main/data/upgrade/3.3.2/schema_update.sql index 9a8c30ab63..9aa4e8baa2 100644 --- a/application/src/main/data/upgrade/3.3.2/schema_update.sql +++ b/application/src/main/data/upgrade/3.3.2/schema_update.sql @@ -28,6 +28,7 @@ CREATE TABLE IF NOT EXISTS entity_alarm ( CREATE INDEX IF NOT EXISTS idx_alarm_tenant_status_created_time ON alarm(tenant_id, status, created_time DESC); CREATE INDEX IF NOT EXISTS idx_entity_alarm_created_time ON entity_alarm(tenant_id, entity_id, created_time DESC); +CREATE INDEX IF NOT EXISTS idx_entity_alarm_alarm_id ON entity_alarm(alarm_id); INSERT INTO entity_alarm(tenant_id, entity_type, entity_id, created_time, alarm_type, customer_id, alarm_id) SELECT tenant_id, diff --git a/dao/src/main/java/org/thingsboard/server/dao/rule/RuleChainDao.java b/dao/src/main/java/org/thingsboard/server/dao/rule/RuleChainDao.java index bf036a8105..6355fc8101 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/rule/RuleChainDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/rule/RuleChainDao.java @@ -81,5 +81,4 @@ public interface RuleChainDao extends Dao, TenantEntityDao { Collection findByTenantIdAndTypeAndName(TenantId tenantId, RuleChainType type, String name); - List getOutputLabelUsage(UUID id, UUID id1); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/rule/JpaRuleChainDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/rule/JpaRuleChainDao.java index b432b04f04..6f437b362c 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/rule/JpaRuleChainDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/rule/JpaRuleChainDao.java @@ -105,11 +105,6 @@ public class JpaRuleChainDao extends JpaAbstractSearchTextDao getOutputLabelUsage(UUID tenantId, UUID ruleChainId) { - return null; - } - @Override public Long countByTenantId(TenantId tenantId) { return ruleChainRepository.countByTenantId(tenantId.getId()); diff --git a/dao/src/main/resources/sql/schema-entities-idx.sql b/dao/src/main/resources/sql/schema-entities-idx.sql index 1238b5ee12..915fd53658 100644 --- a/dao/src/main/resources/sql/schema-entities-idx.sql +++ b/dao/src/main/resources/sql/schema-entities-idx.sql @@ -26,6 +26,8 @@ CREATE INDEX IF NOT EXISTS idx_alarm_tenant_alarm_type_created_time ON alarm(ten CREATE INDEX IF NOT EXISTS idx_entity_alarm_created_time ON entity_alarm(tenant_id, entity_id, created_time DESC); +CREATE INDEX IF NOT EXISTS idx_entity_alarm_alarm_id ON entity_alarm(alarm_id); + CREATE INDEX IF NOT EXISTS idx_relation_to_id ON relation(relation_type_group, to_type, to_id); CREATE INDEX IF NOT EXISTS idx_relation_from_id ON relation(relation_type_group, from_type, from_id); From 09c8f2bdc7fabe3850bda97fa32ecdd5b91857bd Mon Sep 17 00:00:00 2001 From: ArtemDzhereleiko Date: Tue, 14 Dec 2021 12:40:18 +0200 Subject: [PATCH 246/432] Hide page size on tables refactoring --- .../attribute/attribute-table.component.html | 2 +- .../attribute/attribute-table.component.scss | 1 + .../attribute/attribute-table.component.ts | 18 ++++++++------- .../entity/entities-table.component.html | 2 +- .../entity/entities-table.component.scss | 1 + .../entity/entities-table.component.ts | 22 ++++++++----------- .../relation/relation-table.component.html | 2 +- .../relation/relation-table.component.scss | 1 + .../relation/relation-table.component.ts | 12 +++++----- .../manage-widget-actions.component.html | 5 +++-- .../manage-widget-actions.component.scss | 1 + .../action/manage-widget-actions.component.ts | 16 +++++++------- .../lib/alarms-table-widget.component.html | 2 +- .../lib/alarms-table-widget.component.scss | 1 + .../lib/alarms-table-widget.component.ts | 13 ++++++----- .../lib/entities-table-widget.component.html | 2 +- .../lib/entities-table-widget.component.scss | 1 + .../lib/entities-table-widget.component.ts | 13 ++++++----- .../timeseries-table-widget.component.html | 2 +- .../timeseries-table-widget.component.scss | 1 + .../lib/timeseries-table-widget.component.ts | 13 ++++++----- 21 files changed, 70 insertions(+), 61 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/attribute/attribute-table.component.html b/ui-ngx/src/app/modules/home/components/attribute/attribute-table.component.html index 493bfe3e2d..c0612646f3 100644 --- a/ui-ngx/src/app/modules/home/components/attribute/attribute-table.component.html +++ b/ui-ngx/src/app/modules/home/components/attribute/attribute-table.component.html @@ -15,7 +15,7 @@ limitations under the License. --> -
+
diff --git a/ui-ngx/src/app/modules/home/components/attribute/attribute-table.component.scss b/ui-ngx/src/app/modules/home/components/attribute/attribute-table.component.scss index df6b8e7184..715eb71fbc 100644 --- a/ui-ngx/src/app/modules/home/components/attribute/attribute-table.component.scss +++ b/ui-ngx/src/app/modules/home/components/attribute/attribute-table.component.scss @@ -18,6 +18,7 @@ :host { width: 100%; height: 100%; + display: block; .tb-entity-table { .tb-entity-table-content { width: 100%; diff --git a/ui-ngx/src/app/modules/home/components/attribute/attribute-table.component.ts b/ui-ngx/src/app/modules/home/components/attribute/attribute-table.component.ts index 1bd4dea53f..f197f995a6 100644 --- a/ui-ngx/src/app/modules/home/components/attribute/attribute-table.component.ts +++ b/ui-ngx/src/app/modules/home/components/attribute/attribute-table.component.ts @@ -111,6 +111,7 @@ export class AttributeTableComponent extends PageComponent implements AfterViewI pageLink: PageLink; textSearchMode = false; dataSource: AttributeDatasource; + hidePageSize = false; activeValue = false; dirtyValue = false; @@ -129,10 +130,14 @@ export class AttributeTableComponent extends PageComponent implements AfterViewI aliasController: IAliasController; private widgetDatasource: Datasource; + private widgetResize$: ResizeObserver; + private disableAttributeScopeSelectionValue: boolean; + get disableAttributeScopeSelection(): boolean { return this.disableAttributeScopeSelectionValue; } + @Input() set disableAttributeScopeSelection(value: boolean) { this.disableAttributeScopeSelectionValue = coerceBooleanProperty(value); @@ -168,15 +173,11 @@ export class AttributeTableComponent extends PageComponent implements AfterViewI @Input() entityName: string; - @ViewChild('attributeTableContainer', {static: true}) attributeTableContainerRef: ElementRef; @ViewChild('searchInput') searchInputField: ElementRef; @ViewChild(MatPaginator) paginator: MatPaginator; @ViewChild(MatSort) sort: MatSort; - public hidePageSize = false; - private widgetResize$: ResizeObserver; - constructor(protected store: Store, private attributeService: AttributeService, private telemetryWsService: TelemetryWebsocketService, @@ -190,7 +191,8 @@ export class AttributeTableComponent extends PageComponent implements AfterViewI private dashboardUtils: DashboardUtilsService, private widgetService: WidgetService, private zone: NgZone, - private cd: ChangeDetectorRef) { + private cd: ChangeDetectorRef, + private elementRef: ElementRef) { super(store); this.dirtyValue = !this.activeValue; const sortOrder: SortOrder = { property: 'key', direction: Direction.ASC }; @@ -200,13 +202,13 @@ export class AttributeTableComponent extends PageComponent implements AfterViewI ngOnInit() { this.widgetResize$ = new ResizeObserver(() => { - const showHidePageSize = this.attributeTableContainerRef.nativeElement.offsetWidth < hidePageSizePixelValue; + const showHidePageSize = this.elementRef.nativeElement.offsetWidth < hidePageSizePixelValue; if (showHidePageSize !== this.hidePageSize) { this.hidePageSize = showHidePageSize; - this.cd.detectChanges(); + this.cd.markForCheck(); } }); - this.widgetResize$.observe(this.attributeTableContainerRef.nativeElement); + this.widgetResize$.observe(this.elementRef.nativeElement); } ngOnDestroy() { diff --git a/ui-ngx/src/app/modules/home/components/entity/entities-table.component.html b/ui-ngx/src/app/modules/home/components/entity/entities-table.component.html index aa86660ebe..a7b15670bb 100644 --- a/ui-ngx/src/app/modules/home/components/entity/entities-table.component.html +++ b/ui-ngx/src/app/modules/home/components/entity/entities-table.component.html @@ -32,7 +32,7 @@ -
+
diff --git a/ui-ngx/src/app/modules/home/components/entity/entities-table.component.scss b/ui-ngx/src/app/modules/home/components/entity/entities-table.component.scss index ac7648d07a..dde91efc26 100644 --- a/ui-ngx/src/app/modules/home/components/entity/entities-table.component.scss +++ b/ui-ngx/src/app/modules/home/components/entity/entities-table.component.scss @@ -18,6 +18,7 @@ :host { width: 100%; height: 100%; + display: block; .tb-entity-table { .tb-entity-table-content { width: 100%; diff --git a/ui-ngx/src/app/modules/home/components/entity/entities-table.component.ts b/ui-ngx/src/app/modules/home/components/entity/entities-table.component.ts index 1851d5e085..79166bb116 100644 --- a/ui-ngx/src/app/modules/home/components/entity/entities-table.component.ts +++ b/ui-ngx/src/app/modules/home/components/entity/entities-table.component.ts @@ -43,7 +43,8 @@ import { TranslateService } from '@ngx-translate/core'; import { BaseData, HasId } from '@shared/models/base-data'; import { ActivatedRoute } from '@angular/router'; import { - CellActionDescriptor, CellActionDescriptorType, + CellActionDescriptor, + CellActionDescriptorType, EntityActionTableColumn, EntityColumn, EntityTableColumn, @@ -55,11 +56,7 @@ import { EntityTypeTranslation } from '@shared/models/entity-type.models'; import { DialogService } from '@core/services/dialog.service'; import { AddEntityDialogComponent } from './add-entity-dialog.component'; import { AddEntityDialogData, EntityAction } from '@home/models/entity/entity-component.models'; -import { - calculateIntervalStartEndTime, - HistoryWindowType, - Timewindow -} from '@shared/models/time/time.models'; +import { calculateIntervalStartEndTime, HistoryWindowType, Timewindow } from '@shared/models/time/time.models'; import { DomSanitizer, SafeHtml } from '@angular/platform-browser'; import { TbAnchorComponent } from '@shared/components/tb-anchor.component'; import { isDefined, isUndefined } from '@core/utils'; @@ -100,6 +97,7 @@ export class EntitiesTableComponent extends PageComponent implements AfterViewIn defaultPageSize = 10; displayPagination = true; + hidePageSize = false; pageSizeOptions; pageLink: PageLink; textSearchMode = false; @@ -111,8 +109,6 @@ export class EntitiesTableComponent extends PageComponent implements AfterViewIn isDetailsOpen = false; detailsPanelOpened = new EventEmitter(); - @ViewChild('entitiesTableContainer', {static: true}) entitiesTableContainerRef: ElementRef; - @ViewChild('entityTableHeader', {static: true}) entityTableHeaderAnchor: TbAnchorComponent; @ViewChild('searchInput') searchInputField: ElementRef; @@ -125,7 +121,6 @@ export class EntitiesTableComponent extends PageComponent implements AfterViewIn private viewInited = false; private widgetResize$: ResizeObserver; - public hidePageSize = false; constructor(protected store: Store, public route: ActivatedRoute, @@ -134,7 +129,8 @@ export class EntitiesTableComponent extends PageComponent implements AfterViewIn private dialogService: DialogService, private domSanitizer: DomSanitizer, private cd: ChangeDetectorRef, - private componentFactoryResolver: ComponentFactoryResolver) { + private componentFactoryResolver: ComponentFactoryResolver, + private elementRef: ElementRef) { super(store); } @@ -145,13 +141,13 @@ export class EntitiesTableComponent extends PageComponent implements AfterViewIn this.init(this.route.snapshot.data.entitiesTableConfig); } this.widgetResize$ = new ResizeObserver(() => { - const showHidePageSize = this.entitiesTableContainerRef.nativeElement.offsetWidth < hidePageSizePixelValue; + const showHidePageSize = this.elementRef.nativeElement.offsetWidth < hidePageSizePixelValue; if (showHidePageSize !== this.hidePageSize) { this.hidePageSize = showHidePageSize; - this.cd.detectChanges(); + this.cd.markForCheck(); } }); - this.widgetResize$.observe(this.entitiesTableContainerRef.nativeElement); + this.widgetResize$.observe(this.elementRef.nativeElement); } ngOnDestroy() { diff --git a/ui-ngx/src/app/modules/home/components/relation/relation-table.component.html b/ui-ngx/src/app/modules/home/components/relation/relation-table.component.html index edf5d1d04d..b5ae8c2d52 100644 --- a/ui-ngx/src/app/modules/home/components/relation/relation-table.component.html +++ b/ui-ngx/src/app/modules/home/components/relation/relation-table.component.html @@ -15,7 +15,7 @@ limitations under the License. --> -
+
diff --git a/ui-ngx/src/app/modules/home/components/relation/relation-table.component.scss b/ui-ngx/src/app/modules/home/components/relation/relation-table.component.scss index dfb94a7383..b5c43647e3 100644 --- a/ui-ngx/src/app/modules/home/components/relation/relation-table.component.scss +++ b/ui-ngx/src/app/modules/home/components/relation/relation-table.component.scss @@ -18,6 +18,7 @@ :host { width: 100%; height: 100%; + display: block; .tb-entity-table { .tb-entity-table-content { width: 100%; diff --git a/ui-ngx/src/app/modules/home/components/relation/relation-table.component.ts b/ui-ngx/src/app/modules/home/components/relation/relation-table.component.ts index 8f0b503717..db1fad53b7 100644 --- a/ui-ngx/src/app/modules/home/components/relation/relation-table.component.ts +++ b/ui-ngx/src/app/modules/home/components/relation/relation-table.component.ts @@ -67,6 +67,7 @@ export class RelationTableComponent extends PageComponent implements AfterViewIn displayedColumns: string[]; direction: EntitySearchDirection; pageLink: PageLink; + hidePageSize = false; textSearchMode = false; dataSource: RelationsDatasource; @@ -77,7 +78,6 @@ export class RelationTableComponent extends PageComponent implements AfterViewIn viewsInited = false; private widgetResize$: ResizeObserver; - public hidePageSize = false; @Input() set active(active: boolean) { @@ -105,7 +105,6 @@ export class RelationTableComponent extends PageComponent implements AfterViewIn } } - @ViewChild('relationTableContainer', {static: true}) relationTableContainerRef: ElementRef; @ViewChild('searchInput') searchInputField: ElementRef; @ViewChild(MatPaginator) paginator: MatPaginator; @@ -116,7 +115,8 @@ export class RelationTableComponent extends PageComponent implements AfterViewIn public translate: TranslateService, public dialog: MatDialog, private dialogService: DialogService, - private cd: ChangeDetectorRef) { + private cd: ChangeDetectorRef, + private elementRef: ElementRef) { super(store); this.dirtyValue = !this.activeValue; const sortOrder: SortOrder = { property: 'type', direction: Direction.ASC }; @@ -128,13 +128,13 @@ export class RelationTableComponent extends PageComponent implements AfterViewIn ngOnInit() { this.widgetResize$ = new ResizeObserver(() => { - const showHidePageSize = this.relationTableContainerRef.nativeElement.offsetWidth < hidePageSizePixelValue; + const showHidePageSize = this.elementRef.nativeElement.offsetWidth < hidePageSizePixelValue; if (showHidePageSize !== this.hidePageSize) { this.hidePageSize = showHidePageSize; - this.cd.detectChanges(); + this.cd.markForCheck(); } }); - this.widgetResize$.observe(this.relationTableContainerRef.nativeElement); + this.widgetResize$.observe(this.elementRef.nativeElement); } ngOnDestroy() { diff --git a/ui-ngx/src/app/modules/home/components/widget/action/manage-widget-actions.component.html b/ui-ngx/src/app/modules/home/components/widget/action/manage-widget-actions.component.html index d0c1db566c..9512c58b4a 100644 --- a/ui-ngx/src/app/modules/home/components/widget/action/manage-widget-actions.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/action/manage-widget-actions.component.html @@ -15,7 +15,7 @@ limitations under the License. --> -
+
@@ -119,6 +119,7 @@ + [pageSizeOptions]="[10, 20, 30]" + [hidePageSize]="hidePageSize">
diff --git a/ui-ngx/src/app/modules/home/components/widget/action/manage-widget-actions.component.scss b/ui-ngx/src/app/modules/home/components/widget/action/manage-widget-actions.component.scss index d71ec2e0d1..3406215b33 100644 --- a/ui-ngx/src/app/modules/home/components/widget/action/manage-widget-actions.component.scss +++ b/ui-ngx/src/app/modules/home/components/widget/action/manage-widget-actions.component.scss @@ -16,6 +16,7 @@ :host { width: 100%; height: 100%; + display: block; .tb-entity-table { .tb-entity-table-content { width: 100%; diff --git a/ui-ngx/src/app/modules/home/components/widget/action/manage-widget-actions.component.ts b/ui-ngx/src/app/modules/home/components/widget/action/manage-widget-actions.component.ts index 5173e00954..f131b84783 100644 --- a/ui-ngx/src/app/modules/home/components/widget/action/manage-widget-actions.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/action/manage-widget-actions.component.ts @@ -46,13 +46,12 @@ import { WidgetActionsDatasource } from '@home/components/widget/action/manage-widget-actions.component.models'; import { UtilsService } from '@core/services/utils.service'; -import { WidgetActionDescriptor, WidgetActionSource } from '@shared/models/widget.models'; +import { WidgetActionDescriptor, WidgetActionSource, widgetType } from '@shared/models/widget.models'; import { WidgetActionDialogComponent, WidgetActionDialogData } from '@home/components/widget/action/widget-action-dialog.component'; import { deepClone } from '@core/utils'; -import { widgetType } from '@shared/models/widget.models'; import { ResizeObserver } from '@juggle/resize-observer'; import { hidePageSizePixelValue } from '@shared/models/constants'; @@ -81,14 +80,14 @@ export class ManageWidgetActionsComponent extends PageComponent implements OnIni displayedColumns: string[]; pageLink: PageLink; textSearchMode = false; + hidePageSize = false; dataSource: WidgetActionsDatasource; viewsInited = false; dirtyValue = false; - public hidePageSize = false; + private widgetResize$: ResizeObserver; - @ViewChild('manageActionWidgetContainer', {static: true}) manageActionWidgetContainerRef: ElementRef; @ViewChild('searchInput') searchInputField: ElementRef; @ViewChild(MatPaginator) paginator: MatPaginator; @@ -101,7 +100,8 @@ export class ManageWidgetActionsComponent extends PageComponent implements OnIni private utils: UtilsService, private dialog: MatDialog, private dialogs: DialogService, - private cd: ChangeDetectorRef) { + private cd: ChangeDetectorRef, + private elementRef: ElementRef) { super(store); const sortOrder: SortOrder = { property: 'actionSourceName', direction: Direction.ASC }; this.pageLink = new PageLink(10, 0, null, sortOrder); @@ -111,13 +111,13 @@ export class ManageWidgetActionsComponent extends PageComponent implements OnIni ngOnInit(): void { this.widgetResize$ = new ResizeObserver(() => { - const showHidePageSize = this.manageActionWidgetContainerRef.nativeElement.offsetWidth < hidePageSizePixelValue; + const showHidePageSize = this.elementRef.nativeElement.offsetWidth < hidePageSizePixelValue; if (showHidePageSize !== this.hidePageSize) { this.hidePageSize = showHidePageSize; - this.cd.detectChanges(); + this.cd.markForCheck(); } }); - this.widgetResize$.observe(this.manageActionWidgetContainerRef.nativeElement); + this.widgetResize$.observe(this.elementRef.nativeElement); } ngOnDestroy(): void { diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.html index 872e040bad..a2b0868370 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.html @@ -15,7 +15,7 @@ limitations under the License. --> -
+
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.scss b/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.scss index edc52a9c48..15664c4750 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.scss +++ b/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.scss @@ -16,6 +16,7 @@ :host { width: 100%; height: 100%; + display: block; .tb-table-widget { .table-container { position: relative; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.ts index e12fcfcebd..5cd0f9643d 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.ts @@ -16,6 +16,7 @@ import { AfterViewInit, + ChangeDetectorRef, Component, ElementRef, EventEmitter, @@ -154,7 +155,6 @@ export class AlarmsTableWidgetComponent extends PageComponent implements OnInit, @Input() ctx: WidgetContext; - @ViewChild('alarmWidgetContainer', {static: true}) alarmWidgetContainerRef: ElementRef; @ViewChild('searchInput') searchInputField: ElementRef; @ViewChild(MatPaginator) paginator: MatPaginator; @ViewChild(MatSort) sort: MatSort; @@ -167,11 +167,11 @@ export class AlarmsTableWidgetComponent extends PageComponent implements OnInit, public pageLink: AlarmDataPageLink; public sortOrderProperty: string; public textSearchMode = false; + public hidePageSize = false; public columns: Array = []; public displayedColumns: string[] = []; public alarmsDatasource: AlarmsDatasource; public noDataDisplayMessageText: string; - public hidePageSize = false; private setCellButtonAction: boolean; private cellContentCache: Array = []; @@ -240,7 +240,8 @@ export class AlarmsTableWidgetComponent extends PageComponent implements OnInit, private datePipe: DatePipe, private dialog: MatDialog, private dialogService: DialogService, - private alarmService: AlarmService) { + private alarmService: AlarmService, + private cd: ChangeDetectorRef) { super(store); this.pageLink = { page: 0, @@ -263,13 +264,13 @@ export class AlarmsTableWidgetComponent extends PageComponent implements OnInit, () => this.pageLink.page = 0 ); this.widgetResize$ = new ResizeObserver(() => { - const showHidePageSize = this.alarmWidgetContainerRef.nativeElement.offsetWidth < hidePageSizePixelValue; + const showHidePageSize = this.elementRef.nativeElement.offsetWidth < hidePageSizePixelValue; if (showHidePageSize !== this.hidePageSize) { this.hidePageSize = showHidePageSize; - this.ctx.detectChanges(); + this.cd.markForCheck(); } }); - this.widgetResize$.observe(this.alarmWidgetContainerRef.nativeElement); + this.widgetResize$.observe(this.elementRef.nativeElement); } } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.html index 7f8ae9b9b1..c2d1997945 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.html @@ -15,7 +15,7 @@ limitations under the License. --> -
+
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.scss b/ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.scss index edc52a9c48..15664c4750 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.scss +++ b/ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.scss @@ -16,6 +16,7 @@ :host { width: 100%; height: 100%; + display: block; .tb-table-widget { .table-container { position: relative; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.ts index 32a07cecb8..f4429fb4cc 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.ts @@ -16,6 +16,7 @@ import { AfterViewInit, + ChangeDetectorRef, Component, ElementRef, Injector, @@ -131,7 +132,6 @@ export class EntitiesTableWidgetComponent extends PageComponent implements OnIni @Input() ctx: WidgetContext; - @ViewChild('entitiesWidgetContainer', {static: true}) entitiesWidgetContainerRef: ElementRef; @ViewChild('searchInput') searchInputField: ElementRef; @ViewChild(MatPaginator) paginator: MatPaginator; @ViewChild(MatSort) sort: MatSort; @@ -143,11 +143,11 @@ export class EntitiesTableWidgetComponent extends PageComponent implements OnIni public pageLink: EntityDataPageLink; public sortOrderProperty: string; public textSearchMode = false; + public hidePageSize = false; public columns: Array = []; public displayedColumns: string[] = []; public entityDatasource: EntityDatasource; public noDataDisplayMessageText: string; - public hidePageSize = false; private setCellButtonAction: boolean; private cellContentCache: Array = []; @@ -198,7 +198,8 @@ export class EntitiesTableWidgetComponent extends PageComponent implements OnIni private utils: UtilsService, private datePipe: DatePipe, private translate: TranslateService, - private domSanitizer: DomSanitizer) { + private domSanitizer: DomSanitizer, + private cd: ChangeDetectorRef) { super(store); this.pageLink = { page: 0, @@ -218,13 +219,13 @@ export class EntitiesTableWidgetComponent extends PageComponent implements OnIni this.ctx.updateWidgetParams(); if (this.displayPagination) { this.widgetResize$ = new ResizeObserver(() => { - const showHidePageSize = this.entitiesWidgetContainerRef.nativeElement.offsetWidth < hidePageSizePixelValue; + const showHidePageSize = this.elementRef.nativeElement.offsetWidth < hidePageSizePixelValue; if (showHidePageSize !== this.hidePageSize) { this.hidePageSize = showHidePageSize; - this.ctx.detectChanges(); + this.cd.markForCheck(); } }); - this.widgetResize$.observe(this.entitiesWidgetContainerRef.nativeElement); + this.widgetResize$.observe(this.elementRef.nativeElement); } } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.html index 236d81036c..6e37d38762 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.html @@ -15,7 +15,7 @@ limitations under the License. --> -
+
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.scss b/ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.scss index 57052d4bf8..eb309c2cf7 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.scss +++ b/ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.scss @@ -16,6 +16,7 @@ :host { width: 100%; height: 100%; + display: block; .tb-table-widget { mat-footer-row, mat-row { height: 38px; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.ts index a5a2cbc12e..07d35a1405 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.ts @@ -16,6 +16,7 @@ import { AfterViewInit, + ChangeDetectorRef, Component, ElementRef, Input, @@ -117,7 +118,6 @@ export class TimeseriesTableWidgetComponent extends PageComponent implements OnI @Input() ctx: WidgetContext; - @ViewChild('timeseriesWidgetContainer', {static: true}) timeseriesWidgetContainerRef: ElementRef; @ViewChild('searchInput') searchInputField: ElementRef; @ViewChildren(MatPaginator) paginators: QueryList; @ViewChildren(MatSort) sorts: QueryList; @@ -127,11 +127,11 @@ export class TimeseriesTableWidgetComponent extends PageComponent implements OnI public enableStickyAction = true; public pageSizeOptions; public textSearchMode = false; + public hidePageSize = false; public textSearch: string = null; public sources: TimeseriesTableSource[]; public sourceIndex: number; public noDataDisplayMessageText: string; - public hidePageSize = false; private setCellButtonAction: boolean; private cellContentCache: Array = []; @@ -172,7 +172,8 @@ export class TimeseriesTableWidgetComponent extends PageComponent implements OnI private utils: UtilsService, private translate: TranslateService, private domSanitizer: DomSanitizer, - private datePipe: DatePipe) { + private datePipe: DatePipe, + private cd: ChangeDetectorRef) { super(store); } @@ -196,13 +197,13 @@ export class TimeseriesTableWidgetComponent extends PageComponent implements OnI } ); this.widgetResize$ = new ResizeObserver(() => { - const showHidePageSize = this.timeseriesWidgetContainerRef.nativeElement.offsetWidth < hidePageSizePixelValue; + const showHidePageSize = this.elementRef.nativeElement.offsetWidth < hidePageSizePixelValue; if (showHidePageSize !== this.hidePageSize) { this.hidePageSize = showHidePageSize; - this.ctx.detectChanges(); + this.cd.markForCheck(); } }); - this.widgetResize$.observe(this.timeseriesWidgetContainerRef.nativeElement); + this.widgetResize$.observe(this.elementRef.nativeElement); } } From 3d8d50d172b50f047f8688a446704b2c6215e668 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Tue, 14 Dec 2021 17:29:03 +0200 Subject: [PATCH 247/432] Use nodejs image to build js related docker images --- msa/js-executor/docker/Dockerfile | 29 ++++----- msa/js-executor/docker/start-js-executor.sh | 6 +- msa/js-executor/install.js | 7 +-- msa/js-executor/package.json | 5 +- msa/js-executor/pom.xml | 64 ++++++++++++++++++++ msa/web-ui/docker/Dockerfile | 28 ++++----- msa/web-ui/docker/start-web-ui.sh | 6 +- msa/web-ui/install.js | 7 +-- msa/web-ui/package.json | 5 +- msa/web-ui/pom.xml | 32 ++++++++++ packaging/js/build.gradle | 65 ++------------------- 11 files changed, 143 insertions(+), 111 deletions(-) diff --git a/msa/js-executor/docker/Dockerfile b/msa/js-executor/docker/Dockerfile index 92b2229e79..3a808944b6 100644 --- a/msa/js-executor/docker/Dockerfile +++ b/msa/js-executor/docker/Dockerfile @@ -14,26 +14,29 @@ # limitations under the License. # -FROM thingsboard/base +FROM node:16.13.1-buster-slim -ARG TARGETPLATFORM - -COPY start-js-executor.sh ${pkg.name}.deb ${pkg.name}-arm64.deb /tmp/ +COPY start-js-executor.sh /tmp/ RUN chmod a+x /tmp/*.sh \ && mv /tmp/start-js-executor.sh /usr/bin -RUN if [ "$TARGETPLATFORM" = "linux/arm64" ]; \ - then yes | dpkg -i /tmp/${pkg.name}-arm64.deb; \ - else yes | dpkg -i /tmp/${pkg.name}.deb; \ - fi -RUN rm /tmp/${pkg.name}.deb -RUN rm /tmp/${pkg.name}-arm64.deb +ENV NODE_ENV production + +WORKDIR ${pkg.installFolder} + +COPY ["src/package.json", "src/yarn.lock", "./"] + +COPY package/linux/conf ./conf +COPY package/linux/conf ./config +COPY src/api ./api +COPY src/queue ./queue +COPY src/server.js ./ -RUN systemctl --no-reload disable --now ${pkg.name}.service > /dev/null 2>&1 || : +RUN chown -R node:node ${pkg.installFolder} -RUN chmod 555 ${pkg.installFolder}/bin/${pkg.name} +RUN yarn install --production && yarn cache clean --all -USER ${pkg.user} +USER node CMD ["start-js-executor.sh"] diff --git a/msa/js-executor/docker/start-js-executor.sh b/msa/js-executor/docker/start-js-executor.sh index a57b441db1..ba0c3eaeed 100755 --- a/msa/js-executor/docker/start-js-executor.sh +++ b/msa/js-executor/docker/start-js-executor.sh @@ -20,12 +20,10 @@ echo "Starting '${project.name}' ..." CONF_FOLDER="${pkg.installFolder}/conf" -mainfile=${pkg.installFolder}/bin/${pkg.name} configfile=${pkg.name}.conf -identity=${pkg.name} source "${CONF_FOLDER}/${configfile}" -cd ${pkg.installFolder}/bin +cd ${pkg.installFolder} -exec /bin/sh -c "$mainfile" +exec /bin/sh -c "node server.js" diff --git a/msa/js-executor/install.js b/msa/js-executor/install.js index 9fe911e7b2..d180a5247a 100644 --- a/msa/js-executor/install.js +++ b/msa/js-executor/install.js @@ -21,13 +21,10 @@ let _projectRoot = null; (async() => { - await fse.move(path.join(projectRoot(), 'target', 'thingsboard-js-executor-linux-x64'), + await fse.move(path.join(projectRoot(), 'target', 'thingsboard-js-executor-linux'), path.join(targetPackageDir('linux'), 'bin', 'tb-js-executor'), {overwrite: true}); - await fse.move(path.join(projectRoot(), 'target', 'thingsboard-js-executor-linux-arm64'), - path.join(targetPackageDir('linux'), 'bin-arm64', 'tb-js-executor'), - {overwrite: true}); - await fse.move(path.join(projectRoot(), 'target', 'thingsboard-js-executor-win-x64.exe'), + await fse.move(path.join(projectRoot(), 'target', 'thingsboard-js-executor-win.exe'), path.join(targetPackageDir('windows'), 'bin', 'tb-js-executor.exe'), {overwrite: true}); })(); diff --git a/msa/js-executor/package.json b/msa/js-executor/package.json index 0e2cee6e54..69fc59eed2 100644 --- a/msa/js-executor/package.json +++ b/msa/js-executor/package.json @@ -6,7 +6,7 @@ "main": "server.js", "bin": "server.js", "scripts": { - "install": "pkg -t node12-linux-x64,node12-linux-arm64,node12-win-x64 --out-path ./target . && node install.js", + "pkg": "pkg -t node12-linux-x64,node12-win-x64 --out-path ./target . && node install.js", "test": "echo \"Error: no test specified\" && exit 1", "start": "nodemon server.js", "start-prod": "NODE_ENV=production nodemon server.js" @@ -27,9 +27,6 @@ "winston": "^3.3.3", "winston-daily-rotate-file": "^4.5.0" }, - "engines": { - "node": ">=12.0.0 <14.0.0" - }, "nyc": { "exclude": [ "test", diff --git a/msa/js-executor/pom.xml b/msa/js-executor/pom.xml index 16f1f0293b..72adb41d76 100644 --- a/msa/js-executor/pom.xml +++ b/msa/js-executor/pom.xml @@ -84,6 +84,15 @@ install + + yarn pkg + + yarn + + + run pkg + + @@ -93,6 +102,61 @@ org.apache.maven.plugins maven-resources-plugin + + + copy-src-api + process-resources + + copy-resources + + + ${project.build.directory}/src/api + + + api + false + + + + + + copy-src-queue + process-resources + + copy-resources + + + ${project.build.directory}/src/queue + + + queue + false + + + + + + copy-src-root + process-resources + + copy-resources + + + ${project.build.directory}/src + + + ${basedir} + + server.js + package.json + yarn.lock + + false + + + + + org.thingsboard diff --git a/msa/web-ui/docker/Dockerfile b/msa/web-ui/docker/Dockerfile index 5b4acf9eb3..9532e5093a 100644 --- a/msa/web-ui/docker/Dockerfile +++ b/msa/web-ui/docker/Dockerfile @@ -14,26 +14,28 @@ # limitations under the License. # -FROM thingsboard/base +FROM node:16.13.1-buster-slim -ARG TARGETPLATFORM - -COPY start-web-ui.sh ${pkg.name}.deb ${pkg.name}-arm64.deb /tmp/ +COPY start-web-ui.sh /tmp/ RUN chmod a+x /tmp/*.sh \ && mv /tmp/start-web-ui.sh /usr/bin -RUN if [ "$TARGETPLATFORM" = "linux/arm64" ]; \ - then yes | dpkg -i /tmp/${pkg.name}-arm64.deb; \ - else yes | dpkg -i /tmp/${pkg.name}.deb; \ - fi -RUN rm /tmp/${pkg.name}.deb -RUN rm /tmp/${pkg.name}-arm64.deb +ENV NODE_ENV production + +WORKDIR ${pkg.installFolder} + +COPY ["src/package.json", "src/yarn.lock", "./"] + +COPY package/linux/conf ./conf +COPY package/linux/conf ./config +COPY web ./web +COPY src/server.js ./ -RUN systemctl --no-reload disable --now ${pkg.name}.service > /dev/null 2>&1 || : +RUN chown -R node:node ${pkg.installFolder} -RUN chmod 555 ${pkg.installFolder}/bin/${pkg.name} +RUN yarn install --production && yarn cache clean --all -USER ${pkg.user} +USER node CMD ["start-web-ui.sh"] diff --git a/msa/web-ui/docker/start-web-ui.sh b/msa/web-ui/docker/start-web-ui.sh index a57b441db1..ba0c3eaeed 100755 --- a/msa/web-ui/docker/start-web-ui.sh +++ b/msa/web-ui/docker/start-web-ui.sh @@ -20,12 +20,10 @@ echo "Starting '${project.name}' ..." CONF_FOLDER="${pkg.installFolder}/conf" -mainfile=${pkg.installFolder}/bin/${pkg.name} configfile=${pkg.name}.conf -identity=${pkg.name} source "${CONF_FOLDER}/${configfile}" -cd ${pkg.installFolder}/bin +cd ${pkg.installFolder} -exec /bin/sh -c "$mainfile" +exec /bin/sh -c "node server.js" diff --git a/msa/web-ui/install.js b/msa/web-ui/install.js index f0021d64f7..36b2311bb0 100644 --- a/msa/web-ui/install.js +++ b/msa/web-ui/install.js @@ -21,13 +21,10 @@ let _projectRoot = null; (async() => { - await fse.move(path.join(projectRoot(), 'target', 'thingsboard-web-ui-linux-x64'), + await fse.move(path.join(projectRoot(), 'target', 'thingsboard-web-ui-linux'), path.join(targetPackageDir('linux'), 'bin', 'tb-web-ui'), {overwrite: true}); - await fse.move(path.join(projectRoot(), 'target', 'thingsboard-web-ui-linux-arm64'), - path.join(targetPackageDir('linux'), 'bin-arm64', 'tb-web-ui'), - {overwrite: true}); - await fse.move(path.join(projectRoot(), 'target', 'thingsboard-web-ui-win-x64.exe'), + await fse.move(path.join(projectRoot(), 'target', 'thingsboard-web-ui-win.exe'), path.join(targetPackageDir('windows'), 'bin', 'tb-web-ui.exe'), {overwrite: true}); })(); diff --git a/msa/web-ui/package.json b/msa/web-ui/package.json index 9e2075010a..9fa272d9b7 100644 --- a/msa/web-ui/package.json +++ b/msa/web-ui/package.json @@ -6,7 +6,7 @@ "main": "server.js", "bin": "server.js", "scripts": { - "install": "pkg -t node12-linux-x64,node12-linux-arm64,node12-win-x64 --out-path ./target . && node install.js", + "pkg": "pkg -t node12-linux-x64,node12-win-x64 --out-path ./target . && node install.js", "test": "echo \"Error: no test specified\" && exit 1", "start": "WEB_FOLDER=./target/web nodemon server.js", "start-prod": "NODE_ENV=production nodemon server.js" @@ -22,9 +22,6 @@ "winston": "^3.3.3", "winston-daily-rotate-file": "^4.5.0" }, - "engines": { - "node": ">=12.0.0 <14.0.0" - }, "nyc": { "exclude": [ "test", diff --git a/msa/web-ui/pom.xml b/msa/web-ui/pom.xml index bf311df492..864d5e2c56 100644 --- a/msa/web-ui/pom.xml +++ b/msa/web-ui/pom.xml @@ -93,6 +93,15 @@ install + + yarn pkg + + yarn + + + run pkg + + @@ -140,6 +149,29 @@ org.apache.maven.plugins maven-resources-plugin + + + copy-src-root + process-resources + + copy-resources + + + ${project.build.directory}/src + + + ${basedir} + + server.js + package.json + yarn.lock + + false + + + + + org.thingsboard diff --git a/packaging/js/build.gradle b/packaging/js/build.gradle index df9d86dde7..929b7ed9d7 100644 --- a/packaging/js/build.gradle +++ b/packaging/js/build.gradle @@ -36,6 +36,12 @@ ospackage { user pkgUser permissionGroup pkgUser + // Copy the executable file + from("${buildDir}/package/linux/bin/${pkgName}") { + fileMode 0500 + into "bin" + } + // Copy the init file from("${buildDir}/package/linux/init/template") { fileMode 0500 @@ -72,17 +78,9 @@ buildRpm { preUninstall file("${buildDir}/control/rpm/prerm") postUninstall file("${buildDir}/control/rpm/postrm") - into pkgInstallFolder - user pkgUser permissionGroup pkgUser - // Copy the executable file - from("${buildDir}/package/linux/bin/${pkgName}") { - fileMode 0500 - into "bin" - } - // Copy the system unit files from("${buildDir}/control/template.service") { addParentDirs = false @@ -113,58 +111,9 @@ buildDeb { preUninstall file("${buildDir}/control/deb/prerm") postUninstall file("${buildDir}/control/deb/postrm") - into pkgInstallFolder - - user pkgUser - permissionGroup pkgUser - - // Copy the executable file - from("${buildDir}/package/linux/bin/${pkgName}") { - fileMode 0500 - into "bin" - } - - // Copy the system unit files - from("${buildDir}/control/template.service") { - addParentDirs = false - fileMode 0644 - into "/lib/systemd/system" - rename { String filename -> - "${pkgName}.service" - } - } - - link("/etc/${pkgName}/conf", "${pkgInstallFolder}/conf") -} - -// Same as the buildRpm task -task buildDebArm64(type: Deb) { - - arch = "arm64" - - archiveFileName = "${pkgName}-arm64.deb" - - configurationFile("${pkgInstallFolder}/conf/${pkgName}.conf") - configurationFile("${pkgInstallFolder}/conf/custom-environment-variables.yml") - configurationFile("${pkgInstallFolder}/conf/default.yml") - configurationFile("${pkgInstallFolder}/conf/logger.js") - - preInstall file("${buildDir}/control/deb/preinst") - postInstall file("${buildDir}/control/deb/postinst") - preUninstall file("${buildDir}/control/deb/prerm") - postUninstall file("${buildDir}/control/deb/postrm") - - into pkgInstallFolder - user pkgUser permissionGroup pkgUser - // Copy the executable file - from("${buildDir}/package/linux/bin-arm64/${pkgName}") { - fileMode 0500 - into "bin" - } - // Copy the system unit files from("${buildDir}/control/template.service") { addParentDirs = false @@ -177,5 +126,3 @@ task buildDebArm64(type: Deb) { link("/etc/${pkgName}/conf", "${pkgInstallFolder}/conf") } - -buildDeb.finalizedBy buildDebArm64 From 7de1343df0c83c92f6feb2aa08e96c2f911adac9 Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Tue, 14 Dec 2021 18:13:26 +0200 Subject: [PATCH 248/432] Ability to limit alarm queries invocation count --- ...efaultTbEntityDataSubscriptionService.java | 13 +++---- .../subscription/TbAbstractDataSubCtx.java | 2 ++ .../subscription/TbAlarmDataSubCtx.java | 35 +++++++++++++++++-- .../subscription/TbEntityDataSubCtx.java | 1 + .../src/main/resources/thingsboard.yml | 1 + 5 files changed, 42 insertions(+), 10 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/subscription/DefaultTbEntityDataSubscriptionService.java b/application/src/main/java/org/thingsboard/server/service/subscription/DefaultTbEntityDataSubscriptionService.java index 127de752d0..4ee8708805 100644 --- a/application/src/main/java/org/thingsboard/server/service/subscription/DefaultTbEntityDataSubscriptionService.java +++ b/application/src/main/java/org/thingsboard/server/service/subscription/DefaultTbEntityDataSubscriptionService.java @@ -36,16 +36,13 @@ import org.thingsboard.server.common.data.kv.TsKvEntry; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.query.AlarmDataQuery; import org.thingsboard.server.common.data.query.EntityData; -import org.thingsboard.server.common.data.query.EntityDataPageLink; import org.thingsboard.server.common.data.query.EntityDataQuery; -import org.thingsboard.server.common.data.query.EntityDataSortOrder; import org.thingsboard.server.common.data.query.EntityKey; import org.thingsboard.server.common.data.query.EntityKeyType; import org.thingsboard.server.common.data.query.TsValue; import org.thingsboard.server.dao.alarm.AlarmService; import org.thingsboard.server.dao.attributes.AttributesService; import org.thingsboard.server.dao.entity.EntityService; -import org.thingsboard.server.dao.model.ModelConstants; import org.thingsboard.server.dao.timeseries.TimeseriesService; import org.thingsboard.server.queue.discovery.TbServiceInfoProvider; import org.thingsboard.server.queue.util.TbCoreComponent; @@ -68,7 +65,6 @@ import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.LinkedHashSet; @@ -83,8 +79,6 @@ import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.ThreadFactory; import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicLong; import java.util.stream.Collectors; @Slf4j @@ -133,6 +127,8 @@ public class DefaultTbEntityDataSubscriptionService implements TbEntityDataSubsc private int maxEntitiesPerDataSubscription; @Value("${server.ws.max_entities_per_alarm_subscription:1000}") private int maxEntitiesPerAlarmSubscription; + @Value("${server.ws.max_alarm_queries_per_refresh_interval:3}") + private int maxAlarmQueriesPerRefreshInterval; private ExecutorService wsCallBackExecutor; private boolean tsInSqlDB; @@ -282,7 +278,7 @@ public class DefaultTbEntityDataSubscriptionService implements TbEntityDataSubsc if (adq.getPageLink().getTimeWindow() > 0) { TbAlarmDataSubCtx finalCtx = ctx; ScheduledFuture task = scheduler.scheduleWithFixedDelay( - finalCtx::cleanupOldAlarms, dynamicPageLinkRefreshInterval, dynamicPageLinkRefreshInterval, TimeUnit.SECONDS); + finalCtx::checkAndResetInvocationCounter, dynamicPageLinkRefreshInterval, dynamicPageLinkRefreshInterval, TimeUnit.SECONDS); finalCtx.setRefreshTask(task); } } @@ -345,7 +341,8 @@ public class DefaultTbEntityDataSubscriptionService implements TbEntityDataSubsc private TbAlarmDataSubCtx createSubCtx(TelemetryWebSocketSessionRef sessionRef, AlarmDataCmd cmd) { Map sessionSubs = subscriptionsBySessionId.computeIfAbsent(sessionRef.getSessionId(), k -> new HashMap<>()); TbAlarmDataSubCtx ctx = new TbAlarmDataSubCtx(serviceId, wsService, entityService, localSubscriptionService, - attributesService, stats, alarmService, sessionRef, cmd.getCmdId(), maxEntitiesPerAlarmSubscription); + attributesService, stats, alarmService, sessionRef, cmd.getCmdId(), maxEntitiesPerAlarmSubscription, + maxAlarmQueriesPerRefreshInterval); ctx.setAndResolveQuery(cmd.getQuery()); sessionSubs.put(cmd.getCmdId(), ctx); return ctx; diff --git a/application/src/main/java/org/thingsboard/server/service/subscription/TbAbstractDataSubCtx.java b/application/src/main/java/org/thingsboard/server/service/subscription/TbAbstractDataSubCtx.java index e054c9436f..1d5f8eb603 100644 --- a/application/src/main/java/org/thingsboard/server/service/subscription/TbAbstractDataSubCtx.java +++ b/application/src/main/java/org/thingsboard/server/service/subscription/TbAbstractDataSubCtx.java @@ -57,6 +57,7 @@ public abstract class TbAbstractDataSubCtx(); } + @Override public void fetchData() { this.data = findEntityData(); } @@ -71,6 +72,7 @@ public abstract class TbAbstractDataSubCtx newData = findEntityData(); diff --git a/application/src/main/java/org/thingsboard/server/service/subscription/TbAlarmDataSubCtx.java b/application/src/main/java/org/thingsboard/server/service/subscription/TbAlarmDataSubCtx.java index c3343effb5..1ea6495517 100644 --- a/application/src/main/java/org/thingsboard/server/service/subscription/TbAlarmDataSubCtx.java +++ b/application/src/main/java/org/thingsboard/server/service/subscription/TbAlarmDataSubCtx.java @@ -68,6 +68,8 @@ public class TbAlarmDataSubCtx extends TbAbstractDataSubCtx { private final int maxEntitiesPerAlarmSubscription; + private final int maxAlarmQueriesPerRefreshInterval; + @Getter @Setter private PageData alarms; @@ -75,18 +77,30 @@ public class TbAlarmDataSubCtx extends TbAbstractDataSubCtx { @Setter private boolean tooManyEntities; + private int alarmInvocationAttempts; + public TbAlarmDataSubCtx(String serviceId, TelemetryWebSocketService wsService, EntityService entityService, TbLocalSubscriptionService localSubscriptionService, AttributesService attributesService, SubscriptionServiceStatistics stats, AlarmService alarmService, - TelemetryWebSocketSessionRef sessionRef, int cmdId, int maxEntitiesPerAlarmSubscription) { + TelemetryWebSocketSessionRef sessionRef, int cmdId, + int maxEntitiesPerAlarmSubscription, int maxAlarmQueriesPerRefreshInterval) { super(serviceId, wsService, entityService, localSubscriptionService, attributesService, stats, sessionRef, cmdId); this.maxEntitiesPerAlarmSubscription = maxEntitiesPerAlarmSubscription; + this.maxAlarmQueriesPerRefreshInterval = maxAlarmQueriesPerRefreshInterval; this.alarmService = alarmService; this.entitiesMap = new LinkedHashMap<>(); this.alarmsMap = new HashMap<>(); } public void fetchAlarms() { + alarmInvocationAttempts++; + log.trace("[{}] Fetching alarms: {}", cmdId, alarmInvocationAttempts); + if (alarmInvocationAttempts <= maxAlarmQueriesPerRefreshInterval) { + doFetchAlarms(); + } + } + + private void doFetchAlarms() { AlarmDataUpdate update; if (!entitiesMap.isEmpty()) { long start = System.currentTimeMillis(); @@ -103,6 +117,8 @@ public class TbAlarmDataSubCtx extends TbAbstractDataSubCtx { } public void fetchData() { + resetInvocationCounter(); + log.trace("[{}] Fetching data: {}", cmdId, alarmInvocationAttempts); super.fetchData(); entitiesMap.clear(); tooManyEntities = data.hasNext(); @@ -222,7 +238,7 @@ public class TbAlarmDataSubCtx extends TbAbstractDataSubCtx { } } if (shouldRefresh) { - fetchAlarms(); + doFetchAlarms(); } } @@ -256,8 +272,19 @@ public class TbAlarmDataSubCtx extends TbAbstractDataSubCtx { return true; } + public synchronized void checkAndResetInvocationCounter() { + boolean fetchNeeded = this.alarmInvocationAttempts > maxAlarmQueriesPerRefreshInterval; + resetInvocationCounter(); + if (fetchNeeded) { + fetchAlarms(); + } else { + cleanupOldAlarms(); + } + } + @Override protected synchronized void doUpdate(Map newDataMap) { + resetInvocationCounter(); entitiesMap.clear(); tooManyEntities = data.hasNext(); for (EntityData entityData : data.getData()) { @@ -295,6 +322,10 @@ public class TbAlarmDataSubCtx extends TbAbstractDataSubCtx { subsToAdd.forEach(localSubscriptionService::addSubscription); } + private void resetInvocationCounter() { + alarmInvocationAttempts = 0; + } + @Override protected EntityDataQuery buildEntityDataQuery() { EntityDataSortOrder sortOrder = query.getPageLink().getSortOrder(); diff --git a/application/src/main/java/org/thingsboard/server/service/subscription/TbEntityDataSubCtx.java b/application/src/main/java/org/thingsboard/server/service/subscription/TbEntityDataSubCtx.java index 7325fe7878..d31456ff6c 100644 --- a/application/src/main/java/org/thingsboard/server/service/subscription/TbEntityDataSubCtx.java +++ b/application/src/main/java/org/thingsboard/server/service/subscription/TbEntityDataSubCtx.java @@ -165,6 +165,7 @@ public class TbEntityDataSubCtx extends TbAbstractDataSubCtx { return data.getData().stream().filter(item -> item.getEntityId().equals(entityId)).findFirst().orElse(null); } + @Override public synchronized void doUpdate(Map newDataMap) { List subIdsToCancel = new ArrayList<>(); List subsToAdd = new ArrayList<>(); diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index 8f02a7cb02..e0f45be7dc 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -70,6 +70,7 @@ server: dynamic_page_link: refresh_interval: "${TB_SERVER_WS_DYNAMIC_PAGE_LINK_REFRESH_INTERVAL_SEC:60}" refresh_pool_size: "${TB_SERVER_WS_DYNAMIC_PAGE_LINK_REFRESH_POOL_SIZE:1}" + max_alarm_queries_per_refresh_interval: "${TB_SERVER_WS_MAX_ALARM_QUERIES_PER_REFRESH_INTERVAL:3}" max_per_user: "${TB_SERVER_WS_DYNAMIC_PAGE_LINK_MAX_PER_USER:10}" max_entities_per_data_subscription: "${TB_SERVER_WS_MAX_ENTITIES_PER_DATA_SUBSCRIPTION:10000}" max_entities_per_alarm_subscription: "${TB_SERVER_WS_MAX_ENTITIES_PER_ALARM_SUBSCRIPTION:10000}" From 9826893be8cfe4404a8a4a98006f0012a01fcccb Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Tue, 14 Dec 2021 19:46:26 +0200 Subject: [PATCH 249/432] Improve nodejs docker images --- msa/js-executor/docker/Dockerfile | 1 + msa/web-ui/docker/Dockerfile | 1 + 2 files changed, 2 insertions(+) diff --git a/msa/js-executor/docker/Dockerfile b/msa/js-executor/docker/Dockerfile index 3a808944b6..8db32da784 100644 --- a/msa/js-executor/docker/Dockerfile +++ b/msa/js-executor/docker/Dockerfile @@ -22,6 +22,7 @@ RUN chmod a+x /tmp/*.sh \ && mv /tmp/start-js-executor.sh /usr/bin ENV NODE_ENV production +ENV DOCKER_MODE true WORKDIR ${pkg.installFolder} diff --git a/msa/web-ui/docker/Dockerfile b/msa/web-ui/docker/Dockerfile index 9532e5093a..dbc079d857 100644 --- a/msa/web-ui/docker/Dockerfile +++ b/msa/web-ui/docker/Dockerfile @@ -22,6 +22,7 @@ RUN chmod a+x /tmp/*.sh \ && mv /tmp/start-web-ui.sh /usr/bin ENV NODE_ENV production +ENV DOCKER_MODE true WORKDIR ${pkg.installFolder} From 45bac3751ab68564ea17ae831555ed60064ffc91 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Wed, 15 Dec 2021 12:56:45 +0200 Subject: [PATCH 250/432] Update base image version for js-executor and web-ui docker builds --- msa/js-executor/docker/Dockerfile | 2 +- msa/web-ui/docker/Dockerfile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/msa/js-executor/docker/Dockerfile b/msa/js-executor/docker/Dockerfile index 8db32da784..992353dd3e 100644 --- a/msa/js-executor/docker/Dockerfile +++ b/msa/js-executor/docker/Dockerfile @@ -14,7 +14,7 @@ # limitations under the License. # -FROM node:16.13.1-buster-slim +FROM node:16.13.1-bullseye-slim COPY start-js-executor.sh /tmp/ diff --git a/msa/web-ui/docker/Dockerfile b/msa/web-ui/docker/Dockerfile index dbc079d857..4942a712b6 100644 --- a/msa/web-ui/docker/Dockerfile +++ b/msa/web-ui/docker/Dockerfile @@ -14,7 +14,7 @@ # limitations under the License. # -FROM node:16.13.1-buster-slim +FROM node:16.13.1-bullseye-slim COPY start-web-ui.sh /tmp/ From bb99ef14ede4d413e0cf32209be47ee3bdade448 Mon Sep 17 00:00:00 2001 From: Sergey Tarnavskiy Date: Wed, 15 Dec 2021 13:26:20 +0200 Subject: [PATCH 251/432] Refactoring LwM2M Config with enabled/disabled bootstrap --- .../app/core/http/device-profile.service.ts | 30 ++++++++++--------- ...2m-bootstrap-config-servers.component.html | 7 +++-- ...wm2m-bootstrap-config-servers.component.ts | 24 +++++++++++++-- .../lwm2m-device-config-server.component.ts | 12 ++++++++ ...ile-transport-configuration.component.html | 7 ++++- ...ofile-transport-configuration.component.ts | 9 +++++- 6 files changed, 67 insertions(+), 22 deletions(-) diff --git a/ui-ngx/src/app/core/http/device-profile.service.ts b/ui-ngx/src/app/core/http/device-profile.service.ts index 1514b262aa..19aac62204 100644 --- a/ui-ngx/src/app/core/http/device-profile.service.ts +++ b/ui-ngx/src/app/core/http/device-profile.service.ts @@ -84,20 +84,22 @@ export class DeviceProfileService { return this.getLwm2mBootstrapSecurityInfo(isBootstrapServer, config).pipe( map(securityConfig => { const serverSecurityConfigInfo = deepClone(securityConfig); - switch (securityMode) { - case Lwm2mSecurityType.PSK: - serverSecurityConfigInfo.port = serverSecurityConfigInfo.securityPort; - serverSecurityConfigInfo.host = serverSecurityConfigInfo.securityHost; - serverSecurityConfigInfo.serverPublicKey = ''; - break; - case Lwm2mSecurityType.RPK: - case Lwm2mSecurityType.X509: - serverSecurityConfigInfo.port = serverSecurityConfigInfo.securityPort; - serverSecurityConfigInfo.host = serverSecurityConfigInfo.securityHost; - break; - case Lwm2mSecurityType.NO_SEC: - serverSecurityConfigInfo.serverPublicKey = ''; - break; + if (serverSecurityConfigInfo) { + switch (securityMode) { + case Lwm2mSecurityType.PSK: + serverSecurityConfigInfo.port = serverSecurityConfigInfo.securityPort; + serverSecurityConfigInfo.host = serverSecurityConfigInfo.securityHost; + serverSecurityConfigInfo.serverPublicKey = ''; + break; + case Lwm2mSecurityType.RPK: + case Lwm2mSecurityType.X509: + serverSecurityConfigInfo.port = serverSecurityConfigInfo.securityPort; + serverSecurityConfigInfo.host = serverSecurityConfigInfo.securityHost; + break; + case Lwm2mSecurityType.NO_SEC: + serverSecurityConfigInfo.serverPublicKey = ''; + break; + } } return serverSecurityConfigInfo; }) diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-bootstrap-config-servers.component.html b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-bootstrap-config-servers.component.html index ebd80ef558..443264eead 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-bootstrap-config-servers.component.html +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-bootstrap-config-servers.component.html @@ -20,7 +20,8 @@
+ (removeServer)="removeServerConfig($event, $index)" + (isTransportWasRunWithBootstrapChange)="updateIsTransportWasRunWithBootstrap($event)">
@@ -32,8 +33,8 @@
diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-bootstrap-config-servers.component.ts b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-bootstrap-config-servers.component.ts index 9230195efe..b7786a5fa2 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-bootstrap-config-servers.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-bootstrap-config-servers.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { ChangeDetectorRef, Component, forwardRef, Input, OnInit } from '@angular/core'; +import { Component, EventEmitter, forwardRef, Input, OnInit, Output } from '@angular/core'; import { AbstractControl, ControlValueAccessor, @@ -57,6 +57,12 @@ export class Lwm2mBootstrapConfigServersComponent implements OnInit, ControlValu @Input() disabled: boolean; + @Input() + isTransportWasRunWithBootstrap: boolean; + + @Output() + isTransportWasRunWithBootstrapChange = new EventEmitter(); + public isBootstrapServerUpdateEnableValue: boolean; @Input() set isBootstrapServerUpdateEnable(value: boolean) { @@ -147,7 +153,7 @@ export class Lwm2mBootstrapConfigServersComponent implements OnInit, ControlValu } addServerConfig(): void { - const addDialogObs = (this.isBootstrapAdded() || !this.isBootstrapServerUpdateEnableValue) ? of(false) : + const addDialogObs = this.isBootstrapServerNotAvailable() ? of(false) : this.matDialog.open(Lwm2mBootstrapAddConfigServerDialogComponent, { disableClose: true, panelClass: ['tb-dialog', 'tb-fullscreen-dialog'] @@ -165,10 +171,18 @@ export class Lwm2mBootstrapConfigServersComponent implements OnInit, ControlValu serverConfig.securityMode = Lwm2mSecurityType.NO_SEC; this.serverConfigsFromArray().push(this.fb.control(serverConfig)); this.updateModel(); + } else { + this.isTransportWasRunWithBootstrap = false; + this.isTransportWasRunWithBootstrapChange.emit(this.isTransportWasRunWithBootstrap); } }); } + updateIsTransportWasRunWithBootstrap(newValue: boolean): void { + this.isTransportWasRunWithBootstrap = newValue; + this.isTransportWasRunWithBootstrapChange.emit(this.isTransportWasRunWithBootstrap); + } + public validate(c: FormControl) { return (this.bootstrapConfigServersFormGroup.valid) ? null : { serverConfigs: { @@ -177,7 +191,11 @@ export class Lwm2mBootstrapConfigServersComponent implements OnInit, ControlValu }; } - public isBootstrapAdded() { + public isBootstrapServerNotAvailable(): boolean { + return this.isBootstrapAdded() || !this.isBootstrapServerUpdateEnableValue || !this.isTransportWasRunWithBootstrap; + } + + private isBootstrapAdded(): boolean { const serverConfigsArray = this.serverConfigsFromArray().getRawValue(); for (let i = 0; i < serverConfigsArray.length; i++) { if (serverConfigsArray[i].bootstrapServerIs) { diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-config-server.component.ts b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-config-server.component.ts index c92cf9ef45..fa6d31153c 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-config-server.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-config-server.component.ts @@ -71,10 +71,14 @@ export class Lwm2mDeviceConfigServerComponent implements OnInit, ControlValueAcc credentialTypeLwM2MNamesMap = Lwm2mSecurityTypeTranslationMap; publicKeyOrIdTooltipNamesMap = Lwm2mPublicKeyOrIdTooltipTranslationsMap; currentSecurityMode = null; + bootstrapDisabled = false; @Output() removeServer = new EventEmitter(); + @Output() + isTransportWasRunWithBootstrapChange = new EventEmitter(); + private propagateChange = (v: any) => { }; constructor(public fb: FormBuilder, @@ -136,6 +140,11 @@ export class Lwm2mDeviceConfigServerComponent implements OnInit, ControlValueAcc if (!serverData) { this.serverFormGroup.patchValue(value); } + if (!value && this.serverFormGroup.get('bootstrapServerIs').value === true) { + this.isTransportWasRunWithBootstrapChange.emit(false); + this.bootstrapDisabled = true; + this.serverFormGroup.get('securityMode').disable({emitEvent: false}); + } }); } } @@ -150,6 +159,9 @@ export class Lwm2mDeviceConfigServerComponent implements OnInit, ControlValueAcc this.serverFormGroup.disable({emitEvent: false}); } else { this.serverFormGroup.enable({emitEvent: false}); + if (this.bootstrapDisabled) { + this.serverFormGroup.get('securityMode').disable({emitEvent: false}); + } } } diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.html b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.html index 05643ae497..4133600ba8 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.html +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.html @@ -33,12 +33,17 @@
+
+ warning + LwM2M transport was run without bootstrap server +
{{ 'device-profile.lwm2m.include-bootstrap-server' | translate }}
+ [isBootstrapServerUpdateEnable]="isBootstrapServerUpdateEnable" + [(isTransportWasRunWithBootstrap)]="isTransportWasRunWithBootstrap">
diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts index d8fc933fdb..7da250fa4e 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts @@ -74,6 +74,7 @@ import { TranslateService } from '@ngx-translate/core'; export class Lwm2mDeviceProfileTransportConfigurationComponent implements ControlValueAccessor, Validator, OnDestroy { public disabled = false; + public isTransportWasRunWithBootstrap = true; public isBootstrapServerUpdateEnable: boolean; private requiredValue: boolean; private destroy$ = new Subject(); @@ -226,10 +227,16 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro } private async defaultProfileConfig(): Promise { - const lwm2m: ServerSecurityConfig = await this.deviceProfileService.getLwm2mBootstrapSecurityInfoBySecurityType(false).toPromise(); + let lwm2m: ServerSecurityConfig; + let bootstrap: ServerSecurityConfig; + [bootstrap, lwm2m] = await Promise.all([ + this.deviceProfileService.getLwm2mBootstrapSecurityInfoBySecurityType(true).toPromise(), + this.deviceProfileService.getLwm2mBootstrapSecurityInfoBySecurityType(false).toPromise(), + ]); if (lwm2m) { lwm2m.securityMode = Lwm2mSecurityType.NO_SEC; } + this.isTransportWasRunWithBootstrap = !!bootstrap; this.configurationValue.bootstrap = [lwm2m]; this.lwm2mDeviceProfileFormGroup.patchValue({ bootstrap: this.configurationValue.bootstrap From 24f50dee33c1b53933ca0ec0938892fa527aebf1 Mon Sep 17 00:00:00 2001 From: "T. Langhorst" <71644972+megla-tlanghorst@users.noreply.github.com> Date: Wed, 15 Dec 2021 12:34:25 +0100 Subject: [PATCH 252/432] Upgrade log4j artifacts to 2.16 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index af4180baab..182491d4f8 100755 --- a/pom.xml +++ b/pom.xml @@ -47,7 +47,7 @@ 3.3.0 0.7.0 1.7.32 - 2.15.0 + 2.16.0 1.2.6 0.10 4.10.0 From 2570f22c17546f3976c3de9ee0c192cdf0396dc5 Mon Sep 17 00:00:00 2001 From: Sergey Tarnavskiy Date: Wed, 15 Dec 2021 13:37:23 +0200 Subject: [PATCH 253/432] Fixed minor grammatical error --- ui-ngx/src/assets/locale/locale.constant-en_US.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui-ngx/src/assets/locale/locale.constant-en_US.json b/ui-ngx/src/assets/locale/locale.constant-en_US.json index b9ca3a3ad7..1bd054fb26 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -1345,7 +1345,7 @@ "tqs": "TQS: both TCP and SMS connections active; TCP in queue mode, SMS in standard mode (is not supported since LWM2M 1.1)", "sq": "SQ: SMS connection in queue mode (is not supported since LWM2M 1.1)" }, - "binding-tooltip": "Tis is the list in the\"binding\" resource of the LwM2M server object - /1/x/7.\nIndicates the supported binding modes in the LwM2M Client.\nThis value SHOULD be the same as the value in the “Supported Binding and Modes” resource in the Device Object (/3/0/16).\nWhile multiple transports are supported, only one transport binding can be used during the entire Transport Session.\nAs an example, when UDP and SMS are both supported, the LwM2M Client and the LwM2M Server can choose to communicate either over UDP or SMS during the entire Transport Session.", + "binding-tooltip": "This is the list in the\"binding\" resource of the LwM2M server object - /1/x/7.\nIndicates the supported binding modes in the LwM2M Client.\nThis value SHOULD be the same as the value in the “Supported Binding and Modes” resource in the Device Object (/3/0/16).\nWhile multiple transports are supported, only one transport binding can be used during the entire Transport Session.\nAs an example, when UDP and SMS are both supported, the LwM2M Client and the LwM2M Server can choose to communicate either over UDP or SMS during the entire Transport Session.", "bootstrap-server": "Bootstrap Server", "lwm2m-server": "LwM2M Server", "include-bootstrap-server": "Include Bootstrap Server updates", From 84e02f05fdab8811d0e64a698f8fbaec7ebe7652 Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Wed, 15 Dec 2021 17:01:03 +0200 Subject: [PATCH 254/432] UI: Fixed incorrect work buttons in fullscreen mode at json-form --- .../json-form/json-form.component.html | 3 +- .../json-form/json-form.component.ts | 11 +- .../json-form/react/json-form-ace-editor.tsx | 109 +++++++++--------- .../json-form/react/json-form-schema-form.tsx | 4 +- .../json-form/react/json-form.models.ts | 2 +- 5 files changed, 67 insertions(+), 62 deletions(-) diff --git a/ui-ngx/src/app/shared/components/json-form/json-form.component.html b/ui-ngx/src/app/shared/components/json-form/json-form.component.html index 85bb0a71b8..e709307e90 100644 --- a/ui-ngx/src/app/shared/components/json-form/json-form.component.html +++ b/ui-ngx/src/app/shared/components/json-form/json-form.component.html @@ -15,8 +15,9 @@ limitations under the License. --> -
+
diff --git a/ui-ngx/src/app/shared/components/json-form/json-form.component.ts b/ui-ngx/src/app/shared/components/json-form/json-form.component.ts index fa8b9b3427..5d28c12247 100644 --- a/ui-ngx/src/app/shared/components/json-form/json-form.component.ts +++ b/ui-ngx/src/app/shared/components/json-form/json-form.component.ts @@ -73,6 +73,9 @@ export class JsonFormComponent implements OnInit, ControlValueAccessor, Validato @ViewChild('reactRoot', {static: true}) reactRootElmRef: ElementRef; + @ViewChild('reactFullscreen', {static: true}) + reactFullscreenElmRef: ElementRef; + private readonlyValue: boolean; get readonly(): boolean { return this.readonlyValue; @@ -106,8 +109,7 @@ export class JsonFormComponent implements OnInit, ControlValueAccessor, Validato isModelValid = true; isFullscreen = false; - targetFullscreenElement: HTMLElement; - fullscreenFinishFn: () => void; + fullscreenFinishFn: (el: Element) => void; private propagateChange = null; private propagateChangePending = false; @@ -233,8 +235,7 @@ export class JsonFormComponent implements OnInit, ControlValueAccessor, Validato }); } - private onToggleFullscreen(element: HTMLElement, fullscreenFinishFn?: () => void) { - this.targetFullscreenElement = element; + private onToggleFullscreen(fullscreenFinishFn?: (el: Element) => void) { this.isFullscreen = !this.isFullscreen; this.fullscreenFinishFn = fullscreenFinishFn; this.cd.markForCheck(); @@ -244,7 +245,7 @@ export class JsonFormComponent implements OnInit, ControlValueAccessor, Validato this.formProps.isFullscreen = fullscreen; this.renderReactSchemaForm(false); if (this.fullscreenFinishFn) { - this.fullscreenFinishFn(); + this.fullscreenFinishFn(this.reactFullscreenElmRef.nativeElement); this.fullscreenFinishFn = null; } } diff --git a/ui-ngx/src/app/shared/components/json-form/react/json-form-ace-editor.tsx b/ui-ngx/src/app/shared/components/json-form/react/json-form-ace-editor.tsx index 12879d1fae..1ae375908f 100644 --- a/ui-ngx/src/app/shared/components/json-form/react/json-form-ace-editor.tsx +++ b/ui-ngx/src/app/shared/components/json-form/react/json-form-ace-editor.tsx @@ -14,6 +14,7 @@ * limitations under the License. */ import * as React from 'react'; +import * as ReactDOM from 'react-dom'; import ThingsboardBaseComponent from './json-form-base-component'; import reactCSS from 'reactcss'; import Button from '@material-ui/core/Button'; @@ -42,6 +43,7 @@ interface ThingsboardAceEditorProps extends JsonFormFieldProps { interface ThingsboardAceEditorState extends JsonFormFieldState { isFull: boolean; + fullscreenContainerElement: Element; helpVisible: boolean; helpReady: boolean; focused: boolean; @@ -49,7 +51,6 @@ interface ThingsboardAceEditorState extends JsonFormFieldState { class ThingsboardAceEditor extends React.Component { - hostElement: HTMLElement; private aceEditor: IEditorProps; constructor(props) { @@ -64,6 +65,7 @@ class ThingsboardAceEditor extends React.Component { - if (this.aceEditor) { - this.aceEditor.resize(); - this.aceEditor.renderer.updateFull(); - } + this.props.onToggleFullscreen((el) => { + this.setState({ isFull: !this.state.isFull, fullscreenContainerElement: el }); }); } @@ -177,56 +175,61 @@ class ThingsboardAceEditor extends React.Component -
(this.hostElement = c)}> -
- -
-
- - { this.props.onTidy ? : null } - { this.props.form.helpId ?
- - {this.state.helpVisible ? : } - - { this.state.helpVisible && !this.state.helpReady ? -
- -
: null }
: null } - -
- Loading...
}> - - -
-
{this.props.error}
+ const formDom = ( +
+ +
+
+ + { this.props.onTidy ? : null } + { this.props.form.helpId ?
+ + {this.state.helpVisible ? : } + + { this.state.helpVisible && !this.state.helpReady ? +
+ +
: null }
: null } +
+ Loading...
}> + +
+
{this.props.error}
); + if (this.state.isFull) { + return ReactDOM.createPortal(formDom, this.state.fullscreenContainerElement); + } else { + return ( +
+ {formDom} +
+ ); + } } } diff --git a/ui-ngx/src/app/shared/components/json-form/react/json-form-schema-form.tsx b/ui-ngx/src/app/shared/components/json-form/react/json-form-schema-form.tsx index 782ac11ef8..e600e8b6fa 100644 --- a/ui-ngx/src/app/shared/components/json-form/react/json-form-schema-form.tsx +++ b/ui-ngx/src/app/shared/components/json-form/react/json-form-schema-form.tsx @@ -106,8 +106,8 @@ class ThingsboardSchemaForm extends React.Component { this.props.onIconClick(key, val, iconSelectedFn); } - onToggleFullscreen(element: HTMLElement, fullscreenFinishFn?: () => void) { - this.props.onToggleFullscreen(element, fullscreenFinishFn); + onToggleFullscreen(fullscreenFinishFn?: (el: Element) => void) { + this.props.onToggleFullscreen(fullscreenFinishFn); } onHelpClick(event: MouseEvent, helpId: string, helpVisibleFn: (visible: boolean) => void, helpReadyFn: (ready: boolean) => void) { diff --git a/ui-ngx/src/app/shared/components/json-form/react/json-form.models.ts b/ui-ngx/src/app/shared/components/json-form/react/json-form.models.ts index e36b36010b..b170bacb28 100644 --- a/ui-ngx/src/app/shared/components/json-form/react/json-form.models.ts +++ b/ui-ngx/src/app/shared/components/json-form/react/json-form.models.ts @@ -48,7 +48,7 @@ export type OnColorClickFn = (key: (string | number)[], val: tinycolor.ColorForm colorSelectedFn: (color: tinycolor.ColorFormats.RGBA) => void) => void; export type OnIconClickFn = (key: (string | number)[], val: string, iconSelectedFn: (icon: string) => void) => void; -export type onToggleFullscreenFn = (element: HTMLElement, fullscreenFinishFn?: () => void) => void; +export type onToggleFullscreenFn = (fullscreenFinishFn?: (el: Element) => void) => void; export type onHelpClickFn = (event: MouseEvent, helpId: string, helpVisibleFn: (visible: boolean) => void, helpReadyFn: (ready: boolean) => void) => void; From 14f4f10a952692889f764d75fd58264e35346f9d Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Wed, 15 Dec 2021 18:01:29 +0200 Subject: [PATCH 255/432] Update protobuf, grpc and netty versions --- pom.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index af4180baab..b6632542a4 100755 --- a/pom.xml +++ b/pom.xml @@ -74,11 +74,11 @@ 1.6.2 4.2.0 3.5.5 - 3.17.2 - 1.42.1 + 3.19.1 + 1.43.0 1.18.18 1.2.4 - 4.1.71.Final + 4.1.72.Final 2.0.46.Final 1.7.0 4.8.0 From 52a63b035f29338241d86838d60578d2a2f381c4 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Wed, 15 Dec 2021 19:23:09 +0200 Subject: [PATCH 256/432] Revert versions --- pom.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index b6632542a4..af4180baab 100755 --- a/pom.xml +++ b/pom.xml @@ -74,11 +74,11 @@ 1.6.2 4.2.0 3.5.5 - 3.19.1 - 1.43.0 + 3.17.2 + 1.42.1 1.18.18 1.2.4 - 4.1.72.Final + 4.1.71.Final 2.0.46.Final 1.7.0 4.8.0 From f2d6ed1e8570b405ce40249585aa36334184d3f5 Mon Sep 17 00:00:00 2001 From: desoliture Date: Thu, 16 Dec 2021 10:39:01 +0200 Subject: [PATCH 257/432] refactoring --- .../service/security/system/DefaultSystemSecurityService.java | 2 +- .../server/common/data/security/model/UserPasswordPolicy.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/security/system/DefaultSystemSecurityService.java b/application/src/main/java/org/thingsboard/server/service/security/system/DefaultSystemSecurityService.java index 26f6dbab65..aaf6fecd9b 100644 --- a/application/src/main/java/org/thingsboard/server/service/security/system/DefaultSystemSecurityService.java +++ b/application/src/main/java/org/thingsboard/server/service/security/system/DefaultSystemSecurityService.java @@ -175,7 +175,7 @@ public class DefaultSystemSecurityService implements SystemSecurityService { if (isPositiveInteger(passwordPolicy.getMinimumSpecialCharacters())) { passwordRules.add(new CharacterRule(EnglishCharacterData.Special, passwordPolicy.getMinimumSpecialCharacters())); } - if (!passwordPolicy.getAllowWhitespaces()) { + if (passwordPolicy.getAllowWhitespaces() != null && !passwordPolicy.getAllowWhitespaces()) { passwordRules.add(new WhitespaceRule()); } PasswordValidator validator = new PasswordValidator(passwordRules); diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/security/model/UserPasswordPolicy.java b/common/data/src/main/java/org/thingsboard/server/common/data/security/model/UserPasswordPolicy.java index 1e4aeb0055..7201df78b5 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/security/model/UserPasswordPolicy.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/security/model/UserPasswordPolicy.java @@ -35,7 +35,7 @@ public class UserPasswordPolicy implements Serializable { private Integer minimumDigits; @ApiModelProperty(position = 1, value = "Minimum number of special in the password." ) private Integer minimumSpecialCharacters; - @ApiModelProperty(position = 1, value = "Allow white-spaces") + @ApiModelProperty(position = 1, value = "Allow whitespaces") private Boolean allowWhitespaces = true; @ApiModelProperty(position = 1, value = "Password expiration period (days). Force expiration of the password." ) From e2155deeedabbd3a33057c5e86ed54c20344d2d6 Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Thu, 16 Dec 2021 11:58:23 +0200 Subject: [PATCH 258/432] cache specs environments for CE added --- .../src/main/resources/thingsboard.yml | 60 +++++++++---------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index e0f45be7dc..3932ca28a9 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -380,50 +380,50 @@ cache: caffeine: specs: relations: - timeToLiveInMinutes: 1440 - maxSize: 10000 # maxSize: 0 means the cache is disabled + timeToLiveInMinutes: "${CACHE_SPECS_RELATIONS_TTL:1440}" + maxSize: "${CACHE_SPECS_RELATIONS_MAX_SIZE:10000}" # maxSize: 0 means the cache is disabled deviceCredentials: - timeToLiveInMinutes: 1440 - maxSize: 10000 + timeToLiveInMinutes: "${CACHE_SPECS_DEVICE_CREDENTIALS_TTL:1440}" + maxSize: "${CACHE_SPECS_DEVICE_CREDENTIALS_MAX_SIZE:10000}" devices: - timeToLiveInMinutes: 1440 - maxSize: 10000 + timeToLiveInMinutes: "${CACHE_SPECS_DEVICES_TTL:1440}" + maxSize: "${CACHE_SPECS_DEVICES_MAX_SIZE:10000}" sessions: - timeToLiveInMinutes: 1440 - maxSize: 10000 + timeToLiveInMinutes: "${CACHE_SPECS_SESSIONS_TTL:1440}" + maxSize: "${CACHE_SPECS_SESSIONS_MAX_SIZE:10000}" assets: - timeToLiveInMinutes: 1440 - maxSize: 10000 + timeToLiveInMinutes: "${CACHE_SPECS_ASSETS_TTL:1440}" + maxSize: "${CACHE_SPECS_ASSETS_MAX_SIZE:10000}" entityViews: - timeToLiveInMinutes: 1440 - maxSize: 10000 + timeToLiveInMinutes: "${CACHE_SPECS_ENTITY_VIEWS_TTL:1440}" + maxSize: "${CACHE_SPECS_ENTITY_VIEWS_MAX_SIZE:10000}" claimDevices: - timeToLiveInMinutes: 1440 - maxSize: 1000 + timeToLiveInMinutes: "${CACHE_SPECS_CLAIM_DEVICES_TTL:1440}" + maxSize: "${CACHE_SPECS_CLAIM_DEVICES_MAX_SIZE:1000}" securitySettings: - timeToLiveInMinutes: 1440 - maxSize: 10000 + timeToLiveInMinutes: "${CACHE_SPECS_SECURITY_SETTINGS_TTL:1440}" + maxSize: "${CACHE_SPECS_SECURITY_SETTINGS_MAX_SIZE:10000}" tenantProfiles: - timeToLiveInMinutes: 1440 - maxSize: 10000 + timeToLiveInMinutes: "${CACHE_SPECS_TENANT_PROFILES_TTL:1440}" + maxSize: "${CACHE_SPECS_TENANT_PROFILES_MAX_SIZE:10000}" deviceProfiles: - timeToLiveInMinutes: 1440 - maxSize: 10000 + timeToLiveInMinutes: "${CACHE_SPECS_DEVICE_PROFILES_TTL:1440}" + maxSize: "${CACHE_SPECS_DEVICE_PROFILES_MAX_SIZE:10000}" attributes: - timeToLiveInMinutes: 1440 - maxSize: 100000 + timeToLiveInMinutes: "${CACHE_SPECS_ATTRIBUTES_TTL:1440}" + maxSize: "${CACHE_SPECS_ATTRIBUTES_MAX_SIZE:100000}" tokensOutdatageTime: - timeToLiveInMinutes: 20000 - maxSize: 10000 + timeToLiveInMinutes: "${CACHE_SPECS_TOKENS_OUTDATAGE_TIME_TTL:20000}" + maxSize: "${CACHE_SPECS_TOKENS_OUTDATAGE_TIME_MAX_SIZE:10000}" otaPackages: - timeToLiveInMinutes: 60 - maxSize: 10 + timeToLiveInMinutes: "${CACHE_SPECS_OTA_PACKAGES_TTL:60}" + maxSize: "${CACHE_SPECS_OTA_PACKAGES_MAX_SIZE:10}" otaPackagesData: - timeToLiveInMinutes: 60 - maxSize: 10 + timeToLiveInMinutes: "${CACHE_SPECS_OTA_PACKAGES_DATA_TTL:60}" + maxSize: "${CACHE_SPECS_OTA_PACKAGES_DATA_MAX_SIZE:10}" edges: - timeToLiveInMinutes: 1440 - maxSize: 10000 + timeToLiveInMinutes: "${CACHE_SPECS_EDGES_TTL:1440}" + maxSize: "${CACHE_SPECS_EDGES_MAX_SIZE:10000}" redis: # standalone or cluster From 99cff0225613aac93a334cbfddd172ae906aac62 Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Thu, 16 Dec 2021 13:25:47 +0200 Subject: [PATCH 259/432] device actor - CPU overhead reduce for local cache - do not dump/restore device session for local cache. Test added for Actor system context init, default values supplied to simplify testing. --- .../server/actors/ActorSystemContext.java | 41 ++- .../device/DeviceActorMessageProcessor.java | 6 + .../server/actors/ActorSystemContextTest.java | 257 ++++++++++++++++++ 3 files changed, 290 insertions(+), 14 deletions(-) create mode 100644 application/src/test/java/org/thingsboard/server/actors/ActorSystemContextTest.java diff --git a/application/src/main/java/org/thingsboard/server/actors/ActorSystemContext.java b/application/src/main/java/org/thingsboard/server/actors/ActorSystemContext.java index 6eaddc768a..b9eca74bdf 100644 --- a/application/src/main/java/org/thingsboard/server/actors/ActorSystemContext.java +++ b/application/src/main/java/org/thingsboard/server/actors/ActorSystemContext.java @@ -36,6 +36,7 @@ import org.thingsboard.rule.engine.api.SmsService; import org.thingsboard.rule.engine.api.sms.SmsSenderFactory; import org.thingsboard.server.actors.service.ActorService; import org.thingsboard.server.actors.tenant.DebugTbRateLimits; +import org.thingsboard.server.cluster.TbClusterService; import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.Event; import org.thingsboard.server.common.data.id.EntityId; @@ -82,7 +83,6 @@ import org.thingsboard.server.service.executors.ExternalCallExecutorService; import org.thingsboard.server.service.executors.SharedEventLoopGroupService; import org.thingsboard.server.service.mail.MailExecutorService; import org.thingsboard.server.service.profile.TbDeviceProfileCache; -import org.thingsboard.server.cluster.TbClusterService; import org.thingsboard.server.service.rpc.TbCoreDeviceRpcService; import org.thingsboard.server.service.rpc.TbRpcService; import org.thingsboard.server.service.rpc.TbRuleEngineDeviceRpcService; @@ -95,6 +95,7 @@ import org.thingsboard.server.service.telemetry.TelemetrySubscriptionService; import org.thingsboard.server.service.transport.TbCoreToTransportService; import javax.annotation.Nullable; +import javax.annotation.PostConstruct; import java.io.IOException; import java.io.PrintWriter; import java.io.StringWriter; @@ -333,30 +334,42 @@ public class ActorSystemContext { @Getter private long maxConcurrentSessionsPerDevice; - @Value("${actors.session.sync.timeout}") + @Value("${actors.session.sync.timeout:10000}") @Getter private long syncSessionTimeout; - @Value("${actors.rule.chain.error_persist_frequency}") + @Value("${actors.rule.chain.error_persist_frequency:3000}") @Getter private long ruleChainErrorPersistFrequency; - @Value("${actors.rule.node.error_persist_frequency}") + @Value("${actors.rule.node.error_persist_frequency:3000}") @Getter private long ruleNodeErrorPersistFrequency; - @Value("${actors.statistics.enabled}") + @Value("${actors.statistics.enabled:true}") @Getter private boolean statisticsEnabled; - @Value("${actors.statistics.persist_frequency}") + @Value("${actors.statistics.persist_frequency:3600000}") @Getter private long statisticsPersistFrequency; - @Value("${edges.enabled}") + @Value("${edges.enabled:true}") @Getter private boolean edgesEnabled; + @Value("${cache.type:caffeine}") + @Getter + private String cacheType; + + @Getter + private boolean localCacheType; + + @PostConstruct + public void init() { + this.localCacheType = "caffeine".equals(cacheType); + } + @Scheduled(fixedDelayString = "${actors.statistics.js_print_interval_ms}") public void printStats() { if (statisticsEnabled) { @@ -368,31 +381,31 @@ public class ActorSystemContext { } } - @Value("${actors.tenant.create_components_on_init}") + @Value("${actors.tenant.create_components_on_init:true}") @Getter private boolean tenantComponentsInitEnabled; - @Value("${actors.rule.allow_system_mail_service}") + @Value("${actors.rule.allow_system_mail_service:true}") @Getter private boolean allowSystemMailService; - @Value("${actors.rule.allow_system_sms_service}") + @Value("${actors.rule.allow_system_sms_service:true}") @Getter private boolean allowSystemSmsService; - @Value("${transport.sessions.inactivity_timeout}") + @Value("${transport.sessions.inactivity_timeout:300000}") @Getter private long sessionInactivityTimeout; - @Value("${transport.sessions.report_timeout}") + @Value("${transport.sessions.report_timeout:3000}") @Getter private long sessionReportTimeout; - @Value("${actors.rule.chain.debug_mode_rate_limits_per_tenant.enabled}") + @Value("${actors.rule.chain.debug_mode_rate_limits_per_tenant.enabled:true}") @Getter private boolean debugPerTenantEnabled; - @Value("${actors.rule.chain.debug_mode_rate_limits_per_tenant.configuration}") + @Value("${actors.rule.chain.debug_mode_rate_limits_per_tenant.configuration:50000:3600}") @Getter private String debugPerTenantLimitsConfiguration; diff --git a/application/src/main/java/org/thingsboard/server/actors/device/DeviceActorMessageProcessor.java b/application/src/main/java/org/thingsboard/server/actors/device/DeviceActorMessageProcessor.java index 41d99a682b..20109ad074 100644 --- a/application/src/main/java/org/thingsboard/server/actors/device/DeviceActorMessageProcessor.java +++ b/application/src/main/java/org/thingsboard/server/actors/device/DeviceActorMessageProcessor.java @@ -871,6 +871,9 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { } void restoreSessions() { + if (systemContext.isLocalCacheType()) { + return; + } log.debug("[{}] Restoring sessions from cache", deviceId); DeviceSessionsCacheEntry sessionsDump = null; try { @@ -905,6 +908,9 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { } private void dumpSessions() { + if (systemContext.isLocalCacheType()) { + return; + } log.debug("[{}] Dumping sessions: {}, rpc subscriptions: {}, attribute subscriptions: {} to cache", deviceId, sessions.size(), rpcSubscriptions.size(), attributeSubscriptions.size()); List sessionsList = new ArrayList<>(sessions.size()); sessions.forEach((uuid, sessionMD) -> { diff --git a/application/src/test/java/org/thingsboard/server/actors/ActorSystemContextTest.java b/application/src/test/java/org/thingsboard/server/actors/ActorSystemContextTest.java new file mode 100644 index 0000000000..35120a7460 --- /dev/null +++ b/application/src/test/java/org/thingsboard/server/actors/ActorSystemContextTest.java @@ -0,0 +1,257 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.actors; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.TestPropertySource; +import org.springframework.test.context.junit.jupiter.SpringExtension; +import org.thingsboard.rule.engine.api.MailService; +import org.thingsboard.rule.engine.api.SmsService; +import org.thingsboard.rule.engine.api.sms.SmsSenderFactory; +import org.thingsboard.server.actors.service.ActorService; +import org.thingsboard.server.cluster.TbClusterService; +import org.thingsboard.server.common.transport.util.DataDecodingEncodingService; +import org.thingsboard.server.dao.asset.AssetService; +import org.thingsboard.server.dao.attributes.AttributesService; +import org.thingsboard.server.dao.audit.AuditLogService; +import org.thingsboard.server.dao.cassandra.CassandraCluster; +import org.thingsboard.server.dao.customer.CustomerService; +import org.thingsboard.server.dao.dashboard.DashboardService; +import org.thingsboard.server.dao.device.ClaimDevicesService; +import org.thingsboard.server.dao.device.DeviceService; +import org.thingsboard.server.dao.edge.EdgeEventService; +import org.thingsboard.server.dao.edge.EdgeService; +import org.thingsboard.server.dao.entityview.EntityViewService; +import org.thingsboard.server.dao.event.EventService; +import org.thingsboard.server.dao.nosql.CassandraBufferedRateReadExecutor; +import org.thingsboard.server.dao.nosql.CassandraBufferedRateWriteExecutor; +import org.thingsboard.server.dao.ota.OtaPackageService; +import org.thingsboard.server.dao.relation.RelationService; +import org.thingsboard.server.dao.resource.ResourceService; +import org.thingsboard.server.dao.rule.RuleChainService; +import org.thingsboard.server.dao.rule.RuleNodeStateService; +import org.thingsboard.server.dao.tenant.TbTenantProfileCache; +import org.thingsboard.server.dao.tenant.TenantProfileService; +import org.thingsboard.server.dao.tenant.TenantService; +import org.thingsboard.server.dao.timeseries.TimeseriesService; +import org.thingsboard.server.dao.user.UserService; +import org.thingsboard.server.queue.discovery.PartitionService; +import org.thingsboard.server.queue.discovery.TbServiceInfoProvider; +import org.thingsboard.server.queue.usagestats.TbApiUsageClient; +import org.thingsboard.server.service.apiusage.TbApiUsageStateService; +import org.thingsboard.server.service.component.ComponentDiscoveryService; +import org.thingsboard.server.service.edge.rpc.EdgeRpcService; +import org.thingsboard.server.service.executors.DbCallbackExecutorService; +import org.thingsboard.server.service.executors.ExternalCallExecutorService; +import org.thingsboard.server.service.executors.SharedEventLoopGroupService; +import org.thingsboard.server.service.mail.MailExecutorService; +import org.thingsboard.server.service.profile.TbDeviceProfileCache; +import org.thingsboard.server.service.rpc.TbCoreDeviceRpcService; +import org.thingsboard.server.service.rpc.TbRpcService; +import org.thingsboard.server.service.rpc.TbRuleEngineDeviceRpcService; +import org.thingsboard.server.service.script.JsInvokeService; +import org.thingsboard.server.service.session.DeviceSessionCacheService; +import org.thingsboard.server.service.sms.SmsExecutorService; +import org.thingsboard.server.service.state.DeviceStateService; +import org.thingsboard.server.service.telemetry.AlarmSubscriptionService; +import org.thingsboard.server.service.telemetry.TelemetrySubscriptionService; +import org.thingsboard.server.service.transport.TbCoreToTransportService; + +import static org.assertj.core.api.Assertions.assertThat; + +@ExtendWith(SpringExtension.class) +@ContextConfiguration(classes = ActorSystemContext.class) +@EnableConfigurationProperties +@TestPropertySource(properties = { + "cache.type=caffeine", +}) +public class ActorSystemContextTest { + + @Autowired + ActorSystemContext ctx; + + @MockBean + private TbApiUsageStateService apiUsageStateService; + + @MockBean + private TbApiUsageClient apiUsageClient; + + @MockBean + private TbServiceInfoProvider serviceInfoProvider; + + @MockBean + private ActorService actorService; + + @MockBean + private ComponentDiscoveryService componentService; + + @MockBean + private DataDecodingEncodingService encodingService; + + @MockBean + private DeviceService deviceService; + + @MockBean + private TbTenantProfileCache tenantProfileCache; + + @MockBean + private TbDeviceProfileCache deviceProfileCache; + + @MockBean + private AssetService assetService; + + @MockBean + private DashboardService dashboardService; + + @MockBean + private TenantService tenantService; + + @MockBean + private TenantProfileService tenantProfileService; + + @MockBean + private CustomerService customerService; + + @MockBean + private UserService userService; + + @MockBean + private RuleChainService ruleChainService; + + @MockBean + private RuleNodeStateService ruleNodeStateService; + + @MockBean + private PartitionService partitionService; + + @MockBean + private TbClusterService clusterService; + + @MockBean + private TimeseriesService tsService; + + @MockBean + private AttributesService attributesService; + + @MockBean + private EventService eventService; + + @MockBean + private RelationService relationService; + + @MockBean + private AuditLogService auditLogService; + + @MockBean + private EntityViewService entityViewService; + + @MockBean + private TelemetrySubscriptionService tsSubService; + + @MockBean + private AlarmSubscriptionService alarmService; + + @MockBean + private JsInvokeService jsSandbox; + + @MockBean + private MailExecutorService mailExecutor; + + @MockBean + private SmsExecutorService smsExecutor; + + @MockBean + private DbCallbackExecutorService dbCallbackExecutor; + + @MockBean + private ExternalCallExecutorService externalCallExecutorService; + + @MockBean + private SharedEventLoopGroupService sharedEventLoopGroupService; + + @MockBean + private MailService mailService; + + @MockBean + private SmsService smsService; + + @MockBean + private SmsSenderFactory smsSenderFactory; + + @MockBean + private ClaimDevicesService claimDevicesService; + + @MockBean + private JsInvokeStats jsInvokeStats; + + @MockBean + private DeviceStateService deviceStateService; + + @MockBean + private DeviceSessionCacheService deviceSessionCacheService; + + @MockBean + private TbCoreToTransportService tbCoreToTransportService; + + @MockBean + private TbRuleEngineDeviceRpcService tbRuleEngineDeviceRpcService; + + @MockBean + private TbCoreDeviceRpcService tbCoreDeviceRpcService; + + @MockBean + private EdgeService edgeService; + + @MockBean + private EdgeEventService edgeEventService; + + @MockBean + private EdgeRpcService edgeRpcService; + + @MockBean + private ResourceService resourceService; + + @MockBean + private OtaPackageService otaPackageService; + + @MockBean + private TbRpcService tbRpcService; + + @MockBean + private CassandraCluster cassandraCluster; + + @MockBean + private CassandraBufferedRateReadExecutor cassandraBufferedRateReadExecutor; + + @MockBean + private CassandraBufferedRateWriteExecutor cassandraBufferedRateWriteExecutor; + + @MockBean + private RedisTemplate redisTemplate; + + @Test + void givenCaffeineCache_whenInit_thenIsLocalCacheTrue() { + assertThat(ctx.getCacheType()).isEqualTo("caffeine"); + assertThat(ctx.isLocalCacheType()).as("caffeine is the local cache type").isTrue(); + } + +} From 2d9c5e1924f3a11382af915b5888026484593684 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Thu, 16 Dec 2021 14:35:14 +0200 Subject: [PATCH 260/432] Update modules map --- ui-ngx/src/app/modules/common/modules-map.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/ui-ngx/src/app/modules/common/modules-map.ts b/ui-ngx/src/app/modules/common/modules-map.ts index 8404a03aa0..03ed0804bd 100644 --- a/ui-ngx/src/app/modules/common/modules-map.ts +++ b/ui-ngx/src/app/modules/common/modules-map.ts @@ -23,6 +23,7 @@ import * as AngularFlexLayoutFlex from '@angular/flex-layout/flex'; import * as AngularFlexLayoutGrid from '@angular/flex-layout/grid'; import * as AngularFlexLayoutExtended from '@angular/flex-layout/extended'; import * as AngularPlatformBrowser from '@angular/platform-browser'; +import * as AngularPlatformBrowserAnimations from '@angular/platform-browser/animations'; import * as AngularRouter from '@angular/router'; import * as AngularCdkCoercion from '@angular/cdk/coercion'; import * as AngularCdkCollections from '@angular/cdk/collections'; @@ -30,6 +31,8 @@ import * as AngularCdkKeycodes from '@angular/cdk/keycodes'; import * as AngularCdkLayout from '@angular/cdk/layout'; import * as AngularCdkOverlay from '@angular/cdk/overlay'; import * as AngularCdkPortal from '@angular/cdk/portal'; +import * as AngularCdkBidi from '@angular/cdk/bidi'; +import * as AngularCdkPlatform from '@angular/cdk/platform'; import * as AngularMaterialAutocomplete from '@angular/material/autocomplete'; import * as AngularMaterialBadge from '@angular/material/badge'; import * as AngularMaterialBottomSheet from '@angular/material/bottom-sheet'; @@ -73,6 +76,7 @@ import * as RxJs from 'rxjs'; import * as RxJsOperators from 'rxjs/operators'; import * as TranslateCore from '@ngx-translate/core'; import * as _moment from 'moment'; +import * as tslib from 'tslib'; import * as TbCore from '@core/public-api'; import * as TbShared from '@shared/public-api'; @@ -301,6 +305,7 @@ class ModulesMap implements IModulesMap { '@angular/flex-layout/grid': AngularFlexLayoutGrid, '@angular/flex-layout/extended': AngularFlexLayoutExtended, '@angular/platform-browser': AngularPlatformBrowser, + '@angular/platform-browser/animations': AngularPlatformBrowserAnimations, '@angular/router': AngularRouter, '@angular/cdk/coercion': AngularCdkCoercion, '@angular/cdk/collections': AngularCdkCollections, @@ -308,6 +313,8 @@ class ModulesMap implements IModulesMap { '@angular/cdk/layout': AngularCdkLayout, '@angular/cdk/overlay': AngularCdkOverlay, '@angular/cdk/portal': AngularCdkPortal, + '@angular/cdk/bidi': AngularCdkBidi, + '@angular/cdk/platform': AngularCdkPlatform, '@angular/cdk/drag-drop': DragDropModule, '@angular/material/autocomplete': AngularMaterialAutocomplete, '@angular/material/badge': AngularMaterialBadge, @@ -349,6 +356,7 @@ class ModulesMap implements IModulesMap { 'rxjs/operators': RxJsOperators, '@ngx-translate/core': TranslateCore, moment: _moment, + tslib, '@core/public-api': TbCore, '@shared/public-api': TbShared, From c5533d79d13610a160cc6ffd460de415dd93f40f Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Thu, 16 Dec 2021 15:19:30 +0200 Subject: [PATCH 261/432] Add minified version of rulenode UI js --- .../static/rulenode/rulenode-core-config.js | 4265 +---------------- 1 file changed, 1 insertion(+), 4264 deletions(-) diff --git a/rule-engine/rule-engine-components/src/main/resources/public/static/rulenode/rulenode-core-config.js b/rule-engine/rule-engine-components/src/main/resources/public/static/rulenode/rulenode-core-config.js index ae61853e4b..0720bb79c4 100644 --- a/rule-engine/rule-engine-components/src/main/resources/public/static/rulenode/rulenode-core-config.js +++ b/rule-engine/rule-engine-components/src/main/resources/public/static/rulenode/rulenode-core-config.js @@ -1,4264 +1 @@ -import * as i0 from '@angular/core'; -import { Component, Pipe, ViewChild, forwardRef, Input, NgModule } from '@angular/core'; -import * as i3$4 from '@shared/public-api'; -import { RuleNodeConfigurationComponent, AttributeScope, telemetryTypeTranslations, ServiceType, AlarmSeverity, alarmSeverityTranslations, EntitySearchDirection, entitySearchDirectionTranslations, EntityType, PageComponent, MessageType, messageTypeNames, SharedModule, AggregationType, aggregationTranslations, alarmStatusTranslations, AlarmStatus } from '@shared/public-api'; -import * as i1 from '@ngrx/store'; -import * as i2 from '@angular/forms'; -import { Validators, NgControl, NG_VALUE_ACCESSOR, NG_VALIDATORS, FormControl } from '@angular/forms'; -import * as i3 from '@angular/material/form-field'; -import * as i3$1 from '@angular/material/checkbox'; -import * as i8 from '@angular/flex-layout/flex'; -import * as i4 from '@ngx-translate/core'; -import * as i11 from '@angular/material/input'; -import * as i10 from '@angular/common'; -import { CommonModule } from '@angular/common'; -import * as i1$1 from '@angular/platform-browser'; -import * as i4$1 from '@angular/material/select'; -import * as i5 from '@angular/material/core'; -import * as i4$2 from '@angular/material/expansion'; -import * as i7 from '@shared/components/button/toggle-password.component'; -import * as i8$1 from '@shared/components/file-input.component'; -import * as i3$2 from '@shared/components/queue/queue-type-list.component'; -import * as i3$3 from '@core/public-api'; -import { isDefinedAndNotNull } from '@core/public-api'; -import * as i5$1 from '@shared/components/js-func.component'; -import * as i6 from '@angular/material/button'; -import { ENTER, COMMA, SEMICOLON } from '@angular/cdk/keycodes'; -import * as i5$2 from '@angular/material/chips'; -import * as i6$1 from '@angular/material/icon'; -import * as i7$1 from '@shared/components/entity/entity-type-select.component'; -import * as i6$2 from '@shared/components/entity/entity-select.component'; -import { coerceBooleanProperty } from '@angular/cdk/coercion'; -import * as i9 from '@shared/components/tb-error.component'; -import * as i9$1 from '@angular/flex-layout/extended'; -import * as i12 from '@angular/material/tooltip'; -import { distinctUntilChanged, startWith, map, mergeMap, share } from 'rxjs/operators'; -import * as i7$2 from '@shared/components/tb-checkbox.component'; -import * as i5$3 from '@home/components/sms/sms-provider-configuration.component'; -import { HomeComponentsModule } from '@home/components/public-api'; -import * as i7$3 from '@shared/components/relation/relation-type-autocomplete.component'; -import * as i8$2 from '@shared/components/entity/entity-subtype-list.component'; -import * as i7$4 from '@home/components/relation/relation-filters.component'; -import { of } from 'rxjs'; -import * as i7$5 from '@angular/material/autocomplete'; -import * as i12$1 from '@shared/pipe/highlight.pipe'; -import * as i8$3 from '@shared/components/entity/entity-autocomplete.component'; -import * as i3$5 from '@shared/components/entity/entity-type-list.component'; - -class EmptyConfigComponent extends RuleNodeConfigurationComponent { - constructor(store, fb) { - super(store); - this.store = store; - this.fb = fb; - } - configForm() { - return this.emptyConfigForm; - } - onConfigurationSet(configuration) { - this.emptyConfigForm = this.fb.group({}); - } -} -EmptyConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: EmptyConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); -EmptyConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: EmptyConfigComponent, selector: "tb-node-empty-config", usesInheritance: true, ngImport: i0, template: '
', isInline: true }); -i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: EmptyConfigComponent, decorators: [{ - type: Component, - args: [{ - selector: 'tb-node-empty-config', - template: '
', - styleUrls: [] - }] - }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); - -class SafeHtmlPipe { - constructor(sanitizer) { - this.sanitizer = sanitizer; - } - transform(html) { - return this.sanitizer.bypassSecurityTrustHtml(html); - } -} -SafeHtmlPipe.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: SafeHtmlPipe, deps: [{ token: i1$1.DomSanitizer }], target: i0.ɵɵFactoryTarget.Pipe }); -SafeHtmlPipe.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: SafeHtmlPipe, name: "safeHtml" }); -i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: SafeHtmlPipe, decorators: [{ - type: Pipe, - args: [{ - name: 'safeHtml', - }] - }], ctorParameters: function () { return [{ type: i1$1.DomSanitizer }]; } }); - -class AssignCustomerConfigComponent extends RuleNodeConfigurationComponent { - constructor(store, fb) { - super(store); - this.store = store; - this.fb = fb; - } - configForm() { - return this.assignCustomerConfigForm; - } - onConfigurationSet(configuration) { - this.assignCustomerConfigForm = this.fb.group({ - customerNamePattern: [configuration ? configuration.customerNamePattern : null, [Validators.required, Validators.pattern(/.*\S.*/)]], - createCustomerIfNotExists: [configuration ? configuration.createCustomerIfNotExists : false, []], - customerCacheExpiration: [configuration ? configuration.customerCacheExpiration : null, [Validators.required, Validators.min(0)]] - }); - } - prepareOutputConfig(configuration) { - configuration.customerNamePattern = configuration.customerNamePattern.trim(); - return configuration; - } -} -AssignCustomerConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: AssignCustomerConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); -AssignCustomerConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: AssignCustomerConfigComponent, selector: "tb-action-node-assign-to-customer-config", usesInheritance: true, ngImport: i0, template: "
\n \n tb.rulenode.customer-name-pattern\n \n \n {{ 'tb.rulenode.customer-name-pattern-required' | translate }}\n \n \n \n \n {{ 'tb.rulenode.create-customer-if-not-exists' | translate }}\n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ 'tb.rulenode.customer-cache-expiration-required' | translate }}\n \n \n {{ 'tb.rulenode.customer-cache-expiration-range' | translate }}\n \n tb.rulenode.customer-cache-expiration-hint\n \n
\n", components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }, { type: i3$1.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex", "aria-label", "aria-labelledby", "id", "labelPosition", "name", "required", "checked", "disabled", "indeterminate", "aria-describedby", "value"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.MatError, selector: "mat-error", inputs: ["id"] }, { type: i3.MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }, { type: i2.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { type: i2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }], pipes: { "translate": i4.TranslatePipe, "safeHtml": SafeHtmlPipe } }); -i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: AssignCustomerConfigComponent, decorators: [{ - type: Component, - args: [{ - selector: 'tb-action-node-assign-to-customer-config', - templateUrl: './assign-customer-config.component.html', - styleUrls: [] - }] - }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); - -class AttributesConfigComponent extends RuleNodeConfigurationComponent { - constructor(store, fb) { - super(store); - this.store = store; - this.fb = fb; - this.attributeScopes = Object.keys(AttributeScope); - this.telemetryTypeTranslationsMap = telemetryTypeTranslations; - } - configForm() { - return this.attributesConfigForm; - } - onConfigurationSet(configuration) { - this.attributesConfigForm = this.fb.group({ - scope: [configuration ? configuration.scope : null, [Validators.required]], - notifyDevice: [configuration ? configuration.scope : true, []] - }); - } -} -AttributesConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: AttributesConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); -AttributesConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: AttributesConfigComponent, selector: "tb-action-node-attributes-config", usesInheritance: true, ngImport: i0, template: "
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n \n {{ 'tb.rulenode.notify-device' | translate }}\n \n
tb.rulenode.notify-device-hint
\n
\n
\n", components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }, { type: i4$1.MatSelect, selector: "mat-select", inputs: ["disabled", "disableRipple", "tabIndex"], exportAs: ["matSelect"] }, { type: i5.MatOption, selector: "mat-option", exportAs: ["matOption"] }, { type: i3$1.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex", "aria-label", "aria-labelledby", "id", "labelPosition", "name", "required", "checked", "disabled", "indeterminate", "aria-describedby", "value"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i10.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], pipes: { "translate": i4.TranslatePipe } }); -i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: AttributesConfigComponent, decorators: [{ - type: Component, - args: [{ - selector: 'tb-action-node-attributes-config', - templateUrl: './attributes-config.component.html', - styleUrls: [] - }] - }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); - -var OriginatorSource; -(function (OriginatorSource) { - OriginatorSource["CUSTOMER"] = "CUSTOMER"; - OriginatorSource["TENANT"] = "TENANT"; - OriginatorSource["RELATED"] = "RELATED"; - OriginatorSource["ALARM_ORIGINATOR"] = "ALARM_ORIGINATOR"; -})(OriginatorSource || (OriginatorSource = {})); -const originatorSourceTranslations = new Map([ - [OriginatorSource.CUSTOMER, 'tb.rulenode.originator-customer'], - [OriginatorSource.TENANT, 'tb.rulenode.originator-tenant'], - [OriginatorSource.RELATED, 'tb.rulenode.originator-related'], - [OriginatorSource.ALARM_ORIGINATOR, 'tb.rulenode.originator-alarm-originator'], -]); -var PerimeterType; -(function (PerimeterType) { - PerimeterType["CIRCLE"] = "CIRCLE"; - PerimeterType["POLYGON"] = "POLYGON"; -})(PerimeterType || (PerimeterType = {})); -const perimeterTypeTranslations = new Map([ - [PerimeterType.CIRCLE, 'tb.rulenode.perimeter-circle'], - [PerimeterType.POLYGON, 'tb.rulenode.perimeter-polygon'], -]); -var TimeUnit; -(function (TimeUnit) { - TimeUnit["MILLISECONDS"] = "MILLISECONDS"; - TimeUnit["SECONDS"] = "SECONDS"; - TimeUnit["MINUTES"] = "MINUTES"; - TimeUnit["HOURS"] = "HOURS"; - TimeUnit["DAYS"] = "DAYS"; -})(TimeUnit || (TimeUnit = {})); -const timeUnitTranslations = new Map([ - [TimeUnit.MILLISECONDS, 'tb.rulenode.time-unit-milliseconds'], - [TimeUnit.SECONDS, 'tb.rulenode.time-unit-seconds'], - [TimeUnit.MINUTES, 'tb.rulenode.time-unit-minutes'], - [TimeUnit.HOURS, 'tb.rulenode.time-unit-hours'], - [TimeUnit.DAYS, 'tb.rulenode.time-unit-days'] -]); -var RangeUnit; -(function (RangeUnit) { - RangeUnit["METER"] = "METER"; - RangeUnit["KILOMETER"] = "KILOMETER"; - RangeUnit["FOOT"] = "FOOT"; - RangeUnit["MILE"] = "MILE"; - RangeUnit["NAUTICAL_MILE"] = "NAUTICAL_MILE"; -})(RangeUnit || (RangeUnit = {})); -const rangeUnitTranslations = new Map([ - [RangeUnit.METER, 'tb.rulenode.range-unit-meter'], - [RangeUnit.KILOMETER, 'tb.rulenode.range-unit-kilometer'], - [RangeUnit.FOOT, 'tb.rulenode.range-unit-foot'], - [RangeUnit.MILE, 'tb.rulenode.range-unit-mile'], - [RangeUnit.NAUTICAL_MILE, 'tb.rulenode.range-unit-nautical-mile'] -]); -var EntityDetailsField; -(function (EntityDetailsField) { - EntityDetailsField["TITLE"] = "TITLE"; - EntityDetailsField["COUNTRY"] = "COUNTRY"; - EntityDetailsField["STATE"] = "STATE"; - EntityDetailsField["CITY"] = "CITY"; - EntityDetailsField["ZIP"] = "ZIP"; - EntityDetailsField["ADDRESS"] = "ADDRESS"; - EntityDetailsField["ADDRESS2"] = "ADDRESS2"; - EntityDetailsField["PHONE"] = "PHONE"; - EntityDetailsField["EMAIL"] = "EMAIL"; - EntityDetailsField["ADDITIONAL_INFO"] = "ADDITIONAL_INFO"; -})(EntityDetailsField || (EntityDetailsField = {})); -const entityDetailsTranslations = new Map([ - [EntityDetailsField.TITLE, 'tb.rulenode.entity-details-title'], - [EntityDetailsField.COUNTRY, 'tb.rulenode.entity-details-country'], - [EntityDetailsField.STATE, 'tb.rulenode.entity-details-state'], - [EntityDetailsField.CITY, 'tb.rulenode.entity-details-city'], - [EntityDetailsField.ZIP, 'tb.rulenode.entity-details-zip'], - [EntityDetailsField.ADDRESS, 'tb.rulenode.entity-details-address'], - [EntityDetailsField.ADDRESS2, 'tb.rulenode.entity-details-address2'], - [EntityDetailsField.PHONE, 'tb.rulenode.entity-details-phone'], - [EntityDetailsField.EMAIL, 'tb.rulenode.entity-details-email'], - [EntityDetailsField.ADDITIONAL_INFO, 'tb.rulenode.entity-details-additional_info'] -]); -var FetchMode; -(function (FetchMode) { - FetchMode["FIRST"] = "FIRST"; - FetchMode["LAST"] = "LAST"; - FetchMode["ALL"] = "ALL"; -})(FetchMode || (FetchMode = {})); -var SamplingOrder; -(function (SamplingOrder) { - SamplingOrder["ASC"] = "ASC"; - SamplingOrder["DESC"] = "DESC"; -})(SamplingOrder || (SamplingOrder = {})); -var SqsQueueType; -(function (SqsQueueType) { - SqsQueueType["STANDARD"] = "STANDARD"; - SqsQueueType["FIFO"] = "FIFO"; -})(SqsQueueType || (SqsQueueType = {})); -const sqsQueueTypeTranslations = new Map([ - [SqsQueueType.STANDARD, 'tb.rulenode.sqs-queue-standard'], - [SqsQueueType.FIFO, 'tb.rulenode.sqs-queue-fifo'], -]); -const credentialsTypes = ['anonymous', 'basic', 'cert.PEM']; -const credentialsTypeTranslations = new Map([ - ['anonymous', 'tb.rulenode.credentials-anonymous'], - ['basic', 'tb.rulenode.credentials-basic'], - ['cert.PEM', 'tb.rulenode.credentials-pem'] -]); -const azureIotHubCredentialsTypes = ['sas', 'cert.PEM']; -const azureIotHubCredentialsTypeTranslations = new Map([ - ['sas', 'tb.rulenode.credentials-sas'], - ['cert.PEM', 'tb.rulenode.credentials-pem'] -]); -var HttpRequestType; -(function (HttpRequestType) { - HttpRequestType["GET"] = "GET"; - HttpRequestType["POST"] = "POST"; - HttpRequestType["PUT"] = "PUT"; - HttpRequestType["DELETE"] = "DELETE"; -})(HttpRequestType || (HttpRequestType = {})); -const ToByteStandartCharsetTypes = [ - 'US-ASCII', - 'ISO-8859-1', - 'UTF-8', - 'UTF-16BE', - 'UTF-16LE', - 'UTF-16' -]; -const ToByteStandartCharsetTypeTranslations = new Map([ - ['US-ASCII', 'tb.rulenode.charset-us-ascii'], - ['ISO-8859-1', 'tb.rulenode.charset-iso-8859-1'], - ['UTF-8', 'tb.rulenode.charset-utf-8'], - ['UTF-16BE', 'tb.rulenode.charset-utf-16be'], - ['UTF-16LE', 'tb.rulenode.charset-utf-16le'], - ['UTF-16', 'tb.rulenode.charset-utf-16'], -]); - -class AzureIotHubConfigComponent extends RuleNodeConfigurationComponent { - constructor(store, fb) { - super(store); - this.store = store; - this.fb = fb; - this.allAzureIotHubCredentialsTypes = azureIotHubCredentialsTypes; - this.azureIotHubCredentialsTypeTranslationsMap = azureIotHubCredentialsTypeTranslations; - } - configForm() { - return this.azureIotHubConfigForm; - } - onConfigurationSet(configuration) { - this.azureIotHubConfigForm = this.fb.group({ - topicPattern: [configuration ? configuration.topicPattern : null, [Validators.required]], - host: [configuration ? configuration.host : null, [Validators.required]], - port: [configuration ? configuration.port : null, [Validators.required, Validators.min(1), Validators.max(65535)]], - connectTimeoutSec: [configuration ? configuration.connectTimeoutSec : null, - [Validators.required, Validators.min(1), Validators.max(200)]], - clientId: [configuration ? configuration.clientId : null, [Validators.required]], - cleanSession: [configuration ? configuration.cleanSession : false, []], - ssl: [configuration ? configuration.ssl : false, []], - credentials: this.fb.group({ - type: [configuration && configuration.credentials ? configuration.credentials.type : null, [Validators.required]], - sasKey: [configuration && configuration.credentials ? configuration.credentials.sasKey : null, []], - caCert: [configuration && configuration.credentials ? configuration.credentials.caCert : null, []], - caCertFileName: [configuration && configuration.credentials ? configuration.credentials.caCertFileName : null, []], - privateKey: [configuration && configuration.credentials ? configuration.credentials.privateKey : null, []], - privateKeyFileName: [configuration && configuration.credentials ? configuration.credentials.privateKeyFileName : null, []], - cert: [configuration && configuration.credentials ? configuration.credentials.cert : null, []], - certFileName: [configuration && configuration.credentials ? configuration.credentials.certFileName : null, []], - password: [configuration && configuration.credentials ? configuration.credentials.password : null, []], - }) - }); - } - prepareOutputConfig(configuration) { - const credentialsType = configuration.credentials.type; - if (credentialsType === 'sas') { - configuration.credentials = { - type: credentialsType, - sasKey: configuration.credentials.sasKey, - caCert: configuration.credentials.caCert, - caCertFileName: configuration.credentials.caCertFileName - }; - } - return configuration; - } - validatorTriggers() { - return ['credentials.type']; - } - updateValidators(emitEvent) { - const credentialsControl = this.azureIotHubConfigForm.get('credentials'); - const credentialsType = credentialsControl.get('type').value; - if (emitEvent) { - credentialsControl.reset({ type: credentialsType }, { emitEvent: false }); - } - credentialsControl.get('sasKey').setValidators([]); - credentialsControl.get('privateKey').setValidators([]); - credentialsControl.get('privateKeyFileName').setValidators([]); - credentialsControl.get('cert').setValidators([]); - credentialsControl.get('certFileName').setValidators([]); - switch (credentialsType) { - case 'sas': - credentialsControl.get('sasKey').setValidators([Validators.required]); - break; - case 'cert.PEM': - credentialsControl.get('privateKey').setValidators([Validators.required]); - credentialsControl.get('privateKeyFileName').setValidators([Validators.required]); - credentialsControl.get('cert').setValidators([Validators.required]); - credentialsControl.get('certFileName').setValidators([Validators.required]); - break; - } - credentialsControl.get('sasKey').updateValueAndValidity({ emitEvent }); - credentialsControl.get('privateKey').updateValueAndValidity({ emitEvent }); - credentialsControl.get('privateKeyFileName').updateValueAndValidity({ emitEvent }); - credentialsControl.get('cert').updateValueAndValidity({ emitEvent }); - credentialsControl.get('certFileName').updateValueAndValidity({ emitEvent }); - } -} -AzureIotHubConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: AzureIotHubConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); -AzureIotHubConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: AzureIotHubConfigComponent, selector: "tb-action-node-azure-iot-hub-config", usesInheritance: true, ngImport: i0, template: "
\n \n tb.rulenode.topic\n \n \n {{ 'tb.rulenode.topic-required' | translate }}\n \n \n \n \n tb.rulenode.hostname\n \n \n {{ 'tb.rulenode.hostname-required' | translate }}\n \n \n \n tb.rulenode.device-id\n \n \n {{ 'tb.rulenode.device-id-required' | translate }}\n \n \n \n \n \n tb.rulenode.credentials\n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(azureIotHubConfigForm.get('credentials.type').value) | translate }}\n \n \n
\n \n tb.rulenode.credentials-type\n \n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ 'tb.rulenode.credentials-type-required' | translate }}\n \n \n
\n \n \n \n \n tb.rulenode.sas-key\n \n \n \n {{ 'tb.rulenode.sas-key-required' | translate }}\n \n \n \n \n \n \n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n \n
\n
\n
\n
\n
\n", styles: [":host .tb-mqtt-credentials-panel-group{margin:0 6px}:host .tb-hint.client-id{margin-top:-1.25em;max-width:-moz-fit-content;max-width:fit-content}\n"], components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }, { type: i4$2.MatExpansionPanel, selector: "mat-expansion-panel", inputs: ["disabled", "expanded", "hideToggle", "togglePosition"], outputs: ["opened", "closed", "expandedChange", "afterExpand", "afterCollapse"], exportAs: ["matExpansionPanel"] }, { type: i4$2.MatExpansionPanelHeader, selector: "mat-expansion-panel-header", inputs: ["tabIndex", "expandedHeight", "collapsedHeight"] }, { type: i4$1.MatSelect, selector: "mat-select", inputs: ["disabled", "disableRipple", "tabIndex"], exportAs: ["matSelect"] }, { type: i5.MatOption, selector: "mat-option", exportAs: ["matOption"] }, { type: i7.TogglePasswordComponent, selector: "tb-toggle-password" }, { type: i8$1.FileInputComponent, selector: "tb-file-input", inputs: ["label", "accept", "noFileText", "inputId", "allowedExtensions", "dropLabel", "contentConvertFunction", "required", "requiredAsError", "disabled", "existingFileName", "readAsBinary", "workFromFileObj", "multipleFile"], outputs: ["fileNameChanged"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.MatError, selector: "mat-error", inputs: ["id"] }, { type: i3.MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { type: i4$2.MatAccordion, selector: "mat-accordion", inputs: ["multi", "displayMode", "togglePosition", "hideToggle"], exportAs: ["matAccordion"] }, { type: i4$2.MatExpansionPanelTitle, selector: "mat-panel-title" }, { type: i4$2.MatExpansionPanelDescription, selector: "mat-panel-description" }, { type: i2.FormGroupName, selector: "[formGroupName]", inputs: ["formGroupName"] }, { type: i10.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i10.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { type: i10.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { type: i3.MatSuffix, selector: "[matSuffix]" }], pipes: { "translate": i4.TranslatePipe, "safeHtml": SafeHtmlPipe } }); -i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: AzureIotHubConfigComponent, decorators: [{ - type: Component, - args: [{ - selector: 'tb-action-node-azure-iot-hub-config', - templateUrl: './azure-iot-hub-config.component.html', - styleUrls: ['./mqtt-config.component.scss'] - }] - }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); - -class CheckPointConfigComponent extends RuleNodeConfigurationComponent { - constructor(store, fb) { - super(store); - this.store = store; - this.fb = fb; - this.serviceType = ServiceType.TB_RULE_ENGINE; - } - configForm() { - return this.checkPointConfigForm; - } - onConfigurationSet(configuration) { - this.checkPointConfigForm = this.fb.group({ - queueName: [configuration ? configuration.queueName : null, [Validators.required]] - }); - } -} -CheckPointConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: CheckPointConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); -CheckPointConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: CheckPointConfigComponent, selector: "tb-action-node-check-point-config", usesInheritance: true, ngImport: i0, template: "
\n \n \n
\n", components: [{ type: i3$2.QueueTypeListComponent, selector: "tb-queue-type-list", inputs: ["required", "disabled", "queueType"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }] }); -i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: CheckPointConfigComponent, decorators: [{ - type: Component, - args: [{ - selector: 'tb-action-node-check-point-config', - templateUrl: './check-point-config.component.html', - styleUrls: [] - }] - }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); - -class ClearAlarmConfigComponent extends RuleNodeConfigurationComponent { - constructor(store, fb, nodeScriptTestService, translate) { - super(store); - this.store = store; - this.fb = fb; - this.nodeScriptTestService = nodeScriptTestService; - this.translate = translate; - } - configForm() { - return this.clearAlarmConfigForm; - } - onConfigurationSet(configuration) { - this.clearAlarmConfigForm = this.fb.group({ - alarmDetailsBuildJs: [configuration ? configuration.alarmDetailsBuildJs : null, [Validators.required]], - alarmType: [configuration ? configuration.alarmType : null, [Validators.required]] - }); - } - testScript() { - const script = this.clearAlarmConfigForm.get('alarmDetailsBuildJs').value; - this.nodeScriptTestService.testNodeScript(script, 'json', this.translate.instant('tb.rulenode.details'), 'Details', ['msg', 'metadata', 'msgType'], this.ruleNodeId, 'rulenode/clear_alarm_node_script_fn').subscribe((theScript) => { - if (theScript) { - this.clearAlarmConfigForm.get('alarmDetailsBuildJs').setValue(theScript); - } - }); - } - onValidate() { - this.jsFuncComponent.validateOnSubmit(); - } -} -ClearAlarmConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: ClearAlarmConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }, { token: i3$3.NodeScriptTestService }, { token: i4.TranslateService }], target: i0.ɵɵFactoryTarget.Component }); -ClearAlarmConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: ClearAlarmConfigComponent, selector: "tb-action-node-clear-alarm-config", viewQueries: [{ propertyName: "jsFuncComponent", first: true, predicate: ["jsFuncComponent"], descendants: true, static: true }], usesInheritance: true, ngImport: i0, template: "
\n \n \n \n
\n \n
\n \n tb.rulenode.alarm-type\n \n \n {{ 'tb.rulenode.alarm-type-required' | translate }}\n \n \n \n
\n", components: [{ type: i5$1.JsFuncComponent, selector: "tb-js-func", inputs: ["functionName", "functionArgs", "validationArgs", "resultType", "disabled", "fillHeight", "editorCompleter", "globalVariables", "disableUndefinedCheck", "helpId", "noValidate", "required"] }, { type: i6.MatButton, selector: "button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }, { type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.MatError, selector: "mat-error", inputs: ["id"] }, { type: i3.MatHint, selector: "mat-hint", inputs: ["align", "id"] }], pipes: { "translate": i4.TranslatePipe, "safeHtml": SafeHtmlPipe } }); -i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: ClearAlarmConfigComponent, decorators: [{ - type: Component, - args: [{ - selector: 'tb-action-node-clear-alarm-config', - templateUrl: './clear-alarm-config.component.html', - styleUrls: [] - }] - }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }, { type: i3$3.NodeScriptTestService }, { type: i4.TranslateService }]; }, propDecorators: { jsFuncComponent: [{ - type: ViewChild, - args: ['jsFuncComponent', { static: true }] - }] } }); - -class CreateAlarmConfigComponent extends RuleNodeConfigurationComponent { - constructor(store, fb, nodeScriptTestService, translate) { - super(store); - this.store = store; - this.fb = fb; - this.nodeScriptTestService = nodeScriptTestService; - this.translate = translate; - this.alarmSeverities = Object.keys(AlarmSeverity); - this.alarmSeverityTranslationMap = alarmSeverityTranslations; - this.separatorKeysCodes = [ENTER, COMMA, SEMICOLON]; - } - configForm() { - return this.createAlarmConfigForm; - } - onConfigurationSet(configuration) { - this.createAlarmConfigForm = this.fb.group({ - alarmDetailsBuildJs: [configuration ? configuration.alarmDetailsBuildJs : null, [Validators.required]], - useMessageAlarmData: [configuration ? configuration.useMessageAlarmData : false, []], - alarmType: [configuration ? configuration.alarmType : null, []], - severity: [configuration ? configuration.severity : null, []], - propagate: [configuration ? configuration.propagate : false, []], - relationTypes: [configuration ? configuration.relationTypes : null, []], - dynamicSeverity: false - }); - this.createAlarmConfigForm.get('dynamicSeverity').valueChanges.subscribe((dynamicSeverity) => { - if (dynamicSeverity) { - this.createAlarmConfigForm.get('severity').patchValue('', { emitEvent: false }); - } - else { - this.createAlarmConfigForm.get('severity').patchValue(this.alarmSeverities[0], { emitEvent: false }); - } - }); - } - validatorTriggers() { - return ['useMessageAlarmData']; - } - updateValidators(emitEvent) { - const useMessageAlarmData = this.createAlarmConfigForm.get('useMessageAlarmData').value; - if (useMessageAlarmData) { - this.createAlarmConfigForm.get('alarmType').setValidators([]); - this.createAlarmConfigForm.get('severity').setValidators([]); - } - else { - this.createAlarmConfigForm.get('alarmType').setValidators([Validators.required]); - this.createAlarmConfigForm.get('severity').setValidators([Validators.required]); - } - this.createAlarmConfigForm.get('alarmType').updateValueAndValidity({ emitEvent }); - this.createAlarmConfigForm.get('severity').updateValueAndValidity({ emitEvent }); - } - testScript() { - const script = this.createAlarmConfigForm.get('alarmDetailsBuildJs').value; - this.nodeScriptTestService.testNodeScript(script, 'json', this.translate.instant('tb.rulenode.details'), 'Details', ['msg', 'metadata', 'msgType'], this.ruleNodeId, 'rulenode/create_alarm_node_script_fn').subscribe((theScript) => { - if (theScript) { - this.createAlarmConfigForm.get('alarmDetailsBuildJs').setValue(theScript); - } - }); - } - removeKey(key, keysField) { - const keys = this.createAlarmConfigForm.get(keysField).value; - const index = keys.indexOf(key); - if (index >= 0) { - keys.splice(index, 1); - this.createAlarmConfigForm.get(keysField).setValue(keys, { emitEvent: true }); - } - } - addKey(event, keysField) { - const input = event.input; - let value = event.value; - if ((value || '').trim()) { - value = value.trim(); - let keys = this.createAlarmConfigForm.get(keysField).value; - if (!keys || keys.indexOf(value) === -1) { - if (!keys) { - keys = []; - } - keys.push(value); - this.createAlarmConfigForm.get(keysField).setValue(keys, { emitEvent: true }); - } - } - if (input) { - input.value = ''; - } - } - onValidate() { - this.jsFuncComponent.validateOnSubmit(); - } -} -CreateAlarmConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: CreateAlarmConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }, { token: i3$3.NodeScriptTestService }, { token: i4.TranslateService }], target: i0.ɵɵFactoryTarget.Component }); -CreateAlarmConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: CreateAlarmConfigComponent, selector: "tb-action-node-create-alarm-config", viewQueries: [{ propertyName: "jsFuncComponent", first: true, predicate: ["jsFuncComponent"], descendants: true, static: true }], usesInheritance: true, ngImport: i0, template: "
\n \n \n \n
\n \n
\n
\n \n {{ 'tb.rulenode.use-message-alarm-data' | translate }}\n \n \n {{ 'tb.rulenode.use-dynamically-change-the-severity-of-alar' | translate }}\n \n
\n
\n
\n \n tb.rulenode.alarm-type\n \n \n {{ 'tb.rulenode.alarm-type-required' | translate }}\n \n \n \n \n tb.rulenode.alarm-severity\n \n \n {{ alarmSeverityTranslationMap.get(severity) | translate }}\n \n \n \n {{ 'tb.rulenode.alarm-severity-required' | translate }}\n \n \n \n {{ 'tb.rulenode.alarm-severity' | translate }}\n \n \n {{ 'tb.rulenode.alarm-severity-required' | translate }}\n \n \n \n
\n \n {{ 'tb.rulenode.propagate' | translate }}\n \n
\n \n tb.rulenode.relation-types-list\n \n \n {{key}}\n close\n \n \n \n tb.rulenode.relation-types-list-hint\n \n
\n
\n
\n", components: [{ type: i5$1.JsFuncComponent, selector: "tb-js-func", inputs: ["functionName", "functionArgs", "validationArgs", "resultType", "disabled", "fillHeight", "editorCompleter", "globalVariables", "disableUndefinedCheck", "helpId", "noValidate", "required"] }, { type: i6.MatButton, selector: "button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }, { type: i3$1.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex", "aria-label", "aria-labelledby", "id", "labelPosition", "name", "required", "checked", "disabled", "indeterminate", "aria-describedby", "value"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }, { type: i4$1.MatSelect, selector: "mat-select", inputs: ["disabled", "disableRipple", "tabIndex"], exportAs: ["matSelect"] }, { type: i5.MatOption, selector: "mat-option", exportAs: ["matOption"] }, { type: i5$2.MatChipList, selector: "mat-chip-list", inputs: ["aria-orientation", "multiple", "compareWith", "value", "required", "placeholder", "disabled", "selectable", "tabIndex", "errorStateMatcher"], outputs: ["change", "valueChange"], exportAs: ["matChipList"] }, { type: i6$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i8.DefaultLayoutGapDirective, selector: " [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]", inputs: ["fxLayoutGap", "fxLayoutGap.xs", "fxLayoutGap.sm", "fxLayoutGap.md", "fxLayoutGap.lg", "fxLayoutGap.xl", "fxLayoutGap.lt-sm", "fxLayoutGap.lt-md", "fxLayoutGap.lt-lg", "fxLayoutGap.lt-xl", "fxLayoutGap.gt-xs", "fxLayoutGap.gt-sm", "fxLayoutGap.gt-md", "fxLayoutGap.gt-lg"] }, { type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i3.MatError, selector: "mat-error", inputs: ["id"] }, { type: i3.MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { type: i10.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i5$2.MatChip, selector: "mat-basic-chip, [mat-basic-chip], mat-chip, [mat-chip]", inputs: ["color", "disableRipple", "tabIndex", "selected", "value", "selectable", "disabled", "removable"], outputs: ["selectionChange", "destroyed", "removed"], exportAs: ["matChip"] }, { type: i5$2.MatChipRemove, selector: "[matChipRemove]" }, { type: i5$2.MatChipInput, selector: "input[matChipInputFor]", inputs: ["matChipInputSeparatorKeyCodes", "placeholder", "id", "matChipInputFor", "matChipInputAddOnBlur", "disabled"], outputs: ["matChipInputTokenEnd"], exportAs: ["matChipInput", "matChipInputFor"] }], pipes: { "translate": i4.TranslatePipe, "safeHtml": SafeHtmlPipe } }); -i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: CreateAlarmConfigComponent, decorators: [{ - type: Component, - args: [{ - selector: 'tb-action-node-create-alarm-config', - templateUrl: './create-alarm-config.component.html', - styleUrls: [] - }] - }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }, { type: i3$3.NodeScriptTestService }, { type: i4.TranslateService }]; }, propDecorators: { jsFuncComponent: [{ - type: ViewChild, - args: ['jsFuncComponent', { static: true }] - }] } }); - -class CreateRelationConfigComponent extends RuleNodeConfigurationComponent { - constructor(store, fb) { - super(store); - this.store = store; - this.fb = fb; - this.directionTypes = Object.keys(EntitySearchDirection); - this.directionTypeTranslations = entitySearchDirectionTranslations; - this.entityType = EntityType; - } - configForm() { - return this.createRelationConfigForm; - } - onConfigurationSet(configuration) { - this.createRelationConfigForm = this.fb.group({ - direction: [configuration ? configuration.direction : null, [Validators.required]], - entityType: [configuration ? configuration.entityType : null, [Validators.required]], - entityNamePattern: [configuration ? configuration.entityNamePattern : null, []], - entityTypePattern: [configuration ? configuration.entityTypePattern : null, []], - relationType: [configuration ? configuration.relationType : null, [Validators.required]], - createEntityIfNotExists: [configuration ? configuration.createEntityIfNotExists : false, []], - removeCurrentRelations: [configuration ? configuration.removeCurrentRelations : false, []], - changeOriginatorToRelatedEntity: [configuration ? configuration.changeOriginatorToRelatedEntity : false, []], - entityCacheExpiration: [configuration ? configuration.entityCacheExpiration : null, [Validators.required, Validators.min(0)]], - }); - } - validatorTriggers() { - return ['entityType']; - } - updateValidators(emitEvent) { - const entityType = this.createRelationConfigForm.get('entityType').value; - if (entityType) { - this.createRelationConfigForm.get('entityNamePattern').setValidators([Validators.required, Validators.pattern(/.*\S.*/)]); - } - else { - this.createRelationConfigForm.get('entityNamePattern').setValidators([]); - } - if (entityType && (entityType === EntityType.DEVICE || entityType === EntityType.ASSET)) { - this.createRelationConfigForm.get('entityTypePattern').setValidators([Validators.required, Validators.pattern(/.*\S.*/)]); - } - else { - this.createRelationConfigForm.get('entityTypePattern').setValidators([]); - } - this.createRelationConfigForm.get('entityNamePattern').updateValueAndValidity({ emitEvent }); - this.createRelationConfigForm.get('entityTypePattern').updateValueAndValidity({ emitEvent }); - } - prepareOutputConfig(configuration) { - configuration.entityNamePattern = configuration.entityNamePattern ? configuration.entityNamePattern.trim() : null; - configuration.entityTypePattern = configuration.entityTypePattern ? configuration.entityTypePattern.trim() : null; - return configuration; - } -} -CreateRelationConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: CreateRelationConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); -CreateRelationConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: CreateRelationConfigComponent, selector: "tb-action-node-create-relation-config", usesInheritance: true, ngImport: i0, template: "
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ 'tb.rulenode.entity-name-pattern-required' | translate }}\n \n \n \n \n tb.rulenode.entity-type-pattern\n \n \n {{ 'tb.rulenode.entity-type-pattern-required' | translate }}\n \n \n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ 'tb.rulenode.relation-type-pattern-required' | translate }}\n \n \n \n
\n \n {{ 'tb.rulenode.create-entity-if-not-exists' | translate }}\n \n
tb.rulenode.create-entity-if-not-exists-hint
\n
\n \n {{ 'tb.rulenode.remove-current-relations' | translate }}\n \n
tb.rulenode.remove-current-relations-hint
\n \n {{ 'tb.rulenode.change-originator-to-related-entity' | translate }}\n \n
tb.rulenode.change-originator-to-related-entity-hint
\n \n tb.rulenode.entity-cache-expiration\n \n \n {{ 'tb.rulenode.entity-cache-expiration-required' | translate }}\n \n \n {{ 'tb.rulenode.entity-cache-expiration-range' | translate }}\n \n tb.rulenode.entity-cache-expiration-hint\n \n
\n", components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }, { type: i4$1.MatSelect, selector: "mat-select", inputs: ["disabled", "disableRipple", "tabIndex"], exportAs: ["matSelect"] }, { type: i5.MatOption, selector: "mat-option", exportAs: ["matOption"] }, { type: i7$1.EntityTypeSelectComponent, selector: "tb-entity-type-select", inputs: ["allowedEntityTypes", "useAliasEntityTypes", "showLabel", "required", "disabled"] }, { type: i3$1.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex", "aria-label", "aria-labelledby", "id", "labelPosition", "name", "required", "checked", "disabled", "indeterminate", "aria-describedby", "value"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i10.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i8.DefaultLayoutGapDirective, selector: " [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]", inputs: ["fxLayoutGap", "fxLayoutGap.xs", "fxLayoutGap.sm", "fxLayoutGap.md", "fxLayoutGap.lg", "fxLayoutGap.xl", "fxLayoutGap.lt-sm", "fxLayoutGap.lt-md", "fxLayoutGap.lt-lg", "fxLayoutGap.lt-xl", "fxLayoutGap.gt-xs", "fxLayoutGap.gt-sm", "fxLayoutGap.gt-md", "fxLayoutGap.gt-lg"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i3.MatError, selector: "mat-error", inputs: ["id"] }, { type: i3.MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { type: i2.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { type: i2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }], pipes: { "translate": i4.TranslatePipe, "safeHtml": SafeHtmlPipe } }); -i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: CreateRelationConfigComponent, decorators: [{ - type: Component, - args: [{ - selector: 'tb-action-node-create-relation-config', - templateUrl: './create-relation-config.component.html', - styleUrls: [] - }] - }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); - -class DeleteRelationConfigComponent extends RuleNodeConfigurationComponent { - constructor(store, fb) { - super(store); - this.store = store; - this.fb = fb; - this.directionTypes = Object.keys(EntitySearchDirection); - this.directionTypeTranslations = entitySearchDirectionTranslations; - this.entityType = EntityType; - } - configForm() { - return this.deleteRelationConfigForm; - } - onConfigurationSet(configuration) { - this.deleteRelationConfigForm = this.fb.group({ - deleteForSingleEntity: [configuration ? configuration.deleteForSingleEntity : false, []], - direction: [configuration ? configuration.direction : null, [Validators.required]], - entityType: [configuration ? configuration.entityType : null, []], - entityNamePattern: [configuration ? configuration.entityNamePattern : null, []], - relationType: [configuration ? configuration.relationType : null, [Validators.required]], - entityCacheExpiration: [configuration ? configuration.entityCacheExpiration : null, [Validators.required, Validators.min(0)]], - }); - } - validatorTriggers() { - return ['deleteForSingleEntity', 'entityType']; - } - updateValidators(emitEvent) { - const deleteForSingleEntity = this.deleteRelationConfigForm.get('deleteForSingleEntity').value; - const entityType = this.deleteRelationConfigForm.get('entityType').value; - if (deleteForSingleEntity) { - this.deleteRelationConfigForm.get('entityType').setValidators([Validators.required]); - } - else { - this.deleteRelationConfigForm.get('entityType').setValidators([]); - } - if (deleteForSingleEntity && entityType) { - this.deleteRelationConfigForm.get('entityNamePattern').setValidators([Validators.required, Validators.pattern(/.*\S.*/)]); - } - else { - this.deleteRelationConfigForm.get('entityNamePattern').setValidators([]); - } - this.deleteRelationConfigForm.get('entityType').updateValueAndValidity({ emitEvent: false }); - this.deleteRelationConfigForm.get('entityNamePattern').updateValueAndValidity({ emitEvent }); - } - prepareOutputConfig(configuration) { - configuration.entityNamePattern = configuration.entityNamePattern ? configuration.entityNamePattern.trim() : null; - return configuration; - } -} -DeleteRelationConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: DeleteRelationConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); -DeleteRelationConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: DeleteRelationConfigComponent, selector: "tb-action-node-delete-relation-config", usesInheritance: true, ngImport: i0, template: "
\n \n {{ 'tb.rulenode.delete-relation-to-specific-entity' | translate }}\n \n
tb.rulenode.delete-relation-hint
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ 'tb.rulenode.entity-name-pattern-required' | translate }}\n \n \n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ 'tb.rulenode.relation-type-pattern-required' | translate }}\n \n \n \n \n tb.rulenode.entity-cache-expiration\n \n \n {{ 'tb.rulenode.entity-cache-expiration-required' | translate }}\n \n \n {{ 'tb.rulenode.entity-cache-expiration-range' | translate }}\n \n tb.rulenode.entity-cache-expiration-hint\n \n
\n", components: [{ type: i3$1.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex", "aria-label", "aria-labelledby", "id", "labelPosition", "name", "required", "checked", "disabled", "indeterminate", "aria-describedby", "value"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }, { type: i4$1.MatSelect, selector: "mat-select", inputs: ["disabled", "disableRipple", "tabIndex"], exportAs: ["matSelect"] }, { type: i5.MatOption, selector: "mat-option", exportAs: ["matOption"] }, { type: i7$1.EntityTypeSelectComponent, selector: "tb-entity-type-select", inputs: ["allowedEntityTypes", "useAliasEntityTypes", "showLabel", "required", "disabled"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i10.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i8.DefaultLayoutGapDirective, selector: " [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]", inputs: ["fxLayoutGap", "fxLayoutGap.xs", "fxLayoutGap.sm", "fxLayoutGap.md", "fxLayoutGap.lg", "fxLayoutGap.xl", "fxLayoutGap.lt-sm", "fxLayoutGap.lt-md", "fxLayoutGap.lt-lg", "fxLayoutGap.lt-xl", "fxLayoutGap.gt-xs", "fxLayoutGap.gt-sm", "fxLayoutGap.gt-md", "fxLayoutGap.gt-lg"] }, { type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i3.MatError, selector: "mat-error", inputs: ["id"] }, { type: i3.MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { type: i2.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { type: i2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }], pipes: { "translate": i4.TranslatePipe, "safeHtml": SafeHtmlPipe } }); -i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: DeleteRelationConfigComponent, decorators: [{ - type: Component, - args: [{ - selector: 'tb-action-node-delete-relation-config', - templateUrl: './delete-relation-config.component.html', - styleUrls: [] - }] - }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); - -class DeviceProfileConfigComponent extends RuleNodeConfigurationComponent { - constructor(store, fb) { - super(store); - this.store = store; - this.fb = fb; - } - configForm() { - return this.deviceProfile; - } - onConfigurationSet(configuration) { - this.deviceProfile = this.fb.group({ - persistAlarmRulesState: [configuration ? configuration.persistAlarmRulesState : false, Validators.required], - fetchAlarmRulesStateOnStart: [configuration ? configuration.fetchAlarmRulesStateOnStart : false, Validators.required] - }); - } -} -DeviceProfileConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: DeviceProfileConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); -DeviceProfileConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: DeviceProfileConfigComponent, selector: "tb-device-profile-config", usesInheritance: true, ngImport: i0, template: "
\n \n {{ 'tb.rulenode.persist-alarm-rules' | translate }}\n \n \n {{ 'tb.rulenode.fetch-alarm-rules' | translate }}\n \n
\n", components: [{ type: i3$1.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex", "aria-label", "aria-labelledby", "id", "labelPosition", "name", "required", "checked", "disabled", "indeterminate", "aria-describedby", "value"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }], pipes: { "translate": i4.TranslatePipe } }); -i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: DeviceProfileConfigComponent, decorators: [{ - type: Component, - args: [{ - selector: 'tb-device-profile-config', - templateUrl: './device-profile-config.component.html', - styleUrls: [] - }] - }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); - -class GeneratorConfigComponent extends RuleNodeConfigurationComponent { - constructor(store, fb, nodeScriptTestService, translate) { - super(store); - this.store = store; - this.fb = fb; - this.nodeScriptTestService = nodeScriptTestService; - this.translate = translate; - } - configForm() { - return this.generatorConfigForm; - } - onConfigurationSet(configuration) { - this.generatorConfigForm = this.fb.group({ - msgCount: [configuration ? configuration.msgCount : null, [Validators.required, Validators.min(0)]], - periodInSeconds: [configuration ? configuration.periodInSeconds : null, [Validators.required, Validators.min(1)]], - originator: [configuration ? configuration.originator : null, []], - jsScript: [configuration ? configuration.jsScript : null, [Validators.required]] - }); - } - prepareInputConfig(configuration) { - if (configuration) { - if (configuration.originatorId && configuration.originatorType) { - configuration.originator = { - id: configuration.originatorId, entityType: configuration.originatorType - }; - } - else { - configuration.originator = null; - } - delete configuration.originatorId; - delete configuration.originatorType; - } - return configuration; - } - prepareOutputConfig(configuration) { - if (configuration.originator) { - configuration.originatorId = configuration.originator.id; - configuration.originatorType = configuration.originator.entityType; - } - else { - configuration.originatorId = null; - configuration.originatorType = null; - } - delete configuration.originator; - return configuration; - } - testScript() { - const script = this.generatorConfigForm.get('jsScript').value; - this.nodeScriptTestService.testNodeScript(script, 'generate', this.translate.instant('tb.rulenode.generator'), 'Generate', ['prevMsg', 'prevMetadata', 'prevMsgType'], this.ruleNodeId, 'rulenode/generator_node_script_fn').subscribe((theScript) => { - if (theScript) { - this.generatorConfigForm.get('jsScript').setValue(theScript); - } - }); - } - onValidate() { - this.jsFuncComponent.validateOnSubmit(); - } -} -GeneratorConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: GeneratorConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }, { token: i3$3.NodeScriptTestService }, { token: i4.TranslateService }], target: i0.ɵɵFactoryTarget.Component }); -GeneratorConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: GeneratorConfigComponent, selector: "tb-action-node-generator-config", viewQueries: [{ propertyName: "jsFuncComponent", first: true, predicate: ["jsFuncComponent"], descendants: true, static: true }], usesInheritance: true, ngImport: i0, template: "
\n \n tb.rulenode.message-count\n \n \n {{ 'tb.rulenode.message-count-required' | translate }}\n \n \n {{ 'tb.rulenode.min-message-count-message' | translate }}\n \n \n \n tb.rulenode.period-seconds\n \n \n {{ 'tb.rulenode.period-seconds-required' | translate }}\n \n \n {{ 'tb.rulenode.min-period-seconds-message' | translate }}\n \n \n
\n \n \n \n
\n \n \n \n
\n \n
\n
\n", components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }, { type: i6$2.EntitySelectComponent, selector: "tb-entity-select", inputs: ["allowedEntityTypes", "useAliasEntityTypes", "required", "disabled"] }, { type: i5$1.JsFuncComponent, selector: "tb-js-func", inputs: ["functionName", "functionArgs", "validationArgs", "resultType", "disabled", "fillHeight", "editorCompleter", "globalVariables", "disableUndefinedCheck", "helpId", "noValidate", "required"] }, { type: i6.MatButton, selector: "button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i2.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { type: i2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.MatError, selector: "mat-error", inputs: ["id"] }], pipes: { "translate": i4.TranslatePipe } }); -i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: GeneratorConfigComponent, decorators: [{ - type: Component, - args: [{ - selector: 'tb-action-node-generator-config', - templateUrl: './generator-config.component.html', - styleUrls: [] - }] - }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }, { type: i3$3.NodeScriptTestService }, { type: i4.TranslateService }]; }, propDecorators: { jsFuncComponent: [{ - type: ViewChild, - args: ['jsFuncComponent', { static: true }] - }] } }); - -class GpsGeoActionConfigComponent extends RuleNodeConfigurationComponent { - constructor(store, fb) { - super(store); - this.store = store; - this.fb = fb; - this.perimeterType = PerimeterType; - this.perimeterTypes = Object.keys(PerimeterType); - this.perimeterTypeTranslationMap = perimeterTypeTranslations; - this.rangeUnits = Object.keys(RangeUnit); - this.rangeUnitTranslationMap = rangeUnitTranslations; - this.timeUnits = Object.keys(TimeUnit); - this.timeUnitsTranslationMap = timeUnitTranslations; - } - configForm() { - return this.geoActionConfigForm; - } - onConfigurationSet(configuration) { - this.geoActionConfigForm = this.fb.group({ - latitudeKeyName: [configuration ? configuration.latitudeKeyName : null, [Validators.required]], - longitudeKeyName: [configuration ? configuration.longitudeKeyName : null, [Validators.required]], - fetchPerimeterInfoFromMessageMetadata: [configuration ? configuration.fetchPerimeterInfoFromMessageMetadata : false, []], - perimeterType: [configuration ? configuration.perimeterType : null, []], - centerLatitude: [configuration ? configuration.centerLatitude : null, []], - centerLongitude: [configuration ? configuration.centerLatitude : null, []], - range: [configuration ? configuration.range : null, []], - rangeUnit: [configuration ? configuration.rangeUnit : null, []], - polygonsDefinition: [configuration ? configuration.polygonsDefinition : null, []], - minInsideDuration: [configuration ? configuration.minInsideDuration : null, - [Validators.required, Validators.min(1), Validators.max(2147483647)]], - minInsideDurationTimeUnit: [configuration ? configuration.minInsideDurationTimeUnit : null, [Validators.required]], - minOutsideDuration: [configuration ? configuration.minOutsideDuration : null, - [Validators.required, Validators.min(1), Validators.max(2147483647)]], - minOutsideDurationTimeUnit: [configuration ? configuration.minOutsideDurationTimeUnit : null, [Validators.required]], - }); - } - validatorTriggers() { - return ['fetchPerimeterInfoFromMessageMetadata', 'perimeterType']; - } - updateValidators(emitEvent) { - const fetchPerimeterInfoFromMessageMetadata = this.geoActionConfigForm.get('fetchPerimeterInfoFromMessageMetadata').value; - const perimeterType = this.geoActionConfigForm.get('perimeterType').value; - if (fetchPerimeterInfoFromMessageMetadata) { - this.geoActionConfigForm.get('perimeterType').setValidators([]); - } - else { - this.geoActionConfigForm.get('perimeterType').setValidators([Validators.required]); - } - if (!fetchPerimeterInfoFromMessageMetadata && perimeterType === PerimeterType.CIRCLE) { - this.geoActionConfigForm.get('centerLatitude').setValidators([Validators.required, - Validators.min(-90), Validators.max(90)]); - this.geoActionConfigForm.get('centerLongitude').setValidators([Validators.required, - Validators.min(-180), Validators.max(180)]); - this.geoActionConfigForm.get('range').setValidators([Validators.required, Validators.min(0)]); - this.geoActionConfigForm.get('rangeUnit').setValidators([Validators.required]); - } - else { - this.geoActionConfigForm.get('centerLatitude').setValidators([]); - this.geoActionConfigForm.get('centerLongitude').setValidators([]); - this.geoActionConfigForm.get('range').setValidators([]); - this.geoActionConfigForm.get('rangeUnit').setValidators([]); - } - if (!fetchPerimeterInfoFromMessageMetadata && perimeterType === PerimeterType.POLYGON) { - this.geoActionConfigForm.get('polygonsDefinition').setValidators([Validators.required]); - } - else { - this.geoActionConfigForm.get('polygonsDefinition').setValidators([]); - } - this.geoActionConfigForm.get('perimeterType').updateValueAndValidity({ emitEvent: false }); - this.geoActionConfigForm.get('centerLatitude').updateValueAndValidity({ emitEvent }); - this.geoActionConfigForm.get('centerLongitude').updateValueAndValidity({ emitEvent }); - this.geoActionConfigForm.get('range').updateValueAndValidity({ emitEvent }); - this.geoActionConfigForm.get('rangeUnit').updateValueAndValidity({ emitEvent }); - this.geoActionConfigForm.get('polygonsDefinition').updateValueAndValidity({ emitEvent }); - } -} -GpsGeoActionConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: GpsGeoActionConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); -GpsGeoActionConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: GpsGeoActionConfigComponent, selector: "tb-action-node-gps-geofencing-config", usesInheritance: true, ngImport: i0, template: "
\n \n tb.rulenode.latitude-key-name\n \n \n {{ 'tb.rulenode.latitude-key-name-required' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ 'tb.rulenode.longitude-key-name-required' | translate }}\n \n \n \n {{ 'tb.rulenode.fetch-perimeter-info-from-message-metadata' | translate }}\n \n
\n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n \n tb.rulenode.circle-center-latitude\n \n \n {{ 'tb.rulenode.circle-center-latitude-required' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ 'tb.rulenode.circle-center-longitude-required' | translate }}\n \n \n
\n
\n \n tb.rulenode.range\n \n \n {{ 'tb.rulenode.range-required' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n \n tb.rulenode.polygon-definition\n \n \n {{ 'tb.rulenode.polygon-definition-required' | translate }}\n \n \n
\n
\n \n tb.rulenode.min-inside-duration\n \n \n {{ 'tb.rulenode.min-inside-duration-value-required' | translate }}\n \n \n {{ 'tb.rulenode.time-value-range' | translate }}\n \n \n {{ 'tb.rulenode.time-value-range' | translate }}\n \n \n \n tb.rulenode.min-inside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n tb.rulenode.min-outside-duration\n \n \n {{ 'tb.rulenode.min-outside-duration-value-required' | translate }}\n \n \n {{ 'tb.rulenode.time-value-range' | translate }}\n \n \n {{ 'tb.rulenode.time-value-range' | translate }}\n \n \n \n tb.rulenode.min-outside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n", components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }, { type: i3$1.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex", "aria-label", "aria-labelledby", "id", "labelPosition", "name", "required", "checked", "disabled", "indeterminate", "aria-describedby", "value"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { type: i4$1.MatSelect, selector: "mat-select", inputs: ["disabled", "disableRipple", "tabIndex"], exportAs: ["matSelect"] }, { type: i5.MatOption, selector: "mat-option", exportAs: ["matOption"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.MatError, selector: "mat-error", inputs: ["id"] }, { type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }, { type: i10.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i8.DefaultLayoutGapDirective, selector: " [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]", inputs: ["fxLayoutGap", "fxLayoutGap.xs", "fxLayoutGap.sm", "fxLayoutGap.md", "fxLayoutGap.lg", "fxLayoutGap.xl", "fxLayoutGap.lt-sm", "fxLayoutGap.lt-md", "fxLayoutGap.lt-lg", "fxLayoutGap.lt-xl", "fxLayoutGap.gt-xs", "fxLayoutGap.gt-sm", "fxLayoutGap.gt-md", "fxLayoutGap.gt-lg"] }, { type: i2.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { type: i2.MaxValidator, selector: "input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]", inputs: ["max"] }, { type: i2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }], pipes: { "translate": i4.TranslatePipe } }); -i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: GpsGeoActionConfigComponent, decorators: [{ - type: Component, - args: [{ - selector: 'tb-action-node-gps-geofencing-config', - templateUrl: './gps-geo-action-config.component.html', - styleUrls: [] - }] - }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); - -class KvMapConfigComponent extends PageComponent { - constructor(store, translate, injector, fb) { - super(store); - this.store = store; - this.translate = translate; - this.injector = injector; - this.fb = fb; - this.propagateChange = null; - this.valueChangeSubscription = null; - } - get required() { - return this.requiredValue; - } - set required(value) { - this.requiredValue = coerceBooleanProperty(value); - } - ngOnInit() { - this.ngControl = this.injector.get(NgControl); - if (this.ngControl != null) { - this.ngControl.valueAccessor = this; - } - this.kvListFormGroup = this.fb.group({}); - this.kvListFormGroup.addControl('keyVals', this.fb.array([])); - } - keyValsFormArray() { - return this.kvListFormGroup.get('keyVals'); - } - registerOnChange(fn) { - this.propagateChange = fn; - } - registerOnTouched(fn) { - } - setDisabledState(isDisabled) { - this.disabled = isDisabled; - if (this.disabled) { - this.kvListFormGroup.disable({ emitEvent: false }); - } - else { - this.kvListFormGroup.enable({ emitEvent: false }); - } - } - writeValue(keyValMap) { - if (this.valueChangeSubscription) { - this.valueChangeSubscription.unsubscribe(); - } - const keyValsControls = []; - if (keyValMap) { - for (const property of Object.keys(keyValMap)) { - if (Object.prototype.hasOwnProperty.call(keyValMap, property)) { - keyValsControls.push(this.fb.group({ - key: [property, [Validators.required]], - value: [keyValMap[property], [Validators.required]] - })); - } - } - } - this.kvListFormGroup.setControl('keyVals', this.fb.array(keyValsControls)); - this.valueChangeSubscription = this.kvListFormGroup.valueChanges.subscribe(() => { - this.updateModel(); - }); - } - removeKeyVal(index) { - this.kvListFormGroup.get('keyVals').removeAt(index); - } - addKeyVal() { - const keyValsFormArray = this.kvListFormGroup.get('keyVals'); - keyValsFormArray.push(this.fb.group({ - key: ['', [Validators.required]], - value: ['', [Validators.required]] - })); - } - validate(c) { - const kvList = this.kvListFormGroup.get('keyVals').value; - if (!kvList.length && this.required) { - return { - kvMapRequired: true - }; - } - if (!this.kvListFormGroup.valid) { - return { - kvFieldsRequired: true - }; - } - return null; - } - updateModel() { - const kvList = this.kvListFormGroup.get('keyVals').value; - if (this.required && !kvList.length || !this.kvListFormGroup.valid) { - this.propagateChange(null); - } - else { - const keyValMap = {}; - kvList.forEach((entry) => { - keyValMap[entry.key] = entry.value; - }); - this.propagateChange(keyValMap); - } - } -} -KvMapConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: KvMapConfigComponent, deps: [{ token: i1.Store }, { token: i4.TranslateService }, { token: i0.Injector }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); -KvMapConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: KvMapConfigComponent, selector: "tb-kv-map-config", inputs: { disabled: "disabled", requiredText: "requiredText", keyText: "keyText", keyRequiredText: "keyRequiredText", valText: "valText", valRequiredText: "valRequiredText", required: "required" }, providers: [ - { - provide: NG_VALUE_ACCESSOR, - useExisting: forwardRef(() => KvMapConfigComponent), - multi: true - }, - { - provide: NG_VALIDATORS, - useExisting: forwardRef(() => KvMapConfigComponent), - multi: true, - } - ], usesInheritance: true, ngImport: i0, template: "
\n
\n {{ keyText | translate }}\n {{ valText | translate }}\n \n
\n
\n
\n \n \n \n \n {{ keyRequiredText | translate }}\n \n \n \n \n \n \n {{ valRequiredText | translate }}\n \n \n \n
\n
\n \n
\n \n
\n
\n", styles: [":host .tb-kv-map-config{margin-bottom:16px}:host .tb-kv-map-config .header{padding-left:5px;padding-right:5px;padding-bottom:5px}:host .tb-kv-map-config .header .cell{padding-left:5px;padding-right:5px;color:#0000008a;font-size:12px;font-weight:700;white-space:nowrap}:host .tb-kv-map-config .body{padding-left:5px;padding-right:5px;padding-bottom:20px;max-height:300px;overflow:auto}:host .tb-kv-map-config .body .row{padding-top:5px;max-height:40px}:host .tb-kv-map-config .body .cell{padding-left:5px;padding-right:5px}:host ::ng-deep .tb-kv-map-config .body mat-form-field.cell{margin:0;max-height:40px}:host ::ng-deep .tb-kv-map-config .body mat-form-field.cell .mat-form-field-infix{border-top:0}:host ::ng-deep .tb-kv-map-config .body button.mat-button{margin:0}\n"], components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }, { type: i6.MatButton, selector: "button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }, { type: i6$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { type: i9.TbErrorComponent, selector: "tb-error", inputs: ["error"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }, { type: i8.DefaultLayoutGapDirective, selector: " [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]", inputs: ["fxLayoutGap", "fxLayoutGap.xs", "fxLayoutGap.sm", "fxLayoutGap.md", "fxLayoutGap.lg", "fxLayoutGap.xl", "fxLayoutGap.lt-sm", "fxLayoutGap.lt-md", "fxLayoutGap.lt-lg", "fxLayoutGap.lt-xl", "fxLayoutGap.gt-xs", "fxLayoutGap.gt-sm", "fxLayoutGap.gt-md", "fxLayoutGap.gt-lg"] }, { type: i9$1.DefaultShowHideDirective, selector: " [fxShow], [fxShow.print], [fxShow.xs], [fxShow.sm], [fxShow.md], [fxShow.lg], [fxShow.xl], [fxShow.lt-sm], [fxShow.lt-md], [fxShow.lt-lg], [fxShow.lt-xl], [fxShow.gt-xs], [fxShow.gt-sm], [fxShow.gt-md], [fxShow.gt-lg], [fxHide], [fxHide.print], [fxHide.xs], [fxHide.sm], [fxHide.md], [fxHide.lg], [fxHide.xl], [fxHide.lt-sm], [fxHide.lt-md], [fxHide.lt-lg], [fxHide.lt-xl], [fxHide.gt-xs], [fxHide.gt-sm], [fxHide.gt-md], [fxHide.gt-lg]", inputs: ["fxShow", "fxShow.print", "fxShow.xs", "fxShow.sm", "fxShow.md", "fxShow.lg", "fxShow.xl", "fxShow.lt-sm", "fxShow.lt-md", "fxShow.lt-lg", "fxShow.lt-xl", "fxShow.gt-xs", "fxShow.gt-sm", "fxShow.gt-md", "fxShow.gt-lg", "fxHide", "fxHide.print", "fxHide.xs", "fxHide.sm", "fxHide.md", "fxHide.lg", "fxHide.xl", "fxHide.lt-sm", "fxHide.lt-md", "fxHide.lt-lg", "fxHide.lt-xl", "fxHide.gt-xs", "fxHide.gt-sm", "fxHide.gt-md", "fxHide.gt-lg"] }, { type: i10.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i8.DefaultLayoutAlignDirective, selector: " [fxLayoutAlign], [fxLayoutAlign.xs], [fxLayoutAlign.sm], [fxLayoutAlign.md], [fxLayoutAlign.lg], [fxLayoutAlign.xl], [fxLayoutAlign.lt-sm], [fxLayoutAlign.lt-md], [fxLayoutAlign.lt-lg], [fxLayoutAlign.lt-xl], [fxLayoutAlign.gt-xs], [fxLayoutAlign.gt-sm], [fxLayoutAlign.gt-md], [fxLayoutAlign.gt-lg]", inputs: ["fxLayoutAlign", "fxLayoutAlign.xs", "fxLayoutAlign.sm", "fxLayoutAlign.md", "fxLayoutAlign.lg", "fxLayoutAlign.xl", "fxLayoutAlign.lt-sm", "fxLayoutAlign.lt-md", "fxLayoutAlign.lt-lg", "fxLayoutAlign.lt-xl", "fxLayoutAlign.gt-xs", "fxLayoutAlign.gt-sm", "fxLayoutAlign.gt-md", "fxLayoutAlign.gt-lg"] }, { type: i2.FormArrayName, selector: "[formArrayName]", inputs: ["formArrayName"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlDirective, selector: "[formControl]", inputs: ["disabled", "formControl", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.MatError, selector: "mat-error", inputs: ["id"] }, { type: i12.MatTooltip, selector: "[matTooltip]", exportAs: ["matTooltip"] }], pipes: { "translate": i4.TranslatePipe, "async": i10.AsyncPipe } }); -i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: KvMapConfigComponent, decorators: [{ - type: Component, - args: [{ - selector: 'tb-kv-map-config', - templateUrl: './kv-map-config.component.html', - styleUrls: ['./kv-map-config.component.scss'], - providers: [ - { - provide: NG_VALUE_ACCESSOR, - useExisting: forwardRef(() => KvMapConfigComponent), - multi: true - }, - { - provide: NG_VALIDATORS, - useExisting: forwardRef(() => KvMapConfigComponent), - multi: true, - } - ] - }] - }], ctorParameters: function () { return [{ type: i1.Store }, { type: i4.TranslateService }, { type: i0.Injector }, { type: i2.FormBuilder }]; }, propDecorators: { disabled: [{ - type: Input - }], requiredText: [{ - type: Input - }], keyText: [{ - type: Input - }], keyRequiredText: [{ - type: Input - }], valText: [{ - type: Input - }], valRequiredText: [{ - type: Input - }], required: [{ - type: Input - }] } }); - -class KafkaConfigComponent extends RuleNodeConfigurationComponent { - constructor(store, fb) { - super(store); - this.store = store; - this.fb = fb; - this.ackValues = ['all', '-1', '0', '1']; - this.ToByteStandartCharsetTypesValues = ToByteStandartCharsetTypes; - this.ToByteStandartCharsetTypeTranslationMap = ToByteStandartCharsetTypeTranslations; - } - configForm() { - return this.kafkaConfigForm; - } - onConfigurationSet(configuration) { - this.kafkaConfigForm = this.fb.group({ - topicPattern: [configuration ? configuration.topicPattern : null, [Validators.required]], - bootstrapServers: [configuration ? configuration.bootstrapServers : null, [Validators.required]], - retries: [configuration ? configuration.retries : null, [Validators.min(0)]], - batchSize: [configuration ? configuration.batchSize : null, [Validators.min(0)]], - linger: [configuration ? configuration.linger : null, [Validators.min(0)]], - bufferMemory: [configuration ? configuration.bufferMemory : null, [Validators.min(0)]], - acks: [configuration ? configuration.acks : null, [Validators.required]], - keySerializer: [configuration ? configuration.keySerializer : null, [Validators.required]], - valueSerializer: [configuration ? configuration.valueSerializer : null, [Validators.required]], - otherProperties: [configuration ? configuration.otherProperties : null, []], - addMetadataKeyValuesAsKafkaHeaders: [configuration ? configuration.addMetadataKeyValuesAsKafkaHeaders : false, []], - kafkaHeadersCharset: [configuration ? configuration.kafkaHeadersCharset : null, []] - }); - } - validatorTriggers() { - return ['addMetadataKeyValuesAsKafkaHeaders']; - } - updateValidators(emitEvent) { - const addMetadataKeyValuesAsKafkaHeaders = this.kafkaConfigForm.get('addMetadataKeyValuesAsKafkaHeaders').value; - if (addMetadataKeyValuesAsKafkaHeaders) { - this.kafkaConfigForm.get('kafkaHeadersCharset').setValidators([Validators.required]); - } - else { - this.kafkaConfigForm.get('kafkaHeadersCharset').setValidators([]); - } - this.kafkaConfigForm.get('kafkaHeadersCharset').updateValueAndValidity({ emitEvent }); - } -} -KafkaConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: KafkaConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); -KafkaConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: KafkaConfigComponent, selector: "tb-action-node-kafka-config", usesInheritance: true, ngImport: i0, template: "
\n \n tb.rulenode.topic-pattern\n \n \n {{ 'tb.rulenode.topic-pattern-required' | translate }}\n \n \n \n \n tb.rulenode.bootstrap-servers\n \n \n {{ 'tb.rulenode.bootstrap-servers-required' | translate }}\n \n \n \n tb.rulenode.retries\n \n \n {{ 'tb.rulenode.min-retries-message' | translate }}\n \n \n \n tb.rulenode.batch-size-bytes\n \n \n {{ 'tb.rulenode.min-batch-size-bytes-message' | translate }}\n \n \n \n tb.rulenode.linger-ms\n \n \n {{ 'tb.rulenode.min-linger-ms-message' | translate }}\n \n \n \n tb.rulenode.buffer-memory-bytes\n \n \n {{ 'tb.rulenode.min-buffer-memory-bytes-message' | translate }}\n \n \n \n tb.rulenode.acks\n \n \n {{ ackValue }}\n \n \n \n \n tb.rulenode.key-serializer\n \n \n {{ 'tb.rulenode.key-serializer-required' | translate }}\n \n \n \n tb.rulenode.value-serializer\n \n \n {{ 'tb.rulenode.value-serializer-required' | translate }}\n \n \n \n \n \n \n {{ 'tb.rulenode.add-metadata-key-values-as-kafka-headers' | translate }}\n \n
tb.rulenode.add-metadata-key-values-as-kafka-headers-hint
\n \n tb.rulenode.charset-encoding\n \n \n {{ ToByteStandartCharsetTypeTranslationMap.get(charset) | translate }}\n \n \n \n
\n", components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }, { type: i4$1.MatSelect, selector: "mat-select", inputs: ["disabled", "disableRipple", "tabIndex"], exportAs: ["matSelect"] }, { type: i5.MatOption, selector: "mat-option", exportAs: ["matOption"] }, { type: KvMapConfigComponent, selector: "tb-kv-map-config", inputs: ["disabled", "requiredText", "keyText", "keyRequiredText", "valText", "valRequiredText", "required"] }, { type: i3$1.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex", "aria-label", "aria-labelledby", "id", "labelPosition", "name", "required", "checked", "disabled", "indeterminate", "aria-describedby", "value"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.MatError, selector: "mat-error", inputs: ["id"] }, { type: i3.MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { type: i2.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { type: i2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { type: i10.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }], pipes: { "translate": i4.TranslatePipe, "safeHtml": SafeHtmlPipe } }); -i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: KafkaConfigComponent, decorators: [{ - type: Component, - args: [{ - selector: 'tb-action-node-kafka-config', - templateUrl: './kafka-config.component.html', - styleUrls: [] - }] - }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); - -class LogConfigComponent extends RuleNodeConfigurationComponent { - constructor(store, fb, nodeScriptTestService, translate) { - super(store); - this.store = store; - this.fb = fb; - this.nodeScriptTestService = nodeScriptTestService; - this.translate = translate; - } - configForm() { - return this.logConfigForm; - } - onConfigurationSet(configuration) { - this.logConfigForm = this.fb.group({ - jsScript: [configuration ? configuration.jsScript : null, [Validators.required]] - }); - } - testScript() { - const script = this.logConfigForm.get('jsScript').value; - this.nodeScriptTestService.testNodeScript(script, 'string', this.translate.instant('tb.rulenode.to-string'), 'ToString', ['msg', 'metadata', 'msgType'], this.ruleNodeId, 'rulenode/log_node_script_fn').subscribe((theScript) => { - if (theScript) { - this.logConfigForm.get('jsScript').setValue(theScript); - } - }); - } - onValidate() { - this.jsFuncComponent.validateOnSubmit(); - } -} -LogConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: LogConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }, { token: i3$3.NodeScriptTestService }, { token: i4.TranslateService }], target: i0.ɵɵFactoryTarget.Component }); -LogConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: LogConfigComponent, selector: "tb-action-node-log-config", viewQueries: [{ propertyName: "jsFuncComponent", first: true, predicate: ["jsFuncComponent"], descendants: true, static: true }], usesInheritance: true, ngImport: i0, template: "
\n \n \n \n
\n \n
\n
\n", components: [{ type: i5$1.JsFuncComponent, selector: "tb-js-func", inputs: ["functionName", "functionArgs", "validationArgs", "resultType", "disabled", "fillHeight", "editorCompleter", "globalVariables", "disableUndefinedCheck", "helpId", "noValidate", "required"] }, { type: i6.MatButton, selector: "button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }], pipes: { "translate": i4.TranslatePipe } }); -i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: LogConfigComponent, decorators: [{ - type: Component, - args: [{ - selector: 'tb-action-node-log-config', - templateUrl: './log-config.component.html', - styleUrls: [] - }] - }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }, { type: i3$3.NodeScriptTestService }, { type: i4.TranslateService }]; }, propDecorators: { jsFuncComponent: [{ - type: ViewChild, - args: ['jsFuncComponent', { static: true }] - }] } }); - -class CredentialsConfigComponent extends PageComponent { - constructor(store, fb) { - super(store); - this.store = store; - this.fb = fb; - this.subscriptions = []; - this.disableCertPemCredentials = false; - this.passwordFieldRquired = true; - this.allCredentialsTypes = credentialsTypes; - this.credentialsTypeTranslationsMap = credentialsTypeTranslations; - this.propagateChange = null; - } - get required() { - return this.requiredValue; - } - set required(value) { - this.requiredValue = coerceBooleanProperty(value); - } - ngOnInit() { - this.credentialsConfigFormGroup = this.fb.group({ - type: [null, [Validators.required]], - username: [null, []], - password: [null, []], - caCert: [null, []], - caCertFileName: [null, []], - privateKey: [null, []], - privateKeyFileName: [null, []], - cert: [null, []], - certFileName: [null, []] - }); - this.subscriptions.push(this.credentialsConfigFormGroup.valueChanges.pipe(distinctUntilChanged()).subscribe(() => { - this.updateView(); - })); - this.subscriptions.push(this.credentialsConfigFormGroup.get('type').valueChanges.subscribe(() => { - this.credentialsTypeChanged(); - })); - } - ngOnChanges(changes) { - for (const propName of Object.keys(changes)) { - const change = changes[propName]; - if (!change.firstChange && change.currentValue !== change.previousValue) { - if (change.currentValue && propName === 'disableCertPemCredentials') { - const credentialsTypeValue = this.credentialsConfigFormGroup.get('type').value; - if (credentialsTypeValue === 'cert.PEM') { - setTimeout(() => { - this.credentialsConfigFormGroup.get('type').patchValue('anonymous', { emitEvent: true }); - }); - } - } - } - } - } - ngOnDestroy() { - this.subscriptions.forEach(s => s.unsubscribe()); - } - writeValue(credentials) { - if (isDefinedAndNotNull(credentials)) { - this.credentialsConfigFormGroup.reset(credentials, { emitEvent: false }); - this.updateValidators(false); - } - } - setDisabledState(isDisabled) { - if (isDisabled) { - this.credentialsConfigFormGroup.disable(); - } - else { - this.credentialsConfigFormGroup.enable(); - this.updateValidators(); - } - } - updateView() { - let credentialsConfigValue = this.credentialsConfigFormGroup.value; - const credentialsTypeValue = credentialsConfigValue.type; - switch (credentialsTypeValue) { - case 'anonymous': - credentialsConfigValue = { - type: credentialsTypeValue - }; - break; - case 'basic': - credentialsConfigValue = { - type: credentialsTypeValue, - username: credentialsConfigValue.username, - password: credentialsConfigValue.password, - }; - break; - case 'cert.PEM': - delete credentialsConfigValue.username; - break; - } - this.propagateChange(credentialsConfigValue); - } - registerOnChange(fn) { - this.propagateChange = fn; - } - registerOnTouched(fn) { - } - validate(c) { - return this.credentialsConfigFormGroup.valid ? null : { - credentialsConfig: { - valid: false, - }, - }; - } - credentialsTypeChanged() { - this.credentialsConfigFormGroup.patchValue({ - username: null, - password: null, - caCert: null, - caCertFileName: null, - privateKey: null, - privateKeyFileName: null, - cert: null, - certFileName: null, - }); - this.updateValidators(); - } - updateValidators(emitEvent = false) { - const credentialsTypeValue = this.credentialsConfigFormGroup.get('type').value; - if (emitEvent) { - this.credentialsConfigFormGroup.reset({ type: credentialsTypeValue }, { emitEvent: false }); - } - this.credentialsConfigFormGroup.setValidators([]); - this.credentialsConfigFormGroup.get('username').setValidators([]); - this.credentialsConfigFormGroup.get('password').setValidators([]); - switch (credentialsTypeValue) { - case 'anonymous': - break; - case 'basic': - this.credentialsConfigFormGroup.get('username').setValidators([Validators.required]); - this.credentialsConfigFormGroup.get('password').setValidators(this.passwordFieldRquired ? [Validators.required] : []); - break; - case 'cert.PEM': - this.credentialsConfigFormGroup.setValidators([this.requiredFilesSelected(Validators.required, [['caCert', 'caCertFileName'], ['privateKey', 'privateKeyFileName', 'cert', 'certFileName']])]); - break; - } - this.credentialsConfigFormGroup.get('username').updateValueAndValidity({ emitEvent }); - this.credentialsConfigFormGroup.get('password').updateValueAndValidity({ emitEvent }); - this.credentialsConfigFormGroup.updateValueAndValidity({ emitEvent }); - } - requiredFilesSelected(validator, requiredFieldsSet = null) { - return (group) => { - if (!requiredFieldsSet) { - requiredFieldsSet = [Object.keys(group.controls)]; - } - const allRequiredFilesSelected = (group === null || group === void 0 ? void 0 : group.controls) && - requiredFieldsSet.some(arrFields => arrFields.every(k => !validator(group.controls[k]))); - return allRequiredFilesSelected ? null : { notAllRequiredFilesSelected: true }; - }; - } -} -CredentialsConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: CredentialsConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); -CredentialsConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: CredentialsConfigComponent, selector: "tb-credentials-config", inputs: { required: "required", disableCertPemCredentials: "disableCertPemCredentials", passwordFieldRquired: "passwordFieldRquired" }, providers: [ - { - provide: NG_VALUE_ACCESSOR, - useExisting: forwardRef(() => CredentialsConfigComponent), - multi: true - }, - { - provide: NG_VALIDATORS, - useExisting: forwardRef(() => CredentialsConfigComponent), - multi: true, - } - ], usesInheritance: true, usesOnChanges: true, ngImport: i0, template: "
\n \n \n tb.rulenode.credentials\n \n {{ credentialsTypeTranslationsMap.get(credentialsConfigFormGroup.get('type').value) | translate }}\n \n \n \n \n tb.rulenode.credentials-type\n \n \n {{ credentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ 'tb.rulenode.credentials-type-required' | translate }}\n \n \n
\n \n \n \n \n tb.rulenode.username\n \n \n {{ 'tb.rulenode.username-required' | translate }}\n \n \n \n tb.rulenode.password\n \n \n \n {{ 'tb.rulenode.password-required' | translate }}\n \n \n \n \n
{{ 'tb.rulenode.credentials-pem-hint' | translate }}
\n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n
\n
\n
\n
\n
\n", components: [{ type: i4$2.MatExpansionPanel, selector: "mat-expansion-panel", inputs: ["disabled", "expanded", "hideToggle", "togglePosition"], outputs: ["opened", "closed", "expandedChange", "afterExpand", "afterCollapse"], exportAs: ["matExpansionPanel"] }, { type: i4$2.MatExpansionPanelHeader, selector: "mat-expansion-panel-header", inputs: ["tabIndex", "expandedHeight", "collapsedHeight"] }, { type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }, { type: i4$1.MatSelect, selector: "mat-select", inputs: ["disabled", "disableRipple", "tabIndex"], exportAs: ["matSelect"] }, { type: i5.MatOption, selector: "mat-option", exportAs: ["matOption"] }, { type: i7.TogglePasswordComponent, selector: "tb-toggle-password" }, { type: i8$1.FileInputComponent, selector: "tb-file-input", inputs: ["label", "accept", "noFileText", "inputId", "allowedExtensions", "dropLabel", "contentConvertFunction", "required", "requiredAsError", "disabled", "existingFileName", "readAsBinary", "workFromFileObj", "multipleFile"], outputs: ["fileNameChanged"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i4$2.MatExpansionPanelTitle, selector: "mat-panel-title" }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i4$2.MatExpansionPanelDescription, selector: "mat-panel-description" }, { type: i4$2.MatExpansionPanelContent, selector: "ng-template[matExpansionPanelContent]" }, { type: i3.MatLabel, selector: "mat-label" }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i10.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.MatError, selector: "mat-error", inputs: ["id"] }, { type: i10.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { type: i10.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i3.MatSuffix, selector: "[matSuffix]" }], pipes: { "translate": i4.TranslatePipe } }); -i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: CredentialsConfigComponent, decorators: [{ - type: Component, - args: [{ - selector: 'tb-credentials-config', - templateUrl: './credentials-config.component.html', - styleUrls: [], - providers: [ - { - provide: NG_VALUE_ACCESSOR, - useExisting: forwardRef(() => CredentialsConfigComponent), - multi: true - }, - { - provide: NG_VALIDATORS, - useExisting: forwardRef(() => CredentialsConfigComponent), - multi: true, - } - ] - }] - }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; }, propDecorators: { required: [{ - type: Input - }], disableCertPemCredentials: [{ - type: Input - }], passwordFieldRquired: [{ - type: Input - }] } }); - -class MqttConfigComponent extends RuleNodeConfigurationComponent { - constructor(store, fb) { - super(store); - this.store = store; - this.fb = fb; - } - configForm() { - return this.mqttConfigForm; - } - onConfigurationSet(configuration) { - this.mqttConfigForm = this.fb.group({ - topicPattern: [configuration ? configuration.topicPattern : null, [Validators.required]], - host: [configuration ? configuration.host : null, [Validators.required]], - port: [configuration ? configuration.port : null, [Validators.required, Validators.min(1), Validators.max(65535)]], - connectTimeoutSec: [configuration ? configuration.connectTimeoutSec : null, - [Validators.required, Validators.min(1), Validators.max(200)]], - clientId: [configuration ? configuration.clientId : null, []], - cleanSession: [configuration ? configuration.cleanSession : false, []], - ssl: [configuration ? configuration.ssl : false, []], - credentials: [configuration ? configuration.credentials : null, []] - }); - } -} -MqttConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: MqttConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); -MqttConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: MqttConfigComponent, selector: "tb-action-node-mqtt-config", usesInheritance: true, ngImport: i0, template: "
\n \n tb.rulenode.topic-pattern\n \n \n {{ 'tb.rulenode.topic-pattern-required' | translate }}\n \n \n \n
\n \n tb.rulenode.host\n \n \n {{ 'tb.rulenode.host-required' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ 'tb.rulenode.port-required' | translate }}\n \n \n {{ 'tb.rulenode.port-range' | translate }}\n \n \n {{ 'tb.rulenode.port-range' | translate }}\n \n \n \n tb.rulenode.connect-timeout\n \n \n {{ 'tb.rulenode.connect-timeout-required' | translate }}\n \n \n {{ 'tb.rulenode.connect-timeout-range' | translate }}\n \n \n {{ 'tb.rulenode.connect-timeout-range' | translate }}\n \n \n
\n \n tb.rulenode.client-id\n \n \n
tb.rulenode.client-id-hint
\n \n {{ 'tb.rulenode.clean-session' | translate }}\n \n \n {{ 'tb.rulenode.enable-ssl' | translate }}\n \n \n
\n", styles: [":host .tb-mqtt-credentials-panel-group{margin:0 6px}:host .tb-hint.client-id{margin-top:-1.25em;max-width:-moz-fit-content;max-width:fit-content}\n"], components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }, { type: i3$1.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex", "aria-label", "aria-labelledby", "id", "labelPosition", "name", "required", "checked", "disabled", "indeterminate", "aria-describedby", "value"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { type: CredentialsConfigComponent, selector: "tb-credentials-config", inputs: ["required", "disableCertPemCredentials", "passwordFieldRquired"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.MatError, selector: "mat-error", inputs: ["id"] }, { type: i3.MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }, { type: i8.DefaultLayoutGapDirective, selector: " [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]", inputs: ["fxLayoutGap", "fxLayoutGap.xs", "fxLayoutGap.sm", "fxLayoutGap.md", "fxLayoutGap.lg", "fxLayoutGap.xl", "fxLayoutGap.lt-sm", "fxLayoutGap.lt-md", "fxLayoutGap.lt-lg", "fxLayoutGap.lt-xl", "fxLayoutGap.gt-xs", "fxLayoutGap.gt-sm", "fxLayoutGap.gt-md", "fxLayoutGap.gt-lg"] }, { type: i2.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { type: i2.MaxValidator, selector: "input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]", inputs: ["max"] }, { type: i2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }], pipes: { "translate": i4.TranslatePipe, "safeHtml": SafeHtmlPipe } }); -i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: MqttConfigComponent, decorators: [{ - type: Component, - args: [{ - selector: 'tb-action-node-mqtt-config', - templateUrl: './mqtt-config.component.html', - styleUrls: ['./mqtt-config.component.scss'] - }] - }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); - -class MsgCountConfigComponent extends RuleNodeConfigurationComponent { - constructor(store, fb) { - super(store); - this.store = store; - this.fb = fb; - } - configForm() { - return this.msgCountConfigForm; - } - onConfigurationSet(configuration) { - this.msgCountConfigForm = this.fb.group({ - interval: [configuration ? configuration.interval : null, [Validators.required, Validators.min(1)]], - telemetryPrefix: [configuration ? configuration.telemetryPrefix : null, [Validators.required]] - }); - } -} -MsgCountConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: MsgCountConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); -MsgCountConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: MsgCountConfigComponent, selector: "tb-action-node-msg-count-config", usesInheritance: true, ngImport: i0, template: "
\n \n tb.rulenode.interval-seconds\n \n \n {{ 'tb.rulenode.interval-seconds-required' | translate }}\n \n \n {{ 'tb.rulenode.min-interval-seconds-message' | translate }}\n \n \n \n tb.rulenode.output-timeseries-key-prefix\n \n \n {{ 'tb.rulenode.output-timeseries-key-prefix-required' | translate }}\n \n \n
\n", components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i2.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { type: i2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.MatError, selector: "mat-error", inputs: ["id"] }], pipes: { "translate": i4.TranslatePipe } }); -i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: MsgCountConfigComponent, decorators: [{ - type: Component, - args: [{ - selector: 'tb-action-node-msg-count-config', - templateUrl: './msg-count-config.component.html', - styleUrls: [] - }] - }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); - -class MsgDelayConfigComponent extends RuleNodeConfigurationComponent { - constructor(store, fb) { - super(store); - this.store = store; - this.fb = fb; - } - configForm() { - return this.msgDelayConfigForm; - } - onConfigurationSet(configuration) { - this.msgDelayConfigForm = this.fb.group({ - useMetadataPeriodInSecondsPatterns: [configuration ? configuration.useMetadataPeriodInSecondsPatterns : false, []], - periodInSeconds: [configuration ? configuration.periodInSeconds : null, []], - periodInSecondsPattern: [configuration ? configuration.periodInSecondsPattern : null, []], - maxPendingMsgs: [configuration ? configuration.maxPendingMsgs : null, - [Validators.required, Validators.min(1), Validators.max(100000)]], - }); - } - validatorTriggers() { - return ['useMetadataPeriodInSecondsPatterns']; - } - updateValidators(emitEvent) { - const useMetadataPeriodInSecondsPatterns = this.msgDelayConfigForm.get('useMetadataPeriodInSecondsPatterns').value; - if (useMetadataPeriodInSecondsPatterns) { - this.msgDelayConfigForm.get('periodInSecondsPattern').setValidators([Validators.required]); - this.msgDelayConfigForm.get('periodInSeconds').setValidators([]); - } - else { - this.msgDelayConfigForm.get('periodInSecondsPattern').setValidators([]); - this.msgDelayConfigForm.get('periodInSeconds').setValidators([Validators.required, Validators.min(0)]); - } - this.msgDelayConfigForm.get('periodInSecondsPattern').updateValueAndValidity({ emitEvent }); - this.msgDelayConfigForm.get('periodInSeconds').updateValueAndValidity({ emitEvent }); - } -} -MsgDelayConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: MsgDelayConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); -MsgDelayConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: MsgDelayConfigComponent, selector: "tb-action-node-msg-delay-config", usesInheritance: true, ngImport: i0, template: "
\n \n {{ 'tb.rulenode.use-metadata-period-in-seconds-patterns' | translate }}\n \n
tb.rulenode.use-metadata-period-in-seconds-patterns-hint
\n \n tb.rulenode.period-seconds\n \n \n {{ 'tb.rulenode.period-seconds-required' | translate }}\n \n \n {{ 'tb.rulenode.min-period-0-seconds-message' | translate }}\n \n \n \n \n tb.rulenode.period-in-seconds-pattern\n \n \n {{ 'tb.rulenode.period-in-seconds-pattern-required' | translate }}\n \n \n \n \n \n tb.rulenode.max-pending-messages\n \n \n {{ 'tb.rulenode.max-pending-messages-required' | translate }}\n \n \n {{ 'tb.rulenode.max-pending-messages-range' | translate }}\n \n \n {{ 'tb.rulenode.max-pending-messages-range' | translate }}\n \n \n
\n", components: [{ type: i3$1.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex", "aria-label", "aria-labelledby", "id", "labelPosition", "name", "required", "checked", "disabled", "indeterminate", "aria-describedby", "value"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i2.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { type: i2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i3.MatError, selector: "mat-error", inputs: ["id"] }, { type: i3.MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { type: i2.MaxValidator, selector: "input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]", inputs: ["max"] }], pipes: { "translate": i4.TranslatePipe, "safeHtml": SafeHtmlPipe } }); -i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: MsgDelayConfigComponent, decorators: [{ - type: Component, - args: [{ - selector: 'tb-action-node-msg-delay-config', - templateUrl: './msg-delay-config.component.html', - styleUrls: [] - }] - }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); - -class PubSubConfigComponent extends RuleNodeConfigurationComponent { - constructor(store, fb) { - super(store); - this.store = store; - this.fb = fb; - } - configForm() { - return this.pubSubConfigForm; - } - onConfigurationSet(configuration) { - this.pubSubConfigForm = this.fb.group({ - projectId: [configuration ? configuration.projectId : null, [Validators.required]], - topicName: [configuration ? configuration.topicName : null, [Validators.required]], - serviceAccountKey: [configuration ? configuration.serviceAccountKey : null, [Validators.required]], - serviceAccountKeyFileName: [configuration ? configuration.serviceAccountKeyFileName : null, [Validators.required]], - messageAttributes: [configuration ? configuration.messageAttributes : null, []] - }); - } -} -PubSubConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: PubSubConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); -PubSubConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: PubSubConfigComponent, selector: "tb-action-node-pub-sub-config", usesInheritance: true, ngImport: i0, template: "
\n \n tb.rulenode.gcp-project-id\n \n \n {{ 'tb.rulenode.gcp-project-id-required' | translate }}\n \n \n \n tb.rulenode.pubsub-topic-name\n \n \n {{ 'tb.rulenode.pubsub-topic-name-required' | translate }}\n \n \n \n \n \n
\n \n \n
\n", components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }, { type: i8$1.FileInputComponent, selector: "tb-file-input", inputs: ["label", "accept", "noFileText", "inputId", "allowedExtensions", "dropLabel", "contentConvertFunction", "required", "requiredAsError", "disabled", "existingFileName", "readAsBinary", "workFromFileObj", "multipleFile"], outputs: ["fileNameChanged"] }, { type: KvMapConfigComponent, selector: "tb-kv-map-config", inputs: ["disabled", "requiredText", "keyText", "keyRequiredText", "valText", "valRequiredText", "required"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.MatError, selector: "mat-error", inputs: ["id"] }], pipes: { "translate": i4.TranslatePipe, "safeHtml": SafeHtmlPipe } }); -i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: PubSubConfigComponent, decorators: [{ - type: Component, - args: [{ - selector: 'tb-action-node-pub-sub-config', - templateUrl: './pubsub-config.component.html', - styleUrls: [] - }] - }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); - -class PushToCloudConfigComponent extends RuleNodeConfigurationComponent { - constructor(store, fb) { - super(store); - this.store = store; - this.fb = fb; - this.attributeScopes = Object.keys(AttributeScope); - this.telemetryTypeTranslationsMap = telemetryTypeTranslations; - } - configForm() { - return this.pushToCloudConfigForm; - } - onConfigurationSet(configuration) { - this.pushToCloudConfigForm = this.fb.group({ - scope: [configuration ? configuration.scope : null, [Validators.required]] - }); - } -} -PushToCloudConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: PushToCloudConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); -PushToCloudConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: PushToCloudConfigComponent, selector: "tb-action-node-push-to-cloud-config", usesInheritance: true, ngImport: i0, template: "
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n", components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }, { type: i4$1.MatSelect, selector: "mat-select", inputs: ["disabled", "disableRipple", "tabIndex"], exportAs: ["matSelect"] }, { type: i5.MatOption, selector: "mat-option", exportAs: ["matOption"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i10.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }], pipes: { "translate": i4.TranslatePipe } }); -i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: PushToCloudConfigComponent, decorators: [{ - type: Component, - args: [{ - selector: 'tb-action-node-push-to-cloud-config', - templateUrl: './push-to-cloud-config.component.html', - styleUrls: [] - }] - }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); - -class PushToEdgeConfigComponent extends RuleNodeConfigurationComponent { - constructor(store, fb) { - super(store); - this.store = store; - this.fb = fb; - this.attributeScopes = Object.keys(AttributeScope); - this.telemetryTypeTranslationsMap = telemetryTypeTranslations; - } - configForm() { - return this.pushToEdgeConfigForm; - } - onConfigurationSet(configuration) { - this.pushToEdgeConfigForm = this.fb.group({ - scope: [configuration ? configuration.scope : null, [Validators.required]] - }); - } -} -PushToEdgeConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: PushToEdgeConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); -PushToEdgeConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: PushToEdgeConfigComponent, selector: "tb-action-node-push-to-edge-config", usesInheritance: true, ngImport: i0, template: "
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n", components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }, { type: i4$1.MatSelect, selector: "mat-select", inputs: ["disabled", "disableRipple", "tabIndex"], exportAs: ["matSelect"] }, { type: i5.MatOption, selector: "mat-option", exportAs: ["matOption"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i10.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }], pipes: { "translate": i4.TranslatePipe } }); -i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: PushToEdgeConfigComponent, decorators: [{ - type: Component, - args: [{ - selector: 'tb-action-node-push-to-edge-config', - templateUrl: './push-to-edge-config.component.html', - styleUrls: [] - }] - }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); - -class RabbitMqConfigComponent extends RuleNodeConfigurationComponent { - constructor(store, fb) { - super(store); - this.store = store; - this.fb = fb; - this.messageProperties = [ - null, - 'BASIC', - 'TEXT_PLAIN', - 'MINIMAL_BASIC', - 'MINIMAL_PERSISTENT_BASIC', - 'PERSISTENT_BASIC', - 'PERSISTENT_TEXT_PLAIN' - ]; - } - configForm() { - return this.rabbitMqConfigForm; - } - onConfigurationSet(configuration) { - this.rabbitMqConfigForm = this.fb.group({ - exchangeNamePattern: [configuration ? configuration.exchangeNamePattern : null, []], - routingKeyPattern: [configuration ? configuration.routingKeyPattern : null, []], - messageProperties: [configuration ? configuration.messageProperties : null, []], - host: [configuration ? configuration.host : null, [Validators.required]], - port: [configuration ? configuration.port : null, [Validators.required, Validators.min(1), Validators.max(65535)]], - virtualHost: [configuration ? configuration.virtualHost : null, []], - username: [configuration ? configuration.username : null, []], - password: [configuration ? configuration.password : null, []], - automaticRecoveryEnabled: [configuration ? configuration.automaticRecoveryEnabled : false, []], - connectionTimeout: [configuration ? configuration.connectionTimeout : null, [Validators.min(0)]], - handshakeTimeout: [configuration ? configuration.handshakeTimeout : null, [Validators.min(0)]], - clientProperties: [configuration ? configuration.clientProperties : null, []] - }); - } -} -RabbitMqConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RabbitMqConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); -RabbitMqConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: RabbitMqConfigComponent, selector: "tb-action-node-rabbit-mq-config", usesInheritance: true, ngImport: i0, template: "
\n \n tb.rulenode.exchange-name-pattern\n \n \n \n tb.rulenode.routing-key-pattern\n \n \n \n tb.rulenode.message-properties\n \n \n {{ property }}\n \n \n \n
\n \n tb.rulenode.host\n \n \n {{ 'tb.rulenode.host-required' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ 'tb.rulenode.port-required' | translate }}\n \n \n {{ 'tb.rulenode.port-range' | translate }}\n \n \n {{ 'tb.rulenode.port-range' | translate }}\n \n \n
\n \n tb.rulenode.virtual-host\n \n \n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n \n {{ 'tb.rulenode.automatic-recovery' | translate }}\n \n \n tb.rulenode.connection-timeout-ms\n \n \n {{ 'tb.rulenode.min-connection-timeout-ms-message' | translate }}\n \n \n \n tb.rulenode.handshake-timeout-ms\n \n \n {{ 'tb.rulenode.min-handshake-timeout-ms-message' | translate }}\n \n \n \n \n \n
\n", components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }, { type: i4$1.MatSelect, selector: "mat-select", inputs: ["disabled", "disableRipple", "tabIndex"], exportAs: ["matSelect"] }, { type: i5.MatOption, selector: "mat-option", exportAs: ["matOption"] }, { type: i7.TogglePasswordComponent, selector: "tb-toggle-password" }, { type: i3$1.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex", "aria-label", "aria-labelledby", "id", "labelPosition", "name", "required", "checked", "disabled", "indeterminate", "aria-describedby", "value"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { type: KvMapConfigComponent, selector: "tb-kv-map-config", inputs: ["disabled", "requiredText", "keyText", "keyRequiredText", "valText", "valRequiredText", "required"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i10.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i8.DefaultLayoutGapDirective, selector: " [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]", inputs: ["fxLayoutGap", "fxLayoutGap.xs", "fxLayoutGap.sm", "fxLayoutGap.md", "fxLayoutGap.lg", "fxLayoutGap.xl", "fxLayoutGap.lt-sm", "fxLayoutGap.lt-md", "fxLayoutGap.lt-lg", "fxLayoutGap.lt-xl", "fxLayoutGap.gt-xs", "fxLayoutGap.gt-sm", "fxLayoutGap.gt-md", "fxLayoutGap.gt-lg"] }, { type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.MatError, selector: "mat-error", inputs: ["id"] }, { type: i2.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { type: i2.MaxValidator, selector: "input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]", inputs: ["max"] }, { type: i2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { type: i3.MatSuffix, selector: "[matSuffix]" }], pipes: { "translate": i4.TranslatePipe } }); -i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RabbitMqConfigComponent, decorators: [{ - type: Component, - args: [{ - selector: 'tb-action-node-rabbit-mq-config', - templateUrl: './rabbit-mq-config.component.html', - styleUrls: [] - }] - }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); - -class RestApiCallConfigComponent extends RuleNodeConfigurationComponent { - constructor(store, fb) { - super(store); - this.store = store; - this.fb = fb; - this.proxySchemes = ['http', 'https']; - this.httpRequestTypes = Object.keys(HttpRequestType); - } - configForm() { - return this.restApiCallConfigForm; - } - onConfigurationSet(configuration) { - this.restApiCallConfigForm = this.fb.group({ - restEndpointUrlPattern: [configuration ? configuration.restEndpointUrlPattern : null, [Validators.required]], - requestMethod: [configuration ? configuration.requestMethod : null, [Validators.required]], - useSimpleClientHttpFactory: [configuration ? configuration.useSimpleClientHttpFactory : false, []], - ignoreRequestBody: [configuration ? configuration.ignoreRequestBody : false, []], - enableProxy: [configuration ? configuration.enableProxy : false, []], - useSystemProxyProperties: [configuration ? configuration.enableProxy : false, []], - proxyScheme: [configuration ? configuration.proxyHost : null, []], - proxyHost: [configuration ? configuration.proxyHost : null, []], - proxyPort: [configuration ? configuration.proxyPort : null, []], - proxyUser: [configuration ? configuration.proxyUser : null, []], - proxyPassword: [configuration ? configuration.proxyPassword : null, []], - readTimeoutMs: [configuration ? configuration.readTimeoutMs : null, []], - maxParallelRequestsCount: [configuration ? configuration.maxParallelRequestsCount : null, [Validators.min(0)]], - headers: [configuration ? configuration.headers : null, []], - useRedisQueueForMsgPersistence: [configuration ? configuration.useRedisQueueForMsgPersistence : false, []], - trimQueue: [configuration ? configuration.trimQueue : false, []], - maxQueueSize: [configuration ? configuration.maxQueueSize : null, []], - credentials: [configuration ? configuration.credentials : null, []] - }); - } - validatorTriggers() { - return ['useSimpleClientHttpFactory', 'useRedisQueueForMsgPersistence', 'enableProxy', 'useSystemProxyProperties']; - } - updateValidators(emitEvent) { - const useSimpleClientHttpFactory = this.restApiCallConfigForm.get('useSimpleClientHttpFactory').value; - const useRedisQueueForMsgPersistence = this.restApiCallConfigForm.get('useRedisQueueForMsgPersistence').value; - const enableProxy = this.restApiCallConfigForm.get('enableProxy').value; - const useSystemProxyProperties = this.restApiCallConfigForm.get('useSystemProxyProperties').value; - if (enableProxy && !useSystemProxyProperties) { - this.restApiCallConfigForm.get('proxyHost').setValidators(enableProxy ? [Validators.required] : []); - this.restApiCallConfigForm.get('proxyPort').setValidators(enableProxy ? - [Validators.required, Validators.min(1), Validators.max(65535)] : []); - } - else { - this.restApiCallConfigForm.get('proxyHost').setValidators([]); - this.restApiCallConfigForm.get('proxyPort').setValidators([]); - if (useSimpleClientHttpFactory) { - this.restApiCallConfigForm.get('readTimeoutMs').setValidators([]); - } - else { - this.restApiCallConfigForm.get('readTimeoutMs').setValidators([Validators.min(0)]); - } - } - if (useRedisQueueForMsgPersistence) { - this.restApiCallConfigForm.get('maxQueueSize').setValidators([Validators.min(0)]); - } - else { - this.restApiCallConfigForm.get('maxQueueSize').setValidators([]); - } - this.restApiCallConfigForm.get('readTimeoutMs').updateValueAndValidity({ emitEvent }); - this.restApiCallConfigForm.get('maxQueueSize').updateValueAndValidity({ emitEvent }); - this.restApiCallConfigForm.get('proxyHost').updateValueAndValidity({ emitEvent }); - this.restApiCallConfigForm.get('proxyPort').updateValueAndValidity({ emitEvent }); - this.restApiCallConfigForm.get('credentials').updateValueAndValidity({ emitEvent }); - } -} -RestApiCallConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RestApiCallConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); -RestApiCallConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: RestApiCallConfigComponent, selector: "tb-action-node-rest-api-call-config", usesInheritance: true, ngImport: i0, template: "
\n \n tb.rulenode.endpoint-url-pattern\n \n \n {{ 'tb.rulenode.endpoint-url-pattern-required' | translate }}\n \n \n \n \n tb.rulenode.request-method\n \n \n {{ requestType }}\n \n \n \n \n {{ 'tb.rulenode.enable-proxy' | translate }}\n \n \n {{ 'tb.rulenode.use-simple-client-http-factory' | translate }}\n \n \n {{ 'tb.rulenode.ignore-request-body' | translate }}\n \n
\n \n {{ 'tb.rulenode.use-system-proxy-properties' | translate }}\n \n
\n
\n \n tb.rulenode.proxy-scheme\n \n \n {{ proxyScheme }}\n \n \n \n \n tb.rulenode.proxy-host\n \n \n {{ 'tb.rulenode.proxy-host-required' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ 'tb.rulenode.proxy-port-required' | translate }}\n \n \n {{ 'tb.rulenode.proxy-port-range' | translate }}\n \n \n
\n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
\n
\n \n tb.rulenode.read-timeout\n \n tb.rulenode.read-timeout-hint\n \n \n tb.rulenode.max-parallel-requests-count\n \n tb.rulenode.max-parallel-requests-count-hint\n \n \n
\n \n \n \n {{ 'tb.rulenode.use-redis-queue' | translate }}\n \n
\n \n {{ 'tb.rulenode.trim-redis-queue' | translate }}\n \n \n tb.rulenode.redis-queue-max-size\n \n \n
\n \n
\n", components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }, { type: i4$1.MatSelect, selector: "mat-select", inputs: ["disabled", "disableRipple", "tabIndex"], exportAs: ["matSelect"] }, { type: i5.MatOption, selector: "mat-option", exportAs: ["matOption"] }, { type: i3$1.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex", "aria-label", "aria-labelledby", "id", "labelPosition", "name", "required", "checked", "disabled", "indeterminate", "aria-describedby", "value"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { type: KvMapConfigComponent, selector: "tb-kv-map-config", inputs: ["disabled", "requiredText", "keyText", "keyRequiredText", "valText", "valRequiredText", "required"] }, { type: CredentialsConfigComponent, selector: "tb-credentials-config", inputs: ["required", "disableCertPemCredentials", "passwordFieldRquired"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.MatError, selector: "mat-error", inputs: ["id"] }, { type: i3.MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { type: i10.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i8.DefaultLayoutGapDirective, selector: " [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]", inputs: ["fxLayoutGap", "fxLayoutGap.xs", "fxLayoutGap.sm", "fxLayoutGap.md", "fxLayoutGap.lg", "fxLayoutGap.xl", "fxLayoutGap.lt-sm", "fxLayoutGap.lt-md", "fxLayoutGap.lt-lg", "fxLayoutGap.lt-xl", "fxLayoutGap.gt-xs", "fxLayoutGap.gt-sm", "fxLayoutGap.gt-md", "fxLayoutGap.gt-lg"] }, { type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }, { type: i2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { type: i2.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }], pipes: { "translate": i4.TranslatePipe, "safeHtml": SafeHtmlPipe } }); -i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RestApiCallConfigComponent, decorators: [{ - type: Component, - args: [{ - selector: 'tb-action-node-rest-api-call-config', - templateUrl: './rest-api-call-config.component.html', - styleUrls: [] - }] - }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); - -class RpcReplyConfigComponent extends RuleNodeConfigurationComponent { - constructor(store, fb) { - super(store); - this.store = store; - this.fb = fb; - } - configForm() { - return this.rpcReplyConfigForm; - } - onConfigurationSet(configuration) { - this.rpcReplyConfigForm = this.fb.group({ - requestIdMetaDataAttribute: [configuration ? configuration.requestIdMetaDataAttribute : null, []] - }); - } -} -RpcReplyConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RpcReplyConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); -RpcReplyConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: RpcReplyConfigComponent, selector: "tb-action-node-rpc-reply-config", usesInheritance: true, ngImport: i0, template: "
\n \n tb.rulenode.request-id-metadata-attribute\n \n \n
\n", components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }] }); -i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RpcReplyConfigComponent, decorators: [{ - type: Component, - args: [{ - selector: 'tb-action-node-rpc-reply-config', - templateUrl: './rpc-reply-config.component.html', - styleUrls: [] - }] - }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); - -class RpcRequestConfigComponent extends RuleNodeConfigurationComponent { - constructor(store, fb) { - super(store); - this.store = store; - this.fb = fb; - } - configForm() { - return this.rpcRequestConfigForm; - } - onConfigurationSet(configuration) { - this.rpcRequestConfigForm = this.fb.group({ - timeoutInSeconds: [configuration ? configuration.timeoutInSeconds : null, [Validators.required, Validators.min(0)]] - }); - } -} -RpcRequestConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RpcRequestConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); -RpcRequestConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: RpcRequestConfigComponent, selector: "tb-action-node-rpc-request-config", usesInheritance: true, ngImport: i0, template: "
\n \n tb.rulenode.timeout-sec\n \n \n {{ 'tb.rulenode.timeout-required' | translate }}\n \n \n {{ 'tb.rulenode.min-timeout-message' | translate }}\n \n \n
\n", components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i2.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { type: i2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.MatError, selector: "mat-error", inputs: ["id"] }], pipes: { "translate": i4.TranslatePipe } }); -i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RpcRequestConfigComponent, decorators: [{ - type: Component, - args: [{ - selector: 'tb-action-node-rpc-request-config', - templateUrl: './rpc-request-config.component.html', - styleUrls: [] - }] - }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); - -class SaveToCustomTableConfigComponent extends RuleNodeConfigurationComponent { - constructor(store, fb) { - super(store); - this.store = store; - this.fb = fb; - } - configForm() { - return this.saveToCustomTableConfigForm; - } - onConfigurationSet(configuration) { - this.saveToCustomTableConfigForm = this.fb.group({ - tableName: [configuration ? configuration.tableName : null, [Validators.required, Validators.pattern(/.*\S.*/)]], - fieldsMapping: [configuration ? configuration.fieldsMapping : null, [Validators.required]] - }); - } - prepareOutputConfig(configuration) { - configuration.tableName = configuration.tableName.trim(); - return configuration; - } -} -SaveToCustomTableConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: SaveToCustomTableConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); -SaveToCustomTableConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: SaveToCustomTableConfigComponent, selector: "tb-action-node-custom-table-config", usesInheritance: true, ngImport: i0, template: "
\n \n tb.rulenode.custom-table-name\n \n \n {{ 'tb.rulenode.custom-table-name-required' | translate }}\n \n tb.rulenode.custom-table-hint\n \n \n \n \n
\n", components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }, { type: KvMapConfigComponent, selector: "tb-kv-map-config", inputs: ["disabled", "requiredText", "keyText", "keyRequiredText", "valText", "valRequiredText", "required"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.MatError, selector: "mat-error", inputs: ["id"] }, { type: i3.MatHint, selector: "mat-hint", inputs: ["align", "id"] }], pipes: { "translate": i4.TranslatePipe } }); -i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: SaveToCustomTableConfigComponent, decorators: [{ - type: Component, - args: [{ - selector: 'tb-action-node-custom-table-config', - templateUrl: './save-to-custom-table-config.component.html', - styleUrls: [] - }] - }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); - -class SendEmailConfigComponent extends RuleNodeConfigurationComponent { - constructor(store, fb) { - super(store); - this.store = store; - this.fb = fb; - this.smtpProtocols = [ - 'smtp', - 'smtps' - ]; - this.tlsVersions = ['TLSv1', 'TLSv1.1', 'TLSv1.2', 'TLSv1.3']; - } - configForm() { - return this.sendEmailConfigForm; - } - onConfigurationSet(configuration) { - this.sendEmailConfigForm = this.fb.group({ - useSystemSmtpSettings: [configuration ? configuration.useSystemSmtpSettings : false, []], - smtpProtocol: [configuration ? configuration.smtpProtocol : null, []], - smtpHost: [configuration ? configuration.smtpHost : null, []], - smtpPort: [configuration ? configuration.smtpPort : null, []], - timeout: [configuration ? configuration.timeout : null, []], - enableTls: [configuration ? configuration.enableTls : false, []], - tlsVersion: [configuration ? configuration.tlsVersion : null, []], - enableProxy: [configuration ? configuration.enableProxy : false, []], - proxyHost: [configuration ? configuration.proxyHost : null, []], - proxyPort: [configuration ? configuration.proxyPort : null, []], - proxyUser: [configuration ? configuration.proxyUser : null, []], - proxyPassword: [configuration ? configuration.proxyPassword : null, []], - username: [configuration ? configuration.username : null, []], - password: [configuration ? configuration.password : null, []] - }); - } - validatorTriggers() { - return ['useSystemSmtpSettings', 'enableProxy']; - } - updateValidators(emitEvent) { - const useSystemSmtpSettings = this.sendEmailConfigForm.get('useSystemSmtpSettings').value; - const enableProxy = this.sendEmailConfigForm.get('enableProxy').value; - if (useSystemSmtpSettings) { - this.sendEmailConfigForm.get('smtpProtocol').setValidators([]); - this.sendEmailConfigForm.get('smtpHost').setValidators([]); - this.sendEmailConfigForm.get('smtpPort').setValidators([]); - this.sendEmailConfigForm.get('timeout').setValidators([]); - this.sendEmailConfigForm.get('proxyHost').setValidators([]); - this.sendEmailConfigForm.get('proxyPort').setValidators([]); - } - else { - this.sendEmailConfigForm.get('smtpProtocol').setValidators([Validators.required]); - this.sendEmailConfigForm.get('smtpHost').setValidators([Validators.required]); - this.sendEmailConfigForm.get('smtpPort').setValidators([Validators.required, Validators.min(1), Validators.max(65535)]); - this.sendEmailConfigForm.get('timeout').setValidators([Validators.required, Validators.min(0)]); - this.sendEmailConfigForm.get('proxyHost').setValidators(enableProxy ? [Validators.required] : []); - this.sendEmailConfigForm.get('proxyPort').setValidators(enableProxy ? - [Validators.required, Validators.min(1), Validators.max(65535)] : []); - } - this.sendEmailConfigForm.get('smtpProtocol').updateValueAndValidity({ emitEvent }); - this.sendEmailConfigForm.get('smtpHost').updateValueAndValidity({ emitEvent }); - this.sendEmailConfigForm.get('smtpPort').updateValueAndValidity({ emitEvent }); - this.sendEmailConfigForm.get('timeout').updateValueAndValidity({ emitEvent }); - this.sendEmailConfigForm.get('proxyHost').updateValueAndValidity({ emitEvent }); - this.sendEmailConfigForm.get('proxyPort').updateValueAndValidity({ emitEvent }); - } -} -SendEmailConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: SendEmailConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); -SendEmailConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: SendEmailConfigComponent, selector: "tb-action-node-send-email-config", usesInheritance: true, ngImport: i0, template: "
\n \n {{ 'tb.rulenode.use-system-smtp-settings' | translate }}\n \n
\n \n tb.rulenode.smtp-protocol\n \n \n {{ smtpProtocol.toUpperCase() }}\n \n \n \n
\n \n tb.rulenode.smtp-host\n \n \n {{ 'tb.rulenode.smtp-host-required' | translate }}\n \n \n \n tb.rulenode.smtp-port\n \n \n {{ 'tb.rulenode.smtp-port-required' | translate }}\n \n \n {{ 'tb.rulenode.smtp-port-range' | translate }}\n \n \n {{ 'tb.rulenode.smtp-port-range' | translate }}\n \n \n
\n \n tb.rulenode.timeout-msec\n \n \n {{ 'tb.rulenode.timeout-required' | translate }}\n \n \n {{ 'tb.rulenode.min-timeout-msec-message' | translate }}\n \n \n \n {{ 'tb.rulenode.enable-tls' | translate }}\n \n \n tb.rulenode.tls-version\n \n \n {{ tlsVersion }}\n \n \n \n \n {{ 'tb.rulenode.enable-proxy' | translate }}\n \n
\n
\n \n tb.rulenode.proxy-host\n \n \n {{ 'tb.rulenode.proxy-host-required' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ 'tb.rulenode.proxy-port-required' | translate }}\n \n \n {{ 'tb.rulenode.proxy-port-range' | translate }}\n \n \n
\n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
\n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n
\n
\n", components: [{ type: i3$1.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex", "aria-label", "aria-labelledby", "id", "labelPosition", "name", "required", "checked", "disabled", "indeterminate", "aria-describedby", "value"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }, { type: i4$1.MatSelect, selector: "mat-select", inputs: ["disabled", "disableRipple", "tabIndex"], exportAs: ["matSelect"] }, { type: i5.MatOption, selector: "mat-option", exportAs: ["matOption"] }, { type: i7$2.TbCheckboxComponent, selector: "tb-checkbox", inputs: ["disabled", "trueValue", "falseValue"], outputs: ["valueChange"] }, { type: i7.TogglePasswordComponent, selector: "tb-toggle-password" }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i10.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i8.DefaultLayoutGapDirective, selector: " [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]", inputs: ["fxLayoutGap", "fxLayoutGap.xs", "fxLayoutGap.sm", "fxLayoutGap.md", "fxLayoutGap.lg", "fxLayoutGap.xl", "fxLayoutGap.lt-sm", "fxLayoutGap.lt-md", "fxLayoutGap.lt-lg", "fxLayoutGap.lt-xl", "fxLayoutGap.gt-xs", "fxLayoutGap.gt-sm", "fxLayoutGap.gt-md", "fxLayoutGap.gt-lg"] }, { type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i3.MatError, selector: "mat-error", inputs: ["id"] }, { type: i2.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { type: i2.MaxValidator, selector: "input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]", inputs: ["max"] }, { type: i2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { type: i3.MatSuffix, selector: "[matSuffix]" }], pipes: { "translate": i4.TranslatePipe } }); -i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: SendEmailConfigComponent, decorators: [{ - type: Component, - args: [{ - selector: 'tb-action-node-send-email-config', - templateUrl: './send-email-config.component.html', - styleUrls: [] - }] - }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); - -class SendSmsConfigComponent extends RuleNodeConfigurationComponent { - constructor(store, fb) { - super(store); - this.store = store; - this.fb = fb; - } - configForm() { - return this.sendSmsConfigForm; - } - onConfigurationSet(configuration) { - this.sendSmsConfigForm = this.fb.group({ - numbersToTemplate: [configuration ? configuration.numbersToTemplate : null, [Validators.required]], - smsMessageTemplate: [configuration ? configuration.smsMessageTemplate : null, [Validators.required]], - useSystemSmsSettings: [configuration ? configuration.useSystemSmsSettings : false, []], - smsProviderConfiguration: [configuration ? configuration.smsProviderConfiguration : null, []], - }); - } - validatorTriggers() { - return ['useSystemSmsSettings']; - } - updateValidators(emitEvent) { - const useSystemSmsSettings = this.sendSmsConfigForm.get('useSystemSmsSettings').value; - if (useSystemSmsSettings) { - this.sendSmsConfigForm.get('smsProviderConfiguration').setValidators([]); - } - else { - this.sendSmsConfigForm.get('smsProviderConfiguration').setValidators([Validators.required]); - } - this.sendSmsConfigForm.get('smsProviderConfiguration').updateValueAndValidity({ emitEvent }); - } -} -SendSmsConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: SendSmsConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); -SendSmsConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: SendSmsConfigComponent, selector: "tb-action-node-send-sms-config", usesInheritance: true, ngImport: i0, template: "
\n \n tb.rulenode.numbers-to-template\n \n \n {{ 'tb.rulenode.numbers-to-template-required' | translate }}\n \n \n \n \n tb.rulenode.sms-message-template\n \n \n {{ 'tb.rulenode.sms-message-template-required' | translate }}\n \n \n \n \n {{ 'tb.rulenode.use-system-sms-settings' | translate }}\n \n \n \n
\n", components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }, { type: i3$1.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex", "aria-label", "aria-labelledby", "id", "labelPosition", "name", "required", "checked", "disabled", "indeterminate", "aria-describedby", "value"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { type: i5$3.SmsProviderConfigurationComponent, selector: "tb-sms-provider-configuration", inputs: ["required", "disabled"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.MatError, selector: "mat-error", inputs: ["id"] }, { type: i3.MatHint, selector: "mat-hint", inputs: ["align", "id"] }], pipes: { "translate": i4.TranslatePipe, "safeHtml": SafeHtmlPipe } }); -i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: SendSmsConfigComponent, decorators: [{ - type: Component, - args: [{ - selector: 'tb-action-node-send-sms-config', - templateUrl: './send-sms-config.component.html', - styleUrls: [] - }] - }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); - -class SnsConfigComponent extends RuleNodeConfigurationComponent { - constructor(store, fb) { - super(store); - this.store = store; - this.fb = fb; - } - configForm() { - return this.snsConfigForm; - } - onConfigurationSet(configuration) { - this.snsConfigForm = this.fb.group({ - topicArnPattern: [configuration ? configuration.topicArnPattern : null, [Validators.required]], - accessKeyId: [configuration ? configuration.accessKeyId : null, [Validators.required]], - secretAccessKey: [configuration ? configuration.secretAccessKey : null, [Validators.required]], - region: [configuration ? configuration.region : null, [Validators.required]] - }); - } -} -SnsConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: SnsConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); -SnsConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: SnsConfigComponent, selector: "tb-action-node-sns-config", usesInheritance: true, ngImport: i0, template: "
\n \n tb.rulenode.topic-arn-pattern\n \n \n {{ 'tb.rulenode.topic-arn-pattern-required' | translate }}\n \n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ 'tb.rulenode.aws-access-key-id-required' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ 'tb.rulenode.aws-secret-access-key-required' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ 'tb.rulenode.aws-region-required' | translate }}\n \n \n
\n", components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.MatError, selector: "mat-error", inputs: ["id"] }, { type: i3.MatHint, selector: "mat-hint", inputs: ["align", "id"] }], pipes: { "translate": i4.TranslatePipe, "safeHtml": SafeHtmlPipe } }); -i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: SnsConfigComponent, decorators: [{ - type: Component, - args: [{ - selector: 'tb-action-node-sns-config', - templateUrl: './sns-config.component.html', - styleUrls: [] - }] - }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); - -class SqsConfigComponent extends RuleNodeConfigurationComponent { - constructor(store, fb) { - super(store); - this.store = store; - this.fb = fb; - this.sqsQueueType = SqsQueueType; - this.sqsQueueTypes = Object.keys(SqsQueueType); - this.sqsQueueTypeTranslationsMap = sqsQueueTypeTranslations; - } - configForm() { - return this.sqsConfigForm; - } - onConfigurationSet(configuration) { - this.sqsConfigForm = this.fb.group({ - queueType: [configuration ? configuration.queueType : null, [Validators.required]], - queueUrlPattern: [configuration ? configuration.queueUrlPattern : null, [Validators.required]], - delaySeconds: [configuration ? configuration.delaySeconds : null, [Validators.min(0), Validators.max(900)]], - messageAttributes: [configuration ? configuration.messageAttributes : null, []], - accessKeyId: [configuration ? configuration.accessKeyId : null, [Validators.required]], - secretAccessKey: [configuration ? configuration.secretAccessKey : null, [Validators.required]], - region: [configuration ? configuration.region : null, [Validators.required]] - }); - } -} -SqsConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: SqsConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); -SqsConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: SqsConfigComponent, selector: "tb-action-node-sqs-config", usesInheritance: true, ngImport: i0, template: "
\n \n tb.rulenode.queue-type\n \n \n {{ sqsQueueTypeTranslationsMap.get(type) | translate }}\n \n \n \n \n tb.rulenode.queue-url-pattern\n \n \n {{ 'tb.rulenode.queue-url-pattern-required' | translate }}\n \n \n \n \n tb.rulenode.delay-seconds\n \n \n {{ 'tb.rulenode.min-delay-seconds-message' | translate }}\n \n \n {{ 'tb.rulenode.max-delay-seconds-message' | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ 'tb.rulenode.aws-access-key-id-required' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ 'tb.rulenode.aws-secret-access-key-required' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ 'tb.rulenode.aws-region-required' | translate }}\n \n \n
\n", components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }, { type: i4$1.MatSelect, selector: "mat-select", inputs: ["disabled", "disableRipple", "tabIndex"], exportAs: ["matSelect"] }, { type: i5.MatOption, selector: "mat-option", exportAs: ["matOption"] }, { type: KvMapConfigComponent, selector: "tb-kv-map-config", inputs: ["disabled", "requiredText", "keyText", "keyRequiredText", "valText", "valRequiredText", "required"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i10.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.MatError, selector: "mat-error", inputs: ["id"] }, { type: i3.MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { type: i2.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { type: i2.MaxValidator, selector: "input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]", inputs: ["max"] }, { type: i2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }], pipes: { "translate": i4.TranslatePipe, "safeHtml": SafeHtmlPipe } }); -i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: SqsConfigComponent, decorators: [{ - type: Component, - args: [{ - selector: 'tb-action-node-sqs-config', - templateUrl: './sqs-config.component.html', - styleUrls: [] - }] - }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); - -class TimeseriesConfigComponent extends RuleNodeConfigurationComponent { - constructor(store, fb) { - super(store); - this.store = store; - this.fb = fb; - } - configForm() { - return this.timeseriesConfigForm; - } - onConfigurationSet(configuration) { - this.timeseriesConfigForm = this.fb.group({ - defaultTTL: [configuration ? configuration.defaultTTL : null, [Validators.required, Validators.min(0)]] - }); - } -} -TimeseriesConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: TimeseriesConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); -TimeseriesConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: TimeseriesConfigComponent, selector: "tb-action-node-timeseries-config", usesInheritance: true, ngImport: i0, template: "
\n \n tb.rulenode.default-ttl\n \n \n {{ 'tb.rulenode.default-ttl-required' | translate }}\n \n \n {{ 'tb.rulenode.min-default-ttl-message' | translate }}\n \n \n
\n", components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i2.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { type: i2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.MatError, selector: "mat-error", inputs: ["id"] }], pipes: { "translate": i4.TranslatePipe } }); -i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: TimeseriesConfigComponent, decorators: [{ - type: Component, - args: [{ - selector: 'tb-action-node-timeseries-config', - templateUrl: './timeseries-config.component.html', - styleUrls: [] - }] - }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); - -class UnassignCustomerConfigComponent extends RuleNodeConfigurationComponent { - constructor(store, fb) { - super(store); - this.store = store; - this.fb = fb; - } - configForm() { - return this.unassignCustomerConfigForm; - } - onConfigurationSet(configuration) { - this.unassignCustomerConfigForm = this.fb.group({ - customerNamePattern: [configuration ? configuration.customerNamePattern : null, [Validators.required, Validators.pattern(/.*\S.*/)]], - customerCacheExpiration: [configuration ? configuration.customerCacheExpiration : null, [Validators.required, Validators.min(0)]] - }); - } - prepareOutputConfig(configuration) { - configuration.customerNamePattern = configuration.customerNamePattern.trim(); - return configuration; - } -} -UnassignCustomerConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: UnassignCustomerConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); -UnassignCustomerConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: UnassignCustomerConfigComponent, selector: "tb-action-node-un-assign-to-customer-config", usesInheritance: true, ngImport: i0, template: "
\n \n tb.rulenode.customer-name-pattern\n \n \n {{ 'tb.rulenode.customer-name-pattern-required' | translate }}\n \n \n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ 'tb.rulenode.customer-cache-expiration-required' | translate }}\n \n \n {{ 'tb.rulenode.customer-cache-expiration-range' | translate }}\n \n tb.rulenode.customer-cache-expiration-hint\n \n
\n", components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.MatError, selector: "mat-error", inputs: ["id"] }, { type: i3.MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { type: i2.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { type: i2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }], pipes: { "translate": i4.TranslatePipe, "safeHtml": SafeHtmlPipe } }); -i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: UnassignCustomerConfigComponent, decorators: [{ - type: Component, - args: [{ - selector: 'tb-action-node-un-assign-to-customer-config', - templateUrl: './unassign-customer-config.component.html', - styleUrls: [] - }] - }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); - -class DeviceRelationsQueryConfigComponent extends PageComponent { - constructor(store, fb) { - super(store); - this.store = store; - this.fb = fb; - this.directionTypes = Object.keys(EntitySearchDirection); - this.directionTypeTranslations = entitySearchDirectionTranslations; - this.entityType = EntityType; - this.propagateChange = null; - } - get required() { - return this.requiredValue; - } - set required(value) { - this.requiredValue = coerceBooleanProperty(value); - } - ngOnInit() { - this.deviceRelationsQueryFormGroup = this.fb.group({ - fetchLastLevelOnly: [false, []], - direction: [null, [Validators.required]], - maxLevel: [null, []], - relationType: [null], - deviceTypes: [null, [Validators.required]] - }); - this.deviceRelationsQueryFormGroup.valueChanges.subscribe((query) => { - if (this.deviceRelationsQueryFormGroup.valid) { - this.propagateChange(query); - } - else { - this.propagateChange(null); - } - }); - } - registerOnChange(fn) { - this.propagateChange = fn; - } - registerOnTouched(fn) { - } - setDisabledState(isDisabled) { - this.disabled = isDisabled; - if (this.disabled) { - this.deviceRelationsQueryFormGroup.disable({ emitEvent: false }); - } - else { - this.deviceRelationsQueryFormGroup.enable({ emitEvent: false }); - } - } - writeValue(query) { - this.deviceRelationsQueryFormGroup.reset(query, { emitEvent: false }); - } -} -DeviceRelationsQueryConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: DeviceRelationsQueryConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); -DeviceRelationsQueryConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: DeviceRelationsQueryConfigComponent, selector: "tb-device-relations-query-config", inputs: { disabled: "disabled", required: "required" }, providers: [ - { - provide: NG_VALUE_ACCESSOR, - useExisting: forwardRef(() => DeviceRelationsQueryConfigComponent), - multi: true - } - ], usesInheritance: true, ngImport: i0, template: "
\n \n {{ 'alias.last-level-relation' | translate }}\n \n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n
\n
relation.relation-type
\n \n \n
device.device-types
\n \n \n
\n", components: [{ type: i3$1.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex", "aria-label", "aria-labelledby", "id", "labelPosition", "name", "required", "checked", "disabled", "indeterminate", "aria-describedby", "value"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }, { type: i4$1.MatSelect, selector: "mat-select", inputs: ["disabled", "disableRipple", "tabIndex"], exportAs: ["matSelect"] }, { type: i5.MatOption, selector: "mat-option", exportAs: ["matOption"] }, { type: i7$3.RelationTypeAutocompleteComponent, selector: "tb-relation-type-autocomplete", inputs: ["required", "disabled"] }, { type: i8$2.EntitySubTypeListComponent, selector: "tb-entity-subtype-list", inputs: ["required", "disabled", "entityType"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i8.DefaultLayoutGapDirective, selector: " [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]", inputs: ["fxLayoutGap", "fxLayoutGap.xs", "fxLayoutGap.sm", "fxLayoutGap.md", "fxLayoutGap.lg", "fxLayoutGap.xl", "fxLayoutGap.lt-sm", "fxLayoutGap.lt-md", "fxLayoutGap.lt-lg", "fxLayoutGap.lt-xl", "fxLayoutGap.gt-xs", "fxLayoutGap.gt-sm", "fxLayoutGap.gt-md", "fxLayoutGap.gt-lg"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i10.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i2.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { type: i2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }], pipes: { "translate": i4.TranslatePipe } }); -i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: DeviceRelationsQueryConfigComponent, decorators: [{ - type: Component, - args: [{ - selector: 'tb-device-relations-query-config', - templateUrl: './device-relations-query-config.component.html', - styleUrls: [], - providers: [ - { - provide: NG_VALUE_ACCESSOR, - useExisting: forwardRef(() => DeviceRelationsQueryConfigComponent), - multi: true - } - ] - }] - }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; }, propDecorators: { disabled: [{ - type: Input - }], required: [{ - type: Input - }] } }); - -class RelationsQueryConfigComponent extends PageComponent { - constructor(store, fb) { - super(store); - this.store = store; - this.fb = fb; - this.directionTypes = Object.keys(EntitySearchDirection); - this.directionTypeTranslations = entitySearchDirectionTranslations; - this.propagateChange = null; - } - get required() { - return this.requiredValue; - } - set required(value) { - this.requiredValue = coerceBooleanProperty(value); - } - ngOnInit() { - this.relationsQueryFormGroup = this.fb.group({ - fetchLastLevelOnly: [false, []], - direction: [null, [Validators.required]], - maxLevel: [null, []], - filters: [null] - }); - this.relationsQueryFormGroup.valueChanges.subscribe((query) => { - if (this.relationsQueryFormGroup.valid) { - this.propagateChange(query); - } - else { - this.propagateChange(null); - } - }); - } - registerOnChange(fn) { - this.propagateChange = fn; - } - registerOnTouched(fn) { - } - setDisabledState(isDisabled) { - this.disabled = isDisabled; - if (this.disabled) { - this.relationsQueryFormGroup.disable({ emitEvent: false }); - } - else { - this.relationsQueryFormGroup.enable({ emitEvent: false }); - } - } - writeValue(query) { - this.relationsQueryFormGroup.reset(query || {}, { emitEvent: false }); - } -} -RelationsQueryConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RelationsQueryConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); -RelationsQueryConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: RelationsQueryConfigComponent, selector: "tb-relations-query-config", inputs: { disabled: "disabled", required: "required" }, providers: [ - { - provide: NG_VALUE_ACCESSOR, - useExisting: forwardRef(() => RelationsQueryConfigComponent), - multi: true - } - ], usesInheritance: true, ngImport: i0, template: "
\n \n {{ 'alias.last-level-relation' | translate }}\n \n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n
\n
relation.relation-filters
\n \n
\n", components: [{ type: i3$1.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex", "aria-label", "aria-labelledby", "id", "labelPosition", "name", "required", "checked", "disabled", "indeterminate", "aria-describedby", "value"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }, { type: i4$1.MatSelect, selector: "mat-select", inputs: ["disabled", "disableRipple", "tabIndex"], exportAs: ["matSelect"] }, { type: i5.MatOption, selector: "mat-option", exportAs: ["matOption"] }, { type: i7$4.RelationFiltersComponent, selector: "tb-relation-filters", inputs: ["disabled", "allowedEntityTypes"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i8.DefaultLayoutGapDirective, selector: " [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]", inputs: ["fxLayoutGap", "fxLayoutGap.xs", "fxLayoutGap.sm", "fxLayoutGap.md", "fxLayoutGap.lg", "fxLayoutGap.xl", "fxLayoutGap.lt-sm", "fxLayoutGap.lt-md", "fxLayoutGap.lt-lg", "fxLayoutGap.lt-xl", "fxLayoutGap.gt-xs", "fxLayoutGap.gt-sm", "fxLayoutGap.gt-md", "fxLayoutGap.gt-lg"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i10.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i2.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { type: i2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }], pipes: { "translate": i4.TranslatePipe } }); -i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RelationsQueryConfigComponent, decorators: [{ - type: Component, - args: [{ - selector: 'tb-relations-query-config', - templateUrl: './relations-query-config.component.html', - styleUrls: [], - providers: [ - { - provide: NG_VALUE_ACCESSOR, - useExisting: forwardRef(() => RelationsQueryConfigComponent), - multi: true - } - ] - }] - }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; }, propDecorators: { disabled: [{ - type: Input - }], required: [{ - type: Input - }] } }); - -class MessageTypesConfigComponent extends PageComponent { - constructor(store, translate, truncate, fb) { - super(store); - this.store = store; - this.translate = translate; - this.truncate = truncate; - this.fb = fb; - this.placeholder = 'tb.rulenode.message-type'; - this.separatorKeysCodes = [ENTER, COMMA, SEMICOLON]; - this.messageTypes = []; - this.messageTypesList = []; - this.searchText = ''; - this.propagateChange = (v) => { }; - this.messageTypeConfigForm = this.fb.group({ - messageType: [null] - }); - for (const type of Object.keys(MessageType)) { - this.messageTypesList.push({ - name: messageTypeNames.get(MessageType[type]), - value: type - }); - } - } - get required() { - return this.requiredValue; - } - set required(value) { - this.requiredValue = coerceBooleanProperty(value); - } - registerOnChange(fn) { - this.propagateChange = fn; - } - registerOnTouched(fn) { - } - ngOnInit() { - this.filteredMessageTypes = this.messageTypeConfigForm.get('messageType').valueChanges - .pipe(startWith(''), map((value) => value ? value : ''), mergeMap(name => this.fetchMessageTypes(name)), share()); - } - ngAfterViewInit() { } - setDisabledState(isDisabled) { - this.disabled = isDisabled; - if (this.disabled) { - this.messageTypeConfigForm.disable({ emitEvent: false }); - } - else { - this.messageTypeConfigForm.enable({ emitEvent: false }); - } - } - writeValue(value) { - this.searchText = ''; - this.messageTypes.length = 0; - if (value) { - value.forEach((type) => { - const found = this.messageTypesList.find((messageType => messageType.value === type)); - if (found) { - this.messageTypes.push({ - name: found.name, - value: found.value - }); - } - else { - this.messageTypes.push({ - name: type, - value: type - }); - } - }); - } - } - displayMessageTypeFn(messageType) { - return messageType ? messageType.name : undefined; - } - textIsNotEmpty(text) { - return (text && text != null && text.length > 0) ? true : false; - } - createMessageType($event, value) { - $event.preventDefault(); - this.transformMessageType(value); - } - add(event) { - this.transformMessageType(event.value); - } - fetchMessageTypes(searchText) { - this.searchText = searchText; - if (this.searchText && this.searchText.length) { - const search = this.searchText.toUpperCase(); - return of(this.messageTypesList.filter(messageType => messageType.name.toUpperCase().includes(search))); - } - else { - return of(this.messageTypesList); - } - } - transformMessageType(value) { - if ((value || '').trim()) { - let newMessageType = null; - const messageTypeName = value.trim(); - const existingMessageType = this.messageTypesList.find(messageType => messageType.name === messageTypeName); - if (existingMessageType) { - newMessageType = { - name: existingMessageType.name, - value: existingMessageType.value - }; - } - else { - newMessageType = { - name: messageTypeName, - value: messageTypeName - }; - } - if (newMessageType) { - this.addMessageType(newMessageType); - } - } - this.clear(''); - } - remove(messageType) { - const index = this.messageTypes.indexOf(messageType); - if (index >= 0) { - this.messageTypes.splice(index, 1); - this.updateModel(); - } - } - selected(event) { - this.addMessageType(event.option.value); - this.clear(''); - } - addMessageType(messageType) { - const index = this.messageTypes.findIndex(existingMessageType => existingMessageType.value === messageType.value); - if (index === -1) { - this.messageTypes.push(messageType); - this.updateModel(); - } - } - onFocus() { - this.messageTypeConfigForm.get('messageType').updateValueAndValidity({ onlySelf: true, emitEvent: true }); - } - clear(value = '') { - this.messageTypeInput.nativeElement.value = value; - this.messageTypeConfigForm.get('messageType').patchValue(null, { emitEvent: true }); - setTimeout(() => { - this.messageTypeInput.nativeElement.blur(); - this.messageTypeInput.nativeElement.focus(); - }, 0); - } - updateModel() { - const value = this.messageTypes.map((messageType => messageType.value)); - if (this.required) { - this.chipList.errorState = !value.length; - this.propagateChange(value.length > 0 ? value : null); - } - else { - this.chipList.errorState = false; - this.propagateChange(value); - } - } -} -MessageTypesConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: MessageTypesConfigComponent, deps: [{ token: i1.Store }, { token: i4.TranslateService }, { token: i3$4.TruncatePipe }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); -MessageTypesConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: MessageTypesConfigComponent, selector: "tb-message-types-config", inputs: { required: "required", label: "label", placeholder: "placeholder", disabled: "disabled" }, providers: [ - { - provide: NG_VALUE_ACCESSOR, - useExisting: forwardRef(() => MessageTypesConfigComponent), - multi: true - } - ], viewQueries: [{ propertyName: "chipList", first: true, predicate: ["chipList"], descendants: true }, { propertyName: "matAutocomplete", first: true, predicate: ["messageTypeAutocomplete"], descendants: true }, { propertyName: "messageTypeInput", first: true, predicate: ["messageTypeInput"], descendants: true }], usesInheritance: true, ngImport: i0, template: "\n {{ label }}\n \n \n {{messageType.name}}\n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-message-types-found\n
\n \n \n {{ translate.get('tb.rulenode.no-message-type-matching',\n {messageType: truncate.transform(searchText, true, 6, '...')}) | async }}\n \n \n \n tb.rulenode.create-new-message-type\n \n
\n
\n
\n \n {{ 'tb.rulenode.message-types-required' | translate }}\n \n
\n", components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }, { type: i5$2.MatChipList, selector: "mat-chip-list", inputs: ["aria-orientation", "multiple", "compareWith", "value", "required", "placeholder", "disabled", "selectable", "tabIndex", "errorStateMatcher"], outputs: ["change", "valueChange"], exportAs: ["matChipList"] }, { type: i6$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { type: i7$5.MatAutocomplete, selector: "mat-autocomplete", inputs: ["disableRipple"], exportAs: ["matAutocomplete"] }, { type: i5.MatOption, selector: "mat-option", exportAs: ["matOption"] }], directives: [{ type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i10.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i5$2.MatChip, selector: "mat-basic-chip, [mat-basic-chip], mat-chip, [mat-chip]", inputs: ["color", "disableRipple", "tabIndex", "selected", "value", "selectable", "disabled", "removable"], outputs: ["selectionChange", "destroyed", "removed"], exportAs: ["matChip"] }, { type: i5$2.MatChipRemove, selector: "[matChipRemove]" }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i7$5.MatAutocompleteTrigger, selector: "input[matAutocomplete], textarea[matAutocomplete]", exportAs: ["matAutocompleteTrigger"] }, { type: i5$2.MatChipInput, selector: "input[matChipInputFor]", inputs: ["matChipInputSeparatorKeyCodes", "placeholder", "id", "matChipInputFor", "matChipInputAddOnBlur", "disabled"], outputs: ["matChipInputTokenEnd"], exportAs: ["matChipInput", "matChipInputFor"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i7$5.MatAutocompleteOrigin, selector: "[matAutocompleteOrigin]", exportAs: ["matAutocompleteOrigin"] }, { type: i3.MatError, selector: "mat-error", inputs: ["id"] }], pipes: { "translate": i4.TranslatePipe, "async": i10.AsyncPipe, "highlight": i12$1.HighlightPipe } }); -i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: MessageTypesConfigComponent, decorators: [{ - type: Component, - args: [{ - selector: 'tb-message-types-config', - templateUrl: './message-types-config.component.html', - styleUrls: [], - providers: [ - { - provide: NG_VALUE_ACCESSOR, - useExisting: forwardRef(() => MessageTypesConfigComponent), - multi: true - } - ] - }] - }], ctorParameters: function () { return [{ type: i1.Store }, { type: i4.TranslateService }, { type: i3$4.TruncatePipe }, { type: i2.FormBuilder }]; }, propDecorators: { required: [{ - type: Input - }], label: [{ - type: Input - }], placeholder: [{ - type: Input - }], disabled: [{ - type: Input - }], chipList: [{ - type: ViewChild, - args: ['chipList', { static: false }] - }], matAutocomplete: [{ - type: ViewChild, - args: ['messageTypeAutocomplete', { static: false }] - }], messageTypeInput: [{ - type: ViewChild, - args: ['messageTypeInput', { static: false }] - }] } }); - -class RulenodeCoreConfigCommonModule { -} -RulenodeCoreConfigCommonModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RulenodeCoreConfigCommonModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); -RulenodeCoreConfigCommonModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RulenodeCoreConfigCommonModule, declarations: [KvMapConfigComponent, - DeviceRelationsQueryConfigComponent, - RelationsQueryConfigComponent, - MessageTypesConfigComponent, - CredentialsConfigComponent, - SafeHtmlPipe], imports: [CommonModule, - SharedModule, - HomeComponentsModule], exports: [KvMapConfigComponent, - DeviceRelationsQueryConfigComponent, - RelationsQueryConfigComponent, - MessageTypesConfigComponent, - CredentialsConfigComponent, - SafeHtmlPipe] }); -RulenodeCoreConfigCommonModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RulenodeCoreConfigCommonModule, imports: [[ - CommonModule, - SharedModule, - HomeComponentsModule - ]] }); -i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RulenodeCoreConfigCommonModule, decorators: [{ - type: NgModule, - args: [{ - declarations: [ - KvMapConfigComponent, - DeviceRelationsQueryConfigComponent, - RelationsQueryConfigComponent, - MessageTypesConfigComponent, - CredentialsConfigComponent, - SafeHtmlPipe - ], - imports: [ - CommonModule, - SharedModule, - HomeComponentsModule - ], - exports: [ - KvMapConfigComponent, - DeviceRelationsQueryConfigComponent, - RelationsQueryConfigComponent, - MessageTypesConfigComponent, - CredentialsConfigComponent, - SafeHtmlPipe - ] - }] - }] }); - -class RuleNodeCoreConfigActionModule { -} -RuleNodeCoreConfigActionModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RuleNodeCoreConfigActionModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); -RuleNodeCoreConfigActionModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RuleNodeCoreConfigActionModule, declarations: [AttributesConfigComponent, - TimeseriesConfigComponent, - RpcRequestConfigComponent, - LogConfigComponent, - AssignCustomerConfigComponent, - ClearAlarmConfigComponent, - CreateAlarmConfigComponent, - CreateRelationConfigComponent, - MsgDelayConfigComponent, - DeleteRelationConfigComponent, - GeneratorConfigComponent, - GpsGeoActionConfigComponent, - MsgCountConfigComponent, - RpcReplyConfigComponent, - SaveToCustomTableConfigComponent, - UnassignCustomerConfigComponent, - SnsConfigComponent, - SqsConfigComponent, - PubSubConfigComponent, - KafkaConfigComponent, - MqttConfigComponent, - RabbitMqConfigComponent, - RestApiCallConfigComponent, - SendEmailConfigComponent, - CheckPointConfigComponent, - AzureIotHubConfigComponent, - DeviceProfileConfigComponent, - SendSmsConfigComponent, - PushToEdgeConfigComponent, - PushToCloudConfigComponent], imports: [CommonModule, - SharedModule, - HomeComponentsModule, - RulenodeCoreConfigCommonModule], exports: [AttributesConfigComponent, - TimeseriesConfigComponent, - RpcRequestConfigComponent, - LogConfigComponent, - AssignCustomerConfigComponent, - ClearAlarmConfigComponent, - CreateAlarmConfigComponent, - CreateRelationConfigComponent, - MsgDelayConfigComponent, - DeleteRelationConfigComponent, - GeneratorConfigComponent, - GpsGeoActionConfigComponent, - MsgCountConfigComponent, - RpcReplyConfigComponent, - SaveToCustomTableConfigComponent, - UnassignCustomerConfigComponent, - SnsConfigComponent, - SqsConfigComponent, - PubSubConfigComponent, - KafkaConfigComponent, - MqttConfigComponent, - RabbitMqConfigComponent, - RestApiCallConfigComponent, - SendEmailConfigComponent, - CheckPointConfigComponent, - AzureIotHubConfigComponent, - DeviceProfileConfigComponent, - SendSmsConfigComponent, - PushToEdgeConfigComponent, - PushToCloudConfigComponent] }); -RuleNodeCoreConfigActionModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RuleNodeCoreConfigActionModule, imports: [[ - CommonModule, - SharedModule, - HomeComponentsModule, - RulenodeCoreConfigCommonModule - ]] }); -i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RuleNodeCoreConfigActionModule, decorators: [{ - type: NgModule, - args: [{ - declarations: [ - AttributesConfigComponent, - TimeseriesConfigComponent, - RpcRequestConfigComponent, - LogConfigComponent, - AssignCustomerConfigComponent, - ClearAlarmConfigComponent, - CreateAlarmConfigComponent, - CreateRelationConfigComponent, - MsgDelayConfigComponent, - DeleteRelationConfigComponent, - GeneratorConfigComponent, - GpsGeoActionConfigComponent, - MsgCountConfigComponent, - RpcReplyConfigComponent, - SaveToCustomTableConfigComponent, - UnassignCustomerConfigComponent, - SnsConfigComponent, - SqsConfigComponent, - PubSubConfigComponent, - KafkaConfigComponent, - MqttConfigComponent, - RabbitMqConfigComponent, - RestApiCallConfigComponent, - SendEmailConfigComponent, - CheckPointConfigComponent, - AzureIotHubConfigComponent, - DeviceProfileConfigComponent, - SendSmsConfigComponent, - PushToEdgeConfigComponent, - PushToCloudConfigComponent - ], - imports: [ - CommonModule, - SharedModule, - HomeComponentsModule, - RulenodeCoreConfigCommonModule - ], - exports: [ - AttributesConfigComponent, - TimeseriesConfigComponent, - RpcRequestConfigComponent, - LogConfigComponent, - AssignCustomerConfigComponent, - ClearAlarmConfigComponent, - CreateAlarmConfigComponent, - CreateRelationConfigComponent, - MsgDelayConfigComponent, - DeleteRelationConfigComponent, - GeneratorConfigComponent, - GpsGeoActionConfigComponent, - MsgCountConfigComponent, - RpcReplyConfigComponent, - SaveToCustomTableConfigComponent, - UnassignCustomerConfigComponent, - SnsConfigComponent, - SqsConfigComponent, - PubSubConfigComponent, - KafkaConfigComponent, - MqttConfigComponent, - RabbitMqConfigComponent, - RestApiCallConfigComponent, - SendEmailConfigComponent, - CheckPointConfigComponent, - AzureIotHubConfigComponent, - DeviceProfileConfigComponent, - SendSmsConfigComponent, - PushToEdgeConfigComponent, - PushToCloudConfigComponent - ] - }] - }] }); - -class CalculateDeltaConfigComponent extends RuleNodeConfigurationComponent { - constructor(store, fb) { - super(store); - this.store = store; - this.fb = fb; - this.separatorKeysCodes = [ENTER, COMMA, SEMICOLON]; - } - configForm() { - return this.calculateDeltaConfigForm; - } - onConfigurationSet(configuration) { - this.calculateDeltaConfigForm = this.fb.group({ - inputValueKey: [configuration ? configuration.inputValueKey : null, [Validators.required]], - outputValueKey: [configuration ? configuration.outputValueKey : null, [Validators.required]], - useCache: [configuration ? configuration.useCache : null, []], - addPeriodBetweenMsgs: [configuration ? configuration.addPeriodBetweenMsgs : false, []], - periodValueKey: [configuration ? configuration.periodValueKey : null, []], - round: [configuration ? configuration.round : null, [Validators.min(0), Validators.max(15)]], - tellFailureIfDeltaIsNegative: [configuration ? configuration.tellFailureIfDeltaIsNegative : null, []] - }); - } - updateValidators(emitEvent) { - const addPeriodBetweenMsgs = this.calculateDeltaConfigForm.get('addPeriodBetweenMsgs').value; - if (addPeriodBetweenMsgs) { - this.calculateDeltaConfigForm.get('periodValueKey').setValidators([Validators.required]); - } - else { - this.calculateDeltaConfigForm.get('periodValueKey').setValidators([]); - } - this.calculateDeltaConfigForm.get('periodValueKey').updateValueAndValidity({ emitEvent }); - } - validatorTriggers() { - return ['addPeriodBetweenMsgs']; - } -} -CalculateDeltaConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: CalculateDeltaConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); -CalculateDeltaConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: CalculateDeltaConfigComponent, selector: "tb-enrichment-node-calculate-delta-config", usesInheritance: true, ngImport: i0, template: "
\n
\n \n tb.rulenode.input-value-key\n \n \n {{ 'tb.rulenode.input-value-key-required' | translate }}\n \n \n \n tb.rulenode.output-value-key\n \n \n {{ 'tb.rulenode.output-value-key-required' | translate }}\n \n \n \n tb.rulenode.round\n \n \n {{ 'tb.rulenode.round-range' | translate }}\n \n \n {{ 'tb.rulenode.round-range' | translate }}\n \n \n
\n \n {{ 'tb.rulenode.use-cache' | translate }}\n \n \n {{ 'tb.rulenode.tell-failure-if-delta-is-negative' | translate }}\n \n \n {{ 'tb.rulenode.add-period-between-msgs' | translate }}\n \n \n tb.rulenode.period-value-key\n \n \n {{ 'tb.rulenode.period-value-key-required' | translate }}\n \n \n
\n", components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }, { type: i3$1.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex", "aria-label", "aria-labelledby", "id", "labelPosition", "name", "required", "checked", "disabled", "indeterminate", "aria-describedby", "value"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i8.DefaultLayoutGapDirective, selector: " [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]", inputs: ["fxLayoutGap", "fxLayoutGap.xs", "fxLayoutGap.sm", "fxLayoutGap.md", "fxLayoutGap.lg", "fxLayoutGap.xl", "fxLayoutGap.lt-sm", "fxLayoutGap.lt-md", "fxLayoutGap.lt-lg", "fxLayoutGap.lt-xl", "fxLayoutGap.gt-xs", "fxLayoutGap.gt-sm", "fxLayoutGap.gt-md", "fxLayoutGap.gt-lg"] }, { type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.MatError, selector: "mat-error", inputs: ["id"] }, { type: i2.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { type: i2.MaxValidator, selector: "input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]", inputs: ["max"] }, { type: i2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }], pipes: { "translate": i4.TranslatePipe } }); -i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: CalculateDeltaConfigComponent, decorators: [{ - type: Component, - args: [{ - selector: 'tb-enrichment-node-calculate-delta-config', - templateUrl: './calculate-delta-config.component.html', - styleUrls: [] - }] - }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); - -class CustomerAttributesConfigComponent extends RuleNodeConfigurationComponent { - constructor(store, fb) { - super(store); - this.store = store; - this.fb = fb; - } - configForm() { - return this.customerAttributesConfigForm; - } - onConfigurationSet(configuration) { - this.customerAttributesConfigForm = this.fb.group({ - telemetry: [configuration ? configuration.telemetry : false, []], - attrMapping: [configuration ? configuration.attrMapping : null, [Validators.required]] - }); - } -} -CustomerAttributesConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: CustomerAttributesConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); -CustomerAttributesConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: CustomerAttributesConfigComponent, selector: "tb-enrichment-node-customer-attributes-config", usesInheritance: true, ngImport: i0, template: "
\n \n \n {{ 'tb.rulenode.latest-telemetry' | translate }}\n \n \n \n
\n", components: [{ type: i3$1.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex", "aria-label", "aria-labelledby", "id", "labelPosition", "name", "required", "checked", "disabled", "indeterminate", "aria-describedby", "value"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { type: KvMapConfigComponent, selector: "tb-kv-map-config", inputs: ["disabled", "requiredText", "keyText", "keyRequiredText", "valText", "valRequiredText", "required"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }], pipes: { "translate": i4.TranslatePipe } }); -i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: CustomerAttributesConfigComponent, decorators: [{ - type: Component, - args: [{ - selector: 'tb-enrichment-node-customer-attributes-config', - templateUrl: './customer-attributes-config.component.html', - styleUrls: [] - }] - }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); - -class DeviceAttributesConfigComponent extends RuleNodeConfigurationComponent { - constructor(store, fb) { - super(store); - this.store = store; - this.fb = fb; - this.separatorKeysCodes = [ENTER, COMMA, SEMICOLON]; - } - configForm() { - return this.deviceAttributesConfigForm; - } - onConfigurationSet(configuration) { - this.deviceAttributesConfigForm = this.fb.group({ - deviceRelationsQuery: [configuration ? configuration.deviceRelationsQuery : null, [Validators.required]], - tellFailureIfAbsent: [configuration ? configuration.tellFailureIfAbsent : false, []], - clientAttributeNames: [configuration ? configuration.clientAttributeNames : null, []], - sharedAttributeNames: [configuration ? configuration.sharedAttributeNames : null, []], - serverAttributeNames: [configuration ? configuration.serverAttributeNames : null, []], - latestTsKeyNames: [configuration ? configuration.latestTsKeyNames : null, []], - getLatestValueWithTs: [configuration ? configuration.getLatestValueWithTs : false, []] - }); - } - removeKey(key, keysField) { - const keys = this.deviceAttributesConfigForm.get(keysField).value; - const index = keys.indexOf(key); - if (index >= 0) { - keys.splice(index, 1); - this.deviceAttributesConfigForm.get(keysField).setValue(keys, { emitEvent: true }); - } - } - addKey(event, keysField) { - const input = event.input; - let value = event.value; - if ((value || '').trim()) { - value = value.trim(); - let keys = this.deviceAttributesConfigForm.get(keysField).value; - if (!keys || keys.indexOf(value) === -1) { - if (!keys) { - keys = []; - } - keys.push(value); - this.deviceAttributesConfigForm.get(keysField).setValue(keys, { emitEvent: true }); - } - } - if (input) { - input.value = ''; - } - } -} -DeviceAttributesConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: DeviceAttributesConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); -DeviceAttributesConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: DeviceAttributesConfigComponent, selector: "tb-enrichment-node-device-attributes-config", usesInheritance: true, ngImport: i0, template: "
\n \n \n \n \n {{ 'tb.rulenode.tell-failure-if-absent' | translate }}\n \n
tb.rulenode.tell-failure-if-absent-hint
\n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n {{ 'tb.rulenode.get-latest-value-with-ts' | translate }}\n \n
\n
\n", styles: [":host label.tb-title{margin-bottom:-10px}\n"], components: [{ type: DeviceRelationsQueryConfigComponent, selector: "tb-device-relations-query-config", inputs: ["disabled", "required"] }, { type: i3$1.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex", "aria-label", "aria-labelledby", "id", "labelPosition", "name", "required", "checked", "disabled", "indeterminate", "aria-describedby", "value"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }, { type: i5$2.MatChipList, selector: "mat-chip-list", inputs: ["aria-orientation", "multiple", "compareWith", "value", "required", "placeholder", "disabled", "selectable", "tabIndex", "errorStateMatcher"], outputs: ["change", "valueChange"], exportAs: ["matChipList"] }, { type: i6$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i10.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i5$2.MatChip, selector: "mat-basic-chip, [mat-basic-chip], mat-chip, [mat-chip]", inputs: ["color", "disableRipple", "tabIndex", "selected", "value", "selectable", "disabled", "removable"], outputs: ["selectionChange", "destroyed", "removed"], exportAs: ["matChip"] }, { type: i5$2.MatChipRemove, selector: "[matChipRemove]" }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i5$2.MatChipInput, selector: "input[matChipInputFor]", inputs: ["matChipInputSeparatorKeyCodes", "placeholder", "id", "matChipInputFor", "matChipInputAddOnBlur", "disabled"], outputs: ["matChipInputTokenEnd"], exportAs: ["matChipInput", "matChipInputFor"] }], pipes: { "translate": i4.TranslatePipe, "safeHtml": SafeHtmlPipe } }); -i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: DeviceAttributesConfigComponent, decorators: [{ - type: Component, - args: [{ - selector: 'tb-enrichment-node-device-attributes-config', - templateUrl: './device-attributes-config.component.html', - styleUrls: ['./device-attributes-config.component.scss'] - }] - }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); - -class EntityDetailsConfigComponent extends RuleNodeConfigurationComponent { - constructor(store, translate, fb) { - super(store); - this.store = store; - this.translate = translate; - this.fb = fb; - this.entityDetailsTranslationsMap = entityDetailsTranslations; - this.entityDetailsList = []; - this.searchText = ''; - this.displayDetailsFn = this.displayDetails.bind(this); - for (const field of Object.keys(EntityDetailsField)) { - this.entityDetailsList.push(EntityDetailsField[field]); - } - this.detailsFormControl = new FormControl(''); - this.filteredEntityDetails = this.detailsFormControl.valueChanges - .pipe(startWith(''), map((value) => value ? value : ''), mergeMap(name => this.fetchEntityDetails(name)), share()); - } - ngOnInit() { - super.ngOnInit(); - } - configForm() { - return this.entityDetailsConfigForm; - } - prepareInputConfig(configuration) { - this.searchText = ''; - this.detailsFormControl.patchValue('', { emitEvent: true }); - return configuration; - } - onConfigurationSet(configuration) { - this.entityDetailsConfigForm = this.fb.group({ - detailsList: [configuration ? configuration.detailsList : null, [Validators.required]], - addToMetadata: [configuration ? configuration.addToMetadata : false, []] - }); - } - displayDetails(details) { - return details ? this.translate.instant(entityDetailsTranslations.get(details)) : undefined; - } - fetchEntityDetails(searchText) { - this.searchText = searchText; - if (this.searchText && this.searchText.length) { - const search = this.searchText.toUpperCase(); - return of(this.entityDetailsList.filter(field => this.translate.instant(entityDetailsTranslations.get(EntityDetailsField[field])).toUpperCase().includes(search))); - } - else { - return of(this.entityDetailsList); - } - } - detailsFieldSelected(event) { - this.addDetailsField(event.option.value); - this.clear(''); - } - removeDetailsField(details) { - const detailsList = this.entityDetailsConfigForm.get('detailsList').value; - if (detailsList) { - const index = detailsList.indexOf(details); - if (index >= 0) { - detailsList.splice(index, 1); - this.entityDetailsConfigForm.get('detailsList').setValue(detailsList); - } - } - } - addDetailsField(details) { - let detailsList = this.entityDetailsConfigForm.get('detailsList').value; - if (!detailsList) { - detailsList = []; - } - const index = detailsList.indexOf(details); - if (index === -1) { - detailsList.push(details); - this.entityDetailsConfigForm.get('detailsList').setValue(detailsList); - } - } - onEntityDetailsInputFocus() { - this.detailsFormControl.updateValueAndValidity({ onlySelf: true, emitEvent: true }); - } - clear(value = '') { - this.detailsInput.nativeElement.value = value; - this.detailsFormControl.patchValue(null, { emitEvent: true }); - setTimeout(() => { - this.detailsInput.nativeElement.blur(); - this.detailsInput.nativeElement.focus(); - }, 0); - } -} -EntityDetailsConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: EntityDetailsConfigComponent, deps: [{ token: i1.Store }, { token: i4.TranslateService }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); -EntityDetailsConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: EntityDetailsConfigComponent, selector: "tb-enrichment-node-entity-details-config", viewQueries: [{ propertyName: "detailsInput", first: true, predicate: ["detailsInput"], descendants: true }], usesInheritance: true, ngImport: i0, template: "
\n \n tb.rulenode.entity-details\n \n \n \n {{entityDetailsTranslationsMap.get(details) | translate}}\n \n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-entity-details-matching\n
\n
\n
\n
\n
\n \n \n {{ 'tb.rulenode.add-to-metadata' | translate }}\n \n
tb.rulenode.add-to-metadata-hint
\n
\n", styles: [":host ::ng-deep mat-form-field.entity-fields-list .mat-form-field-wrapper{margin-bottom:-1.25em}\n"], components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }, { type: i5$2.MatChipList, selector: "mat-chip-list", inputs: ["aria-orientation", "multiple", "compareWith", "value", "required", "placeholder", "disabled", "selectable", "tabIndex", "errorStateMatcher"], outputs: ["change", "valueChange"], exportAs: ["matChipList"] }, { type: i6$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { type: i7$5.MatAutocomplete, selector: "mat-autocomplete", inputs: ["disableRipple"], exportAs: ["matAutocomplete"] }, { type: i5.MatOption, selector: "mat-option", exportAs: ["matOption"] }, { type: i9.TbErrorComponent, selector: "tb-error", inputs: ["error"] }, { type: i3$1.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex", "aria-label", "aria-labelledby", "id", "labelPosition", "name", "required", "checked", "disabled", "indeterminate", "aria-describedby", "value"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i10.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i5$2.MatChip, selector: "mat-basic-chip, [mat-basic-chip], mat-chip, [mat-chip]", inputs: ["color", "disableRipple", "tabIndex", "selected", "value", "selectable", "disabled", "removable"], outputs: ["selectionChange", "destroyed", "removed"], exportAs: ["matChip"] }, { type: i5$2.MatChipRemove, selector: "[matChipRemove]" }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i7$5.MatAutocompleteTrigger, selector: "input[matAutocomplete], textarea[matAutocomplete]", exportAs: ["matAutocompleteTrigger"] }, { type: i5$2.MatChipInput, selector: "input[matChipInputFor]", inputs: ["matChipInputSeparatorKeyCodes", "placeholder", "id", "matChipInputFor", "matChipInputAddOnBlur", "disabled"], outputs: ["matChipInputTokenEnd"], exportAs: ["matChipInput", "matChipInputFor"] }, { type: i7$5.MatAutocompleteOrigin, selector: "[matAutocompleteOrigin]", exportAs: ["matAutocompleteOrigin"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlDirective, selector: "[formControl]", inputs: ["disabled", "formControl", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }], pipes: { "translate": i4.TranslatePipe, "async": i10.AsyncPipe, "highlight": i12$1.HighlightPipe } }); -i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: EntityDetailsConfigComponent, decorators: [{ - type: Component, - args: [{ - selector: 'tb-enrichment-node-entity-details-config', - templateUrl: './entity-details-config.component.html', - styleUrls: ['./entity-details-config.component.scss'] - }] - }], ctorParameters: function () { return [{ type: i1.Store }, { type: i4.TranslateService }, { type: i2.FormBuilder }]; }, propDecorators: { detailsInput: [{ - type: ViewChild, - args: ['detailsInput', { static: false }] - }] } }); - -class GetTelemetryFromDatabaseConfigComponent extends RuleNodeConfigurationComponent { - constructor(store, fb) { - super(store); - this.store = store; - this.fb = fb; - this.separatorKeysCodes = [ENTER, COMMA, SEMICOLON]; - this.aggregationTypes = AggregationType; - this.aggregations = Object.keys(AggregationType); - this.aggregationTypesTranslations = aggregationTranslations; - this.fetchMode = FetchMode; - this.fetchModes = Object.keys(FetchMode); - this.samplingOrders = Object.keys(SamplingOrder); - this.timeUnits = Object.values(TimeUnit); - this.timeUnitsTranslationMap = timeUnitTranslations; - } - configForm() { - return this.getTelemetryFromDatabaseConfigForm; - } - onConfigurationSet(configuration) { - this.getTelemetryFromDatabaseConfigForm = this.fb.group({ - latestTsKeyNames: [configuration ? configuration.latestTsKeyNames : null, []], - aggregation: [configuration ? configuration.aggregation : null, [Validators.required]], - fetchMode: [configuration ? configuration.fetchMode : null, [Validators.required]], - orderBy: [configuration ? configuration.orderBy : null, []], - limit: [configuration ? configuration.limit : null, []], - useMetadataIntervalPatterns: [configuration ? configuration.useMetadataIntervalPatterns : false, []], - startInterval: [configuration ? configuration.startInterval : null, []], - startIntervalTimeUnit: [configuration ? configuration.startIntervalTimeUnit : null, []], - endInterval: [configuration ? configuration.endInterval : null, []], - endIntervalTimeUnit: [configuration ? configuration.endIntervalTimeUnit : null, []], - startIntervalPattern: [configuration ? configuration.startIntervalPattern : null, []], - endIntervalPattern: [configuration ? configuration.endIntervalPattern : null, []], - }); - } - validatorTriggers() { - return ['fetchMode', 'useMetadataIntervalPatterns']; - } - updateValidators(emitEvent) { - const fetchMode = this.getTelemetryFromDatabaseConfigForm.get('fetchMode').value; - const useMetadataIntervalPatterns = this.getTelemetryFromDatabaseConfigForm.get('useMetadataIntervalPatterns').value; - if (fetchMode && fetchMode === FetchMode.ALL) { - this.getTelemetryFromDatabaseConfigForm.get('aggregation').setValidators([Validators.required]); - this.getTelemetryFromDatabaseConfigForm.get('orderBy').setValidators([Validators.required]); - this.getTelemetryFromDatabaseConfigForm.get('limit').setValidators([Validators.required, Validators.min(2), Validators.max(1000)]); - } - else { - this.getTelemetryFromDatabaseConfigForm.get('aggregation').setValidators([]); - this.getTelemetryFromDatabaseConfigForm.get('orderBy').setValidators([]); - this.getTelemetryFromDatabaseConfigForm.get('limit').setValidators([]); - } - if (useMetadataIntervalPatterns) { - this.getTelemetryFromDatabaseConfigForm.get('startInterval').setValidators([]); - this.getTelemetryFromDatabaseConfigForm.get('startIntervalTimeUnit').setValidators([]); - this.getTelemetryFromDatabaseConfigForm.get('endInterval').setValidators([]); - this.getTelemetryFromDatabaseConfigForm.get('endIntervalTimeUnit').setValidators([]); - this.getTelemetryFromDatabaseConfigForm.get('startIntervalPattern').setValidators([Validators.required]); - this.getTelemetryFromDatabaseConfigForm.get('endIntervalPattern').setValidators([Validators.required]); - } - else { - this.getTelemetryFromDatabaseConfigForm.get('startInterval').setValidators([Validators.required, - Validators.min(1), Validators.max(2147483647)]); - this.getTelemetryFromDatabaseConfigForm.get('startIntervalTimeUnit').setValidators([Validators.required]); - this.getTelemetryFromDatabaseConfigForm.get('endInterval').setValidators([Validators.required, - Validators.min(1), Validators.max(2147483647)]); - this.getTelemetryFromDatabaseConfigForm.get('endIntervalTimeUnit').setValidators([Validators.required]); - this.getTelemetryFromDatabaseConfigForm.get('startIntervalPattern').setValidators([]); - this.getTelemetryFromDatabaseConfigForm.get('endIntervalPattern').setValidators([]); - } - this.getTelemetryFromDatabaseConfigForm.get('aggregation').updateValueAndValidity({ emitEvent }); - this.getTelemetryFromDatabaseConfigForm.get('orderBy').updateValueAndValidity({ emitEvent }); - this.getTelemetryFromDatabaseConfigForm.get('limit').updateValueAndValidity({ emitEvent }); - this.getTelemetryFromDatabaseConfigForm.get('startInterval').updateValueAndValidity({ emitEvent }); - this.getTelemetryFromDatabaseConfigForm.get('startIntervalTimeUnit').updateValueAndValidity({ emitEvent }); - this.getTelemetryFromDatabaseConfigForm.get('endInterval').updateValueAndValidity({ emitEvent }); - this.getTelemetryFromDatabaseConfigForm.get('endIntervalTimeUnit').updateValueAndValidity({ emitEvent }); - this.getTelemetryFromDatabaseConfigForm.get('startIntervalPattern').updateValueAndValidity({ emitEvent }); - this.getTelemetryFromDatabaseConfigForm.get('endIntervalPattern').updateValueAndValidity({ emitEvent }); - } - removeKey(key, keysField) { - const keys = this.getTelemetryFromDatabaseConfigForm.get(keysField).value; - const index = keys.indexOf(key); - if (index >= 0) { - keys.splice(index, 1); - this.getTelemetryFromDatabaseConfigForm.get(keysField).setValue(keys, { emitEvent: true }); - } - } - addKey(event, keysField) { - const input = event.input; - let value = event.value; - if ((value || '').trim()) { - value = value.trim(); - let keys = this.getTelemetryFromDatabaseConfigForm.get(keysField).value; - if (!keys || keys.indexOf(value) === -1) { - if (!keys) { - keys = []; - } - keys.push(value); - this.getTelemetryFromDatabaseConfigForm.get(keysField).setValue(keys, { emitEvent: true }); - } - } - if (input) { - input.value = ''; - } - } -} -GetTelemetryFromDatabaseConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: GetTelemetryFromDatabaseConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); -GetTelemetryFromDatabaseConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: GetTelemetryFromDatabaseConfigComponent, selector: "tb-enrichment-node-get-telemetry-from-database", usesInheritance: true, ngImport: i0, template: "
\n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.fetch-mode\n \n \n {{ mode }}\n \n \n tb.rulenode.fetch-mode-hint\n \n
\n \n aggregation.function\n \n \n {{ aggregationTypesTranslations.get(aggregationTypes[aggregation]) | translate }}\n \n \n \n \n tb.rulenode.order-by\n \n \n {{ order }}\n \n \n tb.rulenode.order-by-hint\n \n \n tb.rulenode.limit\n \n tb.rulenode.limit-hint\n \n
\n \n {{ 'tb.rulenode.use-metadata-interval-patterns' | translate }}\n \n
tb.rulenode.use-metadata-interval-patterns-hint
\n
\n
\n \n tb.rulenode.start-interval\n \n \n {{ 'tb.rulenode.start-interval-value-required' | translate }}\n \n \n {{ 'tb.rulenode.time-value-range' | translate }}\n \n \n {{ 'tb.rulenode.time-value-range' | translate }}\n \n \n \n tb.rulenode.start-interval-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n tb.rulenode.end-interval\n \n \n {{ 'tb.rulenode.end-interval-value-required' | translate }}\n \n \n {{ 'tb.rulenode.time-value-range' | translate }}\n \n \n {{ 'tb.rulenode.time-value-range' | translate }}\n \n \n \n tb.rulenode.end-interval-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n \n tb.rulenode.start-interval-pattern\n \n \n {{ 'tb.rulenode.start-interval-pattern-required' | translate }}\n \n \n \n \n tb.rulenode.end-interval-pattern\n \n \n {{ 'tb.rulenode.end-interval-pattern-required' | translate }}\n \n \n \n \n
\n", styles: [":host label.tb-title{margin-bottom:-10px}\n"], components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }, { type: i5$2.MatChipList, selector: "mat-chip-list", inputs: ["aria-orientation", "multiple", "compareWith", "value", "required", "placeholder", "disabled", "selectable", "tabIndex", "errorStateMatcher"], outputs: ["change", "valueChange"], exportAs: ["matChipList"] }, { type: i6$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { type: i4$1.MatSelect, selector: "mat-select", inputs: ["disabled", "disableRipple", "tabIndex"], exportAs: ["matSelect"] }, { type: i5.MatOption, selector: "mat-option", exportAs: ["matOption"] }, { type: i3$1.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex", "aria-label", "aria-labelledby", "id", "labelPosition", "name", "required", "checked", "disabled", "indeterminate", "aria-describedby", "value"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i10.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i5$2.MatChip, selector: "mat-basic-chip, [mat-basic-chip], mat-chip, [mat-chip]", inputs: ["color", "disableRipple", "tabIndex", "selected", "value", "selectable", "disabled", "removable"], outputs: ["selectionChange", "destroyed", "removed"], exportAs: ["matChip"] }, { type: i5$2.MatChipRemove, selector: "[matChipRemove]" }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i5$2.MatChipInput, selector: "input[matChipInputFor]", inputs: ["matChipInputSeparatorKeyCodes", "placeholder", "id", "matChipInputFor", "matChipInputAddOnBlur", "disabled"], outputs: ["matChipInputTokenEnd"], exportAs: ["matChipInput", "matChipInputFor"] }, { type: i3.MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i2.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { type: i2.MaxValidator, selector: "input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]", inputs: ["max"] }, { type: i2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i8.DefaultLayoutGapDirective, selector: " [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]", inputs: ["fxLayoutGap", "fxLayoutGap.xs", "fxLayoutGap.sm", "fxLayoutGap.md", "fxLayoutGap.lg", "fxLayoutGap.xl", "fxLayoutGap.lt-sm", "fxLayoutGap.lt-md", "fxLayoutGap.lt-lg", "fxLayoutGap.lt-xl", "fxLayoutGap.gt-xs", "fxLayoutGap.gt-sm", "fxLayoutGap.gt-md", "fxLayoutGap.gt-lg"] }, { type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }, { type: i3.MatError, selector: "mat-error", inputs: ["id"] }], pipes: { "translate": i4.TranslatePipe, "safeHtml": SafeHtmlPipe } }); -i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: GetTelemetryFromDatabaseConfigComponent, decorators: [{ - type: Component, - args: [{ - selector: 'tb-enrichment-node-get-telemetry-from-database', - templateUrl: './get-telemetry-from-database-config.component.html', - styleUrls: ['./get-telemetry-from-database-config.component.scss'] - }] - }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); - -class OriginatorAttributesConfigComponent extends RuleNodeConfigurationComponent { - constructor(store, fb) { - super(store); - this.store = store; - this.fb = fb; - this.separatorKeysCodes = [ENTER, COMMA, SEMICOLON]; - } - configForm() { - return this.originatorAttributesConfigForm; - } - onConfigurationSet(configuration) { - this.originatorAttributesConfigForm = this.fb.group({ - tellFailureIfAbsent: [configuration ? configuration.tellFailureIfAbsent : false, []], - clientAttributeNames: [configuration ? configuration.clientAttributeNames : null, []], - sharedAttributeNames: [configuration ? configuration.sharedAttributeNames : null, []], - serverAttributeNames: [configuration ? configuration.serverAttributeNames : null, []], - latestTsKeyNames: [configuration ? configuration.latestTsKeyNames : null, []], - getLatestValueWithTs: [configuration ? configuration.getLatestValueWithTs : false, []] - }); - } - removeKey(key, keysField) { - const keys = this.originatorAttributesConfigForm.get(keysField).value; - const index = keys.indexOf(key); - if (index >= 0) { - keys.splice(index, 1); - this.originatorAttributesConfigForm.get(keysField).setValue(keys, { emitEvent: true }); - } - } - addKey(event, keysField) { - const input = event.input; - let value = event.value; - if ((value || '').trim()) { - value = value.trim(); - let keys = this.originatorAttributesConfigForm.get(keysField).value; - if (!keys || keys.indexOf(value) === -1) { - if (!keys) { - keys = []; - } - keys.push(value); - this.originatorAttributesConfigForm.get(keysField).setValue(keys, { emitEvent: true }); - } - } - if (input) { - input.value = ''; - } - } -} -OriginatorAttributesConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: OriginatorAttributesConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); -OriginatorAttributesConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: OriginatorAttributesConfigComponent, selector: "tb-enrichment-node-originator-attributes-config", usesInheritance: true, ngImport: i0, template: "
\n \n {{ 'tb.rulenode.tell-failure-if-absent' | translate }}\n \n
tb.rulenode.tell-failure-if-absent-hint
\n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n {{ 'tb.rulenode.get-latest-value-with-ts' | translate }}\n \n
\n
\n", styles: [":host label.tb-title{margin-bottom:-10px}\n"], components: [{ type: i3$1.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex", "aria-label", "aria-labelledby", "id", "labelPosition", "name", "required", "checked", "disabled", "indeterminate", "aria-describedby", "value"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }, { type: i5$2.MatChipList, selector: "mat-chip-list", inputs: ["aria-orientation", "multiple", "compareWith", "value", "required", "placeholder", "disabled", "selectable", "tabIndex", "errorStateMatcher"], outputs: ["change", "valueChange"], exportAs: ["matChipList"] }, { type: i6$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i10.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i5$2.MatChip, selector: "mat-basic-chip, [mat-basic-chip], mat-chip, [mat-chip]", inputs: ["color", "disableRipple", "tabIndex", "selected", "value", "selectable", "disabled", "removable"], outputs: ["selectionChange", "destroyed", "removed"], exportAs: ["matChip"] }, { type: i5$2.MatChipRemove, selector: "[matChipRemove]" }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i5$2.MatChipInput, selector: "input[matChipInputFor]", inputs: ["matChipInputSeparatorKeyCodes", "placeholder", "id", "matChipInputFor", "matChipInputAddOnBlur", "disabled"], outputs: ["matChipInputTokenEnd"], exportAs: ["matChipInput", "matChipInputFor"] }, { type: i3.MatHint, selector: "mat-hint", inputs: ["align", "id"] }], pipes: { "translate": i4.TranslatePipe, "safeHtml": SafeHtmlPipe } }); -i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: OriginatorAttributesConfigComponent, decorators: [{ - type: Component, - args: [{ - selector: 'tb-enrichment-node-originator-attributes-config', - templateUrl: './originator-attributes-config.component.html', - styleUrls: ['./originator-attributes-config.component.scss'] - }] - }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); - -class OriginatorFieldsConfigComponent extends RuleNodeConfigurationComponent { - constructor(store, fb) { - super(store); - this.store = store; - this.fb = fb; - } - configForm() { - return this.originatorFieldsConfigForm; - } - onConfigurationSet(configuration) { - this.originatorFieldsConfigForm = this.fb.group({ - fieldsMapping: [configuration ? configuration.fieldsMapping : null, [Validators.required]] - }); - } -} -OriginatorFieldsConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: OriginatorFieldsConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); -OriginatorFieldsConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: OriginatorFieldsConfigComponent, selector: "tb-enrichment-node-originator-fields-config", usesInheritance: true, ngImport: i0, template: "
\n \n \n \n
\n", components: [{ type: KvMapConfigComponent, selector: "tb-kv-map-config", inputs: ["disabled", "requiredText", "keyText", "keyRequiredText", "valText", "valRequiredText", "required"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }] }); -i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: OriginatorFieldsConfigComponent, decorators: [{ - type: Component, - args: [{ - selector: 'tb-enrichment-node-originator-fields-config', - templateUrl: './originator-fields-config.component.html', - styleUrls: [] - }] - }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); - -class RelatedAttributesConfigComponent extends RuleNodeConfigurationComponent { - constructor(store, fb) { - super(store); - this.store = store; - this.fb = fb; - } - configForm() { - return this.relatedAttributesConfigForm; - } - onConfigurationSet(configuration) { - this.relatedAttributesConfigForm = this.fb.group({ - relationsQuery: [configuration ? configuration.relationsQuery : null, [Validators.required]], - telemetry: [configuration ? configuration.telemetry : false, []], - attrMapping: [configuration ? configuration.attrMapping : null, [Validators.required]] - }); - } -} -RelatedAttributesConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RelatedAttributesConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); -RelatedAttributesConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: RelatedAttributesConfigComponent, selector: "tb-enrichment-node-related-attributes-config", usesInheritance: true, ngImport: i0, template: "
\n \n \n \n \n \n {{ 'tb.rulenode.latest-telemetry' | translate }}\n \n \n \n
\n", components: [{ type: RelationsQueryConfigComponent, selector: "tb-relations-query-config", inputs: ["disabled", "required"] }, { type: i3$1.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex", "aria-label", "aria-labelledby", "id", "labelPosition", "name", "required", "checked", "disabled", "indeterminate", "aria-describedby", "value"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { type: KvMapConfigComponent, selector: "tb-kv-map-config", inputs: ["disabled", "requiredText", "keyText", "keyRequiredText", "valText", "valRequiredText", "required"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }], pipes: { "translate": i4.TranslatePipe } }); -i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RelatedAttributesConfigComponent, decorators: [{ - type: Component, - args: [{ - selector: 'tb-enrichment-node-related-attributes-config', - templateUrl: './related-attributes-config.component.html', - styleUrls: [] - }] - }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); - -class TenantAttributesConfigComponent extends RuleNodeConfigurationComponent { - constructor(store, fb) { - super(store); - this.store = store; - this.fb = fb; - } - configForm() { - return this.tenantAttributesConfigForm; - } - onConfigurationSet(configuration) { - this.tenantAttributesConfigForm = this.fb.group({ - telemetry: [configuration ? configuration.telemetry : false, []], - attrMapping: [configuration ? configuration.attrMapping : null, [Validators.required]] - }); - } -} -TenantAttributesConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: TenantAttributesConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); -TenantAttributesConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: TenantAttributesConfigComponent, selector: "tb-enrichment-node-tenant-attributes-config", usesInheritance: true, ngImport: i0, template: "
\n \n \n {{ 'tb.rulenode.latest-telemetry' | translate }}\n \n \n \n
\n", components: [{ type: i3$1.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex", "aria-label", "aria-labelledby", "id", "labelPosition", "name", "required", "checked", "disabled", "indeterminate", "aria-describedby", "value"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { type: KvMapConfigComponent, selector: "tb-kv-map-config", inputs: ["disabled", "requiredText", "keyText", "keyRequiredText", "valText", "valRequiredText", "required"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }], pipes: { "translate": i4.TranslatePipe } }); -i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: TenantAttributesConfigComponent, decorators: [{ - type: Component, - args: [{ - selector: 'tb-enrichment-node-tenant-attributes-config', - templateUrl: './tenant-attributes-config.component.html', - styleUrls: [] - }] - }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); - -class RulenodeCoreConfigEnrichmentModule { -} -RulenodeCoreConfigEnrichmentModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RulenodeCoreConfigEnrichmentModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); -RulenodeCoreConfigEnrichmentModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RulenodeCoreConfigEnrichmentModule, declarations: [CustomerAttributesConfigComponent, - EntityDetailsConfigComponent, - DeviceAttributesConfigComponent, - OriginatorAttributesConfigComponent, - OriginatorFieldsConfigComponent, - GetTelemetryFromDatabaseConfigComponent, - RelatedAttributesConfigComponent, - TenantAttributesConfigComponent, - CalculateDeltaConfigComponent], imports: [CommonModule, - SharedModule, - RulenodeCoreConfigCommonModule], exports: [CustomerAttributesConfigComponent, - EntityDetailsConfigComponent, - DeviceAttributesConfigComponent, - OriginatorAttributesConfigComponent, - OriginatorFieldsConfigComponent, - GetTelemetryFromDatabaseConfigComponent, - RelatedAttributesConfigComponent, - TenantAttributesConfigComponent, - CalculateDeltaConfigComponent] }); -RulenodeCoreConfigEnrichmentModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RulenodeCoreConfigEnrichmentModule, imports: [[ - CommonModule, - SharedModule, - RulenodeCoreConfigCommonModule - ]] }); -i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RulenodeCoreConfigEnrichmentModule, decorators: [{ - type: NgModule, - args: [{ - declarations: [ - CustomerAttributesConfigComponent, - EntityDetailsConfigComponent, - DeviceAttributesConfigComponent, - OriginatorAttributesConfigComponent, - OriginatorFieldsConfigComponent, - GetTelemetryFromDatabaseConfigComponent, - RelatedAttributesConfigComponent, - TenantAttributesConfigComponent, - CalculateDeltaConfigComponent - ], - imports: [ - CommonModule, - SharedModule, - RulenodeCoreConfigCommonModule - ], - exports: [ - CustomerAttributesConfigComponent, - EntityDetailsConfigComponent, - DeviceAttributesConfigComponent, - OriginatorAttributesConfigComponent, - OriginatorFieldsConfigComponent, - GetTelemetryFromDatabaseConfigComponent, - RelatedAttributesConfigComponent, - TenantAttributesConfigComponent, - CalculateDeltaConfigComponent - ] - }] - }] }); - -class CheckAlarmStatusComponent extends RuleNodeConfigurationComponent { - constructor(store, translate, fb) { - super(store); - this.store = store; - this.translate = translate; - this.fb = fb; - this.alarmStatusTranslationsMap = alarmStatusTranslations; - this.alarmStatusList = []; - this.searchText = ''; - this.displayStatusFn = this.displayStatus.bind(this); - for (const field of Object.keys(AlarmStatus)) { - this.alarmStatusList.push(AlarmStatus[field]); - } - this.statusFormControl = new FormControl(''); - this.filteredAlarmStatus = this.statusFormControl.valueChanges - .pipe(startWith(''), map((value) => value ? value : ''), mergeMap(name => this.fetchAlarmStatus(name)), share()); - } - ngOnInit() { - super.ngOnInit(); - } - configForm() { - return this.alarmStatusConfigForm; - } - prepareInputConfig(configuration) { - this.searchText = ''; - this.statusFormControl.patchValue('', { emitEvent: true }); - return configuration; - } - onConfigurationSet(configuration) { - this.alarmStatusConfigForm = this.fb.group({ - alarmStatusList: [configuration ? configuration.alarmStatusList : null, [Validators.required]], - }); - } - displayStatus(status) { - return status ? this.translate.instant(alarmStatusTranslations.get(status)) : undefined; - } - fetchAlarmStatus(searchText) { - const alarmStatusList = this.getAlarmStatusList(); - this.searchText = searchText; - if (this.searchText && this.searchText.length) { - const search = this.searchText.toUpperCase(); - return of(alarmStatusList.filter(field => this.translate.instant(alarmStatusTranslations.get(AlarmStatus[field])).toUpperCase().includes(search))); - } - else { - return of(alarmStatusList); - } - } - alarmStatusSelected(event) { - this.addAlarmStatus(event.option.value); - this.clear(''); - } - removeAlarmStatus(status) { - const alarmStatusList = this.alarmStatusConfigForm.get('alarmStatusList').value; - if (alarmStatusList) { - const index = alarmStatusList.indexOf(status); - if (index >= 0) { - alarmStatusList.splice(index, 1); - this.alarmStatusConfigForm.get('alarmStatusList').setValue(alarmStatusList); - } - } - } - addAlarmStatus(status) { - let alarmStatusList = this.alarmStatusConfigForm.get('alarmStatusList').value; - if (!alarmStatusList) { - alarmStatusList = []; - } - const index = alarmStatusList.indexOf(status); - if (index === -1) { - alarmStatusList.push(status); - this.alarmStatusConfigForm.get('alarmStatusList').setValue(alarmStatusList); - } - } - getAlarmStatusList() { - return this.alarmStatusList.filter((listItem) => { - return this.alarmStatusConfigForm.get('alarmStatusList').value.indexOf(listItem) === -1; - }); - } - onAlarmStatusInputFocus() { - this.statusFormControl.updateValueAndValidity({ onlySelf: true, emitEvent: true }); - } - clear(value = '') { - this.alarmStatusInput.nativeElement.value = value; - this.statusFormControl.patchValue(null, { emitEvent: true }); - setTimeout(() => { - this.alarmStatusInput.nativeElement.blur(); - this.alarmStatusInput.nativeElement.focus(); - }, 0); - } -} -CheckAlarmStatusComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: CheckAlarmStatusComponent, deps: [{ token: i1.Store }, { token: i4.TranslateService }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); -CheckAlarmStatusComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: CheckAlarmStatusComponent, selector: "tb-filter-node-check-alarm-status-config", viewQueries: [{ propertyName: "alarmStatusInput", first: true, predicate: ["alarmStatusInput"], descendants: true }], usesInheritance: true, ngImport: i0, template: "
\n \n tb.rulenode.alarm-status-filter\n \n \n \n {{alarmStatusTranslationsMap.get(alarmStatus) | translate}}\n \n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-alarm-status-matching\n
\n
\n
\n
\n
\n \n
\n\n\n\n", components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }, { type: i5$2.MatChipList, selector: "mat-chip-list", inputs: ["aria-orientation", "multiple", "compareWith", "value", "required", "placeholder", "disabled", "selectable", "tabIndex", "errorStateMatcher"], outputs: ["change", "valueChange"], exportAs: ["matChipList"] }, { type: i6$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { type: i7$5.MatAutocomplete, selector: "mat-autocomplete", inputs: ["disableRipple"], exportAs: ["matAutocomplete"] }, { type: i5.MatOption, selector: "mat-option", exportAs: ["matOption"] }, { type: i9.TbErrorComponent, selector: "tb-error", inputs: ["error"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i10.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i5$2.MatChip, selector: "mat-basic-chip, [mat-basic-chip], mat-chip, [mat-chip]", inputs: ["color", "disableRipple", "tabIndex", "selected", "value", "selectable", "disabled", "removable"], outputs: ["selectionChange", "destroyed", "removed"], exportAs: ["matChip"] }, { type: i5$2.MatChipRemove, selector: "[matChipRemove]" }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i7$5.MatAutocompleteTrigger, selector: "input[matAutocomplete], textarea[matAutocomplete]", exportAs: ["matAutocompleteTrigger"] }, { type: i5$2.MatChipInput, selector: "input[matChipInputFor]", inputs: ["matChipInputSeparatorKeyCodes", "placeholder", "id", "matChipInputFor", "matChipInputAddOnBlur", "disabled"], outputs: ["matChipInputTokenEnd"], exportAs: ["matChipInput", "matChipInputFor"] }, { type: i7$5.MatAutocompleteOrigin, selector: "[matAutocompleteOrigin]", exportAs: ["matAutocompleteOrigin"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlDirective, selector: "[formControl]", inputs: ["disabled", "formControl", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], pipes: { "translate": i4.TranslatePipe, "async": i10.AsyncPipe, "highlight": i12$1.HighlightPipe } }); -i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: CheckAlarmStatusComponent, decorators: [{ - type: Component, - args: [{ - selector: 'tb-filter-node-check-alarm-status-config', - templateUrl: './check-alarm-status.component.html', - styleUrls: [] - }] - }], ctorParameters: function () { return [{ type: i1.Store }, { type: i4.TranslateService }, { type: i2.FormBuilder }]; }, propDecorators: { alarmStatusInput: [{ - type: ViewChild, - args: ['alarmStatusInput', { static: false }] - }] } }); - -class CheckMessageConfigComponent extends RuleNodeConfigurationComponent { - constructor(store, fb) { - super(store); - this.store = store; - this.fb = fb; - this.separatorKeysCodes = [ENTER, COMMA, SEMICOLON]; - } - configForm() { - return this.checkMessageConfigForm; - } - onConfigurationSet(configuration) { - this.checkMessageConfigForm = this.fb.group({ - messageNames: [configuration ? configuration.messageNames : null, []], - metadataNames: [configuration ? configuration.metadataNames : null, []], - checkAllKeys: [configuration ? configuration.checkAllKeys : false, []], - }); - } - validateConfig() { - const messageNames = this.checkMessageConfigForm.get('messageNames').value; - const metadataNames = this.checkMessageConfigForm.get('metadataNames').value; - return messageNames.length > 0 || metadataNames.length > 0; - } - removeMessageName(messageName) { - const messageNames = this.checkMessageConfigForm.get('messageNames').value; - const index = messageNames.indexOf(messageName); - if (index >= 0) { - messageNames.splice(index, 1); - this.checkMessageConfigForm.get('messageNames').setValue(messageNames, { emitEvent: true }); - } - } - removeMetadataName(metadataName) { - const metadataNames = this.checkMessageConfigForm.get('metadataNames').value; - const index = metadataNames.indexOf(metadataName); - if (index >= 0) { - metadataNames.splice(index, 1); - this.checkMessageConfigForm.get('metadataNames').setValue(metadataNames, { emitEvent: true }); - } - } - addMessageName(event) { - const input = event.input; - let value = event.value; - if ((value || '').trim()) { - value = value.trim(); - let messageNames = this.checkMessageConfigForm.get('messageNames').value; - if (!messageNames || messageNames.indexOf(value) === -1) { - if (!messageNames) { - messageNames = []; - } - messageNames.push(value); - this.checkMessageConfigForm.get('messageNames').setValue(messageNames, { emitEvent: true }); - } - } - if (input) { - input.value = ''; - } - } - addMetadataName(event) { - const input = event.input; - let value = event.value; - if ((value || '').trim()) { - value = value.trim(); - let metadataNames = this.checkMessageConfigForm.get('metadataNames').value; - if (!metadataNames || metadataNames.indexOf(value) === -1) { - if (!metadataNames) { - metadataNames = []; - } - metadataNames.push(value); - this.checkMessageConfigForm.get('metadataNames').setValue(metadataNames, { emitEvent: true }); - } - } - if (input) { - input.value = ''; - } - } -} -CheckMessageConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: CheckMessageConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); -CheckMessageConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: CheckMessageConfigComponent, selector: "tb-filter-node-check-message-config", usesInheritance: true, ngImport: i0, template: "
\n \n \n \n \n \n {{messageName}}\n close\n \n \n \n \n
tb.rulenode.separator-hint
\n \n \n \n \n \n {{metadataName}}\n close\n \n \n \n \n
tb.rulenode.separator-hint
\n \n {{ 'tb.rulenode.check-all-keys' | translate }}\n \n
tb.rulenode.check-all-keys-hint
\n
\n", styles: [":host label.tb-title{margin-bottom:-10px}\n"], components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }, { type: i5$2.MatChipList, selector: "mat-chip-list", inputs: ["aria-orientation", "multiple", "compareWith", "value", "required", "placeholder", "disabled", "selectable", "tabIndex", "errorStateMatcher"], outputs: ["change", "valueChange"], exportAs: ["matChipList"] }, { type: i6$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { type: i3$1.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex", "aria-label", "aria-labelledby", "id", "labelPosition", "name", "required", "checked", "disabled", "indeterminate", "aria-describedby", "value"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i10.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i5$2.MatChip, selector: "mat-basic-chip, [mat-basic-chip], mat-chip, [mat-chip]", inputs: ["color", "disableRipple", "tabIndex", "selected", "value", "selectable", "disabled", "removable"], outputs: ["selectionChange", "destroyed", "removed"], exportAs: ["matChip"] }, { type: i5$2.MatChipRemove, selector: "[matChipRemove]" }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i5$2.MatChipInput, selector: "input[matChipInputFor]", inputs: ["matChipInputSeparatorKeyCodes", "placeholder", "id", "matChipInputFor", "matChipInputAddOnBlur", "disabled"], outputs: ["matChipInputTokenEnd"], exportAs: ["matChipInput", "matChipInputFor"] }, { type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }], pipes: { "translate": i4.TranslatePipe } }); -i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: CheckMessageConfigComponent, decorators: [{ - type: Component, - args: [{ - selector: 'tb-filter-node-check-message-config', - templateUrl: './check-message-config.component.html', - styleUrls: ['./check-message-config.component.scss'] - }] - }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); - -class CheckRelationConfigComponent extends RuleNodeConfigurationComponent { - constructor(store, fb) { - super(store); - this.store = store; - this.fb = fb; - this.entitySearchDirection = Object.keys(EntitySearchDirection); - this.entitySearchDirectionTranslationsMap = entitySearchDirectionTranslations; - } - configForm() { - return this.checkRelationConfigForm; - } - onConfigurationSet(configuration) { - this.checkRelationConfigForm = this.fb.group({ - checkForSingleEntity: [configuration ? configuration.checkForSingleEntity : false, []], - direction: [configuration ? configuration.direction : null, []], - entityType: [configuration ? configuration.entityType : null, - configuration && configuration.checkForSingleEntity ? [Validators.required] : []], - entityId: [configuration ? configuration.entityId : null, - configuration && configuration.checkForSingleEntity ? [Validators.required] : []], - relationType: [configuration ? configuration.relationType : null, [Validators.required]] - }); - } - validatorTriggers() { - return ['checkForSingleEntity']; - } - updateValidators(emitEvent) { - const checkForSingleEntity = this.checkRelationConfigForm.get('checkForSingleEntity').value; - this.checkRelationConfigForm.get('entityType').setValidators(checkForSingleEntity ? [Validators.required] : []); - this.checkRelationConfigForm.get('entityType').updateValueAndValidity({ emitEvent }); - this.checkRelationConfigForm.get('entityId').setValidators(checkForSingleEntity ? [Validators.required] : []); - this.checkRelationConfigForm.get('entityId').updateValueAndValidity({ emitEvent }); - } -} -CheckRelationConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: CheckRelationConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); -CheckRelationConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: CheckRelationConfigComponent, selector: "tb-filter-node-check-relation-config", usesInheritance: true, ngImport: i0, template: "
\n \n {{ 'tb.rulenode.check-relation-to-specific-entity' | translate }}\n \n
tb.rulenode.check-relation-hint
\n \n relation.direction\n \n \n {{ entitySearchDirectionTranslationsMap.get(direction) | translate }}\n \n \n \n
\n \n \n \n \n
\n \n \n
\n", components: [{ type: i3$1.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex", "aria-label", "aria-labelledby", "id", "labelPosition", "name", "required", "checked", "disabled", "indeterminate", "aria-describedby", "value"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }, { type: i4$1.MatSelect, selector: "mat-select", inputs: ["disabled", "disableRipple", "tabIndex"], exportAs: ["matSelect"] }, { type: i5.MatOption, selector: "mat-option", exportAs: ["matOption"] }, { type: i7$1.EntityTypeSelectComponent, selector: "tb-entity-type-select", inputs: ["allowedEntityTypes", "useAliasEntityTypes", "showLabel", "required", "disabled"] }, { type: i8$3.EntityAutocompleteComponent, selector: "tb-entity-autocomplete", inputs: ["entityType", "entitySubtype", "excludeEntityIds", "labelText", "requiredText", "required", "disabled"], outputs: ["entityChanged"] }, { type: i7$3.RelationTypeAutocompleteComponent, selector: "tb-relation-type-autocomplete", inputs: ["required", "disabled"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i10.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], pipes: { "translate": i4.TranslatePipe } }); -i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: CheckRelationConfigComponent, decorators: [{ - type: Component, - args: [{ - selector: 'tb-filter-node-check-relation-config', - templateUrl: './check-relation-config.component.html', - styleUrls: [] - }] - }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); - -class GpsGeoFilterConfigComponent extends RuleNodeConfigurationComponent { - constructor(store, fb) { - super(store); - this.store = store; - this.fb = fb; - this.perimeterType = PerimeterType; - this.perimeterTypes = Object.keys(PerimeterType); - this.perimeterTypeTranslationMap = perimeterTypeTranslations; - this.rangeUnits = Object.keys(RangeUnit); - this.rangeUnitTranslationMap = rangeUnitTranslations; - } - configForm() { - return this.geoFilterConfigForm; - } - onConfigurationSet(configuration) { - this.geoFilterConfigForm = this.fb.group({ - latitudeKeyName: [configuration ? configuration.latitudeKeyName : null, [Validators.required]], - longitudeKeyName: [configuration ? configuration.longitudeKeyName : null, [Validators.required]], - fetchPerimeterInfoFromMessageMetadata: [configuration ? configuration.fetchPerimeterInfoFromMessageMetadata : false, []], - perimeterType: [configuration ? configuration.perimeterType : null, []], - centerLatitude: [configuration ? configuration.centerLatitude : null, []], - centerLongitude: [configuration ? configuration.centerLatitude : null, []], - range: [configuration ? configuration.range : null, []], - rangeUnit: [configuration ? configuration.rangeUnit : null, []], - polygonsDefinition: [configuration ? configuration.polygonsDefinition : null, []] - }); - } - validatorTriggers() { - return ['fetchPerimeterInfoFromMessageMetadata', 'perimeterType']; - } - updateValidators(emitEvent) { - const fetchPerimeterInfoFromMessageMetadata = this.geoFilterConfigForm.get('fetchPerimeterInfoFromMessageMetadata').value; - const perimeterType = this.geoFilterConfigForm.get('perimeterType').value; - if (fetchPerimeterInfoFromMessageMetadata) { - this.geoFilterConfigForm.get('perimeterType').setValidators([]); - } - else { - this.geoFilterConfigForm.get('perimeterType').setValidators([Validators.required]); - } - if (!fetchPerimeterInfoFromMessageMetadata && perimeterType === PerimeterType.CIRCLE) { - this.geoFilterConfigForm.get('centerLatitude').setValidators([Validators.required, - Validators.min(-90), Validators.max(90)]); - this.geoFilterConfigForm.get('centerLongitude').setValidators([Validators.required, - Validators.min(-180), Validators.max(180)]); - this.geoFilterConfigForm.get('range').setValidators([Validators.required, Validators.min(0)]); - this.geoFilterConfigForm.get('rangeUnit').setValidators([Validators.required]); - } - else { - this.geoFilterConfigForm.get('centerLatitude').setValidators([]); - this.geoFilterConfigForm.get('centerLongitude').setValidators([]); - this.geoFilterConfigForm.get('range').setValidators([]); - this.geoFilterConfigForm.get('rangeUnit').setValidators([]); - } - if (!fetchPerimeterInfoFromMessageMetadata && perimeterType === PerimeterType.POLYGON) { - this.geoFilterConfigForm.get('polygonsDefinition').setValidators([Validators.required]); - } - else { - this.geoFilterConfigForm.get('polygonsDefinition').setValidators([]); - } - this.geoFilterConfigForm.get('perimeterType').updateValueAndValidity({ emitEvent: false }); - this.geoFilterConfigForm.get('centerLatitude').updateValueAndValidity({ emitEvent }); - this.geoFilterConfigForm.get('centerLongitude').updateValueAndValidity({ emitEvent }); - this.geoFilterConfigForm.get('range').updateValueAndValidity({ emitEvent }); - this.geoFilterConfigForm.get('rangeUnit').updateValueAndValidity({ emitEvent }); - this.geoFilterConfigForm.get('polygonsDefinition').updateValueAndValidity({ emitEvent }); - } -} -GpsGeoFilterConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: GpsGeoFilterConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); -GpsGeoFilterConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: GpsGeoFilterConfigComponent, selector: "tb-filter-node-gps-geofencing-config", usesInheritance: true, ngImport: i0, template: "
\n \n tb.rulenode.latitude-key-name\n \n \n {{ 'tb.rulenode.latitude-key-name-required' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ 'tb.rulenode.longitude-key-name-required' | translate }}\n \n \n \n {{ 'tb.rulenode.fetch-perimeter-info-from-message-metadata' | translate }}\n \n
\n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n \n tb.rulenode.circle-center-latitude\n \n \n {{ 'tb.rulenode.circle-center-latitude-required' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ 'tb.rulenode.circle-center-longitude-required' | translate }}\n \n \n
\n
\n \n tb.rulenode.range\n \n \n {{ 'tb.rulenode.range-required' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n
\n \n tb.rulenode.polygon-definition\n \n \n {{ 'tb.rulenode.polygon-definition-required' | translate }}\n \n \n
\n
\n
\n", components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }, { type: i3$1.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex", "aria-label", "aria-labelledby", "id", "labelPosition", "name", "required", "checked", "disabled", "indeterminate", "aria-describedby", "value"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { type: i4$1.MatSelect, selector: "mat-select", inputs: ["disabled", "disableRipple", "tabIndex"], exportAs: ["matSelect"] }, { type: i5.MatOption, selector: "mat-option", exportAs: ["matOption"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.MatError, selector: "mat-error", inputs: ["id"] }, { type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }, { type: i10.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i8.DefaultLayoutGapDirective, selector: " [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]", inputs: ["fxLayoutGap", "fxLayoutGap.xs", "fxLayoutGap.sm", "fxLayoutGap.md", "fxLayoutGap.lg", "fxLayoutGap.xl", "fxLayoutGap.lt-sm", "fxLayoutGap.lt-md", "fxLayoutGap.lt-lg", "fxLayoutGap.lt-xl", "fxLayoutGap.gt-xs", "fxLayoutGap.gt-sm", "fxLayoutGap.gt-md", "fxLayoutGap.gt-lg"] }, { type: i2.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { type: i2.MaxValidator, selector: "input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]", inputs: ["max"] }, { type: i2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }], pipes: { "translate": i4.TranslatePipe } }); -i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: GpsGeoFilterConfigComponent, decorators: [{ - type: Component, - args: [{ - selector: 'tb-filter-node-gps-geofencing-config', - templateUrl: './gps-geo-filter-config.component.html', - styleUrls: [] - }] - }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); - -class MessageTypeConfigComponent extends RuleNodeConfigurationComponent { - constructor(store, fb) { - super(store); - this.store = store; - this.fb = fb; - } - configForm() { - return this.messageTypeConfigForm; - } - onConfigurationSet(configuration) { - this.messageTypeConfigForm = this.fb.group({ - messageTypes: [configuration ? configuration.messageTypes : null, [Validators.required]] - }); - } -} -MessageTypeConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: MessageTypeConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); -MessageTypeConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: MessageTypeConfigComponent, selector: "tb-filter-node-message-type-config", usesInheritance: true, ngImport: i0, template: "
\n \n
\n", components: [{ type: MessageTypesConfigComponent, selector: "tb-message-types-config", inputs: ["required", "label", "placeholder", "disabled"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }] }); -i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: MessageTypeConfigComponent, decorators: [{ - type: Component, - args: [{ - selector: 'tb-filter-node-message-type-config', - templateUrl: './message-type-config.component.html', - styleUrls: [] - }] - }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); - -class OriginatorTypeConfigComponent extends RuleNodeConfigurationComponent { - constructor(store, fb) { - super(store); - this.store = store; - this.fb = fb; - this.allowedEntityTypes = [ - EntityType.DEVICE, - EntityType.ASSET, - EntityType.ENTITY_VIEW, - EntityType.TENANT, - EntityType.CUSTOMER, - EntityType.USER, - EntityType.DASHBOARD, - EntityType.RULE_CHAIN, - EntityType.RULE_NODE - ]; - } - configForm() { - return this.originatorTypeConfigForm; - } - onConfigurationSet(configuration) { - this.originatorTypeConfigForm = this.fb.group({ - originatorTypes: [configuration ? configuration.originatorTypes : null, [Validators.required]] - }); - } -} -OriginatorTypeConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: OriginatorTypeConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); -OriginatorTypeConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: OriginatorTypeConfigComponent, selector: "tb-filter-node-originator-type-config", usesInheritance: true, ngImport: i0, template: "
\n \n \n \n
\n", styles: [":host ::ng-deep tb-entity-type-list .mat-form-field-flex{padding-top:0}:host ::ng-deep tb-entity-type-list .mat-form-field-infix{border-top:0}\n"], components: [{ type: i3$5.EntityTypeListComponent, selector: "tb-entity-type-list", inputs: ["required", "disabled", "allowedEntityTypes", "ignoreAuthorityFilter"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }] }); -i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: OriginatorTypeConfigComponent, decorators: [{ - type: Component, - args: [{ - selector: 'tb-filter-node-originator-type-config', - templateUrl: './originator-type-config.component.html', - styleUrls: ['./originator-type-config.component.scss'] - }] - }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); - -class ScriptConfigComponent extends RuleNodeConfigurationComponent { - constructor(store, fb, nodeScriptTestService, translate) { - super(store); - this.store = store; - this.fb = fb; - this.nodeScriptTestService = nodeScriptTestService; - this.translate = translate; - } - configForm() { - return this.scriptConfigForm; - } - onConfigurationSet(configuration) { - this.scriptConfigForm = this.fb.group({ - jsScript: [configuration ? configuration.jsScript : null, [Validators.required]] - }); - } - testScript() { - const script = this.scriptConfigForm.get('jsScript').value; - this.nodeScriptTestService.testNodeScript(script, 'filter', this.translate.instant('tb.rulenode.filter'), 'Filter', ['msg', 'metadata', 'msgType'], this.ruleNodeId, 'rulenode/filter_node_script_fn').subscribe((theScript) => { - if (theScript) { - this.scriptConfigForm.get('jsScript').setValue(theScript); - } - }); - } - onValidate() { - this.jsFuncComponent.validateOnSubmit(); - } -} -ScriptConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: ScriptConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }, { token: i3$3.NodeScriptTestService }, { token: i4.TranslateService }], target: i0.ɵɵFactoryTarget.Component }); -ScriptConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: ScriptConfigComponent, selector: "tb-filter-node-script-config", viewQueries: [{ propertyName: "jsFuncComponent", first: true, predicate: ["jsFuncComponent"], descendants: true, static: true }], usesInheritance: true, ngImport: i0, template: "
\n \n \n \n
\n \n
\n
\n", components: [{ type: i5$1.JsFuncComponent, selector: "tb-js-func", inputs: ["functionName", "functionArgs", "validationArgs", "resultType", "disabled", "fillHeight", "editorCompleter", "globalVariables", "disableUndefinedCheck", "helpId", "noValidate", "required"] }, { type: i6.MatButton, selector: "button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }], pipes: { "translate": i4.TranslatePipe } }); -i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: ScriptConfigComponent, decorators: [{ - type: Component, - args: [{ - selector: 'tb-filter-node-script-config', - templateUrl: './script-config.component.html', - styleUrls: [] - }] - }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }, { type: i3$3.NodeScriptTestService }, { type: i4.TranslateService }]; }, propDecorators: { jsFuncComponent: [{ - type: ViewChild, - args: ['jsFuncComponent', { static: true }] - }] } }); - -class SwitchConfigComponent extends RuleNodeConfigurationComponent { - constructor(store, fb, nodeScriptTestService, translate) { - super(store); - this.store = store; - this.fb = fb; - this.nodeScriptTestService = nodeScriptTestService; - this.translate = translate; - } - configForm() { - return this.switchConfigForm; - } - onConfigurationSet(configuration) { - this.switchConfigForm = this.fb.group({ - jsScript: [configuration ? configuration.jsScript : null, [Validators.required]] - }); - } - testScript() { - const script = this.switchConfigForm.get('jsScript').value; - this.nodeScriptTestService.testNodeScript(script, 'switch', this.translate.instant('tb.rulenode.switch'), 'Switch', ['msg', 'metadata', 'msgType'], this.ruleNodeId, 'rulenode/switch_node_script_fn').subscribe((theScript) => { - if (theScript) { - this.switchConfigForm.get('jsScript').setValue(theScript); - } - }); - } - onValidate() { - this.jsFuncComponent.validateOnSubmit(); - } -} -SwitchConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: SwitchConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }, { token: i3$3.NodeScriptTestService }, { token: i4.TranslateService }], target: i0.ɵɵFactoryTarget.Component }); -SwitchConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: SwitchConfigComponent, selector: "tb-filter-node-switch-config", viewQueries: [{ propertyName: "jsFuncComponent", first: true, predicate: ["jsFuncComponent"], descendants: true, static: true }], usesInheritance: true, ngImport: i0, template: "
\n \n \n \n
\n \n
\n
\n", components: [{ type: i5$1.JsFuncComponent, selector: "tb-js-func", inputs: ["functionName", "functionArgs", "validationArgs", "resultType", "disabled", "fillHeight", "editorCompleter", "globalVariables", "disableUndefinedCheck", "helpId", "noValidate", "required"] }, { type: i6.MatButton, selector: "button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }], pipes: { "translate": i4.TranslatePipe } }); -i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: SwitchConfigComponent, decorators: [{ - type: Component, - args: [{ - selector: 'tb-filter-node-switch-config', - templateUrl: './switch-config.component.html', - styleUrls: [] - }] - }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }, { type: i3$3.NodeScriptTestService }, { type: i4.TranslateService }]; }, propDecorators: { jsFuncComponent: [{ - type: ViewChild, - args: ['jsFuncComponent', { static: true }] - }] } }); - -class RuleNodeCoreConfigFilterModule { -} -RuleNodeCoreConfigFilterModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RuleNodeCoreConfigFilterModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); -RuleNodeCoreConfigFilterModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RuleNodeCoreConfigFilterModule, declarations: [CheckMessageConfigComponent, - CheckRelationConfigComponent, - GpsGeoFilterConfigComponent, - MessageTypeConfigComponent, - OriginatorTypeConfigComponent, - ScriptConfigComponent, - SwitchConfigComponent, - CheckAlarmStatusComponent], imports: [CommonModule, - SharedModule, - RulenodeCoreConfigCommonModule], exports: [CheckMessageConfigComponent, - CheckRelationConfigComponent, - GpsGeoFilterConfigComponent, - MessageTypeConfigComponent, - OriginatorTypeConfigComponent, - ScriptConfigComponent, - SwitchConfigComponent, - CheckAlarmStatusComponent] }); -RuleNodeCoreConfigFilterModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RuleNodeCoreConfigFilterModule, imports: [[ - CommonModule, - SharedModule, - RulenodeCoreConfigCommonModule - ]] }); -i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RuleNodeCoreConfigFilterModule, decorators: [{ - type: NgModule, - args: [{ - declarations: [ - CheckMessageConfigComponent, - CheckRelationConfigComponent, - GpsGeoFilterConfigComponent, - MessageTypeConfigComponent, - OriginatorTypeConfigComponent, - ScriptConfigComponent, - SwitchConfigComponent, - CheckAlarmStatusComponent - ], - imports: [ - CommonModule, - SharedModule, - RulenodeCoreConfigCommonModule - ], - exports: [ - CheckMessageConfigComponent, - CheckRelationConfigComponent, - GpsGeoFilterConfigComponent, - MessageTypeConfigComponent, - OriginatorTypeConfigComponent, - ScriptConfigComponent, - SwitchConfigComponent, - CheckAlarmStatusComponent - ] - }] - }] }); - -class ChangeOriginatorConfigComponent extends RuleNodeConfigurationComponent { - constructor(store, fb) { - super(store); - this.store = store; - this.fb = fb; - this.originatorSource = OriginatorSource; - this.originatorSources = Object.keys(OriginatorSource); - this.originatorSourceTranslationMap = originatorSourceTranslations; - } - configForm() { - return this.changeOriginatorConfigForm; - } - onConfigurationSet(configuration) { - this.changeOriginatorConfigForm = this.fb.group({ - originatorSource: [configuration ? configuration.originatorSource : null, [Validators.required]], - relationsQuery: [configuration ? configuration.relationsQuery : null, []] - }); - } - validatorTriggers() { - return ['originatorSource']; - } - updateValidators(emitEvent) { - const originatorSource = this.changeOriginatorConfigForm.get('originatorSource').value; - if (originatorSource && originatorSource === OriginatorSource.RELATED) { - this.changeOriginatorConfigForm.get('relationsQuery').setValidators([Validators.required]); - } - else { - this.changeOriginatorConfigForm.get('relationsQuery').setValidators([]); - } - this.changeOriginatorConfigForm.get('relationsQuery').updateValueAndValidity({ emitEvent }); - } -} -ChangeOriginatorConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: ChangeOriginatorConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); -ChangeOriginatorConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: ChangeOriginatorConfigComponent, selector: "tb-transformation-node-change-originator-config", usesInheritance: true, ngImport: i0, template: "
\n \n tb.rulenode.originator-source\n \n \n {{ originatorSourceTranslationMap.get(source) | translate }}\n \n \n \n
\n \n \n \n
\n
\n", components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }, { type: i4$1.MatSelect, selector: "mat-select", inputs: ["disabled", "disableRipple", "tabIndex"], exportAs: ["matSelect"] }, { type: i5.MatOption, selector: "mat-option", exportAs: ["matOption"] }, { type: RelationsQueryConfigComponent, selector: "tb-relations-query-config", inputs: ["disabled", "required"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i10.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], pipes: { "translate": i4.TranslatePipe } }); -i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: ChangeOriginatorConfigComponent, decorators: [{ - type: Component, - args: [{ - selector: 'tb-transformation-node-change-originator-config', - templateUrl: './change-originator-config.component.html', - styleUrls: [] - }] - }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); - -class TransformScriptConfigComponent extends RuleNodeConfigurationComponent { - constructor(store, fb, nodeScriptTestService, translate) { - super(store); - this.store = store; - this.fb = fb; - this.nodeScriptTestService = nodeScriptTestService; - this.translate = translate; - } - configForm() { - return this.scriptConfigForm; - } - onConfigurationSet(configuration) { - this.scriptConfigForm = this.fb.group({ - jsScript: [configuration ? configuration.jsScript : null, [Validators.required]] - }); - } - testScript() { - const script = this.scriptConfigForm.get('jsScript').value; - this.nodeScriptTestService.testNodeScript(script, 'update', this.translate.instant('tb.rulenode.transformer'), 'Transform', ['msg', 'metadata', 'msgType'], this.ruleNodeId, 'rulenode/transformation_node_script_fn').subscribe((theScript) => { - if (theScript) { - this.scriptConfigForm.get('jsScript').setValue(theScript); - } - }); - } - onValidate() { - this.jsFuncComponent.validateOnSubmit(); - } -} -TransformScriptConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: TransformScriptConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }, { token: i3$3.NodeScriptTestService }, { token: i4.TranslateService }], target: i0.ɵɵFactoryTarget.Component }); -TransformScriptConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: TransformScriptConfigComponent, selector: "tb-transformation-node-script-config", viewQueries: [{ propertyName: "jsFuncComponent", first: true, predicate: ["jsFuncComponent"], descendants: true, static: true }], usesInheritance: true, ngImport: i0, template: "
\n \n \n \n
\n \n
\n
\n", components: [{ type: i5$1.JsFuncComponent, selector: "tb-js-func", inputs: ["functionName", "functionArgs", "validationArgs", "resultType", "disabled", "fillHeight", "editorCompleter", "globalVariables", "disableUndefinedCheck", "helpId", "noValidate", "required"] }, { type: i6.MatButton, selector: "button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }], pipes: { "translate": i4.TranslatePipe } }); -i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: TransformScriptConfigComponent, decorators: [{ - type: Component, - args: [{ - selector: 'tb-transformation-node-script-config', - templateUrl: './script-config.component.html', - styleUrls: [] - }] - }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }, { type: i3$3.NodeScriptTestService }, { type: i4.TranslateService }]; }, propDecorators: { jsFuncComponent: [{ - type: ViewChild, - args: ['jsFuncComponent', { static: true }] - }] } }); - -class ToEmailConfigComponent extends RuleNodeConfigurationComponent { - constructor(store, fb) { - super(store); - this.store = store; - this.fb = fb; - this.mailBodyTypes = [ - { name: 'tb.mail-body-type.plain-text', value: 'false' }, - { name: 'tb.mail-body-type.html', value: 'true' }, - { name: 'tb.mail-body-type.dynamic', value: 'dynamic' } - ]; - } - configForm() { - return this.toEmailConfigForm; - } - onConfigurationSet(configuration) { - this.toEmailConfigForm = this.fb.group({ - fromTemplate: [configuration ? configuration.fromTemplate : null, [Validators.required]], - toTemplate: [configuration ? configuration.toTemplate : null, [Validators.required]], - ccTemplate: [configuration ? configuration.ccTemplate : null, []], - bccTemplate: [configuration ? configuration.bccTemplate : null, []], - subjectTemplate: [configuration ? configuration.subjectTemplate : null, [Validators.required]], - mailBodyType: [configuration ? configuration.mailBodyType : null], - isHtmlTemplate: [configuration ? configuration.isHtmlTemplate : null], - bodyTemplate: [configuration ? configuration.bodyTemplate : null, [Validators.required]], - }); - this.toEmailConfigForm.get('mailBodyType').valueChanges.pipe(startWith([configuration === null || configuration === void 0 ? void 0 : configuration.subjectTemplate])).subscribe((mailBodyType) => { - if (mailBodyType === 'dynamic') { - this.toEmailConfigForm.get('isHtmlTemplate').patchValue('', { emitEvent: false }); - this.toEmailConfigForm.get('isHtmlTemplate').setValidators(Validators.required); - } - else { - this.toEmailConfigForm.get('isHtmlTemplate').clearValidators(); - } - this.toEmailConfigForm.get('isHtmlTemplate').updateValueAndValidity(); - }); - } -} -ToEmailConfigComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: ToEmailConfigComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); -ToEmailConfigComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: ToEmailConfigComponent, selector: "tb-transformation-node-to-email-config", usesInheritance: true, ngImport: i0, template: "
\n \n tb.rulenode.from-template\n \n \n {{ 'tb.rulenode.from-template-required' | translate }}\n \n \n \n \n tb.rulenode.to-template\n \n \n {{ 'tb.rulenode.to-template-required' | translate }}\n \n \n \n \n tb.rulenode.cc-template\n \n \n \n \n tb.rulenode.bcc-template\n \n \n \n \n tb.rulenode.subject-template\n \n \n {{ 'tb.rulenode.subject-template-required' | translate }}\n \n \n \n \n tb.rulenode.mail-body-type\n \n \n {{ type.name | translate }}\n \n \n \n \n tb.rulenode.dynamic-mail-body-type\n \n \n \n \n tb.rulenode.body-template\n \n \n {{ 'tb.rulenode.body-template-required' | translate }}\n \n \n \n
\n", components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }, { type: i4$1.MatSelect, selector: "mat-select", inputs: ["disabled", "disableRipple", "tabIndex"], exportAs: ["matSelect"] }, { type: i5.MatOption, selector: "mat-option", exportAs: ["matOption"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.MatError, selector: "mat-error", inputs: ["id"] }, { type: i3.MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { type: i10.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }], pipes: { "translate": i4.TranslatePipe, "safeHtml": SafeHtmlPipe } }); -i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: ToEmailConfigComponent, decorators: [{ - type: Component, - args: [{ - selector: 'tb-transformation-node-to-email-config', - templateUrl: './to-email-config.component.html', - styleUrls: [] - }] - }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); - -class RulenodeCoreConfigTransformModule { -} -RulenodeCoreConfigTransformModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RulenodeCoreConfigTransformModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); -RulenodeCoreConfigTransformModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RulenodeCoreConfigTransformModule, declarations: [ChangeOriginatorConfigComponent, - TransformScriptConfigComponent, - ToEmailConfigComponent], imports: [CommonModule, - SharedModule, - RulenodeCoreConfigCommonModule], exports: [ChangeOriginatorConfigComponent, - TransformScriptConfigComponent, - ToEmailConfigComponent] }); -RulenodeCoreConfigTransformModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RulenodeCoreConfigTransformModule, imports: [[ - CommonModule, - SharedModule, - RulenodeCoreConfigCommonModule - ]] }); -i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RulenodeCoreConfigTransformModule, decorators: [{ - type: NgModule, - args: [{ - declarations: [ - ChangeOriginatorConfigComponent, - TransformScriptConfigComponent, - ToEmailConfigComponent - ], - imports: [ - CommonModule, - SharedModule, - RulenodeCoreConfigCommonModule - ], - exports: [ - ChangeOriginatorConfigComponent, - TransformScriptConfigComponent, - ToEmailConfigComponent - ] - }] - }] }); - -class RuleChainInputComponent extends RuleNodeConfigurationComponent { - constructor(store, fb) { - super(store); - this.store = store; - this.fb = fb; - this.entityType = EntityType; - } - configForm() { - return this.ruleChainInputConfigForm; - } - onConfigurationSet(configuration) { - this.ruleChainInputConfigForm = this.fb.group({ - ruleChainId: [configuration ? configuration.ruleChainId : null, [Validators.required]] - }); - } -} -RuleChainInputComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RuleChainInputComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); -RuleChainInputComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: RuleChainInputComponent, selector: "tb-flow-node-rule-chain-input-config", usesInheritance: true, ngImport: i0, template: "
\n \n \n
\n", components: [{ type: i8$3.EntityAutocompleteComponent, selector: "tb-entity-autocomplete", inputs: ["entityType", "entitySubtype", "excludeEntityIds", "labelText", "requiredText", "required", "disabled"], outputs: ["entityChanged"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }] }); -i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RuleChainInputComponent, decorators: [{ - type: Component, - args: [{ - selector: 'tb-flow-node-rule-chain-input-config', - templateUrl: './rule-chain-input.component.html', - styleUrls: [] - }] - }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); - -class RuleChainOutputComponent extends RuleNodeConfigurationComponent { - constructor(store, fb) { - super(store); - this.store = store; - this.fb = fb; - } - configForm() { - return this.ruleChainOutputConfigForm; - } - onConfigurationSet(configuration) { - this.ruleChainOutputConfigForm = this.fb.group({}); - } -} -RuleChainOutputComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RuleChainOutputComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); -RuleChainOutputComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: RuleChainOutputComponent, selector: "tb-flow-node-rule-chain-output-config", usesInheritance: true, ngImport: i0, template: "
\n
\n
\n", directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }], pipes: { "translate": i4.TranslatePipe } }); -i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RuleChainOutputComponent, decorators: [{ - type: Component, - args: [{ - selector: 'tb-flow-node-rule-chain-output-config', - templateUrl: './rule-chain-output.component.html', - styleUrls: [] - }] - }], ctorParameters: function () { return [{ type: i1.Store }, { type: i2.FormBuilder }]; } }); - -class RuleNodeCoreConfigFlowModule { -} -RuleNodeCoreConfigFlowModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RuleNodeCoreConfigFlowModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); -RuleNodeCoreConfigFlowModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RuleNodeCoreConfigFlowModule, declarations: [RuleChainInputComponent, - RuleChainOutputComponent], imports: [CommonModule, - SharedModule, - RulenodeCoreConfigCommonModule], exports: [RuleChainInputComponent, - RuleChainOutputComponent] }); -RuleNodeCoreConfigFlowModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RuleNodeCoreConfigFlowModule, imports: [[ - CommonModule, - SharedModule, - RulenodeCoreConfigCommonModule - ]] }); -i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RuleNodeCoreConfigFlowModule, decorators: [{ - type: NgModule, - args: [{ - declarations: [ - RuleChainInputComponent, - RuleChainOutputComponent - ], - imports: [ - CommonModule, - SharedModule, - RulenodeCoreConfigCommonModule - ], - exports: [ - RuleChainInputComponent, - RuleChainOutputComponent - ] - }] - }] }); - -function addRuleNodeCoreLocaleEnglish(translate) { - const enUS = { - tb: { - rulenode: { - 'create-entity-if-not-exists': 'Create new entity if not exists', - 'create-entity-if-not-exists-hint': 'Create a new entity set above if it does not exist.', - 'entity-name-pattern': 'Name pattern', - 'entity-name-pattern-required': 'Name pattern is required', - 'entity-type-pattern': 'Type pattern', - 'entity-type-pattern-required': 'Type pattern is required', - 'entity-cache-expiration': 'Entities cache expiration time (sec)', - 'entity-cache-expiration-hint': 'Specifies maximum time interval allowed to store found entity records. 0 value means that records will never expire.', - 'entity-cache-expiration-required': 'Entities cache expiration time is required.', - 'entity-cache-expiration-range': 'Entities cache expiration time should be greater than or equal to 0.', - 'customer-name-pattern': 'Customer name pattern', - 'customer-name-pattern-required': 'Customer name pattern is required', - 'create-customer-if-not-exists': 'Create new customer if not exists', - 'customer-cache-expiration': 'Customers cache expiration time (sec)', - 'customer-cache-expiration-hint': 'Specifies maximum time interval allowed to store found customer records. 0 value means that records will never expire.', - 'customer-cache-expiration-required': 'Customers cache expiration time is required.', - 'customer-cache-expiration-range': 'Customers cache expiration time should be greater than or equal to 0.', - 'start-interval': 'Start Interval', - 'end-interval': 'End Interval', - 'start-interval-time-unit': 'Start Interval Time Unit', - 'end-interval-time-unit': 'End Interval Time Unit', - 'fetch-mode': 'Fetch mode', - 'fetch-mode-hint': 'If selected fetch mode \'ALL\' you able to choose telemetry sampling order.', - 'order-by': 'Order by', - 'order-by-hint': 'Select to choose telemetry sampling order.', - limit: 'Limit', - 'limit-hint': 'Min limit value is 2, max - 1000. In case you want to fetch a single entry, ' + - 'select fetch mode \'FIRST\' or \'LAST\'.', - 'time-unit-milliseconds': 'Milliseconds', - 'time-unit-seconds': 'Seconds', - 'time-unit-minutes': 'Minutes', - 'time-unit-hours': 'Hours', - 'time-unit-days': 'Days', - 'time-value-range': 'Time value should be in a range from 1 to 2147483647.', - 'start-interval-value-required': 'Start interval value is required.', - 'end-interval-value-required': 'End interval value is required.', - filter: 'Filter', - switch: 'Switch', - 'message-type': 'Message type', - 'message-type-required': 'Message type is required.', - 'message-types-filter': 'Message types filter', - 'no-message-types-found': 'No message types found', - 'no-message-type-matching': '\'{{messageType}}\' not found.', - 'create-new-message-type': 'Create a new one!', - 'message-types-required': 'Message types are required.', - 'client-attributes': 'Client attributes', - 'shared-attributes': 'Shared attributes', - 'server-attributes': 'Server attributes', - 'notify-device': 'Notify Device', - 'notify-device-hint': 'If the message arrives from the device, we will push it back to the device by default.', - 'latest-timeseries': 'Latest timeseries', - 'timeseries-key': 'Timeseries key', - 'data-keys': 'Message data', - 'metadata-keys': 'Message metadata', - 'relations-query': 'Relations query', - 'device-relations-query': 'Device relations query', - 'max-relation-level': 'Max relation level', - 'relation-type-pattern': 'Relation type pattern', - 'relation-type-pattern-required': 'Relation type pattern is required', - 'relation-types-list': 'Relation types to propagate', - 'relation-types-list-hint': 'If Propagate relation types are not selected, ' + - 'alarms will be propagated without filtering by relation type.', - 'unlimited-level': 'Unlimited level', - 'latest-telemetry': 'Latest telemetry', - 'attr-mapping': 'Attributes mapping', - 'source-attribute': 'Source attribute', - 'source-attribute-required': 'Source attribute is required.', - 'source-telemetry': 'Source telemetry', - 'source-telemetry-required': 'Source telemetry is required.', - 'target-attribute': 'Target attribute', - 'target-attribute-required': 'Target attribute is required.', - 'attr-mapping-required': 'At least one attribute mapping should be specified.', - 'fields-mapping': 'Fields mapping', - 'fields-mapping-required': 'At least one field mapping should be specified.', - 'source-field': 'Source field', - 'source-field-required': 'Source field is required.', - 'originator-source': 'Originator source', - 'originator-customer': 'Customer', - 'originator-tenant': 'Tenant', - 'originator-related': 'Related', - 'originator-alarm-originator': 'Alarm Originator', - 'clone-message': 'Clone message', - transform: 'Transform', - 'default-ttl': 'Default TTL in seconds', - 'default-ttl-required': 'Default TTL is required.', - 'min-default-ttl-message': 'Only 0 minimum TTL is allowed.', - 'message-count': 'Message count (0 - unlimited)', - 'message-count-required': 'Message count is required.', - 'min-message-count-message': 'Only 0 minimum message count is allowed.', - 'period-seconds': 'Period in seconds', - 'period-seconds-required': 'Period is required.', - 'use-metadata-period-in-seconds-patterns': 'Use period in seconds pattern', - 'use-metadata-period-in-seconds-patterns-hint': 'If selected, rule node use period in seconds interval pattern from message metadata or data ' + - 'assuming that intervals are in the seconds.', - 'period-in-seconds-pattern': 'Period in seconds pattern', - 'period-in-seconds-pattern-required': 'Period in seconds pattern is required', - 'min-period-seconds-message': 'Only 1 second minimum period is allowed.', - originator: 'Originator', - 'message-body': 'Message body', - 'message-metadata': 'Message metadata', - generate: 'Generate', - 'test-generator-function': 'Test generator function', - generator: 'Generator', - 'test-filter-function': 'Test filter function', - 'test-switch-function': 'Test switch function', - 'test-transformer-function': 'Test transformer function', - transformer: 'Transformer', - 'alarm-create-condition': 'Alarm create condition', - 'test-condition-function': 'Test condition function', - 'alarm-clear-condition': 'Alarm clear condition', - 'alarm-details-builder': 'Alarm details builder', - 'test-details-function': 'Test details function', - 'alarm-type': 'Alarm type', - 'alarm-type-required': 'Alarm type is required.', - 'alarm-severity': 'Alarm severity', - 'alarm-severity-required': 'Alarm severity is required', - 'alarm-status-filter': 'Alarm status filter', - 'alarm-status-list-empty': 'Alarm status list is empty', - 'no-alarm-status-matching': 'No alarm status matching were found.', - propagate: 'Propagate', - condition: 'Condition', - details: 'Details', - 'to-string': 'To string', - 'test-to-string-function': 'Test to string function', - 'from-template': 'From Template', - 'from-template-required': 'From Template is required', - 'to-template': 'To Template', - 'to-template-required': 'To Template is required', - 'mail-address-list-template-hint': 'Comma separated address list, use ${metadataKey' + - '} for value from metadata, $[messageKey' + - '] for value from message body', - 'cc-template': 'Cc Template', - 'bcc-template': 'Bcc Template', - 'subject-template': 'Subject Template', - 'subject-template-required': 'Subject Template is required', - 'body-template': 'Body Template', - 'body-template-required': 'Body Template is required', - 'dynamic-mail-body-type': 'Dynamic mail body type', - 'mail-body-type': 'Mail body type', - 'request-id-metadata-attribute': 'Request Id Metadata attribute name', - 'timeout-sec': 'Timeout in seconds', - 'timeout-required': 'Timeout is required', - 'min-timeout-message': 'Only 0 minimum timeout value is allowed.', - 'endpoint-url-pattern': 'Endpoint URL pattern', - 'endpoint-url-pattern-required': 'Endpoint URL pattern is required', - 'request-method': 'Request method', - 'use-simple-client-http-factory': 'Use simple client HTTP factory', - 'ignore-request-body': 'Without request body', - 'read-timeout': 'Read timeout in millis', - 'read-timeout-hint': 'The value of 0 means an infinite timeout', - 'max-parallel-requests-count': 'Max number of parallel requests', - 'max-parallel-requests-count-hint': 'The value of 0 specifies no limit in parallel processing', - headers: 'Headers', - 'headers-hint': 'Use ${metadataKey} ' + - 'for value from metadata, $[messageKey] ' + - 'for value from message body in header/value fields', - header: 'Header', - 'header-required': 'Header is required', - value: 'Value', - 'value-required': 'Value is required', - 'topic-pattern': 'Topic pattern', - 'topic-pattern-required': 'Topic pattern is required', - topic: 'Topic', - 'topic-required': 'Topic is required', - 'bootstrap-servers': 'Bootstrap servers', - 'bootstrap-servers-required': 'Bootstrap servers value is required', - 'other-properties': 'Other properties', - key: 'Key', - 'key-required': 'Key is required', - retries: 'Automatically retry times if fails', - 'min-retries-message': 'Only 0 minimum retries is allowed.', - 'batch-size-bytes': 'Produces batch size in bytes', - 'min-batch-size-bytes-message': 'Only 0 minimum batch size is allowed.', - 'linger-ms': 'Time to buffer locally (ms)', - 'min-linger-ms-message': 'Only 0 ms minimum value is allowed.', - 'buffer-memory-bytes': 'Client buffer max size in bytes', - 'min-buffer-memory-message': 'Only 0 minimum buffer size is allowed.', - acks: 'Number of acknowledgments', - 'key-serializer': 'Key serializer', - 'key-serializer-required': 'Key serializer is required', - 'value-serializer': 'Value serializer', - 'value-serializer-required': 'Value serializer is required', - 'topic-arn-pattern': 'Topic ARN pattern', - 'topic-arn-pattern-required': 'Topic ARN pattern is required', - 'aws-access-key-id': 'AWS Access Key ID', - 'aws-access-key-id-required': 'AWS Access Key ID is required', - 'aws-secret-access-key': 'AWS Secret Access Key', - 'aws-secret-access-key-required': 'AWS Secret Access Key is required', - 'aws-region': 'AWS Region', - 'aws-region-required': 'AWS Region is required', - 'exchange-name-pattern': 'Exchange name pattern', - 'routing-key-pattern': 'Routing key pattern', - 'message-properties': 'Message properties', - host: 'Host', - 'host-required': 'Host is required', - port: 'Port', - 'port-required': 'Port is required', - 'port-range': 'Port should be in a range from 1 to 65535.', - 'virtual-host': 'Virtual host', - username: 'Username', - password: 'Password', - 'automatic-recovery': 'Automatic recovery', - 'connection-timeout-ms': 'Connection timeout (ms)', - 'min-connection-timeout-ms-message': 'Only 0 ms minimum value is allowed.', - 'handshake-timeout-ms': 'Handshake timeout (ms)', - 'min-handshake-timeout-ms-message': 'Only 0 ms minimum value is allowed.', - 'client-properties': 'Client properties', - 'queue-url-pattern': 'Queue URL pattern', - 'queue-url-pattern-required': 'Queue URL pattern is required', - 'delay-seconds': 'Delay (seconds)', - 'min-delay-seconds-message': 'Only 0 seconds minimum value is allowed.', - 'max-delay-seconds-message': 'Only 900 seconds maximum value is allowed.', - name: 'Name', - 'name-required': 'Name is required', - 'queue-type': 'Queue type', - 'sqs-queue-standard': 'Standard', - 'sqs-queue-fifo': 'FIFO', - 'gcp-project-id': 'GCP project ID', - 'gcp-project-id-required': 'GCP project ID is required', - 'gcp-service-account-key': 'GCP service account key file', - 'gcp-service-account-key-required': 'GCP service account key file is required', - 'pubsub-topic-name': 'Topic name', - 'pubsub-topic-name-required': 'Topic name is required', - 'message-attributes': 'Message attributes', - 'message-attributes-hint': 'Use ${metadataKey} ' + - 'for value from metadata, $[messageKey] ' + - 'for value from message body in name/value fields', - 'connect-timeout': 'Connection timeout (sec)', - 'connect-timeout-required': 'Connection timeout is required.', - 'connect-timeout-range': 'Connection timeout should be in a range from 1 to 200.', - 'client-id': 'Client ID', - 'client-id-hint': 'Hint: Optional. Leave empty for auto-generated client id. Be careful when specifying the Client ID.' + - 'Majority of the MQTT brokers will not allow multiple connections with the same client id. ' + - 'To connect to such brokers, your mqtt client id must be unique. ' + - 'When platform is running in a micro-services mode, the copy of rule nodeis launched in each micro-service. ' + - 'This will automatically lead to multiple mqtt clients with the same id and may cause failures of the rule node.', - 'device-id': 'Device ID', - 'device-id-required': 'Device ID is required.', - 'clean-session': 'Clean session', - 'enable-ssl': 'Enable SSL', - credentials: 'Credentials', - 'credentials-type': 'Credentials type', - 'credentials-type-required': 'Credentials type is required.', - 'credentials-anonymous': 'Anonymous', - 'credentials-basic': 'Basic', - 'credentials-pem': 'PEM', - 'credentials-pem-hint': 'At least Server CA certificate file or a pair of Client certificate and Client private key files are required', - 'credentials-sas': 'Shared Access Signature', - 'sas-key': 'SAS Key', - 'sas-key-required': 'SAS Key is required.', - hostname: 'Hostname', - 'hostname-required': 'Hostname is required.', - 'azure-ca-cert': 'CA certificate file', - 'username-required': 'Username is required.', - 'password-required': 'Password is required.', - 'ca-cert': 'Server CA certificate file *', - 'private-key': 'Client private key file *', - cert: 'Client certificate file *', - 'no-file': 'No file selected.', - 'drop-file': 'Drop a file or click to select a file to upload.', - 'private-key-password': 'Private key password', - 'use-system-smtp-settings': 'Use system SMTP settings', - 'use-metadata-interval-patterns': 'Use interval patterns', - 'use-metadata-interval-patterns-hint': 'If selected, rule node use start and end interval patterns from message metadata or data ' + - 'assuming that intervals are in the milliseconds.', - 'use-message-alarm-data': 'Use message alarm data', - 'use-dynamically-change-the-severity-of-alar': 'Use dynamically change the severity of alarm', - 'check-all-keys': 'Check that all selected keys are present', - 'check-all-keys-hint': 'If selected, checks that all specified keys are present in the message data and metadata.', - 'check-relation-to-specific-entity': 'Check relation to specific entity', - 'check-relation-hint': 'Checks existence of relation to specific entity or to any entity based on direction and relation type.', - 'delete-relation-to-specific-entity': 'Delete relation to specific entity', - 'delete-relation-hint': 'Deletes relation from the originator of the incoming message to the specified ' + - 'entity or list of entities based on direction and type.', - 'remove-current-relations': 'Remove current relations', - 'remove-current-relations-hint': 'Removes current relations from the originator of the incoming message based on direction and type.', - 'change-originator-to-related-entity': 'Change originator to related entity', - 'change-originator-to-related-entity-hint': 'Used to process submitted message as a message from another entity.', - 'start-interval-pattern': 'Start interval pattern', - 'end-interval-pattern': 'End interval pattern', - 'start-interval-pattern-required': 'Start interval pattern is required', - 'end-interval-pattern-required': 'End interval pattern is required', - 'smtp-protocol': 'Protocol', - 'smtp-host': 'SMTP host', - 'smtp-host-required': 'SMTP host is required.', - 'smtp-port': 'SMTP port', - 'smtp-port-required': 'You must supply a smtp port.', - 'smtp-port-range': 'SMTP port should be in a range from 1 to 65535.', - 'timeout-msec': 'Timeout ms', - 'min-timeout-msec-message': 'Only 0 ms minimum value is allowed.', - 'enter-username': 'Enter username', - 'enter-password': 'Enter password', - 'enable-tls': 'Enable TLS', - 'tls-version': 'TLS version', - 'enable-proxy': 'Enable proxy', - 'use-system-proxy-properties': 'Use system proxy properties', - 'proxy-host': 'Proxy host', - 'proxy-host-required': 'Proxy host is required.', - 'proxy-port': 'Proxy port', - 'proxy-port-required': 'Proxy port is required.', - 'proxy-port-range': 'Proxy port should be in a range from 1 to 65535.', - 'proxy-user': 'Proxy user', - 'proxy-password': 'Proxy password', - 'proxy-scheme': 'Proxy scheme', - 'numbers-to-template': 'Phone Numbers To Template', - 'numbers-to-template-required': 'Phone Numbers To Template is required', - 'numbers-to-template-hint': 'Comma separated Phone Numbers, use ${' + - 'metadataKey} for value from metadata, ' + - '$[messageKey] for value from message body', - 'sms-message-template': 'SMS message Template', - 'sms-message-template-required': 'SMS message Template is required', - 'use-system-sms-settings': 'Use system SMS provider settings', - 'min-period-0-seconds-message': 'Only 0 second minimum period is allowed.', - 'max-pending-messages': 'Maximum pending messages', - 'max-pending-messages-required': 'Maximum pending messages is required.', - 'max-pending-messages-range': 'Maximum pending messages should be in a range from 1 to 100000.', - 'originator-types-filter': 'Originator types filter', - 'interval-seconds': 'Interval in seconds', - 'interval-seconds-required': 'Interval is required.', - 'min-interval-seconds-message': 'Only 1 second minimum interval is allowed.', - 'output-timeseries-key-prefix': 'Output timeseries key prefix', - 'output-timeseries-key-prefix-required': 'Output timeseries key prefix required.', - 'separator-hint': 'You should press "enter" to complete field input.', - 'entity-details': 'Select entity details:', - 'entity-details-title': 'Title', - 'entity-details-country': 'Country', - 'entity-details-state': 'State', - 'entity-details-city': 'City', - 'entity-details-zip': 'Zip', - 'entity-details-address': 'Address', - 'entity-details-address2': 'Address2', - 'entity-details-additional_info': 'Additional Info', - 'entity-details-phone': 'Phone', - 'entity-details-email': 'Email', - 'add-to-metadata': 'Add selected details to message metadata', - 'add-to-metadata-hint': 'If selected, adds the selected details keys to the message metadata instead of message data.', - 'entity-details-list-empty': 'No entity details selected.', - 'no-entity-details-matching': 'No entity details matching were found.', - 'custom-table-name': 'Custom table name', - 'custom-table-name-required': 'Table Name is required', - 'custom-table-hint': 'You should enter the table name without prefix \'cs_tb_\'.', - 'message-field': 'Message field', - 'message-field-required': 'Message field is required.', - 'table-col': 'Table column', - 'table-col-required': 'Table column is required.', - 'latitude-key-name': 'Latitude key name', - 'longitude-key-name': 'Longitude key name', - 'latitude-key-name-required': 'Latitude key name is required.', - 'longitude-key-name-required': 'Longitude key name is required.', - 'fetch-perimeter-info-from-message-metadata': 'Fetch perimeter information from message metadata', - 'perimeter-circle': 'Circle', - 'perimeter-polygon': 'Polygon', - 'perimeter-type': 'Perimeter type', - 'circle-center-latitude': 'Center latitude', - 'circle-center-latitude-required': 'Center latitude is required.', - 'circle-center-longitude': 'Center longitude', - 'circle-center-longitude-required': 'Center longitude is required.', - 'range-unit-meter': 'Meter', - 'range-unit-kilometer': 'Kilometer', - 'range-unit-foot': 'Foot', - 'range-unit-mile': 'Mile', - 'range-unit-nautical-mile': 'Nautical mile', - 'range-units': 'Range units', - range: 'Range', - 'range-required': 'Range is required.', - 'polygon-definition': 'Polygon definition', - 'polygon-definition-required': 'Polygon definition is required.', - 'polygon-definition-hint': 'Please, use the following format for manual definition of polygon: [[lat1,lon1],[lat2,lon2], ... ,[latN,lonN]].', - 'min-inside-duration': 'Minimal inside duration', - 'min-inside-duration-value-required': 'Minimal inside duration is required', - 'min-inside-duration-time-unit': 'Minimal inside duration time unit', - 'min-outside-duration': 'Minimal outside duration', - 'min-outside-duration-value-required': 'Minimal outside duration is required', - 'min-outside-duration-time-unit': 'Minimal outside duration time unit', - 'tell-failure-if-absent': 'Tell Failure', - 'tell-failure-if-absent-hint': 'If at least one selected key doesn\'t exist the outbound message will report "Failure".', - 'get-latest-value-with-ts': 'Fetch Latest telemetry with Timestamp', - 'get-latest-value-with-ts-hint': 'If selected, latest telemetry values will be added to the outbound message metadata with timestamp, ' + - 'e.g: "temp": "{"ts":1574329385897, "value":42}"', - 'use-redis-queue': 'Use redis queue for message persistence', - 'trim-redis-queue': 'Trim redis queue', - 'redis-queue-max-size': 'Redis queue max size', - 'add-metadata-key-values-as-kafka-headers': 'Add Message metadata key-value pairs to Kafka record headers', - 'add-metadata-key-values-as-kafka-headers-hint': 'If selected, key-value pairs from message metadata will be added to the outgoing records headers as byte arrays with predefined charset encoding.', - 'charset-encoding': 'Charset encoding', - 'charset-encoding-required': 'Charset encoding is required.', - 'charset-us-ascii': 'US-ASCII', - 'charset-iso-8859-1': 'ISO-8859-1', - 'charset-utf-8': 'UTF-8', - 'charset-utf-16be': 'UTF-16BE', - 'charset-utf-16le': 'UTF-16LE', - 'charset-utf-16': 'UTF-16', - 'select-queue-hint': 'The queue name can be selected from a drop-down list or add a custom name.', - 'persist-alarm-rules': 'Persist state of alarm rules', - 'fetch-alarm-rules': 'Fetch state of alarm rules', - 'input-value-key': 'Input value key', - 'input-value-key-required': 'Input value key is required.', - 'output-value-key': 'Output value key', - 'output-value-key-required': 'Output value key is required.', - round: 'Decimals', - 'round-range': 'Decimals should be in a range from 0 to 15.', - 'use-cache': 'Use cache for latest value', - 'tell-failure-if-delta-is-negative': 'Tell Failure if delta is negative', - 'add-period-between-msgs': 'Add period between messages', - 'period-value-key': 'Period value key', - 'period-key-required': 'Period value key is required.', - 'general-pattern-hint': 'Hint: use ${metadataKey} ' + - 'for value from metadata, $[messageKey] ' + - 'for value from message body', - 'alarm-severity-pattern-hint': 'Hint: use ${metadataKey} ' + - 'for value from metadata, $[messageKey] ' + - 'for value from message body. Alarm severity should be system (CRITICAL, MAJOR etc.)', - 'output-node-name-hint': 'The rule node name corresponds to the relation type of the output message, and it is used to forward messages to other rule nodes in the caller rule chain.' - }, - 'key-val': { - key: 'Key', - value: 'Value', - 'remove-entry': 'Remove entry', - 'add-entry': 'Add entry' - }, - 'mail-body-type': { - 'plain-text': 'Plain Text', - html: 'HTML', - dynamic: 'Dynamic' - } - } - }; - translate.setTranslation('en_US', enUS, true); -} - -class RuleNodeCoreConfigModule { - constructor(translate) { - addRuleNodeCoreLocaleEnglish(translate); - } -} -RuleNodeCoreConfigModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RuleNodeCoreConfigModule, deps: [{ token: i4.TranslateService }], target: i0.ɵɵFactoryTarget.NgModule }); -RuleNodeCoreConfigModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RuleNodeCoreConfigModule, declarations: [EmptyConfigComponent], imports: [CommonModule, - SharedModule], exports: [RuleNodeCoreConfigActionModule, - RuleNodeCoreConfigFilterModule, - RulenodeCoreConfigEnrichmentModule, - RulenodeCoreConfigTransformModule, - RuleNodeCoreConfigFlowModule, - EmptyConfigComponent] }); -RuleNodeCoreConfigModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RuleNodeCoreConfigModule, imports: [[ - CommonModule, - SharedModule - ], RuleNodeCoreConfigActionModule, - RuleNodeCoreConfigFilterModule, - RulenodeCoreConfigEnrichmentModule, - RulenodeCoreConfigTransformModule, - RuleNodeCoreConfigFlowModule] }); -i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RuleNodeCoreConfigModule, decorators: [{ - type: NgModule, - args: [{ - declarations: [ - EmptyConfigComponent - ], - imports: [ - CommonModule, - SharedModule - ], - exports: [ - RuleNodeCoreConfigActionModule, - RuleNodeCoreConfigFilterModule, - RulenodeCoreConfigEnrichmentModule, - RulenodeCoreConfigTransformModule, - RuleNodeCoreConfigFlowModule, - EmptyConfigComponent - ] - }] - }], ctorParameters: function () { return [{ type: i4.TranslateService }]; } }); - -/* - * Public API Surface of rule-core-config - */ - -/** - * Generated bundle index. Do not edit. - */ - -export { AssignCustomerConfigComponent, AttributesConfigComponent, AzureIotHubConfigComponent, CalculateDeltaConfigComponent, ChangeOriginatorConfigComponent, CheckAlarmStatusComponent, CheckMessageConfigComponent, CheckPointConfigComponent, CheckRelationConfigComponent, ClearAlarmConfigComponent, CreateAlarmConfigComponent, CreateRelationConfigComponent, CredentialsConfigComponent, CustomerAttributesConfigComponent, DeleteRelationConfigComponent, DeviceAttributesConfigComponent, DeviceProfileConfigComponent, DeviceRelationsQueryConfigComponent, EmptyConfigComponent, EntityDetailsConfigComponent, GeneratorConfigComponent, GetTelemetryFromDatabaseConfigComponent, GpsGeoActionConfigComponent, GpsGeoFilterConfigComponent, KafkaConfigComponent, KvMapConfigComponent, LogConfigComponent, MessageTypeConfigComponent, MessageTypesConfigComponent, MqttConfigComponent, MsgCountConfigComponent, MsgDelayConfigComponent, OriginatorAttributesConfigComponent, OriginatorFieldsConfigComponent, OriginatorTypeConfigComponent, PubSubConfigComponent, PushToCloudConfigComponent, PushToEdgeConfigComponent, RabbitMqConfigComponent, RelatedAttributesConfigComponent, RelationsQueryConfigComponent, RestApiCallConfigComponent, RpcReplyConfigComponent, RpcRequestConfigComponent, RuleChainInputComponent, RuleChainOutputComponent, RuleNodeCoreConfigActionModule, RuleNodeCoreConfigFilterModule, RuleNodeCoreConfigFlowModule, RuleNodeCoreConfigModule, RulenodeCoreConfigCommonModule, RulenodeCoreConfigEnrichmentModule, RulenodeCoreConfigTransformModule, SafeHtmlPipe, SaveToCustomTableConfigComponent, ScriptConfigComponent, SendEmailConfigComponent, SendSmsConfigComponent, SnsConfigComponent, SqsConfigComponent, SwitchConfigComponent, TenantAttributesConfigComponent, TimeseriesConfigComponent, ToEmailConfigComponent, TransformScriptConfigComponent, UnassignCustomerConfigComponent }; -//# sourceMappingURL=rulenode-core-config.js.map +import*as e from"@angular/core";import{Component as t,Pipe as o,ViewChild as r,forwardRef as a,Input as n,NgModule as l}from"@angular/core";import*as i from"@shared/public-api";import{RuleNodeConfigurationComponent as s,AttributeScope as m,telemetryTypeTranslations as u,ServiceType as p,AlarmSeverity as d,alarmSeverityTranslations as f,EntitySearchDirection as c,entitySearchDirectionTranslations as g,EntityType as x,PageComponent as y,MessageType as b,messageTypeNames as h,SharedModule as F,AggregationType as C,aggregationTranslations as L,alarmStatusTranslations as v,AlarmStatus as I}from"@shared/public-api";import*as N from"@ngrx/store";import*as q from"@angular/forms";import{Validators as T,NgControl as k,NG_VALUE_ACCESSOR as M,NG_VALIDATORS as S,FormControl as A}from"@angular/forms";import*as G from"@angular/material/form-field";import*as D from"@angular/material/checkbox";import*as V from"@angular/flex-layout/flex";import*as E from"@ngx-translate/core";import*as P from"@angular/material/input";import*as R from"@angular/common";import{CommonModule as w}from"@angular/common";import*as O from"@angular/platform-browser";import*as H from"@angular/material/select";import*as U from"@angular/material/core";import*as B from"@angular/material/expansion";import*as K from"@shared/components/button/toggle-password.component";import*as j from"@shared/components/file-input.component";import*as z from"@shared/components/queue/queue-type-list.component";import*as _ from"@core/public-api";import{isDefinedAndNotNull as Q}from"@core/public-api";import*as $ from"@shared/components/js-func.component";import*as W from"@angular/material/button";import{ENTER as Y,COMMA as J,SEMICOLON as Z}from"@angular/cdk/keycodes";import*as X from"@angular/material/chips";import*as ee from"@angular/material/icon";import*as te from"@shared/components/entity/entity-type-select.component";import*as oe from"@shared/components/entity/entity-select.component";import{coerceBooleanProperty as re}from"@angular/cdk/coercion";import*as ae from"@shared/components/tb-error.component";import*as ne from"@angular/flex-layout/extended";import*as le from"@angular/material/tooltip";import{distinctUntilChanged as ie,startWith as se,map as me,mergeMap as ue,share as pe}from"rxjs/operators";import*as de from"@shared/components/tb-checkbox.component";import*as fe from"@home/components/sms/sms-provider-configuration.component";import{HomeComponentsModule as ce}from"@home/components/public-api";import*as ge from"@shared/components/relation/relation-type-autocomplete.component";import*as xe from"@shared/components/entity/entity-subtype-list.component";import*as ye from"@home/components/relation/relation-filters.component";import{of as be}from"rxjs";import*as he from"@angular/material/autocomplete";import*as Fe from"@shared/pipe/highlight.pipe";import*as Ce from"@shared/components/entity/entity-autocomplete.component";import*as Le from"@shared/components/entity/entity-type-list.component";class ve extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.emptyConfigForm}onConfigurationSet(e){this.emptyConfigForm=this.fb.group({})}}ve.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:ve,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),ve.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:ve,selector:"tb-node-empty-config",usesInheritance:!0,ngImport:e,template:"
",isInline:!0}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:ve,decorators:[{type:t,args:[{selector:"tb-node-empty-config",template:"
",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class Ie{constructor(e){this.sanitizer=e}transform(e){return this.sanitizer.bypassSecurityTrustHtml(e)}}Ie.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Ie,deps:[{token:O.DomSanitizer}],target:e.ɵɵFactoryTarget.Pipe}),Ie.ɵpipe=e.ɵɵngDeclarePipe({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Ie,name:"safeHtml"}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Ie,decorators:[{type:o,args:[{name:"safeHtml"}]}],ctorParameters:function(){return[{type:O.DomSanitizer}]}});class Ne extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.assignCustomerConfigForm}onConfigurationSet(e){this.assignCustomerConfigForm=this.fb.group({customerNamePattern:[e?e.customerNamePattern:null,[T.required,T.pattern(/.*\S.*/)]],createCustomerIfNotExists:[!!e&&e.createCustomerIfNotExists,[]],customerCacheExpiration:[e?e.customerCacheExpiration:null,[T.required,T.min(0)]]})}prepareOutputConfig(e){return e.customerNamePattern=e.customerNamePattern.trim(),e}}Ne.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Ne,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),Ne.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Ne,selector:"tb-action-node-assign-to-customer-config",usesInheritance:!0,ngImport:e,template:'
\n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.create-customer-if-not-exists\' | translate }}\n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n tb.rulenode.customer-cache-expiration-hint\n \n
\n',components:[{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:D.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:G.MatLabel,selector:"mat-label"},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:G.MatError,selector:"mat-error",inputs:["id"]},{type:G.MatHint,selector:"mat-hint",inputs:["align","id"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"}],pipes:{translate:E.TranslatePipe,safeHtml:Ie}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Ne,decorators:[{type:t,args:[{selector:"tb-action-node-assign-to-customer-config",templateUrl:"./assign-customer-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class qe extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.attributeScopes=Object.keys(m),this.telemetryTypeTranslationsMap=u}configForm(){return this.attributesConfigForm}onConfigurationSet(e){this.attributesConfigForm=this.fb.group({scope:[e?e.scope:null,[T.required]],notifyDevice:[!e||e.scope,[]]})}}var Te;qe.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:qe,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),qe.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:qe,selector:"tb-action-node-attributes-config",usesInheritance:!0,ngImport:e,template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.notify-device\' | translate }}\n \n
tb.rulenode.notify-device-hint
\n
\n
\n',components:[{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:H.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:U.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:D.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:G.MatLabel,selector:"mat-label"},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]}],pipes:{translate:E.TranslatePipe}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:qe,decorators:[{type:t,args:[{selector:"tb-action-node-attributes-config",templateUrl:"./attributes-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}}),function(e){e.CUSTOMER="CUSTOMER",e.TENANT="TENANT",e.RELATED="RELATED",e.ALARM_ORIGINATOR="ALARM_ORIGINATOR"}(Te||(Te={}));const ke=new Map([[Te.CUSTOMER,"tb.rulenode.originator-customer"],[Te.TENANT,"tb.rulenode.originator-tenant"],[Te.RELATED,"tb.rulenode.originator-related"],[Te.ALARM_ORIGINATOR,"tb.rulenode.originator-alarm-originator"]]);var Me;!function(e){e.CIRCLE="CIRCLE",e.POLYGON="POLYGON"}(Me||(Me={}));const Se=new Map([[Me.CIRCLE,"tb.rulenode.perimeter-circle"],[Me.POLYGON,"tb.rulenode.perimeter-polygon"]]);var Ae;!function(e){e.MILLISECONDS="MILLISECONDS",e.SECONDS="SECONDS",e.MINUTES="MINUTES",e.HOURS="HOURS",e.DAYS="DAYS"}(Ae||(Ae={}));const Ge=new Map([[Ae.MILLISECONDS,"tb.rulenode.time-unit-milliseconds"],[Ae.SECONDS,"tb.rulenode.time-unit-seconds"],[Ae.MINUTES,"tb.rulenode.time-unit-minutes"],[Ae.HOURS,"tb.rulenode.time-unit-hours"],[Ae.DAYS,"tb.rulenode.time-unit-days"]]);var De;!function(e){e.METER="METER",e.KILOMETER="KILOMETER",e.FOOT="FOOT",e.MILE="MILE",e.NAUTICAL_MILE="NAUTICAL_MILE"}(De||(De={}));const Ve=new Map([[De.METER,"tb.rulenode.range-unit-meter"],[De.KILOMETER,"tb.rulenode.range-unit-kilometer"],[De.FOOT,"tb.rulenode.range-unit-foot"],[De.MILE,"tb.rulenode.range-unit-mile"],[De.NAUTICAL_MILE,"tb.rulenode.range-unit-nautical-mile"]]);var Ee;!function(e){e.TITLE="TITLE",e.COUNTRY="COUNTRY",e.STATE="STATE",e.CITY="CITY",e.ZIP="ZIP",e.ADDRESS="ADDRESS",e.ADDRESS2="ADDRESS2",e.PHONE="PHONE",e.EMAIL="EMAIL",e.ADDITIONAL_INFO="ADDITIONAL_INFO"}(Ee||(Ee={}));const Pe=new Map([[Ee.TITLE,"tb.rulenode.entity-details-title"],[Ee.COUNTRY,"tb.rulenode.entity-details-country"],[Ee.STATE,"tb.rulenode.entity-details-state"],[Ee.CITY,"tb.rulenode.entity-details-city"],[Ee.ZIP,"tb.rulenode.entity-details-zip"],[Ee.ADDRESS,"tb.rulenode.entity-details-address"],[Ee.ADDRESS2,"tb.rulenode.entity-details-address2"],[Ee.PHONE,"tb.rulenode.entity-details-phone"],[Ee.EMAIL,"tb.rulenode.entity-details-email"],[Ee.ADDITIONAL_INFO,"tb.rulenode.entity-details-additional_info"]]);var Re,we,Oe;!function(e){e.FIRST="FIRST",e.LAST="LAST",e.ALL="ALL"}(Re||(Re={})),function(e){e.ASC="ASC",e.DESC="DESC"}(we||(we={})),function(e){e.STANDARD="STANDARD",e.FIFO="FIFO"}(Oe||(Oe={}));const He=new Map([[Oe.STANDARD,"tb.rulenode.sqs-queue-standard"],[Oe.FIFO,"tb.rulenode.sqs-queue-fifo"]]),Ue=["anonymous","basic","cert.PEM"],Be=new Map([["anonymous","tb.rulenode.credentials-anonymous"],["basic","tb.rulenode.credentials-basic"],["cert.PEM","tb.rulenode.credentials-pem"]]),Ke=["sas","cert.PEM"],je=new Map([["sas","tb.rulenode.credentials-sas"],["cert.PEM","tb.rulenode.credentials-pem"]]);var ze;!function(e){e.GET="GET",e.POST="POST",e.PUT="PUT",e.DELETE="DELETE"}(ze||(ze={}));const _e=["US-ASCII","ISO-8859-1","UTF-8","UTF-16BE","UTF-16LE","UTF-16"],Qe=new Map([["US-ASCII","tb.rulenode.charset-us-ascii"],["ISO-8859-1","tb.rulenode.charset-iso-8859-1"],["UTF-8","tb.rulenode.charset-utf-8"],["UTF-16BE","tb.rulenode.charset-utf-16be"],["UTF-16LE","tb.rulenode.charset-utf-16le"],["UTF-16","tb.rulenode.charset-utf-16"]]);class $e extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.allAzureIotHubCredentialsTypes=Ke,this.azureIotHubCredentialsTypeTranslationsMap=je}configForm(){return this.azureIotHubConfigForm}onConfigurationSet(e){this.azureIotHubConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[T.required]],host:[e?e.host:null,[T.required]],port:[e?e.port:null,[T.required,T.min(1),T.max(65535)]],connectTimeoutSec:[e?e.connectTimeoutSec:null,[T.required,T.min(1),T.max(200)]],clientId:[e?e.clientId:null,[T.required]],cleanSession:[!!e&&e.cleanSession,[]],ssl:[!!e&&e.ssl,[]],credentials:this.fb.group({type:[e&&e.credentials?e.credentials.type:null,[T.required]],sasKey:[e&&e.credentials?e.credentials.sasKey:null,[]],caCert:[e&&e.credentials?e.credentials.caCert:null,[]],caCertFileName:[e&&e.credentials?e.credentials.caCertFileName:null,[]],privateKey:[e&&e.credentials?e.credentials.privateKey:null,[]],privateKeyFileName:[e&&e.credentials?e.credentials.privateKeyFileName:null,[]],cert:[e&&e.credentials?e.credentials.cert:null,[]],certFileName:[e&&e.credentials?e.credentials.certFileName:null,[]],password:[e&&e.credentials?e.credentials.password:null,[]]})})}prepareOutputConfig(e){const t=e.credentials.type;return"sas"===t&&(e.credentials={type:t,sasKey:e.credentials.sasKey,caCert:e.credentials.caCert,caCertFileName:e.credentials.caCertFileName}),e}validatorTriggers(){return["credentials.type"]}updateValidators(e){const t=this.azureIotHubConfigForm.get("credentials"),o=t.get("type").value;switch(e&&t.reset({type:o},{emitEvent:!1}),t.get("sasKey").setValidators([]),t.get("privateKey").setValidators([]),t.get("privateKeyFileName").setValidators([]),t.get("cert").setValidators([]),t.get("certFileName").setValidators([]),o){case"sas":t.get("sasKey").setValidators([T.required]);break;case"cert.PEM":t.get("privateKey").setValidators([T.required]),t.get("privateKeyFileName").setValidators([T.required]),t.get("cert").setValidators([T.required]),t.get("certFileName").setValidators([T.required])}t.get("sasKey").updateValueAndValidity({emitEvent:e}),t.get("privateKey").updateValueAndValidity({emitEvent:e}),t.get("privateKeyFileName").updateValueAndValidity({emitEvent:e}),t.get("cert").updateValueAndValidity({emitEvent:e}),t.get("certFileName").updateValueAndValidity({emitEvent:e})}}$e.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:$e,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),$e.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:$e,selector:"tb-action-node-azure-iot-hub-config",usesInheritance:!0,ngImport:e,template:'
\n \n tb.rulenode.topic\n \n \n {{ \'tb.rulenode.topic-required\' | translate }}\n \n \n \n \n tb.rulenode.hostname\n \n \n {{ \'tb.rulenode.hostname-required\' | translate }}\n \n \n \n tb.rulenode.device-id\n \n \n {{ \'tb.rulenode.device-id-required\' | translate }}\n \n \n \n \n \n tb.rulenode.credentials\n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(azureIotHubConfigForm.get(\'credentials.type\').value) | translate }}\n \n \n
\n \n tb.rulenode.credentials-type\n \n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
\n \n \n \n \n tb.rulenode.sas-key\n \n \n \n {{ \'tb.rulenode.sas-key-required\' | translate }}\n \n \n \n \n \n \n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n \n
\n
\n
\n
\n
\n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}:host .tb-hint.client-id{margin-top:-1.25em;max-width:-moz-fit-content;max-width:fit-content}\n"],components:[{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:B.MatExpansionPanel,selector:"mat-expansion-panel",inputs:["disabled","expanded","hideToggle","togglePosition"],outputs:["opened","closed","expandedChange","afterExpand","afterCollapse"],exportAs:["matExpansionPanel"]},{type:B.MatExpansionPanelHeader,selector:"mat-expansion-panel-header",inputs:["tabIndex","expandedHeight","collapsedHeight"]},{type:H.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:U.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:K.TogglePasswordComponent,selector:"tb-toggle-password"},{type:j.FileInputComponent,selector:"tb-file-input",inputs:["label","accept","noFileText","inputId","allowedExtensions","dropLabel","contentConvertFunction","required","requiredAsError","disabled","existingFileName","readAsBinary","workFromFileObj","multipleFile"],outputs:["fileNameChanged"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:G.MatLabel,selector:"mat-label"},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:G.MatError,selector:"mat-error",inputs:["id"]},{type:G.MatHint,selector:"mat-hint",inputs:["align","id"]},{type:B.MatAccordion,selector:"mat-accordion",inputs:["multi","displayMode","togglePosition","hideToggle"],exportAs:["matAccordion"]},{type:B.MatExpansionPanelTitle,selector:"mat-panel-title"},{type:B.MatExpansionPanelDescription,selector:"mat-panel-description"},{type:q.FormGroupName,selector:"[formGroupName]",inputs:["formGroupName"]},{type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:R.NgSwitch,selector:"[ngSwitch]",inputs:["ngSwitch"]},{type:R.NgSwitchCase,selector:"[ngSwitchCase]",inputs:["ngSwitchCase"]},{type:G.MatSuffix,selector:"[matSuffix]"}],pipes:{translate:E.TranslatePipe,safeHtml:Ie}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:$e,decorators:[{type:t,args:[{selector:"tb-action-node-azure-iot-hub-config",templateUrl:"./azure-iot-hub-config.component.html",styleUrls:["./mqtt-config.component.scss"]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class We extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.serviceType=p.TB_RULE_ENGINE}configForm(){return this.checkPointConfigForm}onConfigurationSet(e){this.checkPointConfigForm=this.fb.group({queueName:[e?e.queueName:null,[T.required]]})}}We.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:We,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),We.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:We,selector:"tb-action-node-check-point-config",usesInheritance:!0,ngImport:e,template:'
\n \n \n
\n',components:[{type:z.QueueTypeListComponent,selector:"tb-queue-type-list",inputs:["required","disabled","queueType"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]}]}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:We,decorators:[{type:t,args:[{selector:"tb-action-node-check-point-config",templateUrl:"./check-point-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class Ye extends s{constructor(e,t,o,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=o,this.translate=r}configForm(){return this.clearAlarmConfigForm}onConfigurationSet(e){this.clearAlarmConfigForm=this.fb.group({alarmDetailsBuildJs:[e?e.alarmDetailsBuildJs:null,[T.required]],alarmType:[e?e.alarmType:null,[T.required]]})}testScript(){const e=this.clearAlarmConfigForm.get("alarmDetailsBuildJs").value;this.nodeScriptTestService.testNodeScript(e,"json",this.translate.instant("tb.rulenode.details"),"Details",["msg","metadata","msgType"],this.ruleNodeId,"rulenode/clear_alarm_node_script_fn").subscribe((e=>{e&&this.clearAlarmConfigForm.get("alarmDetailsBuildJs").setValue(e)}))}onValidate(){this.jsFuncComponent.validateOnSubmit()}}Ye.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Ye,deps:[{token:N.Store},{token:q.FormBuilder},{token:_.NodeScriptTestService},{token:E.TranslateService}],target:e.ɵɵFactoryTarget.Component}),Ye.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Ye,selector:"tb-action-node-clear-alarm-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0,static:!0}],usesInheritance:!0,ngImport:e,template:'
\n \n \n \n
\n \n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n
\n',components:[{type:$.JsFuncComponent,selector:"tb-js-func",inputs:["functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","noValidate","required"]},{type:W.MatButton,selector:"button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:G.MatLabel,selector:"mat-label"},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:G.MatError,selector:"mat-error",inputs:["id"]},{type:G.MatHint,selector:"mat-hint",inputs:["align","id"]}],pipes:{translate:E.TranslatePipe,safeHtml:Ie}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Ye,decorators:[{type:t,args:[{selector:"tb-action-node-clear-alarm-config",templateUrl:"./clear-alarm-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder},{type:_.NodeScriptTestService},{type:E.TranslateService}]},propDecorators:{jsFuncComponent:[{type:r,args:["jsFuncComponent",{static:!0}]}]}});class Je extends s{constructor(e,t,o,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=o,this.translate=r,this.alarmSeverities=Object.keys(d),this.alarmSeverityTranslationMap=f,this.separatorKeysCodes=[Y,J,Z]}configForm(){return this.createAlarmConfigForm}onConfigurationSet(e){this.createAlarmConfigForm=this.fb.group({alarmDetailsBuildJs:[e?e.alarmDetailsBuildJs:null,[T.required]],useMessageAlarmData:[!!e&&e.useMessageAlarmData,[]],alarmType:[e?e.alarmType:null,[]],severity:[e?e.severity:null,[]],propagate:[!!e&&e.propagate,[]],relationTypes:[e?e.relationTypes:null,[]],dynamicSeverity:!1}),this.createAlarmConfigForm.get("dynamicSeverity").valueChanges.subscribe((e=>{e?this.createAlarmConfigForm.get("severity").patchValue("",{emitEvent:!1}):this.createAlarmConfigForm.get("severity").patchValue(this.alarmSeverities[0],{emitEvent:!1})}))}validatorTriggers(){return["useMessageAlarmData"]}updateValidators(e){this.createAlarmConfigForm.get("useMessageAlarmData").value?(this.createAlarmConfigForm.get("alarmType").setValidators([]),this.createAlarmConfigForm.get("severity").setValidators([])):(this.createAlarmConfigForm.get("alarmType").setValidators([T.required]),this.createAlarmConfigForm.get("severity").setValidators([T.required])),this.createAlarmConfigForm.get("alarmType").updateValueAndValidity({emitEvent:e}),this.createAlarmConfigForm.get("severity").updateValueAndValidity({emitEvent:e})}testScript(){const e=this.createAlarmConfigForm.get("alarmDetailsBuildJs").value;this.nodeScriptTestService.testNodeScript(e,"json",this.translate.instant("tb.rulenode.details"),"Details",["msg","metadata","msgType"],this.ruleNodeId,"rulenode/create_alarm_node_script_fn").subscribe((e=>{e&&this.createAlarmConfigForm.get("alarmDetailsBuildJs").setValue(e)}))}removeKey(e,t){const o=this.createAlarmConfigForm.get(t).value,r=o.indexOf(e);r>=0&&(o.splice(r,1),this.createAlarmConfigForm.get(t).setValue(o,{emitEvent:!0}))}addKey(e,t){const o=e.input;let r=e.value;if((r||"").trim()){r=r.trim();let e=this.createAlarmConfigForm.get(t).value;e&&-1!==e.indexOf(r)||(e||(e=[]),e.push(r),this.createAlarmConfigForm.get(t).setValue(e,{emitEvent:!0}))}o&&(o.value="")}onValidate(){this.jsFuncComponent.validateOnSubmit()}}Je.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Je,deps:[{token:N.Store},{token:q.FormBuilder},{token:_.NodeScriptTestService},{token:E.TranslateService}],target:e.ɵɵFactoryTarget.Component}),Je.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Je,selector:"tb-action-node-create-alarm-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0,static:!0}],usesInheritance:!0,ngImport:e,template:'
\n \n \n \n
\n \n
\n
\n \n {{ \'tb.rulenode.use-message-alarm-data\' | translate }}\n \n \n {{ \'tb.rulenode.use-dynamically-change-the-severity-of-alar\' | translate }}\n \n
\n
\n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n \n tb.rulenode.alarm-severity\n \n \n {{ alarmSeverityTranslationMap.get(severity) | translate }}\n \n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.alarm-severity\' | translate }}\n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.propagate\' | translate }}\n \n
\n \n tb.rulenode.relation-types-list\n \n \n {{key}}\n close\n \n \n \n tb.rulenode.relation-types-list-hint\n \n
\n
\n
\n',components:[{type:$.JsFuncComponent,selector:"tb-js-func",inputs:["functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","noValidate","required"]},{type:W.MatButton,selector:"button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{type:D.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:H.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:U.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:X.MatChipList,selector:"mat-chip-list",inputs:["aria-orientation","multiple","compareWith","value","required","placeholder","disabled","selectable","tabIndex","errorStateMatcher"],outputs:["change","valueChange"],exportAs:["matChipList"]},{type:ee.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:V.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:G.MatLabel,selector:"mat-label"},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:G.MatError,selector:"mat-error",inputs:["id"]},{type:G.MatHint,selector:"mat-hint",inputs:["align","id"]},{type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:X.MatChip,selector:"mat-basic-chip, [mat-basic-chip], mat-chip, [mat-chip]",inputs:["color","disableRipple","tabIndex","selected","value","selectable","disabled","removable"],outputs:["selectionChange","destroyed","removed"],exportAs:["matChip"]},{type:X.MatChipRemove,selector:"[matChipRemove]"},{type:X.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputSeparatorKeyCodes","placeholder","id","matChipInputFor","matChipInputAddOnBlur","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]}],pipes:{translate:E.TranslatePipe,safeHtml:Ie}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Je,decorators:[{type:t,args:[{selector:"tb-action-node-create-alarm-config",templateUrl:"./create-alarm-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder},{type:_.NodeScriptTestService},{type:E.TranslateService}]},propDecorators:{jsFuncComponent:[{type:r,args:["jsFuncComponent",{static:!0}]}]}});class Ze extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.keys(c),this.directionTypeTranslations=g,this.entityType=x}configForm(){return this.createRelationConfigForm}onConfigurationSet(e){this.createRelationConfigForm=this.fb.group({direction:[e?e.direction:null,[T.required]],entityType:[e?e.entityType:null,[T.required]],entityNamePattern:[e?e.entityNamePattern:null,[]],entityTypePattern:[e?e.entityTypePattern:null,[]],relationType:[e?e.relationType:null,[T.required]],createEntityIfNotExists:[!!e&&e.createEntityIfNotExists,[]],removeCurrentRelations:[!!e&&e.removeCurrentRelations,[]],changeOriginatorToRelatedEntity:[!!e&&e.changeOriginatorToRelatedEntity,[]],entityCacheExpiration:[e?e.entityCacheExpiration:null,[T.required,T.min(0)]]})}validatorTriggers(){return["entityType"]}updateValidators(e){const t=this.createRelationConfigForm.get("entityType").value;t?this.createRelationConfigForm.get("entityNamePattern").setValidators([T.required,T.pattern(/.*\S.*/)]):this.createRelationConfigForm.get("entityNamePattern").setValidators([]),!t||t!==x.DEVICE&&t!==x.ASSET?this.createRelationConfigForm.get("entityTypePattern").setValidators([]):this.createRelationConfigForm.get("entityTypePattern").setValidators([T.required,T.pattern(/.*\S.*/)]),this.createRelationConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e}),this.createRelationConfigForm.get("entityTypePattern").updateValueAndValidity({emitEvent:e})}prepareOutputConfig(e){return e.entityNamePattern=e.entityNamePattern?e.entityNamePattern.trim():null,e.entityTypePattern=e.entityTypePattern?e.entityTypePattern.trim():null,e}}Ze.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Ze,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),Ze.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Ze,selector:"tb-action-node-create-relation-config",usesInheritance:!0,ngImport:e,template:'
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-type-pattern\n \n \n {{ \'tb.rulenode.entity-type-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.create-entity-if-not-exists\' | translate }}\n \n
tb.rulenode.create-entity-if-not-exists-hint
\n
\n \n {{ \'tb.rulenode.remove-current-relations\' | translate }}\n \n
tb.rulenode.remove-current-relations-hint
\n \n {{ \'tb.rulenode.change-originator-to-related-entity\' | translate }}\n \n
tb.rulenode.change-originator-to-related-entity-hint
\n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n tb.rulenode.entity-cache-expiration-hint\n \n
\n',components:[{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:H.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:U.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:te.EntityTypeSelectComponent,selector:"tb-entity-type-select",inputs:["allowedEntityTypes","useAliasEntityTypes","showLabel","required","disabled"]},{type:D.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:G.MatLabel,selector:"mat-label"},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:V.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:G.MatError,selector:"mat-error",inputs:["id"]},{type:G.MatHint,selector:"mat-hint",inputs:["align","id"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"}],pipes:{translate:E.TranslatePipe,safeHtml:Ie}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Ze,decorators:[{type:t,args:[{selector:"tb-action-node-create-relation-config",templateUrl:"./create-relation-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class Xe extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.keys(c),this.directionTypeTranslations=g,this.entityType=x}configForm(){return this.deleteRelationConfigForm}onConfigurationSet(e){this.deleteRelationConfigForm=this.fb.group({deleteForSingleEntity:[!!e&&e.deleteForSingleEntity,[]],direction:[e?e.direction:null,[T.required]],entityType:[e?e.entityType:null,[]],entityNamePattern:[e?e.entityNamePattern:null,[]],relationType:[e?e.relationType:null,[T.required]],entityCacheExpiration:[e?e.entityCacheExpiration:null,[T.required,T.min(0)]]})}validatorTriggers(){return["deleteForSingleEntity","entityType"]}updateValidators(e){const t=this.deleteRelationConfigForm.get("deleteForSingleEntity").value,o=this.deleteRelationConfigForm.get("entityType").value;t?this.deleteRelationConfigForm.get("entityType").setValidators([T.required]):this.deleteRelationConfigForm.get("entityType").setValidators([]),t&&o?this.deleteRelationConfigForm.get("entityNamePattern").setValidators([T.required,T.pattern(/.*\S.*/)]):this.deleteRelationConfigForm.get("entityNamePattern").setValidators([]),this.deleteRelationConfigForm.get("entityType").updateValueAndValidity({emitEvent:!1}),this.deleteRelationConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e})}prepareOutputConfig(e){return e.entityNamePattern=e.entityNamePattern?e.entityNamePattern.trim():null,e}}Xe.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Xe,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),Xe.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Xe,selector:"tb-action-node-delete-relation-config",usesInheritance:!0,ngImport:e,template:'
\n \n {{ \'tb.rulenode.delete-relation-to-specific-entity\' | translate }}\n \n
tb.rulenode.delete-relation-hint
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n tb.rulenode.entity-cache-expiration-hint\n \n
\n',components:[{type:D.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:H.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:U.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:te.EntityTypeSelectComponent,selector:"tb-entity-type-select",inputs:["allowedEntityTypes","useAliasEntityTypes","showLabel","required","disabled"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:G.MatLabel,selector:"mat-label"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:V.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:G.MatError,selector:"mat-error",inputs:["id"]},{type:G.MatHint,selector:"mat-hint",inputs:["align","id"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"}],pipes:{translate:E.TranslatePipe,safeHtml:Ie}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Xe,decorators:[{type:t,args:[{selector:"tb-action-node-delete-relation-config",templateUrl:"./delete-relation-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class et extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.deviceProfile}onConfigurationSet(e){this.deviceProfile=this.fb.group({persistAlarmRulesState:[!!e&&e.persistAlarmRulesState,T.required],fetchAlarmRulesStateOnStart:[!!e&&e.fetchAlarmRulesStateOnStart,T.required]})}}et.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:et,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),et.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:et,selector:"tb-device-profile-config",usesInheritance:!0,ngImport:e,template:'
\n \n {{ \'tb.rulenode.persist-alarm-rules\' | translate }}\n \n \n {{ \'tb.rulenode.fetch-alarm-rules\' | translate }}\n \n
\n',components:[{type:D.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]}],pipes:{translate:E.TranslatePipe}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:et,decorators:[{type:t,args:[{selector:"tb-device-profile-config",templateUrl:"./device-profile-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class tt extends s{constructor(e,t,o,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=o,this.translate=r}configForm(){return this.generatorConfigForm}onConfigurationSet(e){this.generatorConfigForm=this.fb.group({msgCount:[e?e.msgCount:null,[T.required,T.min(0)]],periodInSeconds:[e?e.periodInSeconds:null,[T.required,T.min(1)]],originator:[e?e.originator:null,[]],jsScript:[e?e.jsScript:null,[T.required]]})}prepareInputConfig(e){return e&&(e.originatorId&&e.originatorType?e.originator={id:e.originatorId,entityType:e.originatorType}:e.originator=null,delete e.originatorId,delete e.originatorType),e}prepareOutputConfig(e){return e.originator?(e.originatorId=e.originator.id,e.originatorType=e.originator.entityType):(e.originatorId=null,e.originatorType=null),delete e.originator,e}testScript(){const e=this.generatorConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(e,"generate",this.translate.instant("tb.rulenode.generator"),"Generate",["prevMsg","prevMetadata","prevMsgType"],this.ruleNodeId,"rulenode/generator_node_script_fn").subscribe((e=>{e&&this.generatorConfigForm.get("jsScript").setValue(e)}))}onValidate(){this.jsFuncComponent.validateOnSubmit()}}tt.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:tt,deps:[{token:N.Store},{token:q.FormBuilder},{token:_.NodeScriptTestService},{token:E.TranslateService}],target:e.ɵɵFactoryTarget.Component}),tt.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:tt,selector:"tb-action-node-generator-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0,static:!0}],usesInheritance:!0,ngImport:e,template:'
\n \n tb.rulenode.message-count\n \n \n {{ \'tb.rulenode.message-count-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-message-count-message\' | translate }}\n \n \n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-seconds-message\' | translate }}\n \n \n
\n \n \n \n
\n \n \n \n
\n \n
\n
\n',components:[{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:oe.EntitySelectComponent,selector:"tb-entity-select",inputs:["allowedEntityTypes","useAliasEntityTypes","required","disabled"]},{type:$.JsFuncComponent,selector:"tb-js-func",inputs:["functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","noValidate","required"]},{type:W.MatButton,selector:"button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:G.MatLabel,selector:"mat-label"},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:G.MatError,selector:"mat-error",inputs:["id"]}],pipes:{translate:E.TranslatePipe}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:tt,decorators:[{type:t,args:[{selector:"tb-action-node-generator-config",templateUrl:"./generator-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder},{type:_.NodeScriptTestService},{type:E.TranslateService}]},propDecorators:{jsFuncComponent:[{type:r,args:["jsFuncComponent",{static:!0}]}]}});class ot extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.perimeterType=Me,this.perimeterTypes=Object.keys(Me),this.perimeterTypeTranslationMap=Se,this.rangeUnits=Object.keys(De),this.rangeUnitTranslationMap=Ve,this.timeUnits=Object.keys(Ae),this.timeUnitsTranslationMap=Ge}configForm(){return this.geoActionConfigForm}onConfigurationSet(e){this.geoActionConfigForm=this.fb.group({latitudeKeyName:[e?e.latitudeKeyName:null,[T.required]],longitudeKeyName:[e?e.longitudeKeyName:null,[T.required]],fetchPerimeterInfoFromMessageMetadata:[!!e&&e.fetchPerimeterInfoFromMessageMetadata,[]],perimeterType:[e?e.perimeterType:null,[]],centerLatitude:[e?e.centerLatitude:null,[]],centerLongitude:[e?e.centerLatitude:null,[]],range:[e?e.range:null,[]],rangeUnit:[e?e.rangeUnit:null,[]],polygonsDefinition:[e?e.polygonsDefinition:null,[]],minInsideDuration:[e?e.minInsideDuration:null,[T.required,T.min(1),T.max(2147483647)]],minInsideDurationTimeUnit:[e?e.minInsideDurationTimeUnit:null,[T.required]],minOutsideDuration:[e?e.minOutsideDuration:null,[T.required,T.min(1),T.max(2147483647)]],minOutsideDurationTimeUnit:[e?e.minOutsideDurationTimeUnit:null,[T.required]]})}validatorTriggers(){return["fetchPerimeterInfoFromMessageMetadata","perimeterType"]}updateValidators(e){const t=this.geoActionConfigForm.get("fetchPerimeterInfoFromMessageMetadata").value,o=this.geoActionConfigForm.get("perimeterType").value;t?this.geoActionConfigForm.get("perimeterType").setValidators([]):this.geoActionConfigForm.get("perimeterType").setValidators([T.required]),t||o!==Me.CIRCLE?(this.geoActionConfigForm.get("centerLatitude").setValidators([]),this.geoActionConfigForm.get("centerLongitude").setValidators([]),this.geoActionConfigForm.get("range").setValidators([]),this.geoActionConfigForm.get("rangeUnit").setValidators([])):(this.geoActionConfigForm.get("centerLatitude").setValidators([T.required,T.min(-90),T.max(90)]),this.geoActionConfigForm.get("centerLongitude").setValidators([T.required,T.min(-180),T.max(180)]),this.geoActionConfigForm.get("range").setValidators([T.required,T.min(0)]),this.geoActionConfigForm.get("rangeUnit").setValidators([T.required])),t||o!==Me.POLYGON?this.geoActionConfigForm.get("polygonsDefinition").setValidators([]):this.geoActionConfigForm.get("polygonsDefinition").setValidators([T.required]),this.geoActionConfigForm.get("perimeterType").updateValueAndValidity({emitEvent:!1}),this.geoActionConfigForm.get("centerLatitude").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("centerLongitude").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("range").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("rangeUnit").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("polygonsDefinition").updateValueAndValidity({emitEvent:e})}}ot.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:ot,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),ot.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:ot,selector:"tb-action-node-gps-geofencing-config",usesInheritance:!0,ngImport:e,template:'
\n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n
\n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.min-inside-duration\n \n \n {{ \'tb.rulenode.min-inside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-inside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n tb.rulenode.min-outside-duration\n \n \n {{ \'tb.rulenode.min-outside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-outside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n',components:[{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:D.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:H.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:U.MatOption,selector:"mat-option",exportAs:["matOption"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:G.MatLabel,selector:"mat-label"},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:G.MatError,selector:"mat-error",inputs:["id"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:V.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"}],pipes:{translate:E.TranslatePipe}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:ot,decorators:[{type:t,args:[{selector:"tb-action-node-gps-geofencing-config",templateUrl:"./gps-geo-action-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class rt extends y{constructor(e,t,o,r){super(e),this.store=e,this.translate=t,this.injector=o,this.fb=r,this.propagateChange=null,this.valueChangeSubscription=null}get required(){return this.requiredValue}set required(e){this.requiredValue=re(e)}ngOnInit(){this.ngControl=this.injector.get(k),null!=this.ngControl&&(this.ngControl.valueAccessor=this),this.kvListFormGroup=this.fb.group({}),this.kvListFormGroup.addControl("keyVals",this.fb.array([]))}keyValsFormArray(){return this.kvListFormGroup.get("keyVals")}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.kvListFormGroup.disable({emitEvent:!1}):this.kvListFormGroup.enable({emitEvent:!1})}writeValue(e){this.valueChangeSubscription&&this.valueChangeSubscription.unsubscribe();const t=[];if(e)for(const o of Object.keys(e))Object.prototype.hasOwnProperty.call(e,o)&&t.push(this.fb.group({key:[o,[T.required]],value:[e[o],[T.required]]}));this.kvListFormGroup.setControl("keyVals",this.fb.array(t)),this.valueChangeSubscription=this.kvListFormGroup.valueChanges.subscribe((()=>{this.updateModel()}))}removeKeyVal(e){this.kvListFormGroup.get("keyVals").removeAt(e)}addKeyVal(){this.kvListFormGroup.get("keyVals").push(this.fb.group({key:["",[T.required]],value:["",[T.required]]}))}validate(e){return!this.kvListFormGroup.get("keyVals").value.length&&this.required?{kvMapRequired:!0}:this.kvListFormGroup.valid?null:{kvFieldsRequired:!0}}updateModel(){const e=this.kvListFormGroup.get("keyVals").value;if(this.required&&!e.length||!this.kvListFormGroup.valid)this.propagateChange(null);else{const t={};e.forEach((e=>{t[e.key]=e.value})),this.propagateChange(t)}}}rt.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:rt,deps:[{token:N.Store},{token:E.TranslateService},{token:e.Injector},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),rt.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:rt,selector:"tb-kv-map-config",inputs:{disabled:"disabled",requiredText:"requiredText",keyText:"keyText",keyRequiredText:"keyRequiredText",valText:"valText",valRequiredText:"valRequiredText",required:"required"},providers:[{provide:M,useExisting:a((()=>rt)),multi:!0},{provide:S,useExisting:a((()=>rt)),multi:!0}],usesInheritance:!0,ngImport:e,template:'
\n
\n {{ keyText | translate }}\n {{ valText | translate }}\n \n
\n
\n
\n \n \n \n \n {{ keyRequiredText | translate }}\n \n \n \n \n \n \n {{ valRequiredText | translate }}\n \n \n \n
\n
\n \n
\n \n
\n
\n',styles:[":host .tb-kv-map-config{margin-bottom:16px}:host .tb-kv-map-config .header{padding-left:5px;padding-right:5px;padding-bottom:5px}:host .tb-kv-map-config .header .cell{padding-left:5px;padding-right:5px;color:#0000008a;font-size:12px;font-weight:700;white-space:nowrap}:host .tb-kv-map-config .body{padding-left:5px;padding-right:5px;padding-bottom:20px;max-height:300px;overflow:auto}:host .tb-kv-map-config .body .row{padding-top:5px;max-height:40px}:host .tb-kv-map-config .body .cell{padding-left:5px;padding-right:5px}:host ::ng-deep .tb-kv-map-config .body mat-form-field.cell{margin:0;max-height:40px}:host ::ng-deep .tb-kv-map-config .body mat-form-field.cell .mat-form-field-infix{border-top:0}:host ::ng-deep .tb-kv-map-config .body button.mat-button{margin:0}\n"],components:[{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:W.MatButton,selector:"button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{type:ee.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{type:ae.TbErrorComponent,selector:"tb-error",inputs:["error"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:V.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{type:ne.DefaultShowHideDirective,selector:" [fxShow], [fxShow.print], [fxShow.xs], [fxShow.sm], [fxShow.md], [fxShow.lg], [fxShow.xl], [fxShow.lt-sm], [fxShow.lt-md], [fxShow.lt-lg], [fxShow.lt-xl], [fxShow.gt-xs], [fxShow.gt-sm], [fxShow.gt-md], [fxShow.gt-lg], [fxHide], [fxHide.print], [fxHide.xs], [fxHide.sm], [fxHide.md], [fxHide.lg], [fxHide.xl], [fxHide.lt-sm], [fxHide.lt-md], [fxHide.lt-lg], [fxHide.lt-xl], [fxHide.gt-xs], [fxHide.gt-sm], [fxHide.gt-md], [fxHide.gt-lg]",inputs:["fxShow","fxShow.print","fxShow.xs","fxShow.sm","fxShow.md","fxShow.lg","fxShow.xl","fxShow.lt-sm","fxShow.lt-md","fxShow.lt-lg","fxShow.lt-xl","fxShow.gt-xs","fxShow.gt-sm","fxShow.gt-md","fxShow.gt-lg","fxHide","fxHide.print","fxHide.xs","fxHide.sm","fxHide.md","fxHide.lg","fxHide.xl","fxHide.lt-sm","fxHide.lt-md","fxHide.lt-lg","fxHide.lt-xl","fxHide.gt-xs","fxHide.gt-sm","fxHide.gt-md","fxHide.gt-lg"]},{type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:V.DefaultLayoutAlignDirective,selector:" [fxLayoutAlign], [fxLayoutAlign.xs], [fxLayoutAlign.sm], [fxLayoutAlign.md], [fxLayoutAlign.lg], [fxLayoutAlign.xl], [fxLayoutAlign.lt-sm], [fxLayoutAlign.lt-md], [fxLayoutAlign.lt-lg], [fxLayoutAlign.lt-xl], [fxLayoutAlign.gt-xs], [fxLayoutAlign.gt-sm], [fxLayoutAlign.gt-md], [fxLayoutAlign.gt-lg]",inputs:["fxLayoutAlign","fxLayoutAlign.xs","fxLayoutAlign.sm","fxLayoutAlign.md","fxLayoutAlign.lg","fxLayoutAlign.xl","fxLayoutAlign.lt-sm","fxLayoutAlign.lt-md","fxLayoutAlign.lt-lg","fxLayoutAlign.lt-xl","fxLayoutAlign.gt-xs","fxLayoutAlign.gt-sm","fxLayoutAlign.gt-md","fxLayoutAlign.gt-lg"]},{type:q.FormArrayName,selector:"[formArrayName]",inputs:["formArrayName"]},{type:G.MatLabel,selector:"mat-label"},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlDirective,selector:"[formControl]",inputs:["disabled","formControl","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:G.MatError,selector:"mat-error",inputs:["id"]},{type:le.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]}],pipes:{translate:E.TranslatePipe,async:R.AsyncPipe}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:rt,decorators:[{type:t,args:[{selector:"tb-kv-map-config",templateUrl:"./kv-map-config.component.html",styleUrls:["./kv-map-config.component.scss"],providers:[{provide:M,useExisting:a((()=>rt)),multi:!0},{provide:S,useExisting:a((()=>rt)),multi:!0}]}]}],ctorParameters:function(){return[{type:N.Store},{type:E.TranslateService},{type:e.Injector},{type:q.FormBuilder}]},propDecorators:{disabled:[{type:n}],requiredText:[{type:n}],keyText:[{type:n}],keyRequiredText:[{type:n}],valText:[{type:n}],valRequiredText:[{type:n}],required:[{type:n}]}});class at extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.ackValues=["all","-1","0","1"],this.ToByteStandartCharsetTypesValues=_e,this.ToByteStandartCharsetTypeTranslationMap=Qe}configForm(){return this.kafkaConfigForm}onConfigurationSet(e){this.kafkaConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[T.required]],bootstrapServers:[e?e.bootstrapServers:null,[T.required]],retries:[e?e.retries:null,[T.min(0)]],batchSize:[e?e.batchSize:null,[T.min(0)]],linger:[e?e.linger:null,[T.min(0)]],bufferMemory:[e?e.bufferMemory:null,[T.min(0)]],acks:[e?e.acks:null,[T.required]],keySerializer:[e?e.keySerializer:null,[T.required]],valueSerializer:[e?e.valueSerializer:null,[T.required]],otherProperties:[e?e.otherProperties:null,[]],addMetadataKeyValuesAsKafkaHeaders:[!!e&&e.addMetadataKeyValuesAsKafkaHeaders,[]],kafkaHeadersCharset:[e?e.kafkaHeadersCharset:null,[]]})}validatorTriggers(){return["addMetadataKeyValuesAsKafkaHeaders"]}updateValidators(e){this.kafkaConfigForm.get("addMetadataKeyValuesAsKafkaHeaders").value?this.kafkaConfigForm.get("kafkaHeadersCharset").setValidators([T.required]):this.kafkaConfigForm.get("kafkaHeadersCharset").setValidators([]),this.kafkaConfigForm.get("kafkaHeadersCharset").updateValueAndValidity({emitEvent:e})}}at.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:at,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),at.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:at,selector:"tb-action-node-kafka-config",usesInheritance:!0,ngImport:e,template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.bootstrap-servers\n \n \n {{ \'tb.rulenode.bootstrap-servers-required\' | translate }}\n \n \n \n tb.rulenode.retries\n \n \n {{ \'tb.rulenode.min-retries-message\' | translate }}\n \n \n \n tb.rulenode.batch-size-bytes\n \n \n {{ \'tb.rulenode.min-batch-size-bytes-message\' | translate }}\n \n \n \n tb.rulenode.linger-ms\n \n \n {{ \'tb.rulenode.min-linger-ms-message\' | translate }}\n \n \n \n tb.rulenode.buffer-memory-bytes\n \n \n {{ \'tb.rulenode.min-buffer-memory-bytes-message\' | translate }}\n \n \n \n tb.rulenode.acks\n \n \n {{ ackValue }}\n \n \n \n \n tb.rulenode.key-serializer\n \n \n {{ \'tb.rulenode.key-serializer-required\' | translate }}\n \n \n \n tb.rulenode.value-serializer\n \n \n {{ \'tb.rulenode.value-serializer-required\' | translate }}\n \n \n \n \n \n \n {{ \'tb.rulenode.add-metadata-key-values-as-kafka-headers\' | translate }}\n \n
tb.rulenode.add-metadata-key-values-as-kafka-headers-hint
\n \n tb.rulenode.charset-encoding\n \n \n {{ ToByteStandartCharsetTypeTranslationMap.get(charset) | translate }}\n \n \n \n
\n',components:[{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:H.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:U.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:rt,selector:"tb-kv-map-config",inputs:["disabled","requiredText","keyText","keyRequiredText","valText","valRequiredText","required"]},{type:D.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:G.MatLabel,selector:"mat-label"},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:G.MatError,selector:"mat-error",inputs:["id"]},{type:G.MatHint,selector:"mat-hint",inputs:["align","id"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]}],pipes:{translate:E.TranslatePipe,safeHtml:Ie}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:at,decorators:[{type:t,args:[{selector:"tb-action-node-kafka-config",templateUrl:"./kafka-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class nt extends s{constructor(e,t,o,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=o,this.translate=r}configForm(){return this.logConfigForm}onConfigurationSet(e){this.logConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[T.required]]})}testScript(){const e=this.logConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(e,"string",this.translate.instant("tb.rulenode.to-string"),"ToString",["msg","metadata","msgType"],this.ruleNodeId,"rulenode/log_node_script_fn").subscribe((e=>{e&&this.logConfigForm.get("jsScript").setValue(e)}))}onValidate(){this.jsFuncComponent.validateOnSubmit()}}nt.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:nt,deps:[{token:N.Store},{token:q.FormBuilder},{token:_.NodeScriptTestService},{token:E.TranslateService}],target:e.ɵɵFactoryTarget.Component}),nt.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:nt,selector:"tb-action-node-log-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0,static:!0}],usesInheritance:!0,ngImport:e,template:'
\n \n \n \n
\n \n
\n
\n',components:[{type:$.JsFuncComponent,selector:"tb-js-func",inputs:["functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","noValidate","required"]},{type:W.MatButton,selector:"button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]}],pipes:{translate:E.TranslatePipe}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:nt,decorators:[{type:t,args:[{selector:"tb-action-node-log-config",templateUrl:"./log-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder},{type:_.NodeScriptTestService},{type:E.TranslateService}]},propDecorators:{jsFuncComponent:[{type:r,args:["jsFuncComponent",{static:!0}]}]}});class lt extends y{constructor(e,t){super(e),this.store=e,this.fb=t,this.subscriptions=[],this.disableCertPemCredentials=!1,this.passwordFieldRquired=!0,this.allCredentialsTypes=Ue,this.credentialsTypeTranslationsMap=Be,this.propagateChange=null}get required(){return this.requiredValue}set required(e){this.requiredValue=re(e)}ngOnInit(){this.credentialsConfigFormGroup=this.fb.group({type:[null,[T.required]],username:[null,[]],password:[null,[]],caCert:[null,[]],caCertFileName:[null,[]],privateKey:[null,[]],privateKeyFileName:[null,[]],cert:[null,[]],certFileName:[null,[]]}),this.subscriptions.push(this.credentialsConfigFormGroup.valueChanges.pipe(ie()).subscribe((()=>{this.updateView()}))),this.subscriptions.push(this.credentialsConfigFormGroup.get("type").valueChanges.subscribe((()=>{this.credentialsTypeChanged()})))}ngOnChanges(e){for(const t of Object.keys(e)){const o=e[t];if(!o.firstChange&&o.currentValue!==o.previousValue&&o.currentValue&&"disableCertPemCredentials"===t){"cert.PEM"===this.credentialsConfigFormGroup.get("type").value&&setTimeout((()=>{this.credentialsConfigFormGroup.get("type").patchValue("anonymous",{emitEvent:!0})}))}}}ngOnDestroy(){this.subscriptions.forEach((e=>e.unsubscribe()))}writeValue(e){Q(e)&&(this.credentialsConfigFormGroup.reset(e,{emitEvent:!1}),this.updateValidators(!1))}setDisabledState(e){e?this.credentialsConfigFormGroup.disable():(this.credentialsConfigFormGroup.enable(),this.updateValidators())}updateView(){let e=this.credentialsConfigFormGroup.value;const t=e.type;switch(t){case"anonymous":e={type:t};break;case"basic":e={type:t,username:e.username,password:e.password};break;case"cert.PEM":delete e.username}this.propagateChange(e)}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}validate(e){return this.credentialsConfigFormGroup.valid?null:{credentialsConfig:{valid:!1}}}credentialsTypeChanged(){this.credentialsConfigFormGroup.patchValue({username:null,password:null,caCert:null,caCertFileName:null,privateKey:null,privateKeyFileName:null,cert:null,certFileName:null}),this.updateValidators()}updateValidators(e=!1){const t=this.credentialsConfigFormGroup.get("type").value;switch(e&&this.credentialsConfigFormGroup.reset({type:t},{emitEvent:!1}),this.credentialsConfigFormGroup.setValidators([]),this.credentialsConfigFormGroup.get("username").setValidators([]),this.credentialsConfigFormGroup.get("password").setValidators([]),t){case"anonymous":break;case"basic":this.credentialsConfigFormGroup.get("username").setValidators([T.required]),this.credentialsConfigFormGroup.get("password").setValidators(this.passwordFieldRquired?[T.required]:[]);break;case"cert.PEM":this.credentialsConfigFormGroup.setValidators([this.requiredFilesSelected(T.required,[["caCert","caCertFileName"],["privateKey","privateKeyFileName","cert","certFileName"]])])}this.credentialsConfigFormGroup.get("username").updateValueAndValidity({emitEvent:e}),this.credentialsConfigFormGroup.get("password").updateValueAndValidity({emitEvent:e}),this.credentialsConfigFormGroup.updateValueAndValidity({emitEvent:e})}requiredFilesSelected(e,t=null){return o=>{t||(t=[Object.keys(o.controls)]);return(null==o?void 0:o.controls)&&t.some((t=>t.every((t=>!e(o.controls[t])))))?null:{notAllRequiredFilesSelected:!0}}}}lt.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:lt,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),lt.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:lt,selector:"tb-credentials-config",inputs:{required:"required",disableCertPemCredentials:"disableCertPemCredentials",passwordFieldRquired:"passwordFieldRquired"},providers:[{provide:M,useExisting:a((()=>lt)),multi:!0},{provide:S,useExisting:a((()=>lt)),multi:!0}],usesInheritance:!0,usesOnChanges:!0,ngImport:e,template:'
\n \n \n tb.rulenode.credentials\n \n {{ credentialsTypeTranslationsMap.get(credentialsConfigFormGroup.get(\'type\').value) | translate }}\n \n \n \n \n tb.rulenode.credentials-type\n \n \n {{ credentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
\n \n \n \n \n tb.rulenode.username\n \n \n {{ \'tb.rulenode.username-required\' | translate }}\n \n \n \n tb.rulenode.password\n \n \n \n {{ \'tb.rulenode.password-required\' | translate }}\n \n \n \n \n
{{ \'tb.rulenode.credentials-pem-hint\' | translate }}
\n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n
\n
\n
\n
\n
\n',components:[{type:B.MatExpansionPanel,selector:"mat-expansion-panel",inputs:["disabled","expanded","hideToggle","togglePosition"],outputs:["opened","closed","expandedChange","afterExpand","afterCollapse"],exportAs:["matExpansionPanel"]},{type:B.MatExpansionPanelHeader,selector:"mat-expansion-panel-header",inputs:["tabIndex","expandedHeight","collapsedHeight"]},{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:H.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:U.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:K.TogglePasswordComponent,selector:"tb-toggle-password"},{type:j.FileInputComponent,selector:"tb-file-input",inputs:["label","accept","noFileText","inputId","allowedExtensions","dropLabel","contentConvertFunction","required","requiredAsError","disabled","existingFileName","readAsBinary","workFromFileObj","multipleFile"],outputs:["fileNameChanged"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:B.MatExpansionPanelTitle,selector:"mat-panel-title"},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:B.MatExpansionPanelDescription,selector:"mat-panel-description"},{type:B.MatExpansionPanelContent,selector:"ng-template[matExpansionPanelContent]"},{type:G.MatLabel,selector:"mat-label"},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:G.MatError,selector:"mat-error",inputs:["id"]},{type:R.NgSwitch,selector:"[ngSwitch]",inputs:["ngSwitch"]},{type:R.NgSwitchCase,selector:"[ngSwitchCase]",inputs:["ngSwitchCase"]},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:G.MatSuffix,selector:"[matSuffix]"}],pipes:{translate:E.TranslatePipe}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:lt,decorators:[{type:t,args:[{selector:"tb-credentials-config",templateUrl:"./credentials-config.component.html",styleUrls:[],providers:[{provide:M,useExisting:a((()=>lt)),multi:!0},{provide:S,useExisting:a((()=>lt)),multi:!0}]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]},propDecorators:{required:[{type:n}],disableCertPemCredentials:[{type:n}],passwordFieldRquired:[{type:n}]}});class it extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.mqttConfigForm}onConfigurationSet(e){this.mqttConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[T.required]],host:[e?e.host:null,[T.required]],port:[e?e.port:null,[T.required,T.min(1),T.max(65535)]],connectTimeoutSec:[e?e.connectTimeoutSec:null,[T.required,T.min(1),T.max(200)]],clientId:[e?e.clientId:null,[]],cleanSession:[!!e&&e.cleanSession,[]],ssl:[!!e&&e.ssl,[]],credentials:[e?e.credentials:null,[]]})}}it.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:it,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),it.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:it,selector:"tb-action-node-mqtt-config",usesInheritance:!0,ngImport:e,template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n \n tb.rulenode.connect-timeout\n \n \n {{ \'tb.rulenode.connect-timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n
\n \n tb.rulenode.client-id\n \n \n
tb.rulenode.client-id-hint
\n \n {{ \'tb.rulenode.clean-session\' | translate }}\n \n \n {{ \'tb.rulenode.enable-ssl\' | translate }}\n \n \n
\n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}:host .tb-hint.client-id{margin-top:-1.25em;max-width:-moz-fit-content;max-width:fit-content}\n"],components:[{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:D.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:lt,selector:"tb-credentials-config",inputs:["required","disableCertPemCredentials","passwordFieldRquired"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:G.MatLabel,selector:"mat-label"},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:G.MatError,selector:"mat-error",inputs:["id"]},{type:G.MatHint,selector:"mat-hint",inputs:["align","id"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:V.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"}],pipes:{translate:E.TranslatePipe,safeHtml:Ie}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:it,decorators:[{type:t,args:[{selector:"tb-action-node-mqtt-config",templateUrl:"./mqtt-config.component.html",styleUrls:["./mqtt-config.component.scss"]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class st extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.msgCountConfigForm}onConfigurationSet(e){this.msgCountConfigForm=this.fb.group({interval:[e?e.interval:null,[T.required,T.min(1)]],telemetryPrefix:[e?e.telemetryPrefix:null,[T.required]]})}}st.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:st,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),st.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:st,selector:"tb-action-node-msg-count-config",usesInheritance:!0,ngImport:e,template:'
\n \n tb.rulenode.interval-seconds\n \n \n {{ \'tb.rulenode.interval-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-interval-seconds-message\' | translate }}\n \n \n \n tb.rulenode.output-timeseries-key-prefix\n \n \n {{ \'tb.rulenode.output-timeseries-key-prefix-required\' | translate }}\n \n \n
\n',components:[{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:G.MatLabel,selector:"mat-label"},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:G.MatError,selector:"mat-error",inputs:["id"]}],pipes:{translate:E.TranslatePipe}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:st,decorators:[{type:t,args:[{selector:"tb-action-node-msg-count-config",templateUrl:"./msg-count-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class mt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.msgDelayConfigForm}onConfigurationSet(e){this.msgDelayConfigForm=this.fb.group({useMetadataPeriodInSecondsPatterns:[!!e&&e.useMetadataPeriodInSecondsPatterns,[]],periodInSeconds:[e?e.periodInSeconds:null,[]],periodInSecondsPattern:[e?e.periodInSecondsPattern:null,[]],maxPendingMsgs:[e?e.maxPendingMsgs:null,[T.required,T.min(1),T.max(1e5)]]})}validatorTriggers(){return["useMetadataPeriodInSecondsPatterns"]}updateValidators(e){this.msgDelayConfigForm.get("useMetadataPeriodInSecondsPatterns").value?(this.msgDelayConfigForm.get("periodInSecondsPattern").setValidators([T.required]),this.msgDelayConfigForm.get("periodInSeconds").setValidators([])):(this.msgDelayConfigForm.get("periodInSecondsPattern").setValidators([]),this.msgDelayConfigForm.get("periodInSeconds").setValidators([T.required,T.min(0)])),this.msgDelayConfigForm.get("periodInSecondsPattern").updateValueAndValidity({emitEvent:e}),this.msgDelayConfigForm.get("periodInSeconds").updateValueAndValidity({emitEvent:e})}}mt.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:mt,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),mt.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:mt,selector:"tb-action-node-msg-delay-config",usesInheritance:!0,ngImport:e,template:'
\n \n {{ \'tb.rulenode.use-metadata-period-in-seconds-patterns\' | translate }}\n \n
tb.rulenode.use-metadata-period-in-seconds-patterns-hint
\n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-0-seconds-message\' | translate }}\n \n \n \n \n tb.rulenode.period-in-seconds-pattern\n \n \n {{ \'tb.rulenode.period-in-seconds-pattern-required\' | translate }}\n \n \n \n \n \n tb.rulenode.max-pending-messages\n \n \n {{ \'tb.rulenode.max-pending-messages-required\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n
\n',components:[{type:D.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:G.MatLabel,selector:"mat-label"},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:G.MatError,selector:"mat-error",inputs:["id"]},{type:G.MatHint,selector:"mat-hint",inputs:["align","id"]},{type:q.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]}],pipes:{translate:E.TranslatePipe,safeHtml:Ie}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:mt,decorators:[{type:t,args:[{selector:"tb-action-node-msg-delay-config",templateUrl:"./msg-delay-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class ut extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.pubSubConfigForm}onConfigurationSet(e){this.pubSubConfigForm=this.fb.group({projectId:[e?e.projectId:null,[T.required]],topicName:[e?e.topicName:null,[T.required]],serviceAccountKey:[e?e.serviceAccountKey:null,[T.required]],serviceAccountKeyFileName:[e?e.serviceAccountKeyFileName:null,[T.required]],messageAttributes:[e?e.messageAttributes:null,[]]})}}ut.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:ut,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),ut.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:ut,selector:"tb-action-node-pub-sub-config",usesInheritance:!0,ngImport:e,template:'
\n \n tb.rulenode.gcp-project-id\n \n \n {{ \'tb.rulenode.gcp-project-id-required\' | translate }}\n \n \n \n tb.rulenode.pubsub-topic-name\n \n \n {{ \'tb.rulenode.pubsub-topic-name-required\' | translate }}\n \n \n \n \n \n
\n \n \n
\n',components:[{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:j.FileInputComponent,selector:"tb-file-input",inputs:["label","accept","noFileText","inputId","allowedExtensions","dropLabel","contentConvertFunction","required","requiredAsError","disabled","existingFileName","readAsBinary","workFromFileObj","multipleFile"],outputs:["fileNameChanged"]},{type:rt,selector:"tb-kv-map-config",inputs:["disabled","requiredText","keyText","keyRequiredText","valText","valRequiredText","required"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:G.MatLabel,selector:"mat-label"},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:G.MatError,selector:"mat-error",inputs:["id"]}],pipes:{translate:E.TranslatePipe,safeHtml:Ie}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:ut,decorators:[{type:t,args:[{selector:"tb-action-node-pub-sub-config",templateUrl:"./pubsub-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class pt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.attributeScopes=Object.keys(m),this.telemetryTypeTranslationsMap=u}configForm(){return this.pushToCloudConfigForm}onConfigurationSet(e){this.pushToCloudConfigForm=this.fb.group({scope:[e?e.scope:null,[T.required]]})}}pt.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:pt,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),pt.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:pt,selector:"tb-action-node-push-to-cloud-config",usesInheritance:!0,ngImport:e,template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n',components:[{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:H.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:U.MatOption,selector:"mat-option",exportAs:["matOption"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:G.MatLabel,selector:"mat-label"},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]}],pipes:{translate:E.TranslatePipe}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:pt,decorators:[{type:t,args:[{selector:"tb-action-node-push-to-cloud-config",templateUrl:"./push-to-cloud-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class dt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.attributeScopes=Object.keys(m),this.telemetryTypeTranslationsMap=u}configForm(){return this.pushToEdgeConfigForm}onConfigurationSet(e){this.pushToEdgeConfigForm=this.fb.group({scope:[e?e.scope:null,[T.required]]})}}dt.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:dt,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),dt.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:dt,selector:"tb-action-node-push-to-edge-config",usesInheritance:!0,ngImport:e,template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n',components:[{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:H.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:U.MatOption,selector:"mat-option",exportAs:["matOption"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:G.MatLabel,selector:"mat-label"},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]}],pipes:{translate:E.TranslatePipe}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:dt,decorators:[{type:t,args:[{selector:"tb-action-node-push-to-edge-config",templateUrl:"./push-to-edge-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class ft extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.messageProperties=[null,"BASIC","TEXT_PLAIN","MINIMAL_BASIC","MINIMAL_PERSISTENT_BASIC","PERSISTENT_BASIC","PERSISTENT_TEXT_PLAIN"]}configForm(){return this.rabbitMqConfigForm}onConfigurationSet(e){this.rabbitMqConfigForm=this.fb.group({exchangeNamePattern:[e?e.exchangeNamePattern:null,[]],routingKeyPattern:[e?e.routingKeyPattern:null,[]],messageProperties:[e?e.messageProperties:null,[]],host:[e?e.host:null,[T.required]],port:[e?e.port:null,[T.required,T.min(1),T.max(65535)]],virtualHost:[e?e.virtualHost:null,[]],username:[e?e.username:null,[]],password:[e?e.password:null,[]],automaticRecoveryEnabled:[!!e&&e.automaticRecoveryEnabled,[]],connectionTimeout:[e?e.connectionTimeout:null,[T.min(0)]],handshakeTimeout:[e?e.handshakeTimeout:null,[T.min(0)]],clientProperties:[e?e.clientProperties:null,[]]})}}ft.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:ft,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),ft.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:ft,selector:"tb-action-node-rabbit-mq-config",usesInheritance:!0,ngImport:e,template:'
\n \n tb.rulenode.exchange-name-pattern\n \n \n \n tb.rulenode.routing-key-pattern\n \n \n \n tb.rulenode.message-properties\n \n \n {{ property }}\n \n \n \n
\n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n
\n \n tb.rulenode.virtual-host\n \n \n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n \n {{ \'tb.rulenode.automatic-recovery\' | translate }}\n \n \n tb.rulenode.connection-timeout-ms\n \n \n {{ \'tb.rulenode.min-connection-timeout-ms-message\' | translate }}\n \n \n \n tb.rulenode.handshake-timeout-ms\n \n \n {{ \'tb.rulenode.min-handshake-timeout-ms-message\' | translate }}\n \n \n \n \n \n
\n',components:[{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:H.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:U.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:K.TogglePasswordComponent,selector:"tb-toggle-password"},{type:D.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:rt,selector:"tb-kv-map-config",inputs:["disabled","requiredText","keyText","keyRequiredText","valText","valRequiredText","required"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:G.MatLabel,selector:"mat-label"},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:V.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:G.MatError,selector:"mat-error",inputs:["id"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{type:G.MatSuffix,selector:"[matSuffix]"}],pipes:{translate:E.TranslatePipe}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:ft,decorators:[{type:t,args:[{selector:"tb-action-node-rabbit-mq-config",templateUrl:"./rabbit-mq-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class ct extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.proxySchemes=["http","https"],this.httpRequestTypes=Object.keys(ze)}configForm(){return this.restApiCallConfigForm}onConfigurationSet(e){this.restApiCallConfigForm=this.fb.group({restEndpointUrlPattern:[e?e.restEndpointUrlPattern:null,[T.required]],requestMethod:[e?e.requestMethod:null,[T.required]],useSimpleClientHttpFactory:[!!e&&e.useSimpleClientHttpFactory,[]],ignoreRequestBody:[!!e&&e.ignoreRequestBody,[]],enableProxy:[!!e&&e.enableProxy,[]],useSystemProxyProperties:[!!e&&e.enableProxy,[]],proxyScheme:[e?e.proxyHost:null,[]],proxyHost:[e?e.proxyHost:null,[]],proxyPort:[e?e.proxyPort:null,[]],proxyUser:[e?e.proxyUser:null,[]],proxyPassword:[e?e.proxyPassword:null,[]],readTimeoutMs:[e?e.readTimeoutMs:null,[]],maxParallelRequestsCount:[e?e.maxParallelRequestsCount:null,[T.min(0)]],headers:[e?e.headers:null,[]],useRedisQueueForMsgPersistence:[!!e&&e.useRedisQueueForMsgPersistence,[]],trimQueue:[!!e&&e.trimQueue,[]],maxQueueSize:[e?e.maxQueueSize:null,[]],credentials:[e?e.credentials:null,[]]})}validatorTriggers(){return["useSimpleClientHttpFactory","useRedisQueueForMsgPersistence","enableProxy","useSystemProxyProperties"]}updateValidators(e){const t=this.restApiCallConfigForm.get("useSimpleClientHttpFactory").value,o=this.restApiCallConfigForm.get("useRedisQueueForMsgPersistence").value,r=this.restApiCallConfigForm.get("enableProxy").value,a=this.restApiCallConfigForm.get("useSystemProxyProperties").value;r&&!a?(this.restApiCallConfigForm.get("proxyHost").setValidators(r?[T.required]:[]),this.restApiCallConfigForm.get("proxyPort").setValidators(r?[T.required,T.min(1),T.max(65535)]:[])):(this.restApiCallConfigForm.get("proxyHost").setValidators([]),this.restApiCallConfigForm.get("proxyPort").setValidators([]),t?this.restApiCallConfigForm.get("readTimeoutMs").setValidators([]):this.restApiCallConfigForm.get("readTimeoutMs").setValidators([T.min(0)])),o?this.restApiCallConfigForm.get("maxQueueSize").setValidators([T.min(0)]):this.restApiCallConfigForm.get("maxQueueSize").setValidators([]),this.restApiCallConfigForm.get("readTimeoutMs").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("maxQueueSize").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("proxyHost").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("proxyPort").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("credentials").updateValueAndValidity({emitEvent:e})}}ct.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:ct,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),ct.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:ct,selector:"tb-action-node-rest-api-call-config",usesInheritance:!0,ngImport:e,template:'
\n \n tb.rulenode.endpoint-url-pattern\n \n \n {{ \'tb.rulenode.endpoint-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.request-method\n \n \n {{ requestType }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n \n {{ \'tb.rulenode.use-simple-client-http-factory\' | translate }}\n \n \n {{ \'tb.rulenode.ignore-request-body\' | translate }}\n \n
\n \n {{ \'tb.rulenode.use-system-proxy-properties\' | translate }}\n \n
\n
\n \n tb.rulenode.proxy-scheme\n \n \n {{ proxyScheme }}\n \n \n \n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
\n
\n \n tb.rulenode.read-timeout\n \n tb.rulenode.read-timeout-hint\n \n \n tb.rulenode.max-parallel-requests-count\n \n tb.rulenode.max-parallel-requests-count-hint\n \n \n
\n \n \n \n {{ \'tb.rulenode.use-redis-queue\' | translate }}\n \n
\n \n {{ \'tb.rulenode.trim-redis-queue\' | translate }}\n \n \n tb.rulenode.redis-queue-max-size\n \n \n
\n \n
\n',components:[{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:H.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:U.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:D.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:rt,selector:"tb-kv-map-config",inputs:["disabled","requiredText","keyText","keyRequiredText","valText","valRequiredText","required"]},{type:lt,selector:"tb-credentials-config",inputs:["required","disableCertPemCredentials","passwordFieldRquired"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:G.MatLabel,selector:"mat-label"},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:G.MatError,selector:"mat-error",inputs:["id"]},{type:G.MatHint,selector:"mat-hint",inputs:["align","id"]},{type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:V.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]}],pipes:{translate:E.TranslatePipe,safeHtml:Ie}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:ct,decorators:[{type:t,args:[{selector:"tb-action-node-rest-api-call-config",templateUrl:"./rest-api-call-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class gt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.rpcReplyConfigForm}onConfigurationSet(e){this.rpcReplyConfigForm=this.fb.group({requestIdMetaDataAttribute:[e?e.requestIdMetaDataAttribute:null,[]]})}}gt.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:gt,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),gt.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:gt,selector:"tb-action-node-rpc-reply-config",usesInheritance:!0,ngImport:e,template:'
\n \n tb.rulenode.request-id-metadata-attribute\n \n \n
\n',components:[{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:G.MatLabel,selector:"mat-label"},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]}]}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:gt,decorators:[{type:t,args:[{selector:"tb-action-node-rpc-reply-config",templateUrl:"./rpc-reply-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class xt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.rpcRequestConfigForm}onConfigurationSet(e){this.rpcRequestConfigForm=this.fb.group({timeoutInSeconds:[e?e.timeoutInSeconds:null,[T.required,T.min(0)]]})}}xt.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:xt,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),xt.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:xt,selector:"tb-action-node-rpc-request-config",usesInheritance:!0,ngImport:e,template:'
\n \n tb.rulenode.timeout-sec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-message\' | translate }}\n \n \n
\n',components:[{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:G.MatLabel,selector:"mat-label"},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:G.MatError,selector:"mat-error",inputs:["id"]}],pipes:{translate:E.TranslatePipe}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:xt,decorators:[{type:t,args:[{selector:"tb-action-node-rpc-request-config",templateUrl:"./rpc-request-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class yt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.saveToCustomTableConfigForm}onConfigurationSet(e){this.saveToCustomTableConfigForm=this.fb.group({tableName:[e?e.tableName:null,[T.required,T.pattern(/.*\S.*/)]],fieldsMapping:[e?e.fieldsMapping:null,[T.required]]})}prepareOutputConfig(e){return e.tableName=e.tableName.trim(),e}}yt.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:yt,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),yt.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:yt,selector:"tb-action-node-custom-table-config",usesInheritance:!0,ngImport:e,template:'
\n \n tb.rulenode.custom-table-name\n \n \n {{ \'tb.rulenode.custom-table-name-required\' | translate }}\n \n tb.rulenode.custom-table-hint\n \n \n \n \n
\n',components:[{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:rt,selector:"tb-kv-map-config",inputs:["disabled","requiredText","keyText","keyRequiredText","valText","valRequiredText","required"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:G.MatLabel,selector:"mat-label"},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:G.MatError,selector:"mat-error",inputs:["id"]},{type:G.MatHint,selector:"mat-hint",inputs:["align","id"]}],pipes:{translate:E.TranslatePipe}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:yt,decorators:[{type:t,args:[{selector:"tb-action-node-custom-table-config",templateUrl:"./save-to-custom-table-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class bt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.smtpProtocols=["smtp","smtps"],this.tlsVersions=["TLSv1","TLSv1.1","TLSv1.2","TLSv1.3"]}configForm(){return this.sendEmailConfigForm}onConfigurationSet(e){this.sendEmailConfigForm=this.fb.group({useSystemSmtpSettings:[!!e&&e.useSystemSmtpSettings,[]],smtpProtocol:[e?e.smtpProtocol:null,[]],smtpHost:[e?e.smtpHost:null,[]],smtpPort:[e?e.smtpPort:null,[]],timeout:[e?e.timeout:null,[]],enableTls:[!!e&&e.enableTls,[]],tlsVersion:[e?e.tlsVersion:null,[]],enableProxy:[!!e&&e.enableProxy,[]],proxyHost:[e?e.proxyHost:null,[]],proxyPort:[e?e.proxyPort:null,[]],proxyUser:[e?e.proxyUser:null,[]],proxyPassword:[e?e.proxyPassword:null,[]],username:[e?e.username:null,[]],password:[e?e.password:null,[]]})}validatorTriggers(){return["useSystemSmtpSettings","enableProxy"]}updateValidators(e){const t=this.sendEmailConfigForm.get("useSystemSmtpSettings").value,o=this.sendEmailConfigForm.get("enableProxy").value;t?(this.sendEmailConfigForm.get("smtpProtocol").setValidators([]),this.sendEmailConfigForm.get("smtpHost").setValidators([]),this.sendEmailConfigForm.get("smtpPort").setValidators([]),this.sendEmailConfigForm.get("timeout").setValidators([]),this.sendEmailConfigForm.get("proxyHost").setValidators([]),this.sendEmailConfigForm.get("proxyPort").setValidators([])):(this.sendEmailConfigForm.get("smtpProtocol").setValidators([T.required]),this.sendEmailConfigForm.get("smtpHost").setValidators([T.required]),this.sendEmailConfigForm.get("smtpPort").setValidators([T.required,T.min(1),T.max(65535)]),this.sendEmailConfigForm.get("timeout").setValidators([T.required,T.min(0)]),this.sendEmailConfigForm.get("proxyHost").setValidators(o?[T.required]:[]),this.sendEmailConfigForm.get("proxyPort").setValidators(o?[T.required,T.min(1),T.max(65535)]:[])),this.sendEmailConfigForm.get("smtpProtocol").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("smtpHost").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("smtpPort").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("timeout").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("proxyHost").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("proxyPort").updateValueAndValidity({emitEvent:e})}}bt.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:bt,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),bt.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:bt,selector:"tb-action-node-send-email-config",usesInheritance:!0,ngImport:e,template:'
\n \n {{ \'tb.rulenode.use-system-smtp-settings\' | translate }}\n \n
\n \n tb.rulenode.smtp-protocol\n \n \n {{ smtpProtocol.toUpperCase() }}\n \n \n \n
\n \n tb.rulenode.smtp-host\n \n \n {{ \'tb.rulenode.smtp-host-required\' | translate }}\n \n \n \n tb.rulenode.smtp-port\n \n \n {{ \'tb.rulenode.smtp-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.timeout-msec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-msec-message\' | translate }}\n \n \n \n {{ \'tb.rulenode.enable-tls\' | translate }}\n \n \n tb.rulenode.tls-version\n \n \n {{ tlsVersion }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n
\n
\n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
\n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n
\n
\n',components:[{type:D.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:H.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:U.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:de.TbCheckboxComponent,selector:"tb-checkbox",inputs:["disabled","trueValue","falseValue"],outputs:["valueChange"]},{type:K.TogglePasswordComponent,selector:"tb-toggle-password"}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:G.MatLabel,selector:"mat-label"},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:V.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:G.MatError,selector:"mat-error",inputs:["id"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{type:G.MatSuffix,selector:"[matSuffix]"}],pipes:{translate:E.TranslatePipe}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:bt,decorators:[{type:t,args:[{selector:"tb-action-node-send-email-config",templateUrl:"./send-email-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class ht extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.sendSmsConfigForm}onConfigurationSet(e){this.sendSmsConfigForm=this.fb.group({numbersToTemplate:[e?e.numbersToTemplate:null,[T.required]],smsMessageTemplate:[e?e.smsMessageTemplate:null,[T.required]],useSystemSmsSettings:[!!e&&e.useSystemSmsSettings,[]],smsProviderConfiguration:[e?e.smsProviderConfiguration:null,[]]})}validatorTriggers(){return["useSystemSmsSettings"]}updateValidators(e){this.sendSmsConfigForm.get("useSystemSmsSettings").value?this.sendSmsConfigForm.get("smsProviderConfiguration").setValidators([]):this.sendSmsConfigForm.get("smsProviderConfiguration").setValidators([T.required]),this.sendSmsConfigForm.get("smsProviderConfiguration").updateValueAndValidity({emitEvent:e})}}ht.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:ht,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),ht.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:ht,selector:"tb-action-node-send-sms-config",usesInheritance:!0,ngImport:e,template:'
\n \n tb.rulenode.numbers-to-template\n \n \n {{ \'tb.rulenode.numbers-to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.sms-message-template\n \n \n {{ \'tb.rulenode.sms-message-template-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-system-sms-settings\' | translate }}\n \n \n \n
\n',components:[{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:D.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:fe.SmsProviderConfigurationComponent,selector:"tb-sms-provider-configuration",inputs:["required","disabled"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:G.MatLabel,selector:"mat-label"},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:G.MatError,selector:"mat-error",inputs:["id"]},{type:G.MatHint,selector:"mat-hint",inputs:["align","id"]}],pipes:{translate:E.TranslatePipe,safeHtml:Ie}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:ht,decorators:[{type:t,args:[{selector:"tb-action-node-send-sms-config",templateUrl:"./send-sms-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class Ft extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.snsConfigForm}onConfigurationSet(e){this.snsConfigForm=this.fb.group({topicArnPattern:[e?e.topicArnPattern:null,[T.required]],accessKeyId:[e?e.accessKeyId:null,[T.required]],secretAccessKey:[e?e.secretAccessKey:null,[T.required]],region:[e?e.region:null,[T.required]]})}}Ft.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Ft,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),Ft.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Ft,selector:"tb-action-node-sns-config",usesInheritance:!0,ngImport:e,template:'
\n \n tb.rulenode.topic-arn-pattern\n \n \n {{ \'tb.rulenode.topic-arn-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
\n',components:[{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:G.MatLabel,selector:"mat-label"},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:G.MatError,selector:"mat-error",inputs:["id"]},{type:G.MatHint,selector:"mat-hint",inputs:["align","id"]}],pipes:{translate:E.TranslatePipe,safeHtml:Ie}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Ft,decorators:[{type:t,args:[{selector:"tb-action-node-sns-config",templateUrl:"./sns-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class Ct extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.sqsQueueType=Oe,this.sqsQueueTypes=Object.keys(Oe),this.sqsQueueTypeTranslationsMap=He}configForm(){return this.sqsConfigForm}onConfigurationSet(e){this.sqsConfigForm=this.fb.group({queueType:[e?e.queueType:null,[T.required]],queueUrlPattern:[e?e.queueUrlPattern:null,[T.required]],delaySeconds:[e?e.delaySeconds:null,[T.min(0),T.max(900)]],messageAttributes:[e?e.messageAttributes:null,[]],accessKeyId:[e?e.accessKeyId:null,[T.required]],secretAccessKey:[e?e.secretAccessKey:null,[T.required]],region:[e?e.region:null,[T.required]]})}}Ct.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Ct,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),Ct.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Ct,selector:"tb-action-node-sqs-config",usesInheritance:!0,ngImport:e,template:'
\n \n tb.rulenode.queue-type\n \n \n {{ sqsQueueTypeTranslationsMap.get(type) | translate }}\n \n \n \n \n tb.rulenode.queue-url-pattern\n \n \n {{ \'tb.rulenode.queue-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.delay-seconds\n \n \n {{ \'tb.rulenode.min-delay-seconds-message\' | translate }}\n \n \n {{ \'tb.rulenode.max-delay-seconds-message\' | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
\n',components:[{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:H.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:U.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:rt,selector:"tb-kv-map-config",inputs:["disabled","requiredText","keyText","keyRequiredText","valText","valRequiredText","required"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:G.MatLabel,selector:"mat-label"},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:G.MatError,selector:"mat-error",inputs:["id"]},{type:G.MatHint,selector:"mat-hint",inputs:["align","id"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"}],pipes:{translate:E.TranslatePipe,safeHtml:Ie}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Ct,decorators:[{type:t,args:[{selector:"tb-action-node-sqs-config",templateUrl:"./sqs-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class Lt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.timeseriesConfigForm}onConfigurationSet(e){this.timeseriesConfigForm=this.fb.group({defaultTTL:[e?e.defaultTTL:null,[T.required,T.min(0)]]})}}Lt.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Lt,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),Lt.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Lt,selector:"tb-action-node-timeseries-config",usesInheritance:!0,ngImport:e,template:'
\n \n tb.rulenode.default-ttl\n \n \n {{ \'tb.rulenode.default-ttl-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-default-ttl-message\' | translate }}\n \n \n
\n',components:[{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:G.MatLabel,selector:"mat-label"},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:G.MatError,selector:"mat-error",inputs:["id"]}],pipes:{translate:E.TranslatePipe}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Lt,decorators:[{type:t,args:[{selector:"tb-action-node-timeseries-config",templateUrl:"./timeseries-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class vt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.unassignCustomerConfigForm}onConfigurationSet(e){this.unassignCustomerConfigForm=this.fb.group({customerNamePattern:[e?e.customerNamePattern:null,[T.required,T.pattern(/.*\S.*/)]],customerCacheExpiration:[e?e.customerCacheExpiration:null,[T.required,T.min(0)]]})}prepareOutputConfig(e){return e.customerNamePattern=e.customerNamePattern.trim(),e}}vt.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:vt,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),vt.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:vt,selector:"tb-action-node-un-assign-to-customer-config",usesInheritance:!0,ngImport:e,template:'
\n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n tb.rulenode.customer-cache-expiration-hint\n \n
\n',components:[{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:G.MatLabel,selector:"mat-label"},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:G.MatError,selector:"mat-error",inputs:["id"]},{type:G.MatHint,selector:"mat-hint",inputs:["align","id"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"}],pipes:{translate:E.TranslatePipe,safeHtml:Ie}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:vt,decorators:[{type:t,args:[{selector:"tb-action-node-un-assign-to-customer-config",templateUrl:"./unassign-customer-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class It extends y{constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.keys(c),this.directionTypeTranslations=g,this.entityType=x,this.propagateChange=null}get required(){return this.requiredValue}set required(e){this.requiredValue=re(e)}ngOnInit(){this.deviceRelationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[T.required]],maxLevel:[null,[]],relationType:[null],deviceTypes:[null,[T.required]]}),this.deviceRelationsQueryFormGroup.valueChanges.subscribe((e=>{this.deviceRelationsQueryFormGroup.valid?this.propagateChange(e):this.propagateChange(null)}))}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.deviceRelationsQueryFormGroup.disable({emitEvent:!1}):this.deviceRelationsQueryFormGroup.enable({emitEvent:!1})}writeValue(e){this.deviceRelationsQueryFormGroup.reset(e,{emitEvent:!1})}}It.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:It,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),It.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:It,selector:"tb-device-relations-query-config",inputs:{disabled:"disabled",required:"required"},providers:[{provide:M,useExisting:a((()=>It)),multi:!0}],usesInheritance:!0,ngImport:e,template:'
\n \n {{ \'alias.last-level-relation\' | translate }}\n \n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n
\n
relation.relation-type
\n \n \n
device.device-types
\n \n \n
\n',components:[{type:D.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:H.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:U.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:ge.RelationTypeAutocompleteComponent,selector:"tb-relation-type-autocomplete",inputs:["required","disabled"]},{type:xe.EntitySubTypeListComponent,selector:"tb-entity-subtype-list",inputs:["required","disabled","entityType"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:V.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{type:G.MatLabel,selector:"mat-label"},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"}],pipes:{translate:E.TranslatePipe}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:It,decorators:[{type:t,args:[{selector:"tb-device-relations-query-config",templateUrl:"./device-relations-query-config.component.html",styleUrls:[],providers:[{provide:M,useExisting:a((()=>It)),multi:!0}]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]},propDecorators:{disabled:[{type:n}],required:[{type:n}]}});class Nt extends y{constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.keys(c),this.directionTypeTranslations=g,this.propagateChange=null}get required(){return this.requiredValue}set required(e){this.requiredValue=re(e)}ngOnInit(){this.relationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[T.required]],maxLevel:[null,[]],filters:[null]}),this.relationsQueryFormGroup.valueChanges.subscribe((e=>{this.relationsQueryFormGroup.valid?this.propagateChange(e):this.propagateChange(null)}))}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.relationsQueryFormGroup.disable({emitEvent:!1}):this.relationsQueryFormGroup.enable({emitEvent:!1})}writeValue(e){this.relationsQueryFormGroup.reset(e||{},{emitEvent:!1})}}Nt.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Nt,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),Nt.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Nt,selector:"tb-relations-query-config",inputs:{disabled:"disabled",required:"required"},providers:[{provide:M,useExisting:a((()=>Nt)),multi:!0}],usesInheritance:!0,ngImport:e,template:'
\n \n {{ \'alias.last-level-relation\' | translate }}\n \n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n
\n
relation.relation-filters
\n \n
\n',components:[{type:D.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:H.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:U.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:ye.RelationFiltersComponent,selector:"tb-relation-filters",inputs:["disabled","allowedEntityTypes"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:V.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{type:G.MatLabel,selector:"mat-label"},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"}],pipes:{translate:E.TranslatePipe}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Nt,decorators:[{type:t,args:[{selector:"tb-relations-query-config",templateUrl:"./relations-query-config.component.html",styleUrls:[],providers:[{provide:M,useExisting:a((()=>Nt)),multi:!0}]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]},propDecorators:{disabled:[{type:n}],required:[{type:n}]}});class qt extends y{constructor(e,t,o,r){super(e),this.store=e,this.translate=t,this.truncate=o,this.fb=r,this.placeholder="tb.rulenode.message-type",this.separatorKeysCodes=[Y,J,Z],this.messageTypes=[],this.messageTypesList=[],this.searchText="",this.propagateChange=e=>{},this.messageTypeConfigForm=this.fb.group({messageType:[null]});for(const e of Object.keys(b))this.messageTypesList.push({name:h.get(b[e]),value:e})}get required(){return this.requiredValue}set required(e){this.requiredValue=re(e)}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}ngOnInit(){this.filteredMessageTypes=this.messageTypeConfigForm.get("messageType").valueChanges.pipe(se(""),me((e=>e||"")),ue((e=>this.fetchMessageTypes(e))),pe())}ngAfterViewInit(){}setDisabledState(e){this.disabled=e,this.disabled?this.messageTypeConfigForm.disable({emitEvent:!1}):this.messageTypeConfigForm.enable({emitEvent:!1})}writeValue(e){this.searchText="",this.messageTypes.length=0,e&&e.forEach((e=>{const t=this.messageTypesList.find((t=>t.value===e));t?this.messageTypes.push({name:t.name,value:t.value}):this.messageTypes.push({name:e,value:e})}))}displayMessageTypeFn(e){return e?e.name:void 0}textIsNotEmpty(e){return!!(e&&null!=e&&e.length>0)}createMessageType(e,t){e.preventDefault(),this.transformMessageType(t)}add(e){this.transformMessageType(e.value)}fetchMessageTypes(e){if(this.searchText=e,this.searchText&&this.searchText.length){const e=this.searchText.toUpperCase();return be(this.messageTypesList.filter((t=>t.name.toUpperCase().includes(e))))}return be(this.messageTypesList)}transformMessageType(e){if((e||"").trim()){let t=null;const o=e.trim(),r=this.messageTypesList.find((e=>e.name===o));t=r?{name:r.name,value:r.value}:{name:o,value:o},t&&this.addMessageType(t)}this.clear("")}remove(e){const t=this.messageTypes.indexOf(e);t>=0&&(this.messageTypes.splice(t,1),this.updateModel())}selected(e){this.addMessageType(e.option.value),this.clear("")}addMessageType(e){-1===this.messageTypes.findIndex((t=>t.value===e.value))&&(this.messageTypes.push(e),this.updateModel())}onFocus(){this.messageTypeConfigForm.get("messageType").updateValueAndValidity({onlySelf:!0,emitEvent:!0})}clear(e=""){this.messageTypeInput.nativeElement.value=e,this.messageTypeConfigForm.get("messageType").patchValue(null,{emitEvent:!0}),setTimeout((()=>{this.messageTypeInput.nativeElement.blur(),this.messageTypeInput.nativeElement.focus()}),0)}updateModel(){const e=this.messageTypes.map((e=>e.value));this.required?(this.chipList.errorState=!e.length,this.propagateChange(e.length>0?e:null)):(this.chipList.errorState=!1,this.propagateChange(e))}}qt.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:qt,deps:[{token:N.Store},{token:E.TranslateService},{token:i.TruncatePipe},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),qt.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:qt,selector:"tb-message-types-config",inputs:{required:"required",label:"label",placeholder:"placeholder",disabled:"disabled"},providers:[{provide:M,useExisting:a((()=>qt)),multi:!0}],viewQueries:[{propertyName:"chipList",first:!0,predicate:["chipList"],descendants:!0},{propertyName:"matAutocomplete",first:!0,predicate:["messageTypeAutocomplete"],descendants:!0},{propertyName:"messageTypeInput",first:!0,predicate:["messageTypeInput"],descendants:!0}],usesInheritance:!0,ngImport:e,template:'\n {{ label }}\n \n \n {{messageType.name}}\n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-message-types-found\n
\n \n \n {{ translate.get(\'tb.rulenode.no-message-type-matching\',\n {messageType: truncate.transform(searchText, true, 6, '...')}) | async }}\n \n \n \n tb.rulenode.create-new-message-type\n \n
\n
\n
\n \n {{ \'tb.rulenode.message-types-required\' | translate }}\n \n
\n',components:[{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:X.MatChipList,selector:"mat-chip-list",inputs:["aria-orientation","multiple","compareWith","value","required","placeholder","disabled","selectable","tabIndex","errorStateMatcher"],outputs:["change","valueChange"],exportAs:["matChipList"]},{type:ee.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{type:he.MatAutocomplete,selector:"mat-autocomplete",inputs:["disableRipple"],exportAs:["matAutocomplete"]},{type:U.MatOption,selector:"mat-option",exportAs:["matOption"]}],directives:[{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:G.MatLabel,selector:"mat-label"},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:X.MatChip,selector:"mat-basic-chip, [mat-basic-chip], mat-chip, [mat-chip]",inputs:["color","disableRipple","tabIndex","selected","value","selectable","disabled","removable"],outputs:["selectionChange","destroyed","removed"],exportAs:["matChip"]},{type:X.MatChipRemove,selector:"[matChipRemove]"},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:he.MatAutocompleteTrigger,selector:"input[matAutocomplete], textarea[matAutocomplete]",exportAs:["matAutocompleteTrigger"]},{type:X.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputSeparatorKeyCodes","placeholder","id","matChipInputFor","matChipInputAddOnBlur","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:he.MatAutocompleteOrigin,selector:"[matAutocompleteOrigin]",exportAs:["matAutocompleteOrigin"]},{type:G.MatError,selector:"mat-error",inputs:["id"]}],pipes:{translate:E.TranslatePipe,async:R.AsyncPipe,highlight:Fe.HighlightPipe}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:qt,decorators:[{type:t,args:[{selector:"tb-message-types-config",templateUrl:"./message-types-config.component.html",styleUrls:[],providers:[{provide:M,useExisting:a((()=>qt)),multi:!0}]}]}],ctorParameters:function(){return[{type:N.Store},{type:E.TranslateService},{type:i.TruncatePipe},{type:q.FormBuilder}]},propDecorators:{required:[{type:n}],label:[{type:n}],placeholder:[{type:n}],disabled:[{type:n}],chipList:[{type:r,args:["chipList",{static:!1}]}],matAutocomplete:[{type:r,args:["messageTypeAutocomplete",{static:!1}]}],messageTypeInput:[{type:r,args:["messageTypeInput",{static:!1}]}]}});class Tt{}Tt.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Tt,deps:[],target:e.ɵɵFactoryTarget.NgModule}),Tt.ɵmod=e.ɵɵngDeclareNgModule({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Tt,declarations:[rt,It,Nt,qt,lt,Ie],imports:[w,F,ce],exports:[rt,It,Nt,qt,lt,Ie]}),Tt.ɵinj=e.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Tt,imports:[[w,F,ce]]}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Tt,decorators:[{type:l,args:[{declarations:[rt,It,Nt,qt,lt,Ie],imports:[w,F,ce],exports:[rt,It,Nt,qt,lt,Ie]}]}]});class kt{}kt.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:kt,deps:[],target:e.ɵɵFactoryTarget.NgModule}),kt.ɵmod=e.ɵɵngDeclareNgModule({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:kt,declarations:[qe,Lt,xt,nt,Ne,Ye,Je,Ze,mt,Xe,tt,ot,st,gt,yt,vt,Ft,Ct,ut,at,it,ft,ct,bt,We,$e,et,ht,dt,pt],imports:[w,F,ce,Tt],exports:[qe,Lt,xt,nt,Ne,Ye,Je,Ze,mt,Xe,tt,ot,st,gt,yt,vt,Ft,Ct,ut,at,it,ft,ct,bt,We,$e,et,ht,dt,pt]}),kt.ɵinj=e.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:kt,imports:[[w,F,ce,Tt]]}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:kt,decorators:[{type:l,args:[{declarations:[qe,Lt,xt,nt,Ne,Ye,Je,Ze,mt,Xe,tt,ot,st,gt,yt,vt,Ft,Ct,ut,at,it,ft,ct,bt,We,$e,et,ht,dt,pt],imports:[w,F,ce,Tt],exports:[qe,Lt,xt,nt,Ne,Ye,Je,Ze,mt,Xe,tt,ot,st,gt,yt,vt,Ft,Ct,ut,at,it,ft,ct,bt,We,$e,et,ht,dt,pt]}]}]});class Mt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.separatorKeysCodes=[Y,J,Z]}configForm(){return this.calculateDeltaConfigForm}onConfigurationSet(e){this.calculateDeltaConfigForm=this.fb.group({inputValueKey:[e?e.inputValueKey:null,[T.required]],outputValueKey:[e?e.outputValueKey:null,[T.required]],useCache:[e?e.useCache:null,[]],addPeriodBetweenMsgs:[!!e&&e.addPeriodBetweenMsgs,[]],periodValueKey:[e?e.periodValueKey:null,[]],round:[e?e.round:null,[T.min(0),T.max(15)]],tellFailureIfDeltaIsNegative:[e?e.tellFailureIfDeltaIsNegative:null,[]]})}updateValidators(e){this.calculateDeltaConfigForm.get("addPeriodBetweenMsgs").value?this.calculateDeltaConfigForm.get("periodValueKey").setValidators([T.required]):this.calculateDeltaConfigForm.get("periodValueKey").setValidators([]),this.calculateDeltaConfigForm.get("periodValueKey").updateValueAndValidity({emitEvent:e})}validatorTriggers(){return["addPeriodBetweenMsgs"]}}Mt.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Mt,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),Mt.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Mt,selector:"tb-enrichment-node-calculate-delta-config",usesInheritance:!0,ngImport:e,template:'
\n
\n \n tb.rulenode.input-value-key\n \n \n {{ \'tb.rulenode.input-value-key-required\' | translate }}\n \n \n \n tb.rulenode.output-value-key\n \n \n {{ \'tb.rulenode.output-value-key-required\' | translate }}\n \n \n \n tb.rulenode.round\n \n \n {{ \'tb.rulenode.round-range\' | translate }}\n \n \n {{ \'tb.rulenode.round-range\' | translate }}\n \n \n
\n \n {{ \'tb.rulenode.use-cache\' | translate }}\n \n \n {{ \'tb.rulenode.tell-failure-if-delta-is-negative\' | translate }}\n \n \n {{ \'tb.rulenode.add-period-between-msgs\' | translate }}\n \n \n tb.rulenode.period-value-key\n \n \n {{ \'tb.rulenode.period-value-key-required\' | translate }}\n \n \n
\n',components:[{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:D.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:V.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:G.MatLabel,selector:"mat-label"},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:G.MatError,selector:"mat-error",inputs:["id"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"}],pipes:{translate:E.TranslatePipe}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Mt,decorators:[{type:t,args:[{selector:"tb-enrichment-node-calculate-delta-config",templateUrl:"./calculate-delta-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class St extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.customerAttributesConfigForm}onConfigurationSet(e){this.customerAttributesConfigForm=this.fb.group({telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[T.required]]})}}St.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:St,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),St.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:St,selector:"tb-enrichment-node-customer-attributes-config",usesInheritance:!0,ngImport:e,template:'
\n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
\n',components:[{type:D.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:rt,selector:"tb-kv-map-config",inputs:["disabled","requiredText","keyText","keyRequiredText","valText","valRequiredText","required"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]}],pipes:{translate:E.TranslatePipe}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:St,decorators:[{type:t,args:[{selector:"tb-enrichment-node-customer-attributes-config",templateUrl:"./customer-attributes-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class At extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.separatorKeysCodes=[Y,J,Z]}configForm(){return this.deviceAttributesConfigForm}onConfigurationSet(e){this.deviceAttributesConfigForm=this.fb.group({deviceRelationsQuery:[e?e.deviceRelationsQuery:null,[T.required]],tellFailureIfAbsent:[!!e&&e.tellFailureIfAbsent,[]],clientAttributeNames:[e?e.clientAttributeNames:null,[]],sharedAttributeNames:[e?e.sharedAttributeNames:null,[]],serverAttributeNames:[e?e.serverAttributeNames:null,[]],latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],getLatestValueWithTs:[!!e&&e.getLatestValueWithTs,[]]})}removeKey(e,t){const o=this.deviceAttributesConfigForm.get(t).value,r=o.indexOf(e);r>=0&&(o.splice(r,1),this.deviceAttributesConfigForm.get(t).setValue(o,{emitEvent:!0}))}addKey(e,t){const o=e.input;let r=e.value;if((r||"").trim()){r=r.trim();let e=this.deviceAttributesConfigForm.get(t).value;e&&-1!==e.indexOf(r)||(e||(e=[]),e.push(r),this.deviceAttributesConfigForm.get(t).setValue(e,{emitEvent:!0}))}o&&(o.value="")}}At.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:At,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),At.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:At,selector:"tb-enrichment-node-device-attributes-config",usesInheritance:!0,ngImport:e,template:'
\n \n \n \n \n {{ \'tb.rulenode.tell-failure-if-absent\' | translate }}\n \n
tb.rulenode.tell-failure-if-absent-hint
\n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n {{ \'tb.rulenode.get-latest-value-with-ts\' | translate }}\n \n
\n
\n',styles:[":host label.tb-title{margin-bottom:-10px}\n"],components:[{type:It,selector:"tb-device-relations-query-config",inputs:["disabled","required"]},{type:D.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:X.MatChipList,selector:"mat-chip-list",inputs:["aria-orientation","multiple","compareWith","value","required","placeholder","disabled","selectable","tabIndex","errorStateMatcher"],outputs:["change","valueChange"],exportAs:["matChipList"]},{type:ee.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:G.MatLabel,selector:"mat-label"},{type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:X.MatChip,selector:"mat-basic-chip, [mat-basic-chip], mat-chip, [mat-chip]",inputs:["color","disableRipple","tabIndex","selected","value","selectable","disabled","removable"],outputs:["selectionChange","destroyed","removed"],exportAs:["matChip"]},{type:X.MatChipRemove,selector:"[matChipRemove]"},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:X.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputSeparatorKeyCodes","placeholder","id","matChipInputFor","matChipInputAddOnBlur","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]}],pipes:{translate:E.TranslatePipe,safeHtml:Ie}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:At,decorators:[{type:t,args:[{selector:"tb-enrichment-node-device-attributes-config",templateUrl:"./device-attributes-config.component.html",styleUrls:["./device-attributes-config.component.scss"]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class Gt extends s{constructor(e,t,o){super(e),this.store=e,this.translate=t,this.fb=o,this.entityDetailsTranslationsMap=Pe,this.entityDetailsList=[],this.searchText="",this.displayDetailsFn=this.displayDetails.bind(this);for(const e of Object.keys(Ee))this.entityDetailsList.push(Ee[e]);this.detailsFormControl=new A(""),this.filteredEntityDetails=this.detailsFormControl.valueChanges.pipe(se(""),me((e=>e||"")),ue((e=>this.fetchEntityDetails(e))),pe())}ngOnInit(){super.ngOnInit()}configForm(){return this.entityDetailsConfigForm}prepareInputConfig(e){return this.searchText="",this.detailsFormControl.patchValue("",{emitEvent:!0}),e}onConfigurationSet(e){this.entityDetailsConfigForm=this.fb.group({detailsList:[e?e.detailsList:null,[T.required]],addToMetadata:[!!e&&e.addToMetadata,[]]})}displayDetails(e){return e?this.translate.instant(Pe.get(e)):void 0}fetchEntityDetails(e){if(this.searchText=e,this.searchText&&this.searchText.length){const e=this.searchText.toUpperCase();return be(this.entityDetailsList.filter((t=>this.translate.instant(Pe.get(Ee[t])).toUpperCase().includes(e))))}return be(this.entityDetailsList)}detailsFieldSelected(e){this.addDetailsField(e.option.value),this.clear("")}removeDetailsField(e){const t=this.entityDetailsConfigForm.get("detailsList").value;if(t){const o=t.indexOf(e);o>=0&&(t.splice(o,1),this.entityDetailsConfigForm.get("detailsList").setValue(t))}}addDetailsField(e){let t=this.entityDetailsConfigForm.get("detailsList").value;t||(t=[]);-1===t.indexOf(e)&&(t.push(e),this.entityDetailsConfigForm.get("detailsList").setValue(t))}onEntityDetailsInputFocus(){this.detailsFormControl.updateValueAndValidity({onlySelf:!0,emitEvent:!0})}clear(e=""){this.detailsInput.nativeElement.value=e,this.detailsFormControl.patchValue(null,{emitEvent:!0}),setTimeout((()=>{this.detailsInput.nativeElement.blur(),this.detailsInput.nativeElement.focus()}),0)}}Gt.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Gt,deps:[{token:N.Store},{token:E.TranslateService},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),Gt.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Gt,selector:"tb-enrichment-node-entity-details-config",viewQueries:[{propertyName:"detailsInput",first:!0,predicate:["detailsInput"],descendants:!0}],usesInheritance:!0,ngImport:e,template:'
\n \n tb.rulenode.entity-details\n \n \n \n {{entityDetailsTranslationsMap.get(details) | translate}}\n \n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-entity-details-matching\n
\n
\n
\n
\n
\n \n \n {{ \'tb.rulenode.add-to-metadata\' | translate }}\n \n
tb.rulenode.add-to-metadata-hint
\n
\n',styles:[":host ::ng-deep mat-form-field.entity-fields-list .mat-form-field-wrapper{margin-bottom:-1.25em}\n"],components:[{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:X.MatChipList,selector:"mat-chip-list",inputs:["aria-orientation","multiple","compareWith","value","required","placeholder","disabled","selectable","tabIndex","errorStateMatcher"],outputs:["change","valueChange"],exportAs:["matChipList"]},{type:ee.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{type:he.MatAutocomplete,selector:"mat-autocomplete",inputs:["disableRipple"],exportAs:["matAutocomplete"]},{type:U.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:ae.TbErrorComponent,selector:"tb-error",inputs:["error"]},{type:D.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:G.MatLabel,selector:"mat-label"},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:X.MatChip,selector:"mat-basic-chip, [mat-basic-chip], mat-chip, [mat-chip]",inputs:["color","disableRipple","tabIndex","selected","value","selectable","disabled","removable"],outputs:["selectionChange","destroyed","removed"],exportAs:["matChip"]},{type:X.MatChipRemove,selector:"[matChipRemove]"},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:he.MatAutocompleteTrigger,selector:"input[matAutocomplete], textarea[matAutocomplete]",exportAs:["matAutocompleteTrigger"]},{type:X.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputSeparatorKeyCodes","placeholder","id","matChipInputFor","matChipInputAddOnBlur","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{type:he.MatAutocompleteOrigin,selector:"[matAutocompleteOrigin]",exportAs:["matAutocompleteOrigin"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlDirective,selector:"[formControl]",inputs:["disabled","formControl","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]}],pipes:{translate:E.TranslatePipe,async:R.AsyncPipe,highlight:Fe.HighlightPipe}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Gt,decorators:[{type:t,args:[{selector:"tb-enrichment-node-entity-details-config",templateUrl:"./entity-details-config.component.html",styleUrls:["./entity-details-config.component.scss"]}]}],ctorParameters:function(){return[{type:N.Store},{type:E.TranslateService},{type:q.FormBuilder}]},propDecorators:{detailsInput:[{type:r,args:["detailsInput",{static:!1}]}]}});class Dt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.separatorKeysCodes=[Y,J,Z],this.aggregationTypes=C,this.aggregations=Object.keys(C),this.aggregationTypesTranslations=L,this.fetchMode=Re,this.fetchModes=Object.keys(Re),this.samplingOrders=Object.keys(we),this.timeUnits=Object.values(Ae),this.timeUnitsTranslationMap=Ge}configForm(){return this.getTelemetryFromDatabaseConfigForm}onConfigurationSet(e){this.getTelemetryFromDatabaseConfigForm=this.fb.group({latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],aggregation:[e?e.aggregation:null,[T.required]],fetchMode:[e?e.fetchMode:null,[T.required]],orderBy:[e?e.orderBy:null,[]],limit:[e?e.limit:null,[]],useMetadataIntervalPatterns:[!!e&&e.useMetadataIntervalPatterns,[]],startInterval:[e?e.startInterval:null,[]],startIntervalTimeUnit:[e?e.startIntervalTimeUnit:null,[]],endInterval:[e?e.endInterval:null,[]],endIntervalTimeUnit:[e?e.endIntervalTimeUnit:null,[]],startIntervalPattern:[e?e.startIntervalPattern:null,[]],endIntervalPattern:[e?e.endIntervalPattern:null,[]]})}validatorTriggers(){return["fetchMode","useMetadataIntervalPatterns"]}updateValidators(e){const t=this.getTelemetryFromDatabaseConfigForm.get("fetchMode").value,o=this.getTelemetryFromDatabaseConfigForm.get("useMetadataIntervalPatterns").value;t&&t===Re.ALL?(this.getTelemetryFromDatabaseConfigForm.get("aggregation").setValidators([T.required]),this.getTelemetryFromDatabaseConfigForm.get("orderBy").setValidators([T.required]),this.getTelemetryFromDatabaseConfigForm.get("limit").setValidators([T.required,T.min(2),T.max(1e3)])):(this.getTelemetryFromDatabaseConfigForm.get("aggregation").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("orderBy").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("limit").setValidators([])),o?(this.getTelemetryFromDatabaseConfigForm.get("startInterval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endInterval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").setValidators([T.required]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").setValidators([T.required])):(this.getTelemetryFromDatabaseConfigForm.get("startInterval").setValidators([T.required,T.min(1),T.max(2147483647)]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").setValidators([T.required]),this.getTelemetryFromDatabaseConfigForm.get("endInterval").setValidators([T.required,T.min(1),T.max(2147483647)]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").setValidators([T.required]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").setValidators([])),this.getTelemetryFromDatabaseConfigForm.get("aggregation").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("orderBy").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("limit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startInterval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endInterval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").updateValueAndValidity({emitEvent:e})}removeKey(e,t){const o=this.getTelemetryFromDatabaseConfigForm.get(t).value,r=o.indexOf(e);r>=0&&(o.splice(r,1),this.getTelemetryFromDatabaseConfigForm.get(t).setValue(o,{emitEvent:!0}))}addKey(e,t){const o=e.input;let r=e.value;if((r||"").trim()){r=r.trim();let e=this.getTelemetryFromDatabaseConfigForm.get(t).value;e&&-1!==e.indexOf(r)||(e||(e=[]),e.push(r),this.getTelemetryFromDatabaseConfigForm.get(t).setValue(e,{emitEvent:!0}))}o&&(o.value="")}}Dt.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Dt,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),Dt.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Dt,selector:"tb-enrichment-node-get-telemetry-from-database",usesInheritance:!0,ngImport:e,template:'
\n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.fetch-mode\n \n \n {{ mode }}\n \n \n tb.rulenode.fetch-mode-hint\n \n
\n \n aggregation.function\n \n \n {{ aggregationTypesTranslations.get(aggregationTypes[aggregation]) | translate }}\n \n \n \n \n tb.rulenode.order-by\n \n \n {{ order }}\n \n \n tb.rulenode.order-by-hint\n \n \n tb.rulenode.limit\n \n tb.rulenode.limit-hint\n \n
\n \n {{ \'tb.rulenode.use-metadata-interval-patterns\' | translate }}\n \n
tb.rulenode.use-metadata-interval-patterns-hint
\n
\n
\n \n tb.rulenode.start-interval\n \n \n {{ \'tb.rulenode.start-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.start-interval-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n tb.rulenode.end-interval\n \n \n {{ \'tb.rulenode.end-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.end-interval-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n \n tb.rulenode.start-interval-pattern\n \n \n {{ \'tb.rulenode.start-interval-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.end-interval-pattern\n \n \n {{ \'tb.rulenode.end-interval-pattern-required\' | translate }}\n \n \n \n \n
\n',styles:[":host label.tb-title{margin-bottom:-10px}\n"],components:[{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:X.MatChipList,selector:"mat-chip-list",inputs:["aria-orientation","multiple","compareWith","value","required","placeholder","disabled","selectable","tabIndex","errorStateMatcher"],outputs:["change","valueChange"],exportAs:["matChipList"]},{type:ee.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{type:H.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:U.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:D.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:G.MatLabel,selector:"mat-label"},{type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:X.MatChip,selector:"mat-basic-chip, [mat-basic-chip], mat-chip, [mat-chip]",inputs:["color","disableRipple","tabIndex","selected","value","selectable","disabled","removable"],outputs:["selectionChange","destroyed","removed"],exportAs:["matChip"]},{type:X.MatChipRemove,selector:"[matChipRemove]"},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:X.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputSeparatorKeyCodes","placeholder","id","matChipInputFor","matChipInputAddOnBlur","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{type:G.MatHint,selector:"mat-hint",inputs:["align","id"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:V.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:G.MatError,selector:"mat-error",inputs:["id"]}],pipes:{translate:E.TranslatePipe,safeHtml:Ie}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Dt,decorators:[{type:t,args:[{selector:"tb-enrichment-node-get-telemetry-from-database",templateUrl:"./get-telemetry-from-database-config.component.html",styleUrls:["./get-telemetry-from-database-config.component.scss"]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class Vt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.separatorKeysCodes=[Y,J,Z]}configForm(){return this.originatorAttributesConfigForm}onConfigurationSet(e){this.originatorAttributesConfigForm=this.fb.group({tellFailureIfAbsent:[!!e&&e.tellFailureIfAbsent,[]],clientAttributeNames:[e?e.clientAttributeNames:null,[]],sharedAttributeNames:[e?e.sharedAttributeNames:null,[]],serverAttributeNames:[e?e.serverAttributeNames:null,[]],latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],getLatestValueWithTs:[!!e&&e.getLatestValueWithTs,[]]})}removeKey(e,t){const o=this.originatorAttributesConfigForm.get(t).value,r=o.indexOf(e);r>=0&&(o.splice(r,1),this.originatorAttributesConfigForm.get(t).setValue(o,{emitEvent:!0}))}addKey(e,t){const o=e.input;let r=e.value;if((r||"").trim()){r=r.trim();let e=this.originatorAttributesConfigForm.get(t).value;e&&-1!==e.indexOf(r)||(e||(e=[]),e.push(r),this.originatorAttributesConfigForm.get(t).setValue(e,{emitEvent:!0}))}o&&(o.value="")}}Vt.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Vt,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),Vt.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Vt,selector:"tb-enrichment-node-originator-attributes-config",usesInheritance:!0,ngImport:e,template:'
\n \n {{ \'tb.rulenode.tell-failure-if-absent\' | translate }}\n \n
tb.rulenode.tell-failure-if-absent-hint
\n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n {{ \'tb.rulenode.get-latest-value-with-ts\' | translate }}\n \n
\n
\n',styles:[":host label.tb-title{margin-bottom:-10px}\n"],components:[{type:D.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:X.MatChipList,selector:"mat-chip-list",inputs:["aria-orientation","multiple","compareWith","value","required","placeholder","disabled","selectable","tabIndex","errorStateMatcher"],outputs:["change","valueChange"],exportAs:["matChipList"]},{type:ee.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:G.MatLabel,selector:"mat-label"},{type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:X.MatChip,selector:"mat-basic-chip, [mat-basic-chip], mat-chip, [mat-chip]",inputs:["color","disableRipple","tabIndex","selected","value","selectable","disabled","removable"],outputs:["selectionChange","destroyed","removed"],exportAs:["matChip"]},{type:X.MatChipRemove,selector:"[matChipRemove]"},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:X.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputSeparatorKeyCodes","placeholder","id","matChipInputFor","matChipInputAddOnBlur","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{type:G.MatHint,selector:"mat-hint",inputs:["align","id"]}],pipes:{translate:E.TranslatePipe,safeHtml:Ie}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Vt,decorators:[{type:t,args:[{selector:"tb-enrichment-node-originator-attributes-config",templateUrl:"./originator-attributes-config.component.html",styleUrls:["./originator-attributes-config.component.scss"]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class Et extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.originatorFieldsConfigForm}onConfigurationSet(e){this.originatorFieldsConfigForm=this.fb.group({fieldsMapping:[e?e.fieldsMapping:null,[T.required]]})}}Et.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Et,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),Et.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Et,selector:"tb-enrichment-node-originator-fields-config",usesInheritance:!0,ngImport:e,template:'
\n \n \n \n
\n',components:[{type:rt,selector:"tb-kv-map-config",inputs:["disabled","requiredText","keyText","keyRequiredText","valText","valRequiredText","required"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]}]}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Et,decorators:[{type:t,args:[{selector:"tb-enrichment-node-originator-fields-config",templateUrl:"./originator-fields-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class Pt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.relatedAttributesConfigForm}onConfigurationSet(e){this.relatedAttributesConfigForm=this.fb.group({relationsQuery:[e?e.relationsQuery:null,[T.required]],telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[T.required]]})}}Pt.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Pt,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),Pt.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Pt,selector:"tb-enrichment-node-related-attributes-config",usesInheritance:!0,ngImport:e,template:'
\n \n \n \n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
\n',components:[{type:Nt,selector:"tb-relations-query-config",inputs:["disabled","required"]},{type:D.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:rt,selector:"tb-kv-map-config",inputs:["disabled","requiredText","keyText","keyRequiredText","valText","valRequiredText","required"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]}],pipes:{translate:E.TranslatePipe}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Pt,decorators:[{type:t,args:[{selector:"tb-enrichment-node-related-attributes-config",templateUrl:"./related-attributes-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class Rt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.tenantAttributesConfigForm}onConfigurationSet(e){this.tenantAttributesConfigForm=this.fb.group({telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[T.required]]})}}Rt.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Rt,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),Rt.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Rt,selector:"tb-enrichment-node-tenant-attributes-config",usesInheritance:!0,ngImport:e,template:'
\n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
\n',components:[{type:D.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:rt,selector:"tb-kv-map-config",inputs:["disabled","requiredText","keyText","keyRequiredText","valText","valRequiredText","required"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]}],pipes:{translate:E.TranslatePipe}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Rt,decorators:[{type:t,args:[{selector:"tb-enrichment-node-tenant-attributes-config",templateUrl:"./tenant-attributes-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class wt{}wt.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:wt,deps:[],target:e.ɵɵFactoryTarget.NgModule}),wt.ɵmod=e.ɵɵngDeclareNgModule({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:wt,declarations:[St,Gt,At,Vt,Et,Dt,Pt,Rt,Mt],imports:[w,F,Tt],exports:[St,Gt,At,Vt,Et,Dt,Pt,Rt,Mt]}),wt.ɵinj=e.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:wt,imports:[[w,F,Tt]]}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:wt,decorators:[{type:l,args:[{declarations:[St,Gt,At,Vt,Et,Dt,Pt,Rt,Mt],imports:[w,F,Tt],exports:[St,Gt,At,Vt,Et,Dt,Pt,Rt,Mt]}]}]});class Ot extends s{constructor(e,t,o){super(e),this.store=e,this.translate=t,this.fb=o,this.alarmStatusTranslationsMap=v,this.alarmStatusList=[],this.searchText="",this.displayStatusFn=this.displayStatus.bind(this);for(const e of Object.keys(I))this.alarmStatusList.push(I[e]);this.statusFormControl=new A(""),this.filteredAlarmStatus=this.statusFormControl.valueChanges.pipe(se(""),me((e=>e||"")),ue((e=>this.fetchAlarmStatus(e))),pe())}ngOnInit(){super.ngOnInit()}configForm(){return this.alarmStatusConfigForm}prepareInputConfig(e){return this.searchText="",this.statusFormControl.patchValue("",{emitEvent:!0}),e}onConfigurationSet(e){this.alarmStatusConfigForm=this.fb.group({alarmStatusList:[e?e.alarmStatusList:null,[T.required]]})}displayStatus(e){return e?this.translate.instant(v.get(e)):void 0}fetchAlarmStatus(e){const t=this.getAlarmStatusList();if(this.searchText=e,this.searchText&&this.searchText.length){const e=this.searchText.toUpperCase();return be(t.filter((t=>this.translate.instant(v.get(I[t])).toUpperCase().includes(e))))}return be(t)}alarmStatusSelected(e){this.addAlarmStatus(e.option.value),this.clear("")}removeAlarmStatus(e){const t=this.alarmStatusConfigForm.get("alarmStatusList").value;if(t){const o=t.indexOf(e);o>=0&&(t.splice(o,1),this.alarmStatusConfigForm.get("alarmStatusList").setValue(t))}}addAlarmStatus(e){let t=this.alarmStatusConfigForm.get("alarmStatusList").value;t||(t=[]);-1===t.indexOf(e)&&(t.push(e),this.alarmStatusConfigForm.get("alarmStatusList").setValue(t))}getAlarmStatusList(){return this.alarmStatusList.filter((e=>-1===this.alarmStatusConfigForm.get("alarmStatusList").value.indexOf(e)))}onAlarmStatusInputFocus(){this.statusFormControl.updateValueAndValidity({onlySelf:!0,emitEvent:!0})}clear(e=""){this.alarmStatusInput.nativeElement.value=e,this.statusFormControl.patchValue(null,{emitEvent:!0}),setTimeout((()=>{this.alarmStatusInput.nativeElement.blur(),this.alarmStatusInput.nativeElement.focus()}),0)}}Ot.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Ot,deps:[{token:N.Store},{token:E.TranslateService},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),Ot.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Ot,selector:"tb-filter-node-check-alarm-status-config",viewQueries:[{propertyName:"alarmStatusInput",first:!0,predicate:["alarmStatusInput"],descendants:!0}],usesInheritance:!0,ngImport:e,template:'
\n \n tb.rulenode.alarm-status-filter\n \n \n \n {{alarmStatusTranslationsMap.get(alarmStatus) | translate}}\n \n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-alarm-status-matching\n
\n
\n
\n
\n
\n \n
\n\n\n\n',components:[{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:X.MatChipList,selector:"mat-chip-list",inputs:["aria-orientation","multiple","compareWith","value","required","placeholder","disabled","selectable","tabIndex","errorStateMatcher"],outputs:["change","valueChange"],exportAs:["matChipList"]},{type:ee.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{type:he.MatAutocomplete,selector:"mat-autocomplete",inputs:["disableRipple"],exportAs:["matAutocomplete"]},{type:U.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:ae.TbErrorComponent,selector:"tb-error",inputs:["error"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:G.MatLabel,selector:"mat-label"},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:X.MatChip,selector:"mat-basic-chip, [mat-basic-chip], mat-chip, [mat-chip]",inputs:["color","disableRipple","tabIndex","selected","value","selectable","disabled","removable"],outputs:["selectionChange","destroyed","removed"],exportAs:["matChip"]},{type:X.MatChipRemove,selector:"[matChipRemove]"},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:he.MatAutocompleteTrigger,selector:"input[matAutocomplete], textarea[matAutocomplete]",exportAs:["matAutocompleteTrigger"]},{type:X.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputSeparatorKeyCodes","placeholder","id","matChipInputFor","matChipInputAddOnBlur","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{type:he.MatAutocompleteOrigin,selector:"[matAutocompleteOrigin]",exportAs:["matAutocompleteOrigin"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlDirective,selector:"[formControl]",inputs:["disabled","formControl","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]}],pipes:{translate:E.TranslatePipe,async:R.AsyncPipe,highlight:Fe.HighlightPipe}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Ot,decorators:[{type:t,args:[{selector:"tb-filter-node-check-alarm-status-config",templateUrl:"./check-alarm-status.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:E.TranslateService},{type:q.FormBuilder}]},propDecorators:{alarmStatusInput:[{type:r,args:["alarmStatusInput",{static:!1}]}]}});class Ht extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.separatorKeysCodes=[Y,J,Z]}configForm(){return this.checkMessageConfigForm}onConfigurationSet(e){this.checkMessageConfigForm=this.fb.group({messageNames:[e?e.messageNames:null,[]],metadataNames:[e?e.metadataNames:null,[]],checkAllKeys:[!!e&&e.checkAllKeys,[]]})}validateConfig(){const e=this.checkMessageConfigForm.get("messageNames").value,t=this.checkMessageConfigForm.get("metadataNames").value;return e.length>0||t.length>0}removeMessageName(e){const t=this.checkMessageConfigForm.get("messageNames").value,o=t.indexOf(e);o>=0&&(t.splice(o,1),this.checkMessageConfigForm.get("messageNames").setValue(t,{emitEvent:!0}))}removeMetadataName(e){const t=this.checkMessageConfigForm.get("metadataNames").value,o=t.indexOf(e);o>=0&&(t.splice(o,1),this.checkMessageConfigForm.get("metadataNames").setValue(t,{emitEvent:!0}))}addMessageName(e){const t=e.input;let o=e.value;if((o||"").trim()){o=o.trim();let e=this.checkMessageConfigForm.get("messageNames").value;e&&-1!==e.indexOf(o)||(e||(e=[]),e.push(o),this.checkMessageConfigForm.get("messageNames").setValue(e,{emitEvent:!0}))}t&&(t.value="")}addMetadataName(e){const t=e.input;let o=e.value;if((o||"").trim()){o=o.trim();let e=this.checkMessageConfigForm.get("metadataNames").value;e&&-1!==e.indexOf(o)||(e||(e=[]),e.push(o),this.checkMessageConfigForm.get("metadataNames").setValue(e,{emitEvent:!0}))}t&&(t.value="")}}Ht.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Ht,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),Ht.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Ht,selector:"tb-filter-node-check-message-config",usesInheritance:!0,ngImport:e,template:'
\n \n \n \n \n \n {{messageName}}\n close\n \n \n \n \n
tb.rulenode.separator-hint
\n \n \n \n \n \n {{metadataName}}\n close\n \n \n \n \n
tb.rulenode.separator-hint
\n \n {{ \'tb.rulenode.check-all-keys\' | translate }}\n \n
tb.rulenode.check-all-keys-hint
\n
\n',styles:[":host label.tb-title{margin-bottom:-10px}\n"],components:[{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:X.MatChipList,selector:"mat-chip-list",inputs:["aria-orientation","multiple","compareWith","value","required","placeholder","disabled","selectable","tabIndex","errorStateMatcher"],outputs:["change","valueChange"],exportAs:["matChipList"]},{type:ee.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{type:D.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:G.MatLabel,selector:"mat-label"},{type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:X.MatChip,selector:"mat-basic-chip, [mat-basic-chip], mat-chip, [mat-chip]",inputs:["color","disableRipple","tabIndex","selected","value","selectable","disabled","removable"],outputs:["selectionChange","destroyed","removed"],exportAs:["matChip"]},{type:X.MatChipRemove,selector:"[matChipRemove]"},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:X.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputSeparatorKeyCodes","placeholder","id","matChipInputFor","matChipInputAddOnBlur","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]}],pipes:{translate:E.TranslatePipe}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Ht,decorators:[{type:t,args:[{selector:"tb-filter-node-check-message-config",templateUrl:"./check-message-config.component.html",styleUrls:["./check-message-config.component.scss"]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class Ut extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.entitySearchDirection=Object.keys(c),this.entitySearchDirectionTranslationsMap=g}configForm(){return this.checkRelationConfigForm}onConfigurationSet(e){this.checkRelationConfigForm=this.fb.group({checkForSingleEntity:[!!e&&e.checkForSingleEntity,[]],direction:[e?e.direction:null,[]],entityType:[e?e.entityType:null,e&&e.checkForSingleEntity?[T.required]:[]],entityId:[e?e.entityId:null,e&&e.checkForSingleEntity?[T.required]:[]],relationType:[e?e.relationType:null,[T.required]]})}validatorTriggers(){return["checkForSingleEntity"]}updateValidators(e){const t=this.checkRelationConfigForm.get("checkForSingleEntity").value;this.checkRelationConfigForm.get("entityType").setValidators(t?[T.required]:[]),this.checkRelationConfigForm.get("entityType").updateValueAndValidity({emitEvent:e}),this.checkRelationConfigForm.get("entityId").setValidators(t?[T.required]:[]),this.checkRelationConfigForm.get("entityId").updateValueAndValidity({emitEvent:e})}}Ut.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Ut,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),Ut.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Ut,selector:"tb-filter-node-check-relation-config",usesInheritance:!0,ngImport:e,template:'
\n \n {{ \'tb.rulenode.check-relation-to-specific-entity\' | translate }}\n \n
tb.rulenode.check-relation-hint
\n \n relation.direction\n \n \n {{ entitySearchDirectionTranslationsMap.get(direction) | translate }}\n \n \n \n
\n \n \n \n \n
\n \n \n
\n',components:[{type:D.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:H.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:U.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:te.EntityTypeSelectComponent,selector:"tb-entity-type-select",inputs:["allowedEntityTypes","useAliasEntityTypes","showLabel","required","disabled"]},{type:Ce.EntityAutocompleteComponent,selector:"tb-entity-autocomplete",inputs:["entityType","entitySubtype","excludeEntityIds","labelText","requiredText","required","disabled"],outputs:["entityChanged"]},{type:ge.RelationTypeAutocompleteComponent,selector:"tb-relation-type-autocomplete",inputs:["required","disabled"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:G.MatLabel,selector:"mat-label"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]}],pipes:{translate:E.TranslatePipe}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Ut,decorators:[{type:t,args:[{selector:"tb-filter-node-check-relation-config",templateUrl:"./check-relation-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class Bt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.perimeterType=Me,this.perimeterTypes=Object.keys(Me),this.perimeterTypeTranslationMap=Se,this.rangeUnits=Object.keys(De),this.rangeUnitTranslationMap=Ve}configForm(){return this.geoFilterConfigForm}onConfigurationSet(e){this.geoFilterConfigForm=this.fb.group({latitudeKeyName:[e?e.latitudeKeyName:null,[T.required]],longitudeKeyName:[e?e.longitudeKeyName:null,[T.required]],fetchPerimeterInfoFromMessageMetadata:[!!e&&e.fetchPerimeterInfoFromMessageMetadata,[]],perimeterType:[e?e.perimeterType:null,[]],centerLatitude:[e?e.centerLatitude:null,[]],centerLongitude:[e?e.centerLatitude:null,[]],range:[e?e.range:null,[]],rangeUnit:[e?e.rangeUnit:null,[]],polygonsDefinition:[e?e.polygonsDefinition:null,[]]})}validatorTriggers(){return["fetchPerimeterInfoFromMessageMetadata","perimeterType"]}updateValidators(e){const t=this.geoFilterConfigForm.get("fetchPerimeterInfoFromMessageMetadata").value,o=this.geoFilterConfigForm.get("perimeterType").value;t?this.geoFilterConfigForm.get("perimeterType").setValidators([]):this.geoFilterConfigForm.get("perimeterType").setValidators([T.required]),t||o!==Me.CIRCLE?(this.geoFilterConfigForm.get("centerLatitude").setValidators([]),this.geoFilterConfigForm.get("centerLongitude").setValidators([]),this.geoFilterConfigForm.get("range").setValidators([]),this.geoFilterConfigForm.get("rangeUnit").setValidators([])):(this.geoFilterConfigForm.get("centerLatitude").setValidators([T.required,T.min(-90),T.max(90)]),this.geoFilterConfigForm.get("centerLongitude").setValidators([T.required,T.min(-180),T.max(180)]),this.geoFilterConfigForm.get("range").setValidators([T.required,T.min(0)]),this.geoFilterConfigForm.get("rangeUnit").setValidators([T.required])),t||o!==Me.POLYGON?this.geoFilterConfigForm.get("polygonsDefinition").setValidators([]):this.geoFilterConfigForm.get("polygonsDefinition").setValidators([T.required]),this.geoFilterConfigForm.get("perimeterType").updateValueAndValidity({emitEvent:!1}),this.geoFilterConfigForm.get("centerLatitude").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("centerLongitude").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("range").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("rangeUnit").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("polygonsDefinition").updateValueAndValidity({emitEvent:e})}}Bt.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Bt,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),Bt.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Bt,selector:"tb-filter-node-gps-geofencing-config",usesInheritance:!0,ngImport:e,template:'
\n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n
\n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n
\n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
\n
\n
\n',components:[{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:D.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:H.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:U.MatOption,selector:"mat-option",exportAs:["matOption"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:G.MatLabel,selector:"mat-label"},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:G.MatError,selector:"mat-error",inputs:["id"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:V.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"}],pipes:{translate:E.TranslatePipe}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Bt,decorators:[{type:t,args:[{selector:"tb-filter-node-gps-geofencing-config",templateUrl:"./gps-geo-filter-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class Kt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.messageTypeConfigForm}onConfigurationSet(e){this.messageTypeConfigForm=this.fb.group({messageTypes:[e?e.messageTypes:null,[T.required]]})}}Kt.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Kt,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),Kt.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Kt,selector:"tb-filter-node-message-type-config",usesInheritance:!0,ngImport:e,template:'
\n \n
\n',components:[{type:qt,selector:"tb-message-types-config",inputs:["required","label","placeholder","disabled"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]}]}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Kt,decorators:[{type:t,args:[{selector:"tb-filter-node-message-type-config",templateUrl:"./message-type-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class jt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.allowedEntityTypes=[x.DEVICE,x.ASSET,x.ENTITY_VIEW,x.TENANT,x.CUSTOMER,x.USER,x.DASHBOARD,x.RULE_CHAIN,x.RULE_NODE]}configForm(){return this.originatorTypeConfigForm}onConfigurationSet(e){this.originatorTypeConfigForm=this.fb.group({originatorTypes:[e?e.originatorTypes:null,[T.required]]})}}jt.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:jt,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),jt.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:jt,selector:"tb-filter-node-originator-type-config",usesInheritance:!0,ngImport:e,template:'
\n \n \n \n
\n',styles:[":host ::ng-deep tb-entity-type-list .mat-form-field-flex{padding-top:0}:host ::ng-deep tb-entity-type-list .mat-form-field-infix{border-top:0}\n"],components:[{type:Le.EntityTypeListComponent,selector:"tb-entity-type-list",inputs:["required","disabled","allowedEntityTypes","ignoreAuthorityFilter"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]}]}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:jt,decorators:[{type:t,args:[{selector:"tb-filter-node-originator-type-config",templateUrl:"./originator-type-config.component.html",styleUrls:["./originator-type-config.component.scss"]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class zt extends s{constructor(e,t,o,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=o,this.translate=r}configForm(){return this.scriptConfigForm}onConfigurationSet(e){this.scriptConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[T.required]]})}testScript(){const e=this.scriptConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(e,"filter",this.translate.instant("tb.rulenode.filter"),"Filter",["msg","metadata","msgType"],this.ruleNodeId,"rulenode/filter_node_script_fn").subscribe((e=>{e&&this.scriptConfigForm.get("jsScript").setValue(e)}))}onValidate(){this.jsFuncComponent.validateOnSubmit()}}zt.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:zt,deps:[{token:N.Store},{token:q.FormBuilder},{token:_.NodeScriptTestService},{token:E.TranslateService}],target:e.ɵɵFactoryTarget.Component}),zt.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:zt,selector:"tb-filter-node-script-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0,static:!0}],usesInheritance:!0,ngImport:e,template:'
\n \n \n \n
\n \n
\n
\n',components:[{type:$.JsFuncComponent,selector:"tb-js-func",inputs:["functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","noValidate","required"]},{type:W.MatButton,selector:"button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]}],pipes:{translate:E.TranslatePipe}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:zt,decorators:[{type:t,args:[{selector:"tb-filter-node-script-config",templateUrl:"./script-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder},{type:_.NodeScriptTestService},{type:E.TranslateService}]},propDecorators:{jsFuncComponent:[{type:r,args:["jsFuncComponent",{static:!0}]}]}});class _t extends s{constructor(e,t,o,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=o,this.translate=r}configForm(){return this.switchConfigForm}onConfigurationSet(e){this.switchConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[T.required]]})}testScript(){const e=this.switchConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(e,"switch",this.translate.instant("tb.rulenode.switch"),"Switch",["msg","metadata","msgType"],this.ruleNodeId,"rulenode/switch_node_script_fn").subscribe((e=>{e&&this.switchConfigForm.get("jsScript").setValue(e)}))}onValidate(){this.jsFuncComponent.validateOnSubmit()}}_t.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:_t,deps:[{token:N.Store},{token:q.FormBuilder},{token:_.NodeScriptTestService},{token:E.TranslateService}],target:e.ɵɵFactoryTarget.Component}),_t.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:_t,selector:"tb-filter-node-switch-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0,static:!0}],usesInheritance:!0,ngImport:e,template:'
\n \n \n \n
\n \n
\n
\n',components:[{type:$.JsFuncComponent,selector:"tb-js-func",inputs:["functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","noValidate","required"]},{type:W.MatButton,selector:"button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]}],pipes:{translate:E.TranslatePipe}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:_t,decorators:[{type:t,args:[{selector:"tb-filter-node-switch-config",templateUrl:"./switch-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder},{type:_.NodeScriptTestService},{type:E.TranslateService}]},propDecorators:{jsFuncComponent:[{type:r,args:["jsFuncComponent",{static:!0}]}]}});class Qt{}Qt.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Qt,deps:[],target:e.ɵɵFactoryTarget.NgModule}),Qt.ɵmod=e.ɵɵngDeclareNgModule({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Qt,declarations:[Ht,Ut,Bt,Kt,jt,zt,_t,Ot],imports:[w,F,Tt],exports:[Ht,Ut,Bt,Kt,jt,zt,_t,Ot]}),Qt.ɵinj=e.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Qt,imports:[[w,F,Tt]]}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Qt,decorators:[{type:l,args:[{declarations:[Ht,Ut,Bt,Kt,jt,zt,_t,Ot],imports:[w,F,Tt],exports:[Ht,Ut,Bt,Kt,jt,zt,_t,Ot]}]}]});class $t extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.originatorSource=Te,this.originatorSources=Object.keys(Te),this.originatorSourceTranslationMap=ke}configForm(){return this.changeOriginatorConfigForm}onConfigurationSet(e){this.changeOriginatorConfigForm=this.fb.group({originatorSource:[e?e.originatorSource:null,[T.required]],relationsQuery:[e?e.relationsQuery:null,[]]})}validatorTriggers(){return["originatorSource"]}updateValidators(e){const t=this.changeOriginatorConfigForm.get("originatorSource").value;t&&t===Te.RELATED?this.changeOriginatorConfigForm.get("relationsQuery").setValidators([T.required]):this.changeOriginatorConfigForm.get("relationsQuery").setValidators([]),this.changeOriginatorConfigForm.get("relationsQuery").updateValueAndValidity({emitEvent:e})}}$t.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:$t,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),$t.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:$t,selector:"tb-transformation-node-change-originator-config",usesInheritance:!0,ngImport:e,template:'
\n \n tb.rulenode.originator-source\n \n \n {{ originatorSourceTranslationMap.get(source) | translate }}\n \n \n \n
\n \n \n \n
\n
\n',components:[{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:H.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:U.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:Nt,selector:"tb-relations-query-config",inputs:["disabled","required"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:G.MatLabel,selector:"mat-label"},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]}],pipes:{translate:E.TranslatePipe}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:$t,decorators:[{type:t,args:[{selector:"tb-transformation-node-change-originator-config",templateUrl:"./change-originator-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class Wt extends s{constructor(e,t,o,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=o,this.translate=r}configForm(){return this.scriptConfigForm}onConfigurationSet(e){this.scriptConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[T.required]]})}testScript(){const e=this.scriptConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(e,"update",this.translate.instant("tb.rulenode.transformer"),"Transform",["msg","metadata","msgType"],this.ruleNodeId,"rulenode/transformation_node_script_fn").subscribe((e=>{e&&this.scriptConfigForm.get("jsScript").setValue(e)}))}onValidate(){this.jsFuncComponent.validateOnSubmit()}}Wt.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Wt,deps:[{token:N.Store},{token:q.FormBuilder},{token:_.NodeScriptTestService},{token:E.TranslateService}],target:e.ɵɵFactoryTarget.Component}),Wt.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Wt,selector:"tb-transformation-node-script-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0,static:!0}],usesInheritance:!0,ngImport:e,template:'
\n \n \n \n
\n \n
\n
\n',components:[{type:$.JsFuncComponent,selector:"tb-js-func",inputs:["functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","noValidate","required"]},{type:W.MatButton,selector:"button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]}],pipes:{translate:E.TranslatePipe}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Wt,decorators:[{type:t,args:[{selector:"tb-transformation-node-script-config",templateUrl:"./script-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder},{type:_.NodeScriptTestService},{type:E.TranslateService}]},propDecorators:{jsFuncComponent:[{type:r,args:["jsFuncComponent",{static:!0}]}]}});class Yt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.mailBodyTypes=[{name:"tb.mail-body-type.plain-text",value:"false"},{name:"tb.mail-body-type.html",value:"true"},{name:"tb.mail-body-type.dynamic",value:"dynamic"}]}configForm(){return this.toEmailConfigForm}onConfigurationSet(e){this.toEmailConfigForm=this.fb.group({fromTemplate:[e?e.fromTemplate:null,[T.required]],toTemplate:[e?e.toTemplate:null,[T.required]],ccTemplate:[e?e.ccTemplate:null,[]],bccTemplate:[e?e.bccTemplate:null,[]],subjectTemplate:[e?e.subjectTemplate:null,[T.required]],mailBodyType:[e?e.mailBodyType:null],isHtmlTemplate:[e?e.isHtmlTemplate:null],bodyTemplate:[e?e.bodyTemplate:null,[T.required]]}),this.toEmailConfigForm.get("mailBodyType").valueChanges.pipe(se([null==e?void 0:e.subjectTemplate])).subscribe((e=>{"dynamic"===e?(this.toEmailConfigForm.get("isHtmlTemplate").patchValue("",{emitEvent:!1}),this.toEmailConfigForm.get("isHtmlTemplate").setValidators(T.required)):this.toEmailConfigForm.get("isHtmlTemplate").clearValidators(),this.toEmailConfigForm.get("isHtmlTemplate").updateValueAndValidity()}))}}Yt.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Yt,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),Yt.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Yt,selector:"tb-transformation-node-to-email-config",usesInheritance:!0,ngImport:e,template:'
\n \n tb.rulenode.from-template\n \n \n {{ \'tb.rulenode.from-template-required\' | translate }}\n \n \n \n \n tb.rulenode.to-template\n \n \n {{ \'tb.rulenode.to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.cc-template\n \n \n \n \n tb.rulenode.bcc-template\n \n \n \n \n tb.rulenode.subject-template\n \n \n {{ \'tb.rulenode.subject-template-required\' | translate }}\n \n \n \n \n tb.rulenode.mail-body-type\n \n \n {{ type.name | translate }}\n \n \n \n \n tb.rulenode.dynamic-mail-body-type\n \n \n \n \n tb.rulenode.body-template\n \n \n {{ \'tb.rulenode.body-template-required\' | translate }}\n \n \n \n
\n',components:[{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:H.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:U.MatOption,selector:"mat-option",exportAs:["matOption"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:G.MatLabel,selector:"mat-label"},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:G.MatError,selector:"mat-error",inputs:["id"]},{type:G.MatHint,selector:"mat-hint",inputs:["align","id"]},{type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]}],pipes:{translate:E.TranslatePipe,safeHtml:Ie}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Yt,decorators:[{type:t,args:[{selector:"tb-transformation-node-to-email-config",templateUrl:"./to-email-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class Jt{}Jt.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Jt,deps:[],target:e.ɵɵFactoryTarget.NgModule}),Jt.ɵmod=e.ɵɵngDeclareNgModule({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Jt,declarations:[$t,Wt,Yt],imports:[w,F,Tt],exports:[$t,Wt,Yt]}),Jt.ɵinj=e.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Jt,imports:[[w,F,Tt]]}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Jt,decorators:[{type:l,args:[{declarations:[$t,Wt,Yt],imports:[w,F,Tt],exports:[$t,Wt,Yt]}]}]});class Zt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.entityType=x}configForm(){return this.ruleChainInputConfigForm}onConfigurationSet(e){this.ruleChainInputConfigForm=this.fb.group({ruleChainId:[e?e.ruleChainId:null,[T.required]]})}}Zt.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Zt,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),Zt.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Zt,selector:"tb-flow-node-rule-chain-input-config",usesInheritance:!0,ngImport:e,template:'
\n \n \n
\n',components:[{type:Ce.EntityAutocompleteComponent,selector:"tb-entity-autocomplete",inputs:["entityType","entitySubtype","excludeEntityIds","labelText","requiredText","required","disabled"],outputs:["entityChanged"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]}]}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Zt,decorators:[{type:t,args:[{selector:"tb-flow-node-rule-chain-input-config",templateUrl:"./rule-chain-input.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class Xt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.ruleChainOutputConfigForm}onConfigurationSet(e){this.ruleChainOutputConfigForm=this.fb.group({})}}Xt.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Xt,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),Xt.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Xt,selector:"tb-flow-node-rule-chain-output-config",usesInheritance:!0,ngImport:e,template:'
\n
\n
\n',directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]}],pipes:{translate:E.TranslatePipe}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Xt,decorators:[{type:t,args:[{selector:"tb-flow-node-rule-chain-output-config",templateUrl:"./rule-chain-output.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class eo{}eo.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:eo,deps:[],target:e.ɵɵFactoryTarget.NgModule}),eo.ɵmod=e.ɵɵngDeclareNgModule({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:eo,declarations:[Zt,Xt],imports:[w,F,Tt],exports:[Zt,Xt]}),eo.ɵinj=e.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:eo,imports:[[w,F,Tt]]}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:eo,decorators:[{type:l,args:[{declarations:[Zt,Xt],imports:[w,F,Tt],exports:[Zt,Xt]}]}]});class to{constructor(e){!function(e){e.setTranslation("en_US",{tb:{rulenode:{"create-entity-if-not-exists":"Create new entity if not exists","create-entity-if-not-exists-hint":"Create a new entity set above if it does not exist.","entity-name-pattern":"Name pattern","entity-name-pattern-required":"Name pattern is required","entity-type-pattern":"Type pattern","entity-type-pattern-required":"Type pattern is required","entity-cache-expiration":"Entities cache expiration time (sec)","entity-cache-expiration-hint":"Specifies maximum time interval allowed to store found entity records. 0 value means that records will never expire.","entity-cache-expiration-required":"Entities cache expiration time is required.","entity-cache-expiration-range":"Entities cache expiration time should be greater than or equal to 0.","customer-name-pattern":"Customer name pattern","customer-name-pattern-required":"Customer name pattern is required","create-customer-if-not-exists":"Create new customer if not exists","customer-cache-expiration":"Customers cache expiration time (sec)","customer-cache-expiration-hint":"Specifies maximum time interval allowed to store found customer records. 0 value means that records will never expire.","customer-cache-expiration-required":"Customers cache expiration time is required.","customer-cache-expiration-range":"Customers cache expiration time should be greater than or equal to 0.","start-interval":"Start Interval","end-interval":"End Interval","start-interval-time-unit":"Start Interval Time Unit","end-interval-time-unit":"End Interval Time Unit","fetch-mode":"Fetch mode","fetch-mode-hint":"If selected fetch mode 'ALL' you able to choose telemetry sampling order.","order-by":"Order by","order-by-hint":"Select to choose telemetry sampling order.",limit:"Limit","limit-hint":"Min limit value is 2, max - 1000. In case you want to fetch a single entry, select fetch mode 'FIRST' or 'LAST'.","time-unit-milliseconds":"Milliseconds","time-unit-seconds":"Seconds","time-unit-minutes":"Minutes","time-unit-hours":"Hours","time-unit-days":"Days","time-value-range":"Time value should be in a range from 1 to 2147483647.","start-interval-value-required":"Start interval value is required.","end-interval-value-required":"End interval value is required.",filter:"Filter",switch:"Switch","message-type":"Message type","message-type-required":"Message type is required.","message-types-filter":"Message types filter","no-message-types-found":"No message types found","no-message-type-matching":"'{{messageType}}' not found.","create-new-message-type":"Create a new one!","message-types-required":"Message types are required.","client-attributes":"Client attributes","shared-attributes":"Shared attributes","server-attributes":"Server attributes","notify-device":"Notify Device","notify-device-hint":"If the message arrives from the device, we will push it back to the device by default.","latest-timeseries":"Latest timeseries","timeseries-key":"Timeseries key","data-keys":"Message data","metadata-keys":"Message metadata","relations-query":"Relations query","device-relations-query":"Device relations query","max-relation-level":"Max relation level","relation-type-pattern":"Relation type pattern","relation-type-pattern-required":"Relation type pattern is required","relation-types-list":"Relation types to propagate","relation-types-list-hint":"If Propagate relation types are not selected, alarms will be propagated without filtering by relation type.","unlimited-level":"Unlimited level","latest-telemetry":"Latest telemetry","attr-mapping":"Attributes mapping","source-attribute":"Source attribute","source-attribute-required":"Source attribute is required.","source-telemetry":"Source telemetry","source-telemetry-required":"Source telemetry is required.","target-attribute":"Target attribute","target-attribute-required":"Target attribute is required.","attr-mapping-required":"At least one attribute mapping should be specified.","fields-mapping":"Fields mapping","fields-mapping-required":"At least one field mapping should be specified.","source-field":"Source field","source-field-required":"Source field is required.","originator-source":"Originator source","originator-customer":"Customer","originator-tenant":"Tenant","originator-related":"Related","originator-alarm-originator":"Alarm Originator","clone-message":"Clone message",transform:"Transform","default-ttl":"Default TTL in seconds","default-ttl-required":"Default TTL is required.","min-default-ttl-message":"Only 0 minimum TTL is allowed.","message-count":"Message count (0 - unlimited)","message-count-required":"Message count is required.","min-message-count-message":"Only 0 minimum message count is allowed.","period-seconds":"Period in seconds","period-seconds-required":"Period is required.","use-metadata-period-in-seconds-patterns":"Use period in seconds pattern","use-metadata-period-in-seconds-patterns-hint":"If selected, rule node use period in seconds interval pattern from message metadata or data assuming that intervals are in the seconds.","period-in-seconds-pattern":"Period in seconds pattern","period-in-seconds-pattern-required":"Period in seconds pattern is required","min-period-seconds-message":"Only 1 second minimum period is allowed.",originator:"Originator","message-body":"Message body","message-metadata":"Message metadata",generate:"Generate","test-generator-function":"Test generator function",generator:"Generator","test-filter-function":"Test filter function","test-switch-function":"Test switch function","test-transformer-function":"Test transformer function",transformer:"Transformer","alarm-create-condition":"Alarm create condition","test-condition-function":"Test condition function","alarm-clear-condition":"Alarm clear condition","alarm-details-builder":"Alarm details builder","test-details-function":"Test details function","alarm-type":"Alarm type","alarm-type-required":"Alarm type is required.","alarm-severity":"Alarm severity","alarm-severity-required":"Alarm severity is required","alarm-status-filter":"Alarm status filter","alarm-status-list-empty":"Alarm status list is empty","no-alarm-status-matching":"No alarm status matching were found.",propagate:"Propagate",condition:"Condition",details:"Details","to-string":"To string","test-to-string-function":"Test to string function","from-template":"From Template","from-template-required":"From Template is required","to-template":"To Template","to-template-required":"To Template is required","mail-address-list-template-hint":'Comma separated address list, use ${metadataKey} for value from metadata, $[messageKey] for value from message body',"cc-template":"Cc Template","bcc-template":"Bcc Template","subject-template":"Subject Template","subject-template-required":"Subject Template is required","body-template":"Body Template","body-template-required":"Body Template is required","dynamic-mail-body-type":"Dynamic mail body type","mail-body-type":"Mail body type","request-id-metadata-attribute":"Request Id Metadata attribute name","timeout-sec":"Timeout in seconds","timeout-required":"Timeout is required","min-timeout-message":"Only 0 minimum timeout value is allowed.","endpoint-url-pattern":"Endpoint URL pattern","endpoint-url-pattern-required":"Endpoint URL pattern is required","request-method":"Request method","use-simple-client-http-factory":"Use simple client HTTP factory","ignore-request-body":"Without request body","read-timeout":"Read timeout in millis","read-timeout-hint":"The value of 0 means an infinite timeout","max-parallel-requests-count":"Max number of parallel requests","max-parallel-requests-count-hint":"The value of 0 specifies no limit in parallel processing",headers:"Headers","headers-hint":'Use ${metadataKey} for value from metadata, $[messageKey] for value from message body in header/value fields',header:"Header","header-required":"Header is required",value:"Value","value-required":"Value is required","topic-pattern":"Topic pattern","topic-pattern-required":"Topic pattern is required",topic:"Topic","topic-required":"Topic is required","bootstrap-servers":"Bootstrap servers","bootstrap-servers-required":"Bootstrap servers value is required","other-properties":"Other properties",key:"Key","key-required":"Key is required",retries:"Automatically retry times if fails","min-retries-message":"Only 0 minimum retries is allowed.","batch-size-bytes":"Produces batch size in bytes","min-batch-size-bytes-message":"Only 0 minimum batch size is allowed.","linger-ms":"Time to buffer locally (ms)","min-linger-ms-message":"Only 0 ms minimum value is allowed.","buffer-memory-bytes":"Client buffer max size in bytes","min-buffer-memory-message":"Only 0 minimum buffer size is allowed.",acks:"Number of acknowledgments","key-serializer":"Key serializer","key-serializer-required":"Key serializer is required","value-serializer":"Value serializer","value-serializer-required":"Value serializer is required","topic-arn-pattern":"Topic ARN pattern","topic-arn-pattern-required":"Topic ARN pattern is required","aws-access-key-id":"AWS Access Key ID","aws-access-key-id-required":"AWS Access Key ID is required","aws-secret-access-key":"AWS Secret Access Key","aws-secret-access-key-required":"AWS Secret Access Key is required","aws-region":"AWS Region","aws-region-required":"AWS Region is required","exchange-name-pattern":"Exchange name pattern","routing-key-pattern":"Routing key pattern","message-properties":"Message properties",host:"Host","host-required":"Host is required",port:"Port","port-required":"Port is required","port-range":"Port should be in a range from 1 to 65535.","virtual-host":"Virtual host",username:"Username",password:"Password","automatic-recovery":"Automatic recovery","connection-timeout-ms":"Connection timeout (ms)","min-connection-timeout-ms-message":"Only 0 ms minimum value is allowed.","handshake-timeout-ms":"Handshake timeout (ms)","min-handshake-timeout-ms-message":"Only 0 ms minimum value is allowed.","client-properties":"Client properties","queue-url-pattern":"Queue URL pattern","queue-url-pattern-required":"Queue URL pattern is required","delay-seconds":"Delay (seconds)","min-delay-seconds-message":"Only 0 seconds minimum value is allowed.","max-delay-seconds-message":"Only 900 seconds maximum value is allowed.",name:"Name","name-required":"Name is required","queue-type":"Queue type","sqs-queue-standard":"Standard","sqs-queue-fifo":"FIFO","gcp-project-id":"GCP project ID","gcp-project-id-required":"GCP project ID is required","gcp-service-account-key":"GCP service account key file","gcp-service-account-key-required":"GCP service account key file is required","pubsub-topic-name":"Topic name","pubsub-topic-name-required":"Topic name is required","message-attributes":"Message attributes","message-attributes-hint":'Use ${metadataKey} for value from metadata, $[messageKey] for value from message body in name/value fields',"connect-timeout":"Connection timeout (sec)","connect-timeout-required":"Connection timeout is required.","connect-timeout-range":"Connection timeout should be in a range from 1 to 200.","client-id":"Client ID","client-id-hint":"Hint: Optional. Leave empty for auto-generated client id. Be careful when specifying the Client ID.Majority of the MQTT brokers will not allow multiple connections with the same client id. To connect to such brokers, your mqtt client id must be unique. When platform is running in a micro-services mode, the copy of rule nodeis launched in each micro-service. This will automatically lead to multiple mqtt clients with the same id and may cause failures of the rule node.","device-id":"Device ID","device-id-required":"Device ID is required.","clean-session":"Clean session","enable-ssl":"Enable SSL",credentials:"Credentials","credentials-type":"Credentials type","credentials-type-required":"Credentials type is required.","credentials-anonymous":"Anonymous","credentials-basic":"Basic","credentials-pem":"PEM","credentials-pem-hint":"At least Server CA certificate file or a pair of Client certificate and Client private key files are required","credentials-sas":"Shared Access Signature","sas-key":"SAS Key","sas-key-required":"SAS Key is required.",hostname:"Hostname","hostname-required":"Hostname is required.","azure-ca-cert":"CA certificate file","username-required":"Username is required.","password-required":"Password is required.","ca-cert":"Server CA certificate file *","private-key":"Client private key file *",cert:"Client certificate file *","no-file":"No file selected.","drop-file":"Drop a file or click to select a file to upload.","private-key-password":"Private key password","use-system-smtp-settings":"Use system SMTP settings","use-metadata-interval-patterns":"Use interval patterns","use-metadata-interval-patterns-hint":"If selected, rule node use start and end interval patterns from message metadata or data assuming that intervals are in the milliseconds.","use-message-alarm-data":"Use message alarm data","use-dynamically-change-the-severity-of-alar":"Use dynamically change the severity of alarm","check-all-keys":"Check that all selected keys are present","check-all-keys-hint":"If selected, checks that all specified keys are present in the message data and metadata.","check-relation-to-specific-entity":"Check relation to specific entity","check-relation-hint":"Checks existence of relation to specific entity or to any entity based on direction and relation type.","delete-relation-to-specific-entity":"Delete relation to specific entity","delete-relation-hint":"Deletes relation from the originator of the incoming message to the specified entity or list of entities based on direction and type.","remove-current-relations":"Remove current relations","remove-current-relations-hint":"Removes current relations from the originator of the incoming message based on direction and type.","change-originator-to-related-entity":"Change originator to related entity","change-originator-to-related-entity-hint":"Used to process submitted message as a message from another entity.","start-interval-pattern":"Start interval pattern","end-interval-pattern":"End interval pattern","start-interval-pattern-required":"Start interval pattern is required","end-interval-pattern-required":"End interval pattern is required","smtp-protocol":"Protocol","smtp-host":"SMTP host","smtp-host-required":"SMTP host is required.","smtp-port":"SMTP port","smtp-port-required":"You must supply a smtp port.","smtp-port-range":"SMTP port should be in a range from 1 to 65535.","timeout-msec":"Timeout ms","min-timeout-msec-message":"Only 0 ms minimum value is allowed.","enter-username":"Enter username","enter-password":"Enter password","enable-tls":"Enable TLS","tls-version":"TLS version","enable-proxy":"Enable proxy","use-system-proxy-properties":"Use system proxy properties","proxy-host":"Proxy host","proxy-host-required":"Proxy host is required.","proxy-port":"Proxy port","proxy-port-required":"Proxy port is required.","proxy-port-range":"Proxy port should be in a range from 1 to 65535.","proxy-user":"Proxy user","proxy-password":"Proxy password","proxy-scheme":"Proxy scheme","numbers-to-template":"Phone Numbers To Template","numbers-to-template-required":"Phone Numbers To Template is required","numbers-to-template-hint":'Comma separated Phone Numbers, use ${metadataKey} for value from metadata, $[messageKey] for value from message body',"sms-message-template":"SMS message Template","sms-message-template-required":"SMS message Template is required","use-system-sms-settings":"Use system SMS provider settings","min-period-0-seconds-message":"Only 0 second minimum period is allowed.","max-pending-messages":"Maximum pending messages","max-pending-messages-required":"Maximum pending messages is required.","max-pending-messages-range":"Maximum pending messages should be in a range from 1 to 100000.","originator-types-filter":"Originator types filter","interval-seconds":"Interval in seconds","interval-seconds-required":"Interval is required.","min-interval-seconds-message":"Only 1 second minimum interval is allowed.","output-timeseries-key-prefix":"Output timeseries key prefix","output-timeseries-key-prefix-required":"Output timeseries key prefix required.","separator-hint":'You should press "enter" to complete field input.',"entity-details":"Select entity details:","entity-details-title":"Title","entity-details-country":"Country","entity-details-state":"State","entity-details-city":"City","entity-details-zip":"Zip","entity-details-address":"Address","entity-details-address2":"Address2","entity-details-additional_info":"Additional Info","entity-details-phone":"Phone","entity-details-email":"Email","add-to-metadata":"Add selected details to message metadata","add-to-metadata-hint":"If selected, adds the selected details keys to the message metadata instead of message data.","entity-details-list-empty":"No entity details selected.","no-entity-details-matching":"No entity details matching were found.","custom-table-name":"Custom table name","custom-table-name-required":"Table Name is required","custom-table-hint":"You should enter the table name without prefix 'cs_tb_'.","message-field":"Message field","message-field-required":"Message field is required.","table-col":"Table column","table-col-required":"Table column is required.","latitude-key-name":"Latitude key name","longitude-key-name":"Longitude key name","latitude-key-name-required":"Latitude key name is required.","longitude-key-name-required":"Longitude key name is required.","fetch-perimeter-info-from-message-metadata":"Fetch perimeter information from message metadata","perimeter-circle":"Circle","perimeter-polygon":"Polygon","perimeter-type":"Perimeter type","circle-center-latitude":"Center latitude","circle-center-latitude-required":"Center latitude is required.","circle-center-longitude":"Center longitude","circle-center-longitude-required":"Center longitude is required.","range-unit-meter":"Meter","range-unit-kilometer":"Kilometer","range-unit-foot":"Foot","range-unit-mile":"Mile","range-unit-nautical-mile":"Nautical mile","range-units":"Range units",range:"Range","range-required":"Range is required.","polygon-definition":"Polygon definition","polygon-definition-required":"Polygon definition is required.","polygon-definition-hint":"Please, use the following format for manual definition of polygon: [[lat1,lon1],[lat2,lon2], ... ,[latN,lonN]].","min-inside-duration":"Minimal inside duration","min-inside-duration-value-required":"Minimal inside duration is required","min-inside-duration-time-unit":"Minimal inside duration time unit","min-outside-duration":"Minimal outside duration","min-outside-duration-value-required":"Minimal outside duration is required","min-outside-duration-time-unit":"Minimal outside duration time unit","tell-failure-if-absent":"Tell Failure","tell-failure-if-absent-hint":'If at least one selected key doesn\'t exist the outbound message will report "Failure".',"get-latest-value-with-ts":"Fetch Latest telemetry with Timestamp","get-latest-value-with-ts-hint":'If selected, latest telemetry values will be added to the outbound message metadata with timestamp, e.g: "temp": "{"ts":1574329385897, "value":42}"',"use-redis-queue":"Use redis queue for message persistence","trim-redis-queue":"Trim redis queue","redis-queue-max-size":"Redis queue max size","add-metadata-key-values-as-kafka-headers":"Add Message metadata key-value pairs to Kafka record headers","add-metadata-key-values-as-kafka-headers-hint":"If selected, key-value pairs from message metadata will be added to the outgoing records headers as byte arrays with predefined charset encoding.","charset-encoding":"Charset encoding","charset-encoding-required":"Charset encoding is required.","charset-us-ascii":"US-ASCII","charset-iso-8859-1":"ISO-8859-1","charset-utf-8":"UTF-8","charset-utf-16be":"UTF-16BE","charset-utf-16le":"UTF-16LE","charset-utf-16":"UTF-16","select-queue-hint":"The queue name can be selected from a drop-down list or add a custom name.","persist-alarm-rules":"Persist state of alarm rules","fetch-alarm-rules":"Fetch state of alarm rules","input-value-key":"Input value key","input-value-key-required":"Input value key is required.","output-value-key":"Output value key","output-value-key-required":"Output value key is required.",round:"Decimals","round-range":"Decimals should be in a range from 0 to 15.","use-cache":"Use cache for latest value","tell-failure-if-delta-is-negative":"Tell Failure if delta is negative","add-period-between-msgs":"Add period between messages","period-value-key":"Period value key","period-key-required":"Period value key is required.","general-pattern-hint":'Hint: use ${metadataKey} for value from metadata, $[messageKey] for value from message body',"alarm-severity-pattern-hint":'Hint: use ${metadataKey} for value from metadata, $[messageKey] for value from message body. Alarm severity should be system (CRITICAL, MAJOR etc.)',"output-node-name-hint":"The rule node name corresponds to the relation type of the output message, and it is used to forward messages to other rule nodes in the caller rule chain."},"key-val":{key:"Key",value:"Value","remove-entry":"Remove entry","add-entry":"Add entry"},"mail-body-type":{"plain-text":"Plain Text",html:"HTML",dynamic:"Dynamic"}}},!0)}(e)}}to.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:to,deps:[{token:E.TranslateService}],target:e.ɵɵFactoryTarget.NgModule}),to.ɵmod=e.ɵɵngDeclareNgModule({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:to,declarations:[ve],imports:[w,F],exports:[kt,Qt,wt,Jt,eo,ve]}),to.ɵinj=e.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:to,imports:[[w,F],kt,Qt,wt,Jt,eo]}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:to,decorators:[{type:l,args:[{declarations:[ve],imports:[w,F],exports:[kt,Qt,wt,Jt,eo,ve]}]}],ctorParameters:function(){return[{type:E.TranslateService}]}});export{Ne as AssignCustomerConfigComponent,qe as AttributesConfigComponent,$e as AzureIotHubConfigComponent,Mt as CalculateDeltaConfigComponent,$t as ChangeOriginatorConfigComponent,Ot as CheckAlarmStatusComponent,Ht as CheckMessageConfigComponent,We as CheckPointConfigComponent,Ut as CheckRelationConfigComponent,Ye as ClearAlarmConfigComponent,Je as CreateAlarmConfigComponent,Ze as CreateRelationConfigComponent,lt as CredentialsConfigComponent,St as CustomerAttributesConfigComponent,Xe as DeleteRelationConfigComponent,At as DeviceAttributesConfigComponent,et as DeviceProfileConfigComponent,It as DeviceRelationsQueryConfigComponent,ve as EmptyConfigComponent,Gt as EntityDetailsConfigComponent,tt as GeneratorConfigComponent,Dt as GetTelemetryFromDatabaseConfigComponent,ot as GpsGeoActionConfigComponent,Bt as GpsGeoFilterConfigComponent,at as KafkaConfigComponent,rt as KvMapConfigComponent,nt as LogConfigComponent,Kt as MessageTypeConfigComponent,qt as MessageTypesConfigComponent,it as MqttConfigComponent,st as MsgCountConfigComponent,mt as MsgDelayConfigComponent,Vt as OriginatorAttributesConfigComponent,Et as OriginatorFieldsConfigComponent,jt as OriginatorTypeConfigComponent,ut as PubSubConfigComponent,pt as PushToCloudConfigComponent,dt as PushToEdgeConfigComponent,ft as RabbitMqConfigComponent,Pt as RelatedAttributesConfigComponent,Nt as RelationsQueryConfigComponent,ct as RestApiCallConfigComponent,gt as RpcReplyConfigComponent,xt as RpcRequestConfigComponent,Zt as RuleChainInputComponent,Xt as RuleChainOutputComponent,kt as RuleNodeCoreConfigActionModule,Qt as RuleNodeCoreConfigFilterModule,eo as RuleNodeCoreConfigFlowModule,to as RuleNodeCoreConfigModule,Tt as RulenodeCoreConfigCommonModule,wt as RulenodeCoreConfigEnrichmentModule,Jt as RulenodeCoreConfigTransformModule,Ie as SafeHtmlPipe,yt as SaveToCustomTableConfigComponent,zt as ScriptConfigComponent,bt as SendEmailConfigComponent,ht as SendSmsConfigComponent,Ft as SnsConfigComponent,Ct as SqsConfigComponent,_t as SwitchConfigComponent,Rt as TenantAttributesConfigComponent,Lt as TimeseriesConfigComponent,Yt as ToEmailConfigComponent,Wt as TransformScriptConfigComponent,vt as UnassignCustomerConfigComponent};//# sourceMappingURL=rulenode-core-config.js.map From b79c2407c49aceb814a17d5a6e99198c5119d020 Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Tue, 14 Dec 2021 09:12:25 +0200 Subject: [PATCH 262/432] ts notification --- .../controller/TelemetryController.java | 7 ++-- .../queue/DefaultTbCoreConsumerService.java | 11 ++++-- .../DefaultSubscriptionManagerService.java | 34 ++++++++++++++++--- .../SubscriptionManagerService.java | 2 ++ .../subscription/TbSubscriptionUtils.java | 22 +++++++++--- .../DefaultTelemetrySubscriptionService.java | 22 ++++++++++++ common/cluster-api/src/main/proto/queue.proto | 10 ++++++ .../common/data/kv/BaseDeleteTsKvQuery.java | 4 ++- .../api/RuleEngineTelemetryService.java | 3 +- 9 files changed, 99 insertions(+), 16 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/TelemetryController.java b/application/src/main/java/org/thingsboard/server/controller/TelemetryController.java index 7a6a1620ae..70a6b029ed 100644 --- a/application/src/main/java/org/thingsboard/server/controller/TelemetryController.java +++ b/application/src/main/java/org/thingsboard/server/controller/TelemetryController.java @@ -573,10 +573,9 @@ public class TelemetryController extends BaseController { for (String key : keys) { deleteTsKvQueries.add(new BaseDeleteTsKvQuery(key, deleteFromTs, deleteToTs, rewriteLatestIfDeleted)); } - ListenableFuture> future = tsService.remove(user.getTenantId(), entityId, deleteTsKvQueries); - Futures.addCallback(future, new FutureCallback<>() { + tsSubService.deleteTimeseriesAndNotify(tenantId, entityId, keys, deleteTsKvQueries, new FutureCallback<>() { @Override - public void onSuccess(@Nullable List tmp) { + public void onSuccess(@Nullable Void tmp) { logTimeseriesDeleted(user, entityId, keys, deleteFromTs, deleteToTs, null); result.setResult(new ResponseEntity<>(HttpStatus.OK)); } @@ -586,7 +585,7 @@ public class TelemetryController extends BaseController { logTimeseriesDeleted(user, entityId, keys, deleteFromTs, deleteToTs, t); result.setResult(new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR)); } - }, executor); + }); }); } diff --git a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbCoreConsumerService.java b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbCoreConsumerService.java index ad7a0340cf..3602aa804e 100644 --- a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbCoreConsumerService.java +++ b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbCoreConsumerService.java @@ -26,14 +26,15 @@ import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.common.util.ThingsBoardThreadFactory; -import org.thingsboard.server.common.data.rpc.RpcError; import org.thingsboard.server.actors.ActorSystemContext; import org.thingsboard.server.common.data.alarm.Alarm; import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.rpc.RpcError; import org.thingsboard.server.common.msg.MsgType; import org.thingsboard.server.common.msg.TbActorMsg; import org.thingsboard.server.common.msg.queue.ServiceType; import org.thingsboard.server.common.msg.queue.TbCallback; +import org.thingsboard.server.common.msg.rpc.FromDeviceRpcResponse; import org.thingsboard.server.common.stats.StatsFactory; import org.thingsboard.server.common.transport.util.DataDecodingEncodingService; import org.thingsboard.server.dao.tenant.TbTenantProfileCache; @@ -47,6 +48,7 @@ import org.thingsboard.server.gen.transport.TransportProtos.TbAlarmUpdateProto; import org.thingsboard.server.gen.transport.TransportProtos.TbAttributeDeleteProto; import org.thingsboard.server.gen.transport.TransportProtos.TbAttributeUpdateProto; import org.thingsboard.server.gen.transport.TransportProtos.TbSubscriptionCloseProto; +import org.thingsboard.server.gen.transport.TransportProtos.TbTimeSeriesDeleteProto; import org.thingsboard.server.gen.transport.TransportProtos.TbTimeSeriesUpdateProto; import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToCoreNotificationMsg; @@ -64,7 +66,6 @@ import org.thingsboard.server.service.ota.OtaPackageStateService; import org.thingsboard.server.service.profile.TbDeviceProfileCache; import org.thingsboard.server.service.queue.processing.AbstractConsumerService; import org.thingsboard.server.service.queue.processing.IdMsgPair; -import org.thingsboard.server.common.msg.rpc.FromDeviceRpcResponse; import org.thingsboard.server.service.rpc.TbCoreDeviceRpcService; import org.thingsboard.server.service.rpc.ToDeviceRpcRequestActorMsg; import org.thingsboard.server.service.state.DeviceStateService; @@ -467,6 +468,12 @@ public class DefaultTbCoreConsumerService extends AbstractConsumerService keys, TbCallback callback) { + onLocalTelemetrySubUpdate(entityId, + s -> { + if (TbSubscriptionType.TIMESERIES.equals(s.getType())) { + return (TbTimeseriesSubscription) s; + } else { + return null; + } + }, s -> true, s -> { + List subscriptionUpdate = null; + for (String key : keys) { + if (s.isAllKeys() || s.getKeyStates().containsKey(key)) { + if (subscriptionUpdate == null) { + subscriptionUpdate = new ArrayList<>(); + } + subscriptionUpdate.add(new BasicTsKvEntry(0, new StringDataEntry(key, null))); + } + } + return subscriptionUpdate; + }, false); + callback.onSuccess(); + } + private void onLocalTelemetrySubUpdate(EntityId entityId, Function castFunction, Predicate filterFunction, diff --git a/application/src/main/java/org/thingsboard/server/service/subscription/SubscriptionManagerService.java b/application/src/main/java/org/thingsboard/server/service/subscription/SubscriptionManagerService.java index 37850b701f..67f2e10614 100644 --- a/application/src/main/java/org/thingsboard/server/service/subscription/SubscriptionManagerService.java +++ b/application/src/main/java/org/thingsboard/server/service/subscription/SubscriptionManagerService.java @@ -40,6 +40,8 @@ public interface SubscriptionManagerService extends ApplicationListener keys, TbCallback empty); + void onTimeSeriesDelete(TenantId tenantId, EntityId entityId, List keys, TbCallback callback); + void onAlarmUpdate(TenantId tenantId, EntityId entityId, Alarm alarm, TbCallback callback); void onAlarmDeleted(TenantId tenantId, EntityId entityId, Alarm alarm, TbCallback callback); diff --git a/application/src/main/java/org/thingsboard/server/service/subscription/TbSubscriptionUtils.java b/application/src/main/java/org/thingsboard/server/service/subscription/TbSubscriptionUtils.java index 25b67d3a06..82e0b17f67 100644 --- a/application/src/main/java/org/thingsboard/server/service/subscription/TbSubscriptionUtils.java +++ b/application/src/main/java/org/thingsboard/server/service/subscription/TbSubscriptionUtils.java @@ -15,6 +15,7 @@ */ package org.thingsboard.server.service.subscription; +import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.alarm.Alarm; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.EntityIdFactory; @@ -30,25 +31,25 @@ import org.thingsboard.server.common.data.kv.KvEntry; import org.thingsboard.server.common.data.kv.LongDataEntry; import org.thingsboard.server.common.data.kv.StringDataEntry; import org.thingsboard.server.common.data.kv.TsKvEntry; -import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.gen.transport.TransportProtos.KeyValueProto; import org.thingsboard.server.gen.transport.TransportProtos.KeyValueType; import org.thingsboard.server.gen.transport.TransportProtos.SubscriptionMgrMsgProto; +import org.thingsboard.server.gen.transport.TransportProtos.TbAlarmDeleteProto; +import org.thingsboard.server.gen.transport.TransportProtos.TbAlarmUpdateProto; +import org.thingsboard.server.gen.transport.TransportProtos.TbAttributeDeleteProto; import org.thingsboard.server.gen.transport.TransportProtos.TbAttributeSubscriptionProto; import org.thingsboard.server.gen.transport.TransportProtos.TbAttributeUpdateProto; -import org.thingsboard.server.gen.transport.TransportProtos.TbAttributeDeleteProto; import org.thingsboard.server.gen.transport.TransportProtos.TbSubscriptionCloseProto; import org.thingsboard.server.gen.transport.TransportProtos.TbSubscriptionKetStateProto; import org.thingsboard.server.gen.transport.TransportProtos.TbSubscriptionProto; import org.thingsboard.server.gen.transport.TransportProtos.TbSubscriptionUpdateProto; import org.thingsboard.server.gen.transport.TransportProtos.TbSubscriptionUpdateTsValue; +import org.thingsboard.server.gen.transport.TransportProtos.TbTimeSeriesDeleteProto; import org.thingsboard.server.gen.transport.TransportProtos.TbTimeSeriesSubscriptionProto; import org.thingsboard.server.gen.transport.TransportProtos.TbTimeSeriesUpdateProto; import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg; import org.thingsboard.server.gen.transport.TransportProtos.TsKvProto; -import org.thingsboard.server.gen.transport.TransportProtos.TbAlarmUpdateProto; -import org.thingsboard.server.gen.transport.TransportProtos.TbAlarmDeleteProto; import org.thingsboard.server.service.telemetry.sub.AlarmSubscriptionUpdate; import org.thingsboard.server.service.telemetry.sub.SubscriptionErrorCode; import org.thingsboard.server.service.telemetry.sub.TelemetrySubscriptionUpdate; @@ -207,6 +208,19 @@ public class TbSubscriptionUtils { return ToCoreMsg.newBuilder().setToSubscriptionMgrMsg(msgBuilder.build()).build(); } + public static ToCoreMsg toTimeseriesDeleteProto(TenantId tenantId, EntityId entityId, List keys) { + TbTimeSeriesDeleteProto.Builder builder = TbTimeSeriesDeleteProto.newBuilder(); + builder.setEntityType(entityId.getEntityType().name()); + builder.setEntityIdMSB(entityId.getId().getMostSignificantBits()); + builder.setEntityIdLSB(entityId.getId().getLeastSignificantBits()); + builder.setTenantIdMSB(tenantId.getId().getMostSignificantBits()); + builder.setTenantIdLSB(tenantId.getId().getLeastSignificantBits()); + builder.addAllKeys(keys); + SubscriptionMgrMsgProto.Builder msgBuilder = SubscriptionMgrMsgProto.newBuilder(); + msgBuilder.setTsDelete(builder); + return ToCoreMsg.newBuilder().setToSubscriptionMgrMsg(msgBuilder.build()).build(); + } + public static ToCoreMsg toAttributesUpdateProto(TenantId tenantId, EntityId entityId, String scope, List attributes) { TbAttributeUpdateProto.Builder builder = TbAttributeUpdateProto.newBuilder(); builder.setEntityType(entityId.getEntityType().name()); diff --git a/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetrySubscriptionService.java b/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetrySubscriptionService.java index a3771988cf..dba664013d 100644 --- a/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetrySubscriptionService.java +++ b/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetrySubscriptionService.java @@ -31,6 +31,7 @@ import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.kv.AttributeKvEntry; import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry; import org.thingsboard.server.common.data.kv.BooleanDataEntry; +import org.thingsboard.server.common.data.kv.DeleteTsKvQuery; import org.thingsboard.server.common.data.kv.DoubleDataEntry; import org.thingsboard.server.common.data.kv.LongDataEntry; import org.thingsboard.server.common.data.kv.StringDataEntry; @@ -271,6 +272,13 @@ public class DefaultTelemetrySubscriptionService extends AbstractSubscriptionSer }, tsCallBackExecutor); } + @Override + public void deleteTimeseriesAndNotify(TenantId tenantId, EntityId entityId, List keys, List deleteTsKvQueries, FutureCallback callback) { + ListenableFuture> deleteFuture = tsService.remove(tenantId, entityId, deleteTsKvQueries); + addVoidCallback(deleteFuture, callback); + addWsCallback(deleteFuture, success -> onTimeSeriesDelete(tenantId, entityId, keys)); + } + @Override public void saveAttrAndNotify(TenantId tenantId, EntityId entityId, String scope, String key, long value, FutureCallback callback) { saveAndNotify(tenantId, entityId, scope, Collections.singletonList(new BaseAttributeKvEntry(new LongDataEntry(key, value) @@ -337,6 +345,20 @@ public class DefaultTelemetrySubscriptionService extends AbstractSubscriptionSer } } + private void onTimeSeriesDelete(TenantId tenantId, EntityId entityId, List keys) { + TopicPartitionInfo tpi = partitionService.resolve(ServiceType.TB_CORE, tenantId, entityId); + if (currentPartitions.contains(tpi)) { + if (subscriptionManagerService.isPresent()) { + subscriptionManagerService.get().onTimeSeriesDelete(tenantId, entityId, keys, TbCallback.EMPTY); + } else { + log.warn("Possible misconfiguration because subscriptionManagerService is null!"); + } + } else { + TransportProtos.ToCoreMsg toCoreMsg = TbSubscriptionUtils.toTimeseriesDeleteProto(tenantId, entityId, keys); + clusterService.pushMsgToCore(tpi, entityId.getId(), toCoreMsg, null); + } + } + private void addVoidCallback(ListenableFuture saveFuture, final FutureCallback callback) { Futures.addCallback(saveFuture, new FutureCallback() { @Override diff --git a/common/cluster-api/src/main/proto/queue.proto b/common/cluster-api/src/main/proto/queue.proto index dca92c1c7a..d576f38340 100644 --- a/common/cluster-api/src/main/proto/queue.proto +++ b/common/cluster-api/src/main/proto/queue.proto @@ -561,6 +561,15 @@ message TbAttributeDeleteProto { repeated string keys = 7; } +message TbTimeSeriesDeleteProto { + string entityType = 1; + int64 entityIdMSB = 2; + int64 entityIdLSB = 3; + int64 tenantIdMSB = 4; + int64 tenantIdLSB = 5; + repeated string keys = 6; +} + message TbTimeSeriesUpdateProto { string entityType = 1; int64 entityIdMSB = 2; @@ -614,6 +623,7 @@ message SubscriptionMgrMsgProto { TbAlarmSubscriptionProto alarmSub = 7; TbAlarmUpdateProto alarmUpdate = 8; TbAlarmDeleteProto alarmDelete = 9; + TbTimeSeriesDeleteProto tsDelete = 10; } message LocalSubscriptionServiceMsgProto { diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/kv/BaseDeleteTsKvQuery.java b/common/data/src/main/java/org/thingsboard/server/common/data/kv/BaseDeleteTsKvQuery.java index 6c9dfbd198..3ffedaa69a 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/kv/BaseDeleteTsKvQuery.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/kv/BaseDeleteTsKvQuery.java @@ -31,5 +31,7 @@ public class BaseDeleteTsKvQuery extends BaseTsKvQuery implements DeleteTsKvQuer this(key, startTs, endTs, false); } - + public Boolean getRewriteLatestIfDeleted() { + return rewriteLatestIfDeleted; + } } diff --git a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/RuleEngineTelemetryService.java b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/RuleEngineTelemetryService.java index e641c83144..a19d0fad0c 100644 --- a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/RuleEngineTelemetryService.java +++ b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/RuleEngineTelemetryService.java @@ -20,6 +20,7 @@ import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.kv.AttributeKvEntry; +import org.thingsboard.server.common.data.kv.DeleteTsKvQuery; import org.thingsboard.server.common.data.kv.TsKvEntry; import java.util.Collection; @@ -54,5 +55,5 @@ public interface RuleEngineTelemetryService { void deleteAllLatest(TenantId tenantId, EntityId entityId, FutureCallback> callback); - + void deleteTimeseriesAndNotify(TenantId tenantId, EntityId entityId, List keys, List deleteTsKvQueries, FutureCallback callback); } From 7072713f129125bba15838edd5437b76d0497d57 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Fri, 17 Dec 2021 13:22:53 +0200 Subject: [PATCH 263/432] Update rule nodes UI js --- .../resources/public/static/rulenode/rulenode-core-config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rule-engine/rule-engine-components/src/main/resources/public/static/rulenode/rulenode-core-config.js b/rule-engine/rule-engine-components/src/main/resources/public/static/rulenode/rulenode-core-config.js index 0720bb79c4..7e4ce0b702 100644 --- a/rule-engine/rule-engine-components/src/main/resources/public/static/rulenode/rulenode-core-config.js +++ b/rule-engine/rule-engine-components/src/main/resources/public/static/rulenode/rulenode-core-config.js @@ -1 +1 @@ -import*as e from"@angular/core";import{Component as t,Pipe as o,ViewChild as r,forwardRef as a,Input as n,NgModule as l}from"@angular/core";import*as i from"@shared/public-api";import{RuleNodeConfigurationComponent as s,AttributeScope as m,telemetryTypeTranslations as u,ServiceType as p,AlarmSeverity as d,alarmSeverityTranslations as f,EntitySearchDirection as c,entitySearchDirectionTranslations as g,EntityType as x,PageComponent as y,MessageType as b,messageTypeNames as h,SharedModule as F,AggregationType as C,aggregationTranslations as L,alarmStatusTranslations as v,AlarmStatus as I}from"@shared/public-api";import*as N from"@ngrx/store";import*as q from"@angular/forms";import{Validators as T,NgControl as k,NG_VALUE_ACCESSOR as M,NG_VALIDATORS as S,FormControl as A}from"@angular/forms";import*as G from"@angular/material/form-field";import*as D from"@angular/material/checkbox";import*as V from"@angular/flex-layout/flex";import*as E from"@ngx-translate/core";import*as P from"@angular/material/input";import*as R from"@angular/common";import{CommonModule as w}from"@angular/common";import*as O from"@angular/platform-browser";import*as H from"@angular/material/select";import*as U from"@angular/material/core";import*as B from"@angular/material/expansion";import*as K from"@shared/components/button/toggle-password.component";import*as j from"@shared/components/file-input.component";import*as z from"@shared/components/queue/queue-type-list.component";import*as _ from"@core/public-api";import{isDefinedAndNotNull as Q}from"@core/public-api";import*as $ from"@shared/components/js-func.component";import*as W from"@angular/material/button";import{ENTER as Y,COMMA as J,SEMICOLON as Z}from"@angular/cdk/keycodes";import*as X from"@angular/material/chips";import*as ee from"@angular/material/icon";import*as te from"@shared/components/entity/entity-type-select.component";import*as oe from"@shared/components/entity/entity-select.component";import{coerceBooleanProperty as re}from"@angular/cdk/coercion";import*as ae from"@shared/components/tb-error.component";import*as ne from"@angular/flex-layout/extended";import*as le from"@angular/material/tooltip";import{distinctUntilChanged as ie,startWith as se,map as me,mergeMap as ue,share as pe}from"rxjs/operators";import*as de from"@shared/components/tb-checkbox.component";import*as fe from"@home/components/sms/sms-provider-configuration.component";import{HomeComponentsModule as ce}from"@home/components/public-api";import*as ge from"@shared/components/relation/relation-type-autocomplete.component";import*as xe from"@shared/components/entity/entity-subtype-list.component";import*as ye from"@home/components/relation/relation-filters.component";import{of as be}from"rxjs";import*as he from"@angular/material/autocomplete";import*as Fe from"@shared/pipe/highlight.pipe";import*as Ce from"@shared/components/entity/entity-autocomplete.component";import*as Le from"@shared/components/entity/entity-type-list.component";class ve extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.emptyConfigForm}onConfigurationSet(e){this.emptyConfigForm=this.fb.group({})}}ve.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:ve,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),ve.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:ve,selector:"tb-node-empty-config",usesInheritance:!0,ngImport:e,template:"
",isInline:!0}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:ve,decorators:[{type:t,args:[{selector:"tb-node-empty-config",template:"
",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class Ie{constructor(e){this.sanitizer=e}transform(e){return this.sanitizer.bypassSecurityTrustHtml(e)}}Ie.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Ie,deps:[{token:O.DomSanitizer}],target:e.ɵɵFactoryTarget.Pipe}),Ie.ɵpipe=e.ɵɵngDeclarePipe({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Ie,name:"safeHtml"}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Ie,decorators:[{type:o,args:[{name:"safeHtml"}]}],ctorParameters:function(){return[{type:O.DomSanitizer}]}});class Ne extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.assignCustomerConfigForm}onConfigurationSet(e){this.assignCustomerConfigForm=this.fb.group({customerNamePattern:[e?e.customerNamePattern:null,[T.required,T.pattern(/.*\S.*/)]],createCustomerIfNotExists:[!!e&&e.createCustomerIfNotExists,[]],customerCacheExpiration:[e?e.customerCacheExpiration:null,[T.required,T.min(0)]]})}prepareOutputConfig(e){return e.customerNamePattern=e.customerNamePattern.trim(),e}}Ne.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Ne,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),Ne.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Ne,selector:"tb-action-node-assign-to-customer-config",usesInheritance:!0,ngImport:e,template:'
\n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.create-customer-if-not-exists\' | translate }}\n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n tb.rulenode.customer-cache-expiration-hint\n \n
\n',components:[{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:D.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:G.MatLabel,selector:"mat-label"},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:G.MatError,selector:"mat-error",inputs:["id"]},{type:G.MatHint,selector:"mat-hint",inputs:["align","id"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"}],pipes:{translate:E.TranslatePipe,safeHtml:Ie}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Ne,decorators:[{type:t,args:[{selector:"tb-action-node-assign-to-customer-config",templateUrl:"./assign-customer-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class qe extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.attributeScopes=Object.keys(m),this.telemetryTypeTranslationsMap=u}configForm(){return this.attributesConfigForm}onConfigurationSet(e){this.attributesConfigForm=this.fb.group({scope:[e?e.scope:null,[T.required]],notifyDevice:[!e||e.scope,[]]})}}var Te;qe.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:qe,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),qe.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:qe,selector:"tb-action-node-attributes-config",usesInheritance:!0,ngImport:e,template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.notify-device\' | translate }}\n \n
tb.rulenode.notify-device-hint
\n
\n
\n',components:[{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:H.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:U.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:D.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:G.MatLabel,selector:"mat-label"},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]}],pipes:{translate:E.TranslatePipe}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:qe,decorators:[{type:t,args:[{selector:"tb-action-node-attributes-config",templateUrl:"./attributes-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}}),function(e){e.CUSTOMER="CUSTOMER",e.TENANT="TENANT",e.RELATED="RELATED",e.ALARM_ORIGINATOR="ALARM_ORIGINATOR"}(Te||(Te={}));const ke=new Map([[Te.CUSTOMER,"tb.rulenode.originator-customer"],[Te.TENANT,"tb.rulenode.originator-tenant"],[Te.RELATED,"tb.rulenode.originator-related"],[Te.ALARM_ORIGINATOR,"tb.rulenode.originator-alarm-originator"]]);var Me;!function(e){e.CIRCLE="CIRCLE",e.POLYGON="POLYGON"}(Me||(Me={}));const Se=new Map([[Me.CIRCLE,"tb.rulenode.perimeter-circle"],[Me.POLYGON,"tb.rulenode.perimeter-polygon"]]);var Ae;!function(e){e.MILLISECONDS="MILLISECONDS",e.SECONDS="SECONDS",e.MINUTES="MINUTES",e.HOURS="HOURS",e.DAYS="DAYS"}(Ae||(Ae={}));const Ge=new Map([[Ae.MILLISECONDS,"tb.rulenode.time-unit-milliseconds"],[Ae.SECONDS,"tb.rulenode.time-unit-seconds"],[Ae.MINUTES,"tb.rulenode.time-unit-minutes"],[Ae.HOURS,"tb.rulenode.time-unit-hours"],[Ae.DAYS,"tb.rulenode.time-unit-days"]]);var De;!function(e){e.METER="METER",e.KILOMETER="KILOMETER",e.FOOT="FOOT",e.MILE="MILE",e.NAUTICAL_MILE="NAUTICAL_MILE"}(De||(De={}));const Ve=new Map([[De.METER,"tb.rulenode.range-unit-meter"],[De.KILOMETER,"tb.rulenode.range-unit-kilometer"],[De.FOOT,"tb.rulenode.range-unit-foot"],[De.MILE,"tb.rulenode.range-unit-mile"],[De.NAUTICAL_MILE,"tb.rulenode.range-unit-nautical-mile"]]);var Ee;!function(e){e.TITLE="TITLE",e.COUNTRY="COUNTRY",e.STATE="STATE",e.CITY="CITY",e.ZIP="ZIP",e.ADDRESS="ADDRESS",e.ADDRESS2="ADDRESS2",e.PHONE="PHONE",e.EMAIL="EMAIL",e.ADDITIONAL_INFO="ADDITIONAL_INFO"}(Ee||(Ee={}));const Pe=new Map([[Ee.TITLE,"tb.rulenode.entity-details-title"],[Ee.COUNTRY,"tb.rulenode.entity-details-country"],[Ee.STATE,"tb.rulenode.entity-details-state"],[Ee.CITY,"tb.rulenode.entity-details-city"],[Ee.ZIP,"tb.rulenode.entity-details-zip"],[Ee.ADDRESS,"tb.rulenode.entity-details-address"],[Ee.ADDRESS2,"tb.rulenode.entity-details-address2"],[Ee.PHONE,"tb.rulenode.entity-details-phone"],[Ee.EMAIL,"tb.rulenode.entity-details-email"],[Ee.ADDITIONAL_INFO,"tb.rulenode.entity-details-additional_info"]]);var Re,we,Oe;!function(e){e.FIRST="FIRST",e.LAST="LAST",e.ALL="ALL"}(Re||(Re={})),function(e){e.ASC="ASC",e.DESC="DESC"}(we||(we={})),function(e){e.STANDARD="STANDARD",e.FIFO="FIFO"}(Oe||(Oe={}));const He=new Map([[Oe.STANDARD,"tb.rulenode.sqs-queue-standard"],[Oe.FIFO,"tb.rulenode.sqs-queue-fifo"]]),Ue=["anonymous","basic","cert.PEM"],Be=new Map([["anonymous","tb.rulenode.credentials-anonymous"],["basic","tb.rulenode.credentials-basic"],["cert.PEM","tb.rulenode.credentials-pem"]]),Ke=["sas","cert.PEM"],je=new Map([["sas","tb.rulenode.credentials-sas"],["cert.PEM","tb.rulenode.credentials-pem"]]);var ze;!function(e){e.GET="GET",e.POST="POST",e.PUT="PUT",e.DELETE="DELETE"}(ze||(ze={}));const _e=["US-ASCII","ISO-8859-1","UTF-8","UTF-16BE","UTF-16LE","UTF-16"],Qe=new Map([["US-ASCII","tb.rulenode.charset-us-ascii"],["ISO-8859-1","tb.rulenode.charset-iso-8859-1"],["UTF-8","tb.rulenode.charset-utf-8"],["UTF-16BE","tb.rulenode.charset-utf-16be"],["UTF-16LE","tb.rulenode.charset-utf-16le"],["UTF-16","tb.rulenode.charset-utf-16"]]);class $e extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.allAzureIotHubCredentialsTypes=Ke,this.azureIotHubCredentialsTypeTranslationsMap=je}configForm(){return this.azureIotHubConfigForm}onConfigurationSet(e){this.azureIotHubConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[T.required]],host:[e?e.host:null,[T.required]],port:[e?e.port:null,[T.required,T.min(1),T.max(65535)]],connectTimeoutSec:[e?e.connectTimeoutSec:null,[T.required,T.min(1),T.max(200)]],clientId:[e?e.clientId:null,[T.required]],cleanSession:[!!e&&e.cleanSession,[]],ssl:[!!e&&e.ssl,[]],credentials:this.fb.group({type:[e&&e.credentials?e.credentials.type:null,[T.required]],sasKey:[e&&e.credentials?e.credentials.sasKey:null,[]],caCert:[e&&e.credentials?e.credentials.caCert:null,[]],caCertFileName:[e&&e.credentials?e.credentials.caCertFileName:null,[]],privateKey:[e&&e.credentials?e.credentials.privateKey:null,[]],privateKeyFileName:[e&&e.credentials?e.credentials.privateKeyFileName:null,[]],cert:[e&&e.credentials?e.credentials.cert:null,[]],certFileName:[e&&e.credentials?e.credentials.certFileName:null,[]],password:[e&&e.credentials?e.credentials.password:null,[]]})})}prepareOutputConfig(e){const t=e.credentials.type;return"sas"===t&&(e.credentials={type:t,sasKey:e.credentials.sasKey,caCert:e.credentials.caCert,caCertFileName:e.credentials.caCertFileName}),e}validatorTriggers(){return["credentials.type"]}updateValidators(e){const t=this.azureIotHubConfigForm.get("credentials"),o=t.get("type").value;switch(e&&t.reset({type:o},{emitEvent:!1}),t.get("sasKey").setValidators([]),t.get("privateKey").setValidators([]),t.get("privateKeyFileName").setValidators([]),t.get("cert").setValidators([]),t.get("certFileName").setValidators([]),o){case"sas":t.get("sasKey").setValidators([T.required]);break;case"cert.PEM":t.get("privateKey").setValidators([T.required]),t.get("privateKeyFileName").setValidators([T.required]),t.get("cert").setValidators([T.required]),t.get("certFileName").setValidators([T.required])}t.get("sasKey").updateValueAndValidity({emitEvent:e}),t.get("privateKey").updateValueAndValidity({emitEvent:e}),t.get("privateKeyFileName").updateValueAndValidity({emitEvent:e}),t.get("cert").updateValueAndValidity({emitEvent:e}),t.get("certFileName").updateValueAndValidity({emitEvent:e})}}$e.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:$e,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),$e.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:$e,selector:"tb-action-node-azure-iot-hub-config",usesInheritance:!0,ngImport:e,template:'
\n \n tb.rulenode.topic\n \n \n {{ \'tb.rulenode.topic-required\' | translate }}\n \n \n \n \n tb.rulenode.hostname\n \n \n {{ \'tb.rulenode.hostname-required\' | translate }}\n \n \n \n tb.rulenode.device-id\n \n \n {{ \'tb.rulenode.device-id-required\' | translate }}\n \n \n \n \n \n tb.rulenode.credentials\n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(azureIotHubConfigForm.get(\'credentials.type\').value) | translate }}\n \n \n
\n \n tb.rulenode.credentials-type\n \n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
\n \n \n \n \n tb.rulenode.sas-key\n \n \n \n {{ \'tb.rulenode.sas-key-required\' | translate }}\n \n \n \n \n \n \n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n \n
\n
\n
\n
\n
\n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}:host .tb-hint.client-id{margin-top:-1.25em;max-width:-moz-fit-content;max-width:fit-content}\n"],components:[{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:B.MatExpansionPanel,selector:"mat-expansion-panel",inputs:["disabled","expanded","hideToggle","togglePosition"],outputs:["opened","closed","expandedChange","afterExpand","afterCollapse"],exportAs:["matExpansionPanel"]},{type:B.MatExpansionPanelHeader,selector:"mat-expansion-panel-header",inputs:["tabIndex","expandedHeight","collapsedHeight"]},{type:H.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:U.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:K.TogglePasswordComponent,selector:"tb-toggle-password"},{type:j.FileInputComponent,selector:"tb-file-input",inputs:["label","accept","noFileText","inputId","allowedExtensions","dropLabel","contentConvertFunction","required","requiredAsError","disabled","existingFileName","readAsBinary","workFromFileObj","multipleFile"],outputs:["fileNameChanged"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:G.MatLabel,selector:"mat-label"},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:G.MatError,selector:"mat-error",inputs:["id"]},{type:G.MatHint,selector:"mat-hint",inputs:["align","id"]},{type:B.MatAccordion,selector:"mat-accordion",inputs:["multi","displayMode","togglePosition","hideToggle"],exportAs:["matAccordion"]},{type:B.MatExpansionPanelTitle,selector:"mat-panel-title"},{type:B.MatExpansionPanelDescription,selector:"mat-panel-description"},{type:q.FormGroupName,selector:"[formGroupName]",inputs:["formGroupName"]},{type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:R.NgSwitch,selector:"[ngSwitch]",inputs:["ngSwitch"]},{type:R.NgSwitchCase,selector:"[ngSwitchCase]",inputs:["ngSwitchCase"]},{type:G.MatSuffix,selector:"[matSuffix]"}],pipes:{translate:E.TranslatePipe,safeHtml:Ie}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:$e,decorators:[{type:t,args:[{selector:"tb-action-node-azure-iot-hub-config",templateUrl:"./azure-iot-hub-config.component.html",styleUrls:["./mqtt-config.component.scss"]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class We extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.serviceType=p.TB_RULE_ENGINE}configForm(){return this.checkPointConfigForm}onConfigurationSet(e){this.checkPointConfigForm=this.fb.group({queueName:[e?e.queueName:null,[T.required]]})}}We.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:We,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),We.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:We,selector:"tb-action-node-check-point-config",usesInheritance:!0,ngImport:e,template:'
\n \n \n
\n',components:[{type:z.QueueTypeListComponent,selector:"tb-queue-type-list",inputs:["required","disabled","queueType"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]}]}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:We,decorators:[{type:t,args:[{selector:"tb-action-node-check-point-config",templateUrl:"./check-point-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class Ye extends s{constructor(e,t,o,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=o,this.translate=r}configForm(){return this.clearAlarmConfigForm}onConfigurationSet(e){this.clearAlarmConfigForm=this.fb.group({alarmDetailsBuildJs:[e?e.alarmDetailsBuildJs:null,[T.required]],alarmType:[e?e.alarmType:null,[T.required]]})}testScript(){const e=this.clearAlarmConfigForm.get("alarmDetailsBuildJs").value;this.nodeScriptTestService.testNodeScript(e,"json",this.translate.instant("tb.rulenode.details"),"Details",["msg","metadata","msgType"],this.ruleNodeId,"rulenode/clear_alarm_node_script_fn").subscribe((e=>{e&&this.clearAlarmConfigForm.get("alarmDetailsBuildJs").setValue(e)}))}onValidate(){this.jsFuncComponent.validateOnSubmit()}}Ye.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Ye,deps:[{token:N.Store},{token:q.FormBuilder},{token:_.NodeScriptTestService},{token:E.TranslateService}],target:e.ɵɵFactoryTarget.Component}),Ye.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Ye,selector:"tb-action-node-clear-alarm-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0,static:!0}],usesInheritance:!0,ngImport:e,template:'
\n \n \n \n
\n \n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n
\n',components:[{type:$.JsFuncComponent,selector:"tb-js-func",inputs:["functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","noValidate","required"]},{type:W.MatButton,selector:"button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:G.MatLabel,selector:"mat-label"},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:G.MatError,selector:"mat-error",inputs:["id"]},{type:G.MatHint,selector:"mat-hint",inputs:["align","id"]}],pipes:{translate:E.TranslatePipe,safeHtml:Ie}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Ye,decorators:[{type:t,args:[{selector:"tb-action-node-clear-alarm-config",templateUrl:"./clear-alarm-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder},{type:_.NodeScriptTestService},{type:E.TranslateService}]},propDecorators:{jsFuncComponent:[{type:r,args:["jsFuncComponent",{static:!0}]}]}});class Je extends s{constructor(e,t,o,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=o,this.translate=r,this.alarmSeverities=Object.keys(d),this.alarmSeverityTranslationMap=f,this.separatorKeysCodes=[Y,J,Z]}configForm(){return this.createAlarmConfigForm}onConfigurationSet(e){this.createAlarmConfigForm=this.fb.group({alarmDetailsBuildJs:[e?e.alarmDetailsBuildJs:null,[T.required]],useMessageAlarmData:[!!e&&e.useMessageAlarmData,[]],alarmType:[e?e.alarmType:null,[]],severity:[e?e.severity:null,[]],propagate:[!!e&&e.propagate,[]],relationTypes:[e?e.relationTypes:null,[]],dynamicSeverity:!1}),this.createAlarmConfigForm.get("dynamicSeverity").valueChanges.subscribe((e=>{e?this.createAlarmConfigForm.get("severity").patchValue("",{emitEvent:!1}):this.createAlarmConfigForm.get("severity").patchValue(this.alarmSeverities[0],{emitEvent:!1})}))}validatorTriggers(){return["useMessageAlarmData"]}updateValidators(e){this.createAlarmConfigForm.get("useMessageAlarmData").value?(this.createAlarmConfigForm.get("alarmType").setValidators([]),this.createAlarmConfigForm.get("severity").setValidators([])):(this.createAlarmConfigForm.get("alarmType").setValidators([T.required]),this.createAlarmConfigForm.get("severity").setValidators([T.required])),this.createAlarmConfigForm.get("alarmType").updateValueAndValidity({emitEvent:e}),this.createAlarmConfigForm.get("severity").updateValueAndValidity({emitEvent:e})}testScript(){const e=this.createAlarmConfigForm.get("alarmDetailsBuildJs").value;this.nodeScriptTestService.testNodeScript(e,"json",this.translate.instant("tb.rulenode.details"),"Details",["msg","metadata","msgType"],this.ruleNodeId,"rulenode/create_alarm_node_script_fn").subscribe((e=>{e&&this.createAlarmConfigForm.get("alarmDetailsBuildJs").setValue(e)}))}removeKey(e,t){const o=this.createAlarmConfigForm.get(t).value,r=o.indexOf(e);r>=0&&(o.splice(r,1),this.createAlarmConfigForm.get(t).setValue(o,{emitEvent:!0}))}addKey(e,t){const o=e.input;let r=e.value;if((r||"").trim()){r=r.trim();let e=this.createAlarmConfigForm.get(t).value;e&&-1!==e.indexOf(r)||(e||(e=[]),e.push(r),this.createAlarmConfigForm.get(t).setValue(e,{emitEvent:!0}))}o&&(o.value="")}onValidate(){this.jsFuncComponent.validateOnSubmit()}}Je.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Je,deps:[{token:N.Store},{token:q.FormBuilder},{token:_.NodeScriptTestService},{token:E.TranslateService}],target:e.ɵɵFactoryTarget.Component}),Je.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Je,selector:"tb-action-node-create-alarm-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0,static:!0}],usesInheritance:!0,ngImport:e,template:'
\n \n \n \n
\n \n
\n
\n \n {{ \'tb.rulenode.use-message-alarm-data\' | translate }}\n \n \n {{ \'tb.rulenode.use-dynamically-change-the-severity-of-alar\' | translate }}\n \n
\n
\n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n \n tb.rulenode.alarm-severity\n \n \n {{ alarmSeverityTranslationMap.get(severity) | translate }}\n \n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.alarm-severity\' | translate }}\n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.propagate\' | translate }}\n \n
\n \n tb.rulenode.relation-types-list\n \n \n {{key}}\n close\n \n \n \n tb.rulenode.relation-types-list-hint\n \n
\n
\n
\n',components:[{type:$.JsFuncComponent,selector:"tb-js-func",inputs:["functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","noValidate","required"]},{type:W.MatButton,selector:"button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{type:D.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:H.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:U.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:X.MatChipList,selector:"mat-chip-list",inputs:["aria-orientation","multiple","compareWith","value","required","placeholder","disabled","selectable","tabIndex","errorStateMatcher"],outputs:["change","valueChange"],exportAs:["matChipList"]},{type:ee.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:V.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:G.MatLabel,selector:"mat-label"},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:G.MatError,selector:"mat-error",inputs:["id"]},{type:G.MatHint,selector:"mat-hint",inputs:["align","id"]},{type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:X.MatChip,selector:"mat-basic-chip, [mat-basic-chip], mat-chip, [mat-chip]",inputs:["color","disableRipple","tabIndex","selected","value","selectable","disabled","removable"],outputs:["selectionChange","destroyed","removed"],exportAs:["matChip"]},{type:X.MatChipRemove,selector:"[matChipRemove]"},{type:X.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputSeparatorKeyCodes","placeholder","id","matChipInputFor","matChipInputAddOnBlur","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]}],pipes:{translate:E.TranslatePipe,safeHtml:Ie}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Je,decorators:[{type:t,args:[{selector:"tb-action-node-create-alarm-config",templateUrl:"./create-alarm-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder},{type:_.NodeScriptTestService},{type:E.TranslateService}]},propDecorators:{jsFuncComponent:[{type:r,args:["jsFuncComponent",{static:!0}]}]}});class Ze extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.keys(c),this.directionTypeTranslations=g,this.entityType=x}configForm(){return this.createRelationConfigForm}onConfigurationSet(e){this.createRelationConfigForm=this.fb.group({direction:[e?e.direction:null,[T.required]],entityType:[e?e.entityType:null,[T.required]],entityNamePattern:[e?e.entityNamePattern:null,[]],entityTypePattern:[e?e.entityTypePattern:null,[]],relationType:[e?e.relationType:null,[T.required]],createEntityIfNotExists:[!!e&&e.createEntityIfNotExists,[]],removeCurrentRelations:[!!e&&e.removeCurrentRelations,[]],changeOriginatorToRelatedEntity:[!!e&&e.changeOriginatorToRelatedEntity,[]],entityCacheExpiration:[e?e.entityCacheExpiration:null,[T.required,T.min(0)]]})}validatorTriggers(){return["entityType"]}updateValidators(e){const t=this.createRelationConfigForm.get("entityType").value;t?this.createRelationConfigForm.get("entityNamePattern").setValidators([T.required,T.pattern(/.*\S.*/)]):this.createRelationConfigForm.get("entityNamePattern").setValidators([]),!t||t!==x.DEVICE&&t!==x.ASSET?this.createRelationConfigForm.get("entityTypePattern").setValidators([]):this.createRelationConfigForm.get("entityTypePattern").setValidators([T.required,T.pattern(/.*\S.*/)]),this.createRelationConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e}),this.createRelationConfigForm.get("entityTypePattern").updateValueAndValidity({emitEvent:e})}prepareOutputConfig(e){return e.entityNamePattern=e.entityNamePattern?e.entityNamePattern.trim():null,e.entityTypePattern=e.entityTypePattern?e.entityTypePattern.trim():null,e}}Ze.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Ze,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),Ze.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Ze,selector:"tb-action-node-create-relation-config",usesInheritance:!0,ngImport:e,template:'
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-type-pattern\n \n \n {{ \'tb.rulenode.entity-type-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.create-entity-if-not-exists\' | translate }}\n \n
tb.rulenode.create-entity-if-not-exists-hint
\n
\n \n {{ \'tb.rulenode.remove-current-relations\' | translate }}\n \n
tb.rulenode.remove-current-relations-hint
\n \n {{ \'tb.rulenode.change-originator-to-related-entity\' | translate }}\n \n
tb.rulenode.change-originator-to-related-entity-hint
\n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n tb.rulenode.entity-cache-expiration-hint\n \n
\n',components:[{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:H.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:U.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:te.EntityTypeSelectComponent,selector:"tb-entity-type-select",inputs:["allowedEntityTypes","useAliasEntityTypes","showLabel","required","disabled"]},{type:D.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:G.MatLabel,selector:"mat-label"},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:V.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:G.MatError,selector:"mat-error",inputs:["id"]},{type:G.MatHint,selector:"mat-hint",inputs:["align","id"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"}],pipes:{translate:E.TranslatePipe,safeHtml:Ie}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Ze,decorators:[{type:t,args:[{selector:"tb-action-node-create-relation-config",templateUrl:"./create-relation-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class Xe extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.keys(c),this.directionTypeTranslations=g,this.entityType=x}configForm(){return this.deleteRelationConfigForm}onConfigurationSet(e){this.deleteRelationConfigForm=this.fb.group({deleteForSingleEntity:[!!e&&e.deleteForSingleEntity,[]],direction:[e?e.direction:null,[T.required]],entityType:[e?e.entityType:null,[]],entityNamePattern:[e?e.entityNamePattern:null,[]],relationType:[e?e.relationType:null,[T.required]],entityCacheExpiration:[e?e.entityCacheExpiration:null,[T.required,T.min(0)]]})}validatorTriggers(){return["deleteForSingleEntity","entityType"]}updateValidators(e){const t=this.deleteRelationConfigForm.get("deleteForSingleEntity").value,o=this.deleteRelationConfigForm.get("entityType").value;t?this.deleteRelationConfigForm.get("entityType").setValidators([T.required]):this.deleteRelationConfigForm.get("entityType").setValidators([]),t&&o?this.deleteRelationConfigForm.get("entityNamePattern").setValidators([T.required,T.pattern(/.*\S.*/)]):this.deleteRelationConfigForm.get("entityNamePattern").setValidators([]),this.deleteRelationConfigForm.get("entityType").updateValueAndValidity({emitEvent:!1}),this.deleteRelationConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e})}prepareOutputConfig(e){return e.entityNamePattern=e.entityNamePattern?e.entityNamePattern.trim():null,e}}Xe.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Xe,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),Xe.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Xe,selector:"tb-action-node-delete-relation-config",usesInheritance:!0,ngImport:e,template:'
\n \n {{ \'tb.rulenode.delete-relation-to-specific-entity\' | translate }}\n \n
tb.rulenode.delete-relation-hint
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n tb.rulenode.entity-cache-expiration-hint\n \n
\n',components:[{type:D.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:H.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:U.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:te.EntityTypeSelectComponent,selector:"tb-entity-type-select",inputs:["allowedEntityTypes","useAliasEntityTypes","showLabel","required","disabled"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:G.MatLabel,selector:"mat-label"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:V.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:G.MatError,selector:"mat-error",inputs:["id"]},{type:G.MatHint,selector:"mat-hint",inputs:["align","id"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"}],pipes:{translate:E.TranslatePipe,safeHtml:Ie}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Xe,decorators:[{type:t,args:[{selector:"tb-action-node-delete-relation-config",templateUrl:"./delete-relation-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class et extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.deviceProfile}onConfigurationSet(e){this.deviceProfile=this.fb.group({persistAlarmRulesState:[!!e&&e.persistAlarmRulesState,T.required],fetchAlarmRulesStateOnStart:[!!e&&e.fetchAlarmRulesStateOnStart,T.required]})}}et.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:et,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),et.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:et,selector:"tb-device-profile-config",usesInheritance:!0,ngImport:e,template:'
\n \n {{ \'tb.rulenode.persist-alarm-rules\' | translate }}\n \n \n {{ \'tb.rulenode.fetch-alarm-rules\' | translate }}\n \n
\n',components:[{type:D.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]}],pipes:{translate:E.TranslatePipe}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:et,decorators:[{type:t,args:[{selector:"tb-device-profile-config",templateUrl:"./device-profile-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class tt extends s{constructor(e,t,o,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=o,this.translate=r}configForm(){return this.generatorConfigForm}onConfigurationSet(e){this.generatorConfigForm=this.fb.group({msgCount:[e?e.msgCount:null,[T.required,T.min(0)]],periodInSeconds:[e?e.periodInSeconds:null,[T.required,T.min(1)]],originator:[e?e.originator:null,[]],jsScript:[e?e.jsScript:null,[T.required]]})}prepareInputConfig(e){return e&&(e.originatorId&&e.originatorType?e.originator={id:e.originatorId,entityType:e.originatorType}:e.originator=null,delete e.originatorId,delete e.originatorType),e}prepareOutputConfig(e){return e.originator?(e.originatorId=e.originator.id,e.originatorType=e.originator.entityType):(e.originatorId=null,e.originatorType=null),delete e.originator,e}testScript(){const e=this.generatorConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(e,"generate",this.translate.instant("tb.rulenode.generator"),"Generate",["prevMsg","prevMetadata","prevMsgType"],this.ruleNodeId,"rulenode/generator_node_script_fn").subscribe((e=>{e&&this.generatorConfigForm.get("jsScript").setValue(e)}))}onValidate(){this.jsFuncComponent.validateOnSubmit()}}tt.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:tt,deps:[{token:N.Store},{token:q.FormBuilder},{token:_.NodeScriptTestService},{token:E.TranslateService}],target:e.ɵɵFactoryTarget.Component}),tt.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:tt,selector:"tb-action-node-generator-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0,static:!0}],usesInheritance:!0,ngImport:e,template:'
\n \n tb.rulenode.message-count\n \n \n {{ \'tb.rulenode.message-count-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-message-count-message\' | translate }}\n \n \n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-seconds-message\' | translate }}\n \n \n
\n \n \n \n
\n \n \n \n
\n \n
\n
\n',components:[{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:oe.EntitySelectComponent,selector:"tb-entity-select",inputs:["allowedEntityTypes","useAliasEntityTypes","required","disabled"]},{type:$.JsFuncComponent,selector:"tb-js-func",inputs:["functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","noValidate","required"]},{type:W.MatButton,selector:"button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:G.MatLabel,selector:"mat-label"},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:G.MatError,selector:"mat-error",inputs:["id"]}],pipes:{translate:E.TranslatePipe}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:tt,decorators:[{type:t,args:[{selector:"tb-action-node-generator-config",templateUrl:"./generator-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder},{type:_.NodeScriptTestService},{type:E.TranslateService}]},propDecorators:{jsFuncComponent:[{type:r,args:["jsFuncComponent",{static:!0}]}]}});class ot extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.perimeterType=Me,this.perimeterTypes=Object.keys(Me),this.perimeterTypeTranslationMap=Se,this.rangeUnits=Object.keys(De),this.rangeUnitTranslationMap=Ve,this.timeUnits=Object.keys(Ae),this.timeUnitsTranslationMap=Ge}configForm(){return this.geoActionConfigForm}onConfigurationSet(e){this.geoActionConfigForm=this.fb.group({latitudeKeyName:[e?e.latitudeKeyName:null,[T.required]],longitudeKeyName:[e?e.longitudeKeyName:null,[T.required]],fetchPerimeterInfoFromMessageMetadata:[!!e&&e.fetchPerimeterInfoFromMessageMetadata,[]],perimeterType:[e?e.perimeterType:null,[]],centerLatitude:[e?e.centerLatitude:null,[]],centerLongitude:[e?e.centerLatitude:null,[]],range:[e?e.range:null,[]],rangeUnit:[e?e.rangeUnit:null,[]],polygonsDefinition:[e?e.polygonsDefinition:null,[]],minInsideDuration:[e?e.minInsideDuration:null,[T.required,T.min(1),T.max(2147483647)]],minInsideDurationTimeUnit:[e?e.minInsideDurationTimeUnit:null,[T.required]],minOutsideDuration:[e?e.minOutsideDuration:null,[T.required,T.min(1),T.max(2147483647)]],minOutsideDurationTimeUnit:[e?e.minOutsideDurationTimeUnit:null,[T.required]]})}validatorTriggers(){return["fetchPerimeterInfoFromMessageMetadata","perimeterType"]}updateValidators(e){const t=this.geoActionConfigForm.get("fetchPerimeterInfoFromMessageMetadata").value,o=this.geoActionConfigForm.get("perimeterType").value;t?this.geoActionConfigForm.get("perimeterType").setValidators([]):this.geoActionConfigForm.get("perimeterType").setValidators([T.required]),t||o!==Me.CIRCLE?(this.geoActionConfigForm.get("centerLatitude").setValidators([]),this.geoActionConfigForm.get("centerLongitude").setValidators([]),this.geoActionConfigForm.get("range").setValidators([]),this.geoActionConfigForm.get("rangeUnit").setValidators([])):(this.geoActionConfigForm.get("centerLatitude").setValidators([T.required,T.min(-90),T.max(90)]),this.geoActionConfigForm.get("centerLongitude").setValidators([T.required,T.min(-180),T.max(180)]),this.geoActionConfigForm.get("range").setValidators([T.required,T.min(0)]),this.geoActionConfigForm.get("rangeUnit").setValidators([T.required])),t||o!==Me.POLYGON?this.geoActionConfigForm.get("polygonsDefinition").setValidators([]):this.geoActionConfigForm.get("polygonsDefinition").setValidators([T.required]),this.geoActionConfigForm.get("perimeterType").updateValueAndValidity({emitEvent:!1}),this.geoActionConfigForm.get("centerLatitude").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("centerLongitude").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("range").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("rangeUnit").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("polygonsDefinition").updateValueAndValidity({emitEvent:e})}}ot.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:ot,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),ot.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:ot,selector:"tb-action-node-gps-geofencing-config",usesInheritance:!0,ngImport:e,template:'
\n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n
\n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.min-inside-duration\n \n \n {{ \'tb.rulenode.min-inside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-inside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n tb.rulenode.min-outside-duration\n \n \n {{ \'tb.rulenode.min-outside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-outside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n',components:[{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:D.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:H.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:U.MatOption,selector:"mat-option",exportAs:["matOption"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:G.MatLabel,selector:"mat-label"},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:G.MatError,selector:"mat-error",inputs:["id"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:V.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"}],pipes:{translate:E.TranslatePipe}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:ot,decorators:[{type:t,args:[{selector:"tb-action-node-gps-geofencing-config",templateUrl:"./gps-geo-action-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class rt extends y{constructor(e,t,o,r){super(e),this.store=e,this.translate=t,this.injector=o,this.fb=r,this.propagateChange=null,this.valueChangeSubscription=null}get required(){return this.requiredValue}set required(e){this.requiredValue=re(e)}ngOnInit(){this.ngControl=this.injector.get(k),null!=this.ngControl&&(this.ngControl.valueAccessor=this),this.kvListFormGroup=this.fb.group({}),this.kvListFormGroup.addControl("keyVals",this.fb.array([]))}keyValsFormArray(){return this.kvListFormGroup.get("keyVals")}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.kvListFormGroup.disable({emitEvent:!1}):this.kvListFormGroup.enable({emitEvent:!1})}writeValue(e){this.valueChangeSubscription&&this.valueChangeSubscription.unsubscribe();const t=[];if(e)for(const o of Object.keys(e))Object.prototype.hasOwnProperty.call(e,o)&&t.push(this.fb.group({key:[o,[T.required]],value:[e[o],[T.required]]}));this.kvListFormGroup.setControl("keyVals",this.fb.array(t)),this.valueChangeSubscription=this.kvListFormGroup.valueChanges.subscribe((()=>{this.updateModel()}))}removeKeyVal(e){this.kvListFormGroup.get("keyVals").removeAt(e)}addKeyVal(){this.kvListFormGroup.get("keyVals").push(this.fb.group({key:["",[T.required]],value:["",[T.required]]}))}validate(e){return!this.kvListFormGroup.get("keyVals").value.length&&this.required?{kvMapRequired:!0}:this.kvListFormGroup.valid?null:{kvFieldsRequired:!0}}updateModel(){const e=this.kvListFormGroup.get("keyVals").value;if(this.required&&!e.length||!this.kvListFormGroup.valid)this.propagateChange(null);else{const t={};e.forEach((e=>{t[e.key]=e.value})),this.propagateChange(t)}}}rt.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:rt,deps:[{token:N.Store},{token:E.TranslateService},{token:e.Injector},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),rt.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:rt,selector:"tb-kv-map-config",inputs:{disabled:"disabled",requiredText:"requiredText",keyText:"keyText",keyRequiredText:"keyRequiredText",valText:"valText",valRequiredText:"valRequiredText",required:"required"},providers:[{provide:M,useExisting:a((()=>rt)),multi:!0},{provide:S,useExisting:a((()=>rt)),multi:!0}],usesInheritance:!0,ngImport:e,template:'
\n
\n {{ keyText | translate }}\n {{ valText | translate }}\n \n
\n
\n
\n \n \n \n \n {{ keyRequiredText | translate }}\n \n \n \n \n \n \n {{ valRequiredText | translate }}\n \n \n \n
\n
\n \n
\n \n
\n
\n',styles:[":host .tb-kv-map-config{margin-bottom:16px}:host .tb-kv-map-config .header{padding-left:5px;padding-right:5px;padding-bottom:5px}:host .tb-kv-map-config .header .cell{padding-left:5px;padding-right:5px;color:#0000008a;font-size:12px;font-weight:700;white-space:nowrap}:host .tb-kv-map-config .body{padding-left:5px;padding-right:5px;padding-bottom:20px;max-height:300px;overflow:auto}:host .tb-kv-map-config .body .row{padding-top:5px;max-height:40px}:host .tb-kv-map-config .body .cell{padding-left:5px;padding-right:5px}:host ::ng-deep .tb-kv-map-config .body mat-form-field.cell{margin:0;max-height:40px}:host ::ng-deep .tb-kv-map-config .body mat-form-field.cell .mat-form-field-infix{border-top:0}:host ::ng-deep .tb-kv-map-config .body button.mat-button{margin:0}\n"],components:[{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:W.MatButton,selector:"button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{type:ee.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{type:ae.TbErrorComponent,selector:"tb-error",inputs:["error"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:V.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{type:ne.DefaultShowHideDirective,selector:" [fxShow], [fxShow.print], [fxShow.xs], [fxShow.sm], [fxShow.md], [fxShow.lg], [fxShow.xl], [fxShow.lt-sm], [fxShow.lt-md], [fxShow.lt-lg], [fxShow.lt-xl], [fxShow.gt-xs], [fxShow.gt-sm], [fxShow.gt-md], [fxShow.gt-lg], [fxHide], [fxHide.print], [fxHide.xs], [fxHide.sm], [fxHide.md], [fxHide.lg], [fxHide.xl], [fxHide.lt-sm], [fxHide.lt-md], [fxHide.lt-lg], [fxHide.lt-xl], [fxHide.gt-xs], [fxHide.gt-sm], [fxHide.gt-md], [fxHide.gt-lg]",inputs:["fxShow","fxShow.print","fxShow.xs","fxShow.sm","fxShow.md","fxShow.lg","fxShow.xl","fxShow.lt-sm","fxShow.lt-md","fxShow.lt-lg","fxShow.lt-xl","fxShow.gt-xs","fxShow.gt-sm","fxShow.gt-md","fxShow.gt-lg","fxHide","fxHide.print","fxHide.xs","fxHide.sm","fxHide.md","fxHide.lg","fxHide.xl","fxHide.lt-sm","fxHide.lt-md","fxHide.lt-lg","fxHide.lt-xl","fxHide.gt-xs","fxHide.gt-sm","fxHide.gt-md","fxHide.gt-lg"]},{type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:V.DefaultLayoutAlignDirective,selector:" [fxLayoutAlign], [fxLayoutAlign.xs], [fxLayoutAlign.sm], [fxLayoutAlign.md], [fxLayoutAlign.lg], [fxLayoutAlign.xl], [fxLayoutAlign.lt-sm], [fxLayoutAlign.lt-md], [fxLayoutAlign.lt-lg], [fxLayoutAlign.lt-xl], [fxLayoutAlign.gt-xs], [fxLayoutAlign.gt-sm], [fxLayoutAlign.gt-md], [fxLayoutAlign.gt-lg]",inputs:["fxLayoutAlign","fxLayoutAlign.xs","fxLayoutAlign.sm","fxLayoutAlign.md","fxLayoutAlign.lg","fxLayoutAlign.xl","fxLayoutAlign.lt-sm","fxLayoutAlign.lt-md","fxLayoutAlign.lt-lg","fxLayoutAlign.lt-xl","fxLayoutAlign.gt-xs","fxLayoutAlign.gt-sm","fxLayoutAlign.gt-md","fxLayoutAlign.gt-lg"]},{type:q.FormArrayName,selector:"[formArrayName]",inputs:["formArrayName"]},{type:G.MatLabel,selector:"mat-label"},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlDirective,selector:"[formControl]",inputs:["disabled","formControl","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:G.MatError,selector:"mat-error",inputs:["id"]},{type:le.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]}],pipes:{translate:E.TranslatePipe,async:R.AsyncPipe}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:rt,decorators:[{type:t,args:[{selector:"tb-kv-map-config",templateUrl:"./kv-map-config.component.html",styleUrls:["./kv-map-config.component.scss"],providers:[{provide:M,useExisting:a((()=>rt)),multi:!0},{provide:S,useExisting:a((()=>rt)),multi:!0}]}]}],ctorParameters:function(){return[{type:N.Store},{type:E.TranslateService},{type:e.Injector},{type:q.FormBuilder}]},propDecorators:{disabled:[{type:n}],requiredText:[{type:n}],keyText:[{type:n}],keyRequiredText:[{type:n}],valText:[{type:n}],valRequiredText:[{type:n}],required:[{type:n}]}});class at extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.ackValues=["all","-1","0","1"],this.ToByteStandartCharsetTypesValues=_e,this.ToByteStandartCharsetTypeTranslationMap=Qe}configForm(){return this.kafkaConfigForm}onConfigurationSet(e){this.kafkaConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[T.required]],bootstrapServers:[e?e.bootstrapServers:null,[T.required]],retries:[e?e.retries:null,[T.min(0)]],batchSize:[e?e.batchSize:null,[T.min(0)]],linger:[e?e.linger:null,[T.min(0)]],bufferMemory:[e?e.bufferMemory:null,[T.min(0)]],acks:[e?e.acks:null,[T.required]],keySerializer:[e?e.keySerializer:null,[T.required]],valueSerializer:[e?e.valueSerializer:null,[T.required]],otherProperties:[e?e.otherProperties:null,[]],addMetadataKeyValuesAsKafkaHeaders:[!!e&&e.addMetadataKeyValuesAsKafkaHeaders,[]],kafkaHeadersCharset:[e?e.kafkaHeadersCharset:null,[]]})}validatorTriggers(){return["addMetadataKeyValuesAsKafkaHeaders"]}updateValidators(e){this.kafkaConfigForm.get("addMetadataKeyValuesAsKafkaHeaders").value?this.kafkaConfigForm.get("kafkaHeadersCharset").setValidators([T.required]):this.kafkaConfigForm.get("kafkaHeadersCharset").setValidators([]),this.kafkaConfigForm.get("kafkaHeadersCharset").updateValueAndValidity({emitEvent:e})}}at.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:at,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),at.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:at,selector:"tb-action-node-kafka-config",usesInheritance:!0,ngImport:e,template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.bootstrap-servers\n \n \n {{ \'tb.rulenode.bootstrap-servers-required\' | translate }}\n \n \n \n tb.rulenode.retries\n \n \n {{ \'tb.rulenode.min-retries-message\' | translate }}\n \n \n \n tb.rulenode.batch-size-bytes\n \n \n {{ \'tb.rulenode.min-batch-size-bytes-message\' | translate }}\n \n \n \n tb.rulenode.linger-ms\n \n \n {{ \'tb.rulenode.min-linger-ms-message\' | translate }}\n \n \n \n tb.rulenode.buffer-memory-bytes\n \n \n {{ \'tb.rulenode.min-buffer-memory-bytes-message\' | translate }}\n \n \n \n tb.rulenode.acks\n \n \n {{ ackValue }}\n \n \n \n \n tb.rulenode.key-serializer\n \n \n {{ \'tb.rulenode.key-serializer-required\' | translate }}\n \n \n \n tb.rulenode.value-serializer\n \n \n {{ \'tb.rulenode.value-serializer-required\' | translate }}\n \n \n \n \n \n \n {{ \'tb.rulenode.add-metadata-key-values-as-kafka-headers\' | translate }}\n \n
tb.rulenode.add-metadata-key-values-as-kafka-headers-hint
\n \n tb.rulenode.charset-encoding\n \n \n {{ ToByteStandartCharsetTypeTranslationMap.get(charset) | translate }}\n \n \n \n
\n',components:[{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:H.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:U.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:rt,selector:"tb-kv-map-config",inputs:["disabled","requiredText","keyText","keyRequiredText","valText","valRequiredText","required"]},{type:D.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:G.MatLabel,selector:"mat-label"},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:G.MatError,selector:"mat-error",inputs:["id"]},{type:G.MatHint,selector:"mat-hint",inputs:["align","id"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]}],pipes:{translate:E.TranslatePipe,safeHtml:Ie}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:at,decorators:[{type:t,args:[{selector:"tb-action-node-kafka-config",templateUrl:"./kafka-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class nt extends s{constructor(e,t,o,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=o,this.translate=r}configForm(){return this.logConfigForm}onConfigurationSet(e){this.logConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[T.required]]})}testScript(){const e=this.logConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(e,"string",this.translate.instant("tb.rulenode.to-string"),"ToString",["msg","metadata","msgType"],this.ruleNodeId,"rulenode/log_node_script_fn").subscribe((e=>{e&&this.logConfigForm.get("jsScript").setValue(e)}))}onValidate(){this.jsFuncComponent.validateOnSubmit()}}nt.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:nt,deps:[{token:N.Store},{token:q.FormBuilder},{token:_.NodeScriptTestService},{token:E.TranslateService}],target:e.ɵɵFactoryTarget.Component}),nt.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:nt,selector:"tb-action-node-log-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0,static:!0}],usesInheritance:!0,ngImport:e,template:'
\n \n \n \n
\n \n
\n
\n',components:[{type:$.JsFuncComponent,selector:"tb-js-func",inputs:["functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","noValidate","required"]},{type:W.MatButton,selector:"button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]}],pipes:{translate:E.TranslatePipe}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:nt,decorators:[{type:t,args:[{selector:"tb-action-node-log-config",templateUrl:"./log-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder},{type:_.NodeScriptTestService},{type:E.TranslateService}]},propDecorators:{jsFuncComponent:[{type:r,args:["jsFuncComponent",{static:!0}]}]}});class lt extends y{constructor(e,t){super(e),this.store=e,this.fb=t,this.subscriptions=[],this.disableCertPemCredentials=!1,this.passwordFieldRquired=!0,this.allCredentialsTypes=Ue,this.credentialsTypeTranslationsMap=Be,this.propagateChange=null}get required(){return this.requiredValue}set required(e){this.requiredValue=re(e)}ngOnInit(){this.credentialsConfigFormGroup=this.fb.group({type:[null,[T.required]],username:[null,[]],password:[null,[]],caCert:[null,[]],caCertFileName:[null,[]],privateKey:[null,[]],privateKeyFileName:[null,[]],cert:[null,[]],certFileName:[null,[]]}),this.subscriptions.push(this.credentialsConfigFormGroup.valueChanges.pipe(ie()).subscribe((()=>{this.updateView()}))),this.subscriptions.push(this.credentialsConfigFormGroup.get("type").valueChanges.subscribe((()=>{this.credentialsTypeChanged()})))}ngOnChanges(e){for(const t of Object.keys(e)){const o=e[t];if(!o.firstChange&&o.currentValue!==o.previousValue&&o.currentValue&&"disableCertPemCredentials"===t){"cert.PEM"===this.credentialsConfigFormGroup.get("type").value&&setTimeout((()=>{this.credentialsConfigFormGroup.get("type").patchValue("anonymous",{emitEvent:!0})}))}}}ngOnDestroy(){this.subscriptions.forEach((e=>e.unsubscribe()))}writeValue(e){Q(e)&&(this.credentialsConfigFormGroup.reset(e,{emitEvent:!1}),this.updateValidators(!1))}setDisabledState(e){e?this.credentialsConfigFormGroup.disable():(this.credentialsConfigFormGroup.enable(),this.updateValidators())}updateView(){let e=this.credentialsConfigFormGroup.value;const t=e.type;switch(t){case"anonymous":e={type:t};break;case"basic":e={type:t,username:e.username,password:e.password};break;case"cert.PEM":delete e.username}this.propagateChange(e)}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}validate(e){return this.credentialsConfigFormGroup.valid?null:{credentialsConfig:{valid:!1}}}credentialsTypeChanged(){this.credentialsConfigFormGroup.patchValue({username:null,password:null,caCert:null,caCertFileName:null,privateKey:null,privateKeyFileName:null,cert:null,certFileName:null}),this.updateValidators()}updateValidators(e=!1){const t=this.credentialsConfigFormGroup.get("type").value;switch(e&&this.credentialsConfigFormGroup.reset({type:t},{emitEvent:!1}),this.credentialsConfigFormGroup.setValidators([]),this.credentialsConfigFormGroup.get("username").setValidators([]),this.credentialsConfigFormGroup.get("password").setValidators([]),t){case"anonymous":break;case"basic":this.credentialsConfigFormGroup.get("username").setValidators([T.required]),this.credentialsConfigFormGroup.get("password").setValidators(this.passwordFieldRquired?[T.required]:[]);break;case"cert.PEM":this.credentialsConfigFormGroup.setValidators([this.requiredFilesSelected(T.required,[["caCert","caCertFileName"],["privateKey","privateKeyFileName","cert","certFileName"]])])}this.credentialsConfigFormGroup.get("username").updateValueAndValidity({emitEvent:e}),this.credentialsConfigFormGroup.get("password").updateValueAndValidity({emitEvent:e}),this.credentialsConfigFormGroup.updateValueAndValidity({emitEvent:e})}requiredFilesSelected(e,t=null){return o=>{t||(t=[Object.keys(o.controls)]);return(null==o?void 0:o.controls)&&t.some((t=>t.every((t=>!e(o.controls[t])))))?null:{notAllRequiredFilesSelected:!0}}}}lt.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:lt,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),lt.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:lt,selector:"tb-credentials-config",inputs:{required:"required",disableCertPemCredentials:"disableCertPemCredentials",passwordFieldRquired:"passwordFieldRquired"},providers:[{provide:M,useExisting:a((()=>lt)),multi:!0},{provide:S,useExisting:a((()=>lt)),multi:!0}],usesInheritance:!0,usesOnChanges:!0,ngImport:e,template:'
\n \n \n tb.rulenode.credentials\n \n {{ credentialsTypeTranslationsMap.get(credentialsConfigFormGroup.get(\'type\').value) | translate }}\n \n \n \n \n tb.rulenode.credentials-type\n \n \n {{ credentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
\n \n \n \n \n tb.rulenode.username\n \n \n {{ \'tb.rulenode.username-required\' | translate }}\n \n \n \n tb.rulenode.password\n \n \n \n {{ \'tb.rulenode.password-required\' | translate }}\n \n \n \n \n
{{ \'tb.rulenode.credentials-pem-hint\' | translate }}
\n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n
\n
\n
\n
\n
\n',components:[{type:B.MatExpansionPanel,selector:"mat-expansion-panel",inputs:["disabled","expanded","hideToggle","togglePosition"],outputs:["opened","closed","expandedChange","afterExpand","afterCollapse"],exportAs:["matExpansionPanel"]},{type:B.MatExpansionPanelHeader,selector:"mat-expansion-panel-header",inputs:["tabIndex","expandedHeight","collapsedHeight"]},{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:H.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:U.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:K.TogglePasswordComponent,selector:"tb-toggle-password"},{type:j.FileInputComponent,selector:"tb-file-input",inputs:["label","accept","noFileText","inputId","allowedExtensions","dropLabel","contentConvertFunction","required","requiredAsError","disabled","existingFileName","readAsBinary","workFromFileObj","multipleFile"],outputs:["fileNameChanged"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:B.MatExpansionPanelTitle,selector:"mat-panel-title"},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:B.MatExpansionPanelDescription,selector:"mat-panel-description"},{type:B.MatExpansionPanelContent,selector:"ng-template[matExpansionPanelContent]"},{type:G.MatLabel,selector:"mat-label"},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:G.MatError,selector:"mat-error",inputs:["id"]},{type:R.NgSwitch,selector:"[ngSwitch]",inputs:["ngSwitch"]},{type:R.NgSwitchCase,selector:"[ngSwitchCase]",inputs:["ngSwitchCase"]},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:G.MatSuffix,selector:"[matSuffix]"}],pipes:{translate:E.TranslatePipe}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:lt,decorators:[{type:t,args:[{selector:"tb-credentials-config",templateUrl:"./credentials-config.component.html",styleUrls:[],providers:[{provide:M,useExisting:a((()=>lt)),multi:!0},{provide:S,useExisting:a((()=>lt)),multi:!0}]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]},propDecorators:{required:[{type:n}],disableCertPemCredentials:[{type:n}],passwordFieldRquired:[{type:n}]}});class it extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.mqttConfigForm}onConfigurationSet(e){this.mqttConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[T.required]],host:[e?e.host:null,[T.required]],port:[e?e.port:null,[T.required,T.min(1),T.max(65535)]],connectTimeoutSec:[e?e.connectTimeoutSec:null,[T.required,T.min(1),T.max(200)]],clientId:[e?e.clientId:null,[]],cleanSession:[!!e&&e.cleanSession,[]],ssl:[!!e&&e.ssl,[]],credentials:[e?e.credentials:null,[]]})}}it.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:it,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),it.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:it,selector:"tb-action-node-mqtt-config",usesInheritance:!0,ngImport:e,template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n \n tb.rulenode.connect-timeout\n \n \n {{ \'tb.rulenode.connect-timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n
\n \n tb.rulenode.client-id\n \n \n
tb.rulenode.client-id-hint
\n \n {{ \'tb.rulenode.clean-session\' | translate }}\n \n \n {{ \'tb.rulenode.enable-ssl\' | translate }}\n \n \n
\n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}:host .tb-hint.client-id{margin-top:-1.25em;max-width:-moz-fit-content;max-width:fit-content}\n"],components:[{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:D.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:lt,selector:"tb-credentials-config",inputs:["required","disableCertPemCredentials","passwordFieldRquired"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:G.MatLabel,selector:"mat-label"},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:G.MatError,selector:"mat-error",inputs:["id"]},{type:G.MatHint,selector:"mat-hint",inputs:["align","id"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:V.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"}],pipes:{translate:E.TranslatePipe,safeHtml:Ie}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:it,decorators:[{type:t,args:[{selector:"tb-action-node-mqtt-config",templateUrl:"./mqtt-config.component.html",styleUrls:["./mqtt-config.component.scss"]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class st extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.msgCountConfigForm}onConfigurationSet(e){this.msgCountConfigForm=this.fb.group({interval:[e?e.interval:null,[T.required,T.min(1)]],telemetryPrefix:[e?e.telemetryPrefix:null,[T.required]]})}}st.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:st,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),st.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:st,selector:"tb-action-node-msg-count-config",usesInheritance:!0,ngImport:e,template:'
\n \n tb.rulenode.interval-seconds\n \n \n {{ \'tb.rulenode.interval-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-interval-seconds-message\' | translate }}\n \n \n \n tb.rulenode.output-timeseries-key-prefix\n \n \n {{ \'tb.rulenode.output-timeseries-key-prefix-required\' | translate }}\n \n \n
\n',components:[{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:G.MatLabel,selector:"mat-label"},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:G.MatError,selector:"mat-error",inputs:["id"]}],pipes:{translate:E.TranslatePipe}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:st,decorators:[{type:t,args:[{selector:"tb-action-node-msg-count-config",templateUrl:"./msg-count-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class mt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.msgDelayConfigForm}onConfigurationSet(e){this.msgDelayConfigForm=this.fb.group({useMetadataPeriodInSecondsPatterns:[!!e&&e.useMetadataPeriodInSecondsPatterns,[]],periodInSeconds:[e?e.periodInSeconds:null,[]],periodInSecondsPattern:[e?e.periodInSecondsPattern:null,[]],maxPendingMsgs:[e?e.maxPendingMsgs:null,[T.required,T.min(1),T.max(1e5)]]})}validatorTriggers(){return["useMetadataPeriodInSecondsPatterns"]}updateValidators(e){this.msgDelayConfigForm.get("useMetadataPeriodInSecondsPatterns").value?(this.msgDelayConfigForm.get("periodInSecondsPattern").setValidators([T.required]),this.msgDelayConfigForm.get("periodInSeconds").setValidators([])):(this.msgDelayConfigForm.get("periodInSecondsPattern").setValidators([]),this.msgDelayConfigForm.get("periodInSeconds").setValidators([T.required,T.min(0)])),this.msgDelayConfigForm.get("periodInSecondsPattern").updateValueAndValidity({emitEvent:e}),this.msgDelayConfigForm.get("periodInSeconds").updateValueAndValidity({emitEvent:e})}}mt.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:mt,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),mt.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:mt,selector:"tb-action-node-msg-delay-config",usesInheritance:!0,ngImport:e,template:'
\n \n {{ \'tb.rulenode.use-metadata-period-in-seconds-patterns\' | translate }}\n \n
tb.rulenode.use-metadata-period-in-seconds-patterns-hint
\n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-0-seconds-message\' | translate }}\n \n \n \n \n tb.rulenode.period-in-seconds-pattern\n \n \n {{ \'tb.rulenode.period-in-seconds-pattern-required\' | translate }}\n \n \n \n \n \n tb.rulenode.max-pending-messages\n \n \n {{ \'tb.rulenode.max-pending-messages-required\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n
\n',components:[{type:D.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:G.MatLabel,selector:"mat-label"},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:G.MatError,selector:"mat-error",inputs:["id"]},{type:G.MatHint,selector:"mat-hint",inputs:["align","id"]},{type:q.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]}],pipes:{translate:E.TranslatePipe,safeHtml:Ie}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:mt,decorators:[{type:t,args:[{selector:"tb-action-node-msg-delay-config",templateUrl:"./msg-delay-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class ut extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.pubSubConfigForm}onConfigurationSet(e){this.pubSubConfigForm=this.fb.group({projectId:[e?e.projectId:null,[T.required]],topicName:[e?e.topicName:null,[T.required]],serviceAccountKey:[e?e.serviceAccountKey:null,[T.required]],serviceAccountKeyFileName:[e?e.serviceAccountKeyFileName:null,[T.required]],messageAttributes:[e?e.messageAttributes:null,[]]})}}ut.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:ut,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),ut.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:ut,selector:"tb-action-node-pub-sub-config",usesInheritance:!0,ngImport:e,template:'
\n \n tb.rulenode.gcp-project-id\n \n \n {{ \'tb.rulenode.gcp-project-id-required\' | translate }}\n \n \n \n tb.rulenode.pubsub-topic-name\n \n \n {{ \'tb.rulenode.pubsub-topic-name-required\' | translate }}\n \n \n \n \n \n
\n \n \n
\n',components:[{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:j.FileInputComponent,selector:"tb-file-input",inputs:["label","accept","noFileText","inputId","allowedExtensions","dropLabel","contentConvertFunction","required","requiredAsError","disabled","existingFileName","readAsBinary","workFromFileObj","multipleFile"],outputs:["fileNameChanged"]},{type:rt,selector:"tb-kv-map-config",inputs:["disabled","requiredText","keyText","keyRequiredText","valText","valRequiredText","required"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:G.MatLabel,selector:"mat-label"},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:G.MatError,selector:"mat-error",inputs:["id"]}],pipes:{translate:E.TranslatePipe,safeHtml:Ie}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:ut,decorators:[{type:t,args:[{selector:"tb-action-node-pub-sub-config",templateUrl:"./pubsub-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class pt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.attributeScopes=Object.keys(m),this.telemetryTypeTranslationsMap=u}configForm(){return this.pushToCloudConfigForm}onConfigurationSet(e){this.pushToCloudConfigForm=this.fb.group({scope:[e?e.scope:null,[T.required]]})}}pt.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:pt,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),pt.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:pt,selector:"tb-action-node-push-to-cloud-config",usesInheritance:!0,ngImport:e,template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n',components:[{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:H.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:U.MatOption,selector:"mat-option",exportAs:["matOption"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:G.MatLabel,selector:"mat-label"},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]}],pipes:{translate:E.TranslatePipe}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:pt,decorators:[{type:t,args:[{selector:"tb-action-node-push-to-cloud-config",templateUrl:"./push-to-cloud-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class dt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.attributeScopes=Object.keys(m),this.telemetryTypeTranslationsMap=u}configForm(){return this.pushToEdgeConfigForm}onConfigurationSet(e){this.pushToEdgeConfigForm=this.fb.group({scope:[e?e.scope:null,[T.required]]})}}dt.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:dt,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),dt.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:dt,selector:"tb-action-node-push-to-edge-config",usesInheritance:!0,ngImport:e,template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n',components:[{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:H.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:U.MatOption,selector:"mat-option",exportAs:["matOption"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:G.MatLabel,selector:"mat-label"},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]}],pipes:{translate:E.TranslatePipe}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:dt,decorators:[{type:t,args:[{selector:"tb-action-node-push-to-edge-config",templateUrl:"./push-to-edge-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class ft extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.messageProperties=[null,"BASIC","TEXT_PLAIN","MINIMAL_BASIC","MINIMAL_PERSISTENT_BASIC","PERSISTENT_BASIC","PERSISTENT_TEXT_PLAIN"]}configForm(){return this.rabbitMqConfigForm}onConfigurationSet(e){this.rabbitMqConfigForm=this.fb.group({exchangeNamePattern:[e?e.exchangeNamePattern:null,[]],routingKeyPattern:[e?e.routingKeyPattern:null,[]],messageProperties:[e?e.messageProperties:null,[]],host:[e?e.host:null,[T.required]],port:[e?e.port:null,[T.required,T.min(1),T.max(65535)]],virtualHost:[e?e.virtualHost:null,[]],username:[e?e.username:null,[]],password:[e?e.password:null,[]],automaticRecoveryEnabled:[!!e&&e.automaticRecoveryEnabled,[]],connectionTimeout:[e?e.connectionTimeout:null,[T.min(0)]],handshakeTimeout:[e?e.handshakeTimeout:null,[T.min(0)]],clientProperties:[e?e.clientProperties:null,[]]})}}ft.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:ft,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),ft.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:ft,selector:"tb-action-node-rabbit-mq-config",usesInheritance:!0,ngImport:e,template:'
\n \n tb.rulenode.exchange-name-pattern\n \n \n \n tb.rulenode.routing-key-pattern\n \n \n \n tb.rulenode.message-properties\n \n \n {{ property }}\n \n \n \n
\n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n
\n \n tb.rulenode.virtual-host\n \n \n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n \n {{ \'tb.rulenode.automatic-recovery\' | translate }}\n \n \n tb.rulenode.connection-timeout-ms\n \n \n {{ \'tb.rulenode.min-connection-timeout-ms-message\' | translate }}\n \n \n \n tb.rulenode.handshake-timeout-ms\n \n \n {{ \'tb.rulenode.min-handshake-timeout-ms-message\' | translate }}\n \n \n \n \n \n
\n',components:[{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:H.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:U.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:K.TogglePasswordComponent,selector:"tb-toggle-password"},{type:D.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:rt,selector:"tb-kv-map-config",inputs:["disabled","requiredText","keyText","keyRequiredText","valText","valRequiredText","required"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:G.MatLabel,selector:"mat-label"},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:V.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:G.MatError,selector:"mat-error",inputs:["id"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{type:G.MatSuffix,selector:"[matSuffix]"}],pipes:{translate:E.TranslatePipe}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:ft,decorators:[{type:t,args:[{selector:"tb-action-node-rabbit-mq-config",templateUrl:"./rabbit-mq-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class ct extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.proxySchemes=["http","https"],this.httpRequestTypes=Object.keys(ze)}configForm(){return this.restApiCallConfigForm}onConfigurationSet(e){this.restApiCallConfigForm=this.fb.group({restEndpointUrlPattern:[e?e.restEndpointUrlPattern:null,[T.required]],requestMethod:[e?e.requestMethod:null,[T.required]],useSimpleClientHttpFactory:[!!e&&e.useSimpleClientHttpFactory,[]],ignoreRequestBody:[!!e&&e.ignoreRequestBody,[]],enableProxy:[!!e&&e.enableProxy,[]],useSystemProxyProperties:[!!e&&e.enableProxy,[]],proxyScheme:[e?e.proxyHost:null,[]],proxyHost:[e?e.proxyHost:null,[]],proxyPort:[e?e.proxyPort:null,[]],proxyUser:[e?e.proxyUser:null,[]],proxyPassword:[e?e.proxyPassword:null,[]],readTimeoutMs:[e?e.readTimeoutMs:null,[]],maxParallelRequestsCount:[e?e.maxParallelRequestsCount:null,[T.min(0)]],headers:[e?e.headers:null,[]],useRedisQueueForMsgPersistence:[!!e&&e.useRedisQueueForMsgPersistence,[]],trimQueue:[!!e&&e.trimQueue,[]],maxQueueSize:[e?e.maxQueueSize:null,[]],credentials:[e?e.credentials:null,[]]})}validatorTriggers(){return["useSimpleClientHttpFactory","useRedisQueueForMsgPersistence","enableProxy","useSystemProxyProperties"]}updateValidators(e){const t=this.restApiCallConfigForm.get("useSimpleClientHttpFactory").value,o=this.restApiCallConfigForm.get("useRedisQueueForMsgPersistence").value,r=this.restApiCallConfigForm.get("enableProxy").value,a=this.restApiCallConfigForm.get("useSystemProxyProperties").value;r&&!a?(this.restApiCallConfigForm.get("proxyHost").setValidators(r?[T.required]:[]),this.restApiCallConfigForm.get("proxyPort").setValidators(r?[T.required,T.min(1),T.max(65535)]:[])):(this.restApiCallConfigForm.get("proxyHost").setValidators([]),this.restApiCallConfigForm.get("proxyPort").setValidators([]),t?this.restApiCallConfigForm.get("readTimeoutMs").setValidators([]):this.restApiCallConfigForm.get("readTimeoutMs").setValidators([T.min(0)])),o?this.restApiCallConfigForm.get("maxQueueSize").setValidators([T.min(0)]):this.restApiCallConfigForm.get("maxQueueSize").setValidators([]),this.restApiCallConfigForm.get("readTimeoutMs").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("maxQueueSize").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("proxyHost").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("proxyPort").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("credentials").updateValueAndValidity({emitEvent:e})}}ct.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:ct,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),ct.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:ct,selector:"tb-action-node-rest-api-call-config",usesInheritance:!0,ngImport:e,template:'
\n \n tb.rulenode.endpoint-url-pattern\n \n \n {{ \'tb.rulenode.endpoint-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.request-method\n \n \n {{ requestType }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n \n {{ \'tb.rulenode.use-simple-client-http-factory\' | translate }}\n \n \n {{ \'tb.rulenode.ignore-request-body\' | translate }}\n \n
\n \n {{ \'tb.rulenode.use-system-proxy-properties\' | translate }}\n \n
\n
\n \n tb.rulenode.proxy-scheme\n \n \n {{ proxyScheme }}\n \n \n \n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
\n
\n \n tb.rulenode.read-timeout\n \n tb.rulenode.read-timeout-hint\n \n \n tb.rulenode.max-parallel-requests-count\n \n tb.rulenode.max-parallel-requests-count-hint\n \n \n
\n \n \n \n {{ \'tb.rulenode.use-redis-queue\' | translate }}\n \n
\n \n {{ \'tb.rulenode.trim-redis-queue\' | translate }}\n \n \n tb.rulenode.redis-queue-max-size\n \n \n
\n \n
\n',components:[{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:H.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:U.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:D.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:rt,selector:"tb-kv-map-config",inputs:["disabled","requiredText","keyText","keyRequiredText","valText","valRequiredText","required"]},{type:lt,selector:"tb-credentials-config",inputs:["required","disableCertPemCredentials","passwordFieldRquired"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:G.MatLabel,selector:"mat-label"},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:G.MatError,selector:"mat-error",inputs:["id"]},{type:G.MatHint,selector:"mat-hint",inputs:["align","id"]},{type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:V.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]}],pipes:{translate:E.TranslatePipe,safeHtml:Ie}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:ct,decorators:[{type:t,args:[{selector:"tb-action-node-rest-api-call-config",templateUrl:"./rest-api-call-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class gt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.rpcReplyConfigForm}onConfigurationSet(e){this.rpcReplyConfigForm=this.fb.group({requestIdMetaDataAttribute:[e?e.requestIdMetaDataAttribute:null,[]]})}}gt.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:gt,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),gt.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:gt,selector:"tb-action-node-rpc-reply-config",usesInheritance:!0,ngImport:e,template:'
\n \n tb.rulenode.request-id-metadata-attribute\n \n \n
\n',components:[{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:G.MatLabel,selector:"mat-label"},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]}]}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:gt,decorators:[{type:t,args:[{selector:"tb-action-node-rpc-reply-config",templateUrl:"./rpc-reply-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class xt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.rpcRequestConfigForm}onConfigurationSet(e){this.rpcRequestConfigForm=this.fb.group({timeoutInSeconds:[e?e.timeoutInSeconds:null,[T.required,T.min(0)]]})}}xt.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:xt,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),xt.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:xt,selector:"tb-action-node-rpc-request-config",usesInheritance:!0,ngImport:e,template:'
\n \n tb.rulenode.timeout-sec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-message\' | translate }}\n \n \n
\n',components:[{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:G.MatLabel,selector:"mat-label"},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:G.MatError,selector:"mat-error",inputs:["id"]}],pipes:{translate:E.TranslatePipe}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:xt,decorators:[{type:t,args:[{selector:"tb-action-node-rpc-request-config",templateUrl:"./rpc-request-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class yt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.saveToCustomTableConfigForm}onConfigurationSet(e){this.saveToCustomTableConfigForm=this.fb.group({tableName:[e?e.tableName:null,[T.required,T.pattern(/.*\S.*/)]],fieldsMapping:[e?e.fieldsMapping:null,[T.required]]})}prepareOutputConfig(e){return e.tableName=e.tableName.trim(),e}}yt.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:yt,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),yt.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:yt,selector:"tb-action-node-custom-table-config",usesInheritance:!0,ngImport:e,template:'
\n \n tb.rulenode.custom-table-name\n \n \n {{ \'tb.rulenode.custom-table-name-required\' | translate }}\n \n tb.rulenode.custom-table-hint\n \n \n \n \n
\n',components:[{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:rt,selector:"tb-kv-map-config",inputs:["disabled","requiredText","keyText","keyRequiredText","valText","valRequiredText","required"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:G.MatLabel,selector:"mat-label"},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:G.MatError,selector:"mat-error",inputs:["id"]},{type:G.MatHint,selector:"mat-hint",inputs:["align","id"]}],pipes:{translate:E.TranslatePipe}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:yt,decorators:[{type:t,args:[{selector:"tb-action-node-custom-table-config",templateUrl:"./save-to-custom-table-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class bt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.smtpProtocols=["smtp","smtps"],this.tlsVersions=["TLSv1","TLSv1.1","TLSv1.2","TLSv1.3"]}configForm(){return this.sendEmailConfigForm}onConfigurationSet(e){this.sendEmailConfigForm=this.fb.group({useSystemSmtpSettings:[!!e&&e.useSystemSmtpSettings,[]],smtpProtocol:[e?e.smtpProtocol:null,[]],smtpHost:[e?e.smtpHost:null,[]],smtpPort:[e?e.smtpPort:null,[]],timeout:[e?e.timeout:null,[]],enableTls:[!!e&&e.enableTls,[]],tlsVersion:[e?e.tlsVersion:null,[]],enableProxy:[!!e&&e.enableProxy,[]],proxyHost:[e?e.proxyHost:null,[]],proxyPort:[e?e.proxyPort:null,[]],proxyUser:[e?e.proxyUser:null,[]],proxyPassword:[e?e.proxyPassword:null,[]],username:[e?e.username:null,[]],password:[e?e.password:null,[]]})}validatorTriggers(){return["useSystemSmtpSettings","enableProxy"]}updateValidators(e){const t=this.sendEmailConfigForm.get("useSystemSmtpSettings").value,o=this.sendEmailConfigForm.get("enableProxy").value;t?(this.sendEmailConfigForm.get("smtpProtocol").setValidators([]),this.sendEmailConfigForm.get("smtpHost").setValidators([]),this.sendEmailConfigForm.get("smtpPort").setValidators([]),this.sendEmailConfigForm.get("timeout").setValidators([]),this.sendEmailConfigForm.get("proxyHost").setValidators([]),this.sendEmailConfigForm.get("proxyPort").setValidators([])):(this.sendEmailConfigForm.get("smtpProtocol").setValidators([T.required]),this.sendEmailConfigForm.get("smtpHost").setValidators([T.required]),this.sendEmailConfigForm.get("smtpPort").setValidators([T.required,T.min(1),T.max(65535)]),this.sendEmailConfigForm.get("timeout").setValidators([T.required,T.min(0)]),this.sendEmailConfigForm.get("proxyHost").setValidators(o?[T.required]:[]),this.sendEmailConfigForm.get("proxyPort").setValidators(o?[T.required,T.min(1),T.max(65535)]:[])),this.sendEmailConfigForm.get("smtpProtocol").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("smtpHost").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("smtpPort").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("timeout").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("proxyHost").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("proxyPort").updateValueAndValidity({emitEvent:e})}}bt.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:bt,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),bt.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:bt,selector:"tb-action-node-send-email-config",usesInheritance:!0,ngImport:e,template:'
\n \n {{ \'tb.rulenode.use-system-smtp-settings\' | translate }}\n \n
\n \n tb.rulenode.smtp-protocol\n \n \n {{ smtpProtocol.toUpperCase() }}\n \n \n \n
\n \n tb.rulenode.smtp-host\n \n \n {{ \'tb.rulenode.smtp-host-required\' | translate }}\n \n \n \n tb.rulenode.smtp-port\n \n \n {{ \'tb.rulenode.smtp-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.timeout-msec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-msec-message\' | translate }}\n \n \n \n {{ \'tb.rulenode.enable-tls\' | translate }}\n \n \n tb.rulenode.tls-version\n \n \n {{ tlsVersion }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n
\n
\n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
\n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n
\n
\n',components:[{type:D.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:H.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:U.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:de.TbCheckboxComponent,selector:"tb-checkbox",inputs:["disabled","trueValue","falseValue"],outputs:["valueChange"]},{type:K.TogglePasswordComponent,selector:"tb-toggle-password"}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:G.MatLabel,selector:"mat-label"},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:V.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:G.MatError,selector:"mat-error",inputs:["id"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{type:G.MatSuffix,selector:"[matSuffix]"}],pipes:{translate:E.TranslatePipe}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:bt,decorators:[{type:t,args:[{selector:"tb-action-node-send-email-config",templateUrl:"./send-email-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class ht extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.sendSmsConfigForm}onConfigurationSet(e){this.sendSmsConfigForm=this.fb.group({numbersToTemplate:[e?e.numbersToTemplate:null,[T.required]],smsMessageTemplate:[e?e.smsMessageTemplate:null,[T.required]],useSystemSmsSettings:[!!e&&e.useSystemSmsSettings,[]],smsProviderConfiguration:[e?e.smsProviderConfiguration:null,[]]})}validatorTriggers(){return["useSystemSmsSettings"]}updateValidators(e){this.sendSmsConfigForm.get("useSystemSmsSettings").value?this.sendSmsConfigForm.get("smsProviderConfiguration").setValidators([]):this.sendSmsConfigForm.get("smsProviderConfiguration").setValidators([T.required]),this.sendSmsConfigForm.get("smsProviderConfiguration").updateValueAndValidity({emitEvent:e})}}ht.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:ht,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),ht.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:ht,selector:"tb-action-node-send-sms-config",usesInheritance:!0,ngImport:e,template:'
\n \n tb.rulenode.numbers-to-template\n \n \n {{ \'tb.rulenode.numbers-to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.sms-message-template\n \n \n {{ \'tb.rulenode.sms-message-template-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-system-sms-settings\' | translate }}\n \n \n \n
\n',components:[{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:D.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:fe.SmsProviderConfigurationComponent,selector:"tb-sms-provider-configuration",inputs:["required","disabled"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:G.MatLabel,selector:"mat-label"},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:G.MatError,selector:"mat-error",inputs:["id"]},{type:G.MatHint,selector:"mat-hint",inputs:["align","id"]}],pipes:{translate:E.TranslatePipe,safeHtml:Ie}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:ht,decorators:[{type:t,args:[{selector:"tb-action-node-send-sms-config",templateUrl:"./send-sms-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class Ft extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.snsConfigForm}onConfigurationSet(e){this.snsConfigForm=this.fb.group({topicArnPattern:[e?e.topicArnPattern:null,[T.required]],accessKeyId:[e?e.accessKeyId:null,[T.required]],secretAccessKey:[e?e.secretAccessKey:null,[T.required]],region:[e?e.region:null,[T.required]]})}}Ft.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Ft,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),Ft.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Ft,selector:"tb-action-node-sns-config",usesInheritance:!0,ngImport:e,template:'
\n \n tb.rulenode.topic-arn-pattern\n \n \n {{ \'tb.rulenode.topic-arn-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
\n',components:[{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:G.MatLabel,selector:"mat-label"},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:G.MatError,selector:"mat-error",inputs:["id"]},{type:G.MatHint,selector:"mat-hint",inputs:["align","id"]}],pipes:{translate:E.TranslatePipe,safeHtml:Ie}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Ft,decorators:[{type:t,args:[{selector:"tb-action-node-sns-config",templateUrl:"./sns-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class Ct extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.sqsQueueType=Oe,this.sqsQueueTypes=Object.keys(Oe),this.sqsQueueTypeTranslationsMap=He}configForm(){return this.sqsConfigForm}onConfigurationSet(e){this.sqsConfigForm=this.fb.group({queueType:[e?e.queueType:null,[T.required]],queueUrlPattern:[e?e.queueUrlPattern:null,[T.required]],delaySeconds:[e?e.delaySeconds:null,[T.min(0),T.max(900)]],messageAttributes:[e?e.messageAttributes:null,[]],accessKeyId:[e?e.accessKeyId:null,[T.required]],secretAccessKey:[e?e.secretAccessKey:null,[T.required]],region:[e?e.region:null,[T.required]]})}}Ct.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Ct,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),Ct.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Ct,selector:"tb-action-node-sqs-config",usesInheritance:!0,ngImport:e,template:'
\n \n tb.rulenode.queue-type\n \n \n {{ sqsQueueTypeTranslationsMap.get(type) | translate }}\n \n \n \n \n tb.rulenode.queue-url-pattern\n \n \n {{ \'tb.rulenode.queue-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.delay-seconds\n \n \n {{ \'tb.rulenode.min-delay-seconds-message\' | translate }}\n \n \n {{ \'tb.rulenode.max-delay-seconds-message\' | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
\n',components:[{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:H.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:U.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:rt,selector:"tb-kv-map-config",inputs:["disabled","requiredText","keyText","keyRequiredText","valText","valRequiredText","required"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:G.MatLabel,selector:"mat-label"},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:G.MatError,selector:"mat-error",inputs:["id"]},{type:G.MatHint,selector:"mat-hint",inputs:["align","id"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"}],pipes:{translate:E.TranslatePipe,safeHtml:Ie}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Ct,decorators:[{type:t,args:[{selector:"tb-action-node-sqs-config",templateUrl:"./sqs-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class Lt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.timeseriesConfigForm}onConfigurationSet(e){this.timeseriesConfigForm=this.fb.group({defaultTTL:[e?e.defaultTTL:null,[T.required,T.min(0)]]})}}Lt.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Lt,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),Lt.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Lt,selector:"tb-action-node-timeseries-config",usesInheritance:!0,ngImport:e,template:'
\n \n tb.rulenode.default-ttl\n \n \n {{ \'tb.rulenode.default-ttl-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-default-ttl-message\' | translate }}\n \n \n
\n',components:[{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:G.MatLabel,selector:"mat-label"},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:G.MatError,selector:"mat-error",inputs:["id"]}],pipes:{translate:E.TranslatePipe}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Lt,decorators:[{type:t,args:[{selector:"tb-action-node-timeseries-config",templateUrl:"./timeseries-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class vt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.unassignCustomerConfigForm}onConfigurationSet(e){this.unassignCustomerConfigForm=this.fb.group({customerNamePattern:[e?e.customerNamePattern:null,[T.required,T.pattern(/.*\S.*/)]],customerCacheExpiration:[e?e.customerCacheExpiration:null,[T.required,T.min(0)]]})}prepareOutputConfig(e){return e.customerNamePattern=e.customerNamePattern.trim(),e}}vt.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:vt,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),vt.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:vt,selector:"tb-action-node-un-assign-to-customer-config",usesInheritance:!0,ngImport:e,template:'
\n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n tb.rulenode.customer-cache-expiration-hint\n \n
\n',components:[{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:G.MatLabel,selector:"mat-label"},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:G.MatError,selector:"mat-error",inputs:["id"]},{type:G.MatHint,selector:"mat-hint",inputs:["align","id"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"}],pipes:{translate:E.TranslatePipe,safeHtml:Ie}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:vt,decorators:[{type:t,args:[{selector:"tb-action-node-un-assign-to-customer-config",templateUrl:"./unassign-customer-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class It extends y{constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.keys(c),this.directionTypeTranslations=g,this.entityType=x,this.propagateChange=null}get required(){return this.requiredValue}set required(e){this.requiredValue=re(e)}ngOnInit(){this.deviceRelationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[T.required]],maxLevel:[null,[]],relationType:[null],deviceTypes:[null,[T.required]]}),this.deviceRelationsQueryFormGroup.valueChanges.subscribe((e=>{this.deviceRelationsQueryFormGroup.valid?this.propagateChange(e):this.propagateChange(null)}))}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.deviceRelationsQueryFormGroup.disable({emitEvent:!1}):this.deviceRelationsQueryFormGroup.enable({emitEvent:!1})}writeValue(e){this.deviceRelationsQueryFormGroup.reset(e,{emitEvent:!1})}}It.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:It,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),It.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:It,selector:"tb-device-relations-query-config",inputs:{disabled:"disabled",required:"required"},providers:[{provide:M,useExisting:a((()=>It)),multi:!0}],usesInheritance:!0,ngImport:e,template:'
\n \n {{ \'alias.last-level-relation\' | translate }}\n \n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n
\n
relation.relation-type
\n \n \n
device.device-types
\n \n \n
\n',components:[{type:D.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:H.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:U.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:ge.RelationTypeAutocompleteComponent,selector:"tb-relation-type-autocomplete",inputs:["required","disabled"]},{type:xe.EntitySubTypeListComponent,selector:"tb-entity-subtype-list",inputs:["required","disabled","entityType"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:V.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{type:G.MatLabel,selector:"mat-label"},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"}],pipes:{translate:E.TranslatePipe}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:It,decorators:[{type:t,args:[{selector:"tb-device-relations-query-config",templateUrl:"./device-relations-query-config.component.html",styleUrls:[],providers:[{provide:M,useExisting:a((()=>It)),multi:!0}]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]},propDecorators:{disabled:[{type:n}],required:[{type:n}]}});class Nt extends y{constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.keys(c),this.directionTypeTranslations=g,this.propagateChange=null}get required(){return this.requiredValue}set required(e){this.requiredValue=re(e)}ngOnInit(){this.relationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[T.required]],maxLevel:[null,[]],filters:[null]}),this.relationsQueryFormGroup.valueChanges.subscribe((e=>{this.relationsQueryFormGroup.valid?this.propagateChange(e):this.propagateChange(null)}))}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.relationsQueryFormGroup.disable({emitEvent:!1}):this.relationsQueryFormGroup.enable({emitEvent:!1})}writeValue(e){this.relationsQueryFormGroup.reset(e||{},{emitEvent:!1})}}Nt.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Nt,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),Nt.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Nt,selector:"tb-relations-query-config",inputs:{disabled:"disabled",required:"required"},providers:[{provide:M,useExisting:a((()=>Nt)),multi:!0}],usesInheritance:!0,ngImport:e,template:'
\n \n {{ \'alias.last-level-relation\' | translate }}\n \n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n
\n
relation.relation-filters
\n \n
\n',components:[{type:D.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:H.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:U.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:ye.RelationFiltersComponent,selector:"tb-relation-filters",inputs:["disabled","allowedEntityTypes"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:V.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{type:G.MatLabel,selector:"mat-label"},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"}],pipes:{translate:E.TranslatePipe}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Nt,decorators:[{type:t,args:[{selector:"tb-relations-query-config",templateUrl:"./relations-query-config.component.html",styleUrls:[],providers:[{provide:M,useExisting:a((()=>Nt)),multi:!0}]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]},propDecorators:{disabled:[{type:n}],required:[{type:n}]}});class qt extends y{constructor(e,t,o,r){super(e),this.store=e,this.translate=t,this.truncate=o,this.fb=r,this.placeholder="tb.rulenode.message-type",this.separatorKeysCodes=[Y,J,Z],this.messageTypes=[],this.messageTypesList=[],this.searchText="",this.propagateChange=e=>{},this.messageTypeConfigForm=this.fb.group({messageType:[null]});for(const e of Object.keys(b))this.messageTypesList.push({name:h.get(b[e]),value:e})}get required(){return this.requiredValue}set required(e){this.requiredValue=re(e)}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}ngOnInit(){this.filteredMessageTypes=this.messageTypeConfigForm.get("messageType").valueChanges.pipe(se(""),me((e=>e||"")),ue((e=>this.fetchMessageTypes(e))),pe())}ngAfterViewInit(){}setDisabledState(e){this.disabled=e,this.disabled?this.messageTypeConfigForm.disable({emitEvent:!1}):this.messageTypeConfigForm.enable({emitEvent:!1})}writeValue(e){this.searchText="",this.messageTypes.length=0,e&&e.forEach((e=>{const t=this.messageTypesList.find((t=>t.value===e));t?this.messageTypes.push({name:t.name,value:t.value}):this.messageTypes.push({name:e,value:e})}))}displayMessageTypeFn(e){return e?e.name:void 0}textIsNotEmpty(e){return!!(e&&null!=e&&e.length>0)}createMessageType(e,t){e.preventDefault(),this.transformMessageType(t)}add(e){this.transformMessageType(e.value)}fetchMessageTypes(e){if(this.searchText=e,this.searchText&&this.searchText.length){const e=this.searchText.toUpperCase();return be(this.messageTypesList.filter((t=>t.name.toUpperCase().includes(e))))}return be(this.messageTypesList)}transformMessageType(e){if((e||"").trim()){let t=null;const o=e.trim(),r=this.messageTypesList.find((e=>e.name===o));t=r?{name:r.name,value:r.value}:{name:o,value:o},t&&this.addMessageType(t)}this.clear("")}remove(e){const t=this.messageTypes.indexOf(e);t>=0&&(this.messageTypes.splice(t,1),this.updateModel())}selected(e){this.addMessageType(e.option.value),this.clear("")}addMessageType(e){-1===this.messageTypes.findIndex((t=>t.value===e.value))&&(this.messageTypes.push(e),this.updateModel())}onFocus(){this.messageTypeConfigForm.get("messageType").updateValueAndValidity({onlySelf:!0,emitEvent:!0})}clear(e=""){this.messageTypeInput.nativeElement.value=e,this.messageTypeConfigForm.get("messageType").patchValue(null,{emitEvent:!0}),setTimeout((()=>{this.messageTypeInput.nativeElement.blur(),this.messageTypeInput.nativeElement.focus()}),0)}updateModel(){const e=this.messageTypes.map((e=>e.value));this.required?(this.chipList.errorState=!e.length,this.propagateChange(e.length>0?e:null)):(this.chipList.errorState=!1,this.propagateChange(e))}}qt.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:qt,deps:[{token:N.Store},{token:E.TranslateService},{token:i.TruncatePipe},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),qt.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:qt,selector:"tb-message-types-config",inputs:{required:"required",label:"label",placeholder:"placeholder",disabled:"disabled"},providers:[{provide:M,useExisting:a((()=>qt)),multi:!0}],viewQueries:[{propertyName:"chipList",first:!0,predicate:["chipList"],descendants:!0},{propertyName:"matAutocomplete",first:!0,predicate:["messageTypeAutocomplete"],descendants:!0},{propertyName:"messageTypeInput",first:!0,predicate:["messageTypeInput"],descendants:!0}],usesInheritance:!0,ngImport:e,template:'\n {{ label }}\n \n \n {{messageType.name}}\n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-message-types-found\n
\n \n \n {{ translate.get(\'tb.rulenode.no-message-type-matching\',\n {messageType: truncate.transform(searchText, true, 6, '...')}) | async }}\n \n \n \n tb.rulenode.create-new-message-type\n \n
\n
\n
\n \n {{ \'tb.rulenode.message-types-required\' | translate }}\n \n
\n',components:[{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:X.MatChipList,selector:"mat-chip-list",inputs:["aria-orientation","multiple","compareWith","value","required","placeholder","disabled","selectable","tabIndex","errorStateMatcher"],outputs:["change","valueChange"],exportAs:["matChipList"]},{type:ee.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{type:he.MatAutocomplete,selector:"mat-autocomplete",inputs:["disableRipple"],exportAs:["matAutocomplete"]},{type:U.MatOption,selector:"mat-option",exportAs:["matOption"]}],directives:[{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:G.MatLabel,selector:"mat-label"},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:X.MatChip,selector:"mat-basic-chip, [mat-basic-chip], mat-chip, [mat-chip]",inputs:["color","disableRipple","tabIndex","selected","value","selectable","disabled","removable"],outputs:["selectionChange","destroyed","removed"],exportAs:["matChip"]},{type:X.MatChipRemove,selector:"[matChipRemove]"},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:he.MatAutocompleteTrigger,selector:"input[matAutocomplete], textarea[matAutocomplete]",exportAs:["matAutocompleteTrigger"]},{type:X.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputSeparatorKeyCodes","placeholder","id","matChipInputFor","matChipInputAddOnBlur","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:he.MatAutocompleteOrigin,selector:"[matAutocompleteOrigin]",exportAs:["matAutocompleteOrigin"]},{type:G.MatError,selector:"mat-error",inputs:["id"]}],pipes:{translate:E.TranslatePipe,async:R.AsyncPipe,highlight:Fe.HighlightPipe}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:qt,decorators:[{type:t,args:[{selector:"tb-message-types-config",templateUrl:"./message-types-config.component.html",styleUrls:[],providers:[{provide:M,useExisting:a((()=>qt)),multi:!0}]}]}],ctorParameters:function(){return[{type:N.Store},{type:E.TranslateService},{type:i.TruncatePipe},{type:q.FormBuilder}]},propDecorators:{required:[{type:n}],label:[{type:n}],placeholder:[{type:n}],disabled:[{type:n}],chipList:[{type:r,args:["chipList",{static:!1}]}],matAutocomplete:[{type:r,args:["messageTypeAutocomplete",{static:!1}]}],messageTypeInput:[{type:r,args:["messageTypeInput",{static:!1}]}]}});class Tt{}Tt.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Tt,deps:[],target:e.ɵɵFactoryTarget.NgModule}),Tt.ɵmod=e.ɵɵngDeclareNgModule({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Tt,declarations:[rt,It,Nt,qt,lt,Ie],imports:[w,F,ce],exports:[rt,It,Nt,qt,lt,Ie]}),Tt.ɵinj=e.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Tt,imports:[[w,F,ce]]}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Tt,decorators:[{type:l,args:[{declarations:[rt,It,Nt,qt,lt,Ie],imports:[w,F,ce],exports:[rt,It,Nt,qt,lt,Ie]}]}]});class kt{}kt.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:kt,deps:[],target:e.ɵɵFactoryTarget.NgModule}),kt.ɵmod=e.ɵɵngDeclareNgModule({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:kt,declarations:[qe,Lt,xt,nt,Ne,Ye,Je,Ze,mt,Xe,tt,ot,st,gt,yt,vt,Ft,Ct,ut,at,it,ft,ct,bt,We,$e,et,ht,dt,pt],imports:[w,F,ce,Tt],exports:[qe,Lt,xt,nt,Ne,Ye,Je,Ze,mt,Xe,tt,ot,st,gt,yt,vt,Ft,Ct,ut,at,it,ft,ct,bt,We,$e,et,ht,dt,pt]}),kt.ɵinj=e.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:kt,imports:[[w,F,ce,Tt]]}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:kt,decorators:[{type:l,args:[{declarations:[qe,Lt,xt,nt,Ne,Ye,Je,Ze,mt,Xe,tt,ot,st,gt,yt,vt,Ft,Ct,ut,at,it,ft,ct,bt,We,$e,et,ht,dt,pt],imports:[w,F,ce,Tt],exports:[qe,Lt,xt,nt,Ne,Ye,Je,Ze,mt,Xe,tt,ot,st,gt,yt,vt,Ft,Ct,ut,at,it,ft,ct,bt,We,$e,et,ht,dt,pt]}]}]});class Mt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.separatorKeysCodes=[Y,J,Z]}configForm(){return this.calculateDeltaConfigForm}onConfigurationSet(e){this.calculateDeltaConfigForm=this.fb.group({inputValueKey:[e?e.inputValueKey:null,[T.required]],outputValueKey:[e?e.outputValueKey:null,[T.required]],useCache:[e?e.useCache:null,[]],addPeriodBetweenMsgs:[!!e&&e.addPeriodBetweenMsgs,[]],periodValueKey:[e?e.periodValueKey:null,[]],round:[e?e.round:null,[T.min(0),T.max(15)]],tellFailureIfDeltaIsNegative:[e?e.tellFailureIfDeltaIsNegative:null,[]]})}updateValidators(e){this.calculateDeltaConfigForm.get("addPeriodBetweenMsgs").value?this.calculateDeltaConfigForm.get("periodValueKey").setValidators([T.required]):this.calculateDeltaConfigForm.get("periodValueKey").setValidators([]),this.calculateDeltaConfigForm.get("periodValueKey").updateValueAndValidity({emitEvent:e})}validatorTriggers(){return["addPeriodBetweenMsgs"]}}Mt.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Mt,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),Mt.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Mt,selector:"tb-enrichment-node-calculate-delta-config",usesInheritance:!0,ngImport:e,template:'
\n
\n \n tb.rulenode.input-value-key\n \n \n {{ \'tb.rulenode.input-value-key-required\' | translate }}\n \n \n \n tb.rulenode.output-value-key\n \n \n {{ \'tb.rulenode.output-value-key-required\' | translate }}\n \n \n \n tb.rulenode.round\n \n \n {{ \'tb.rulenode.round-range\' | translate }}\n \n \n {{ \'tb.rulenode.round-range\' | translate }}\n \n \n
\n \n {{ \'tb.rulenode.use-cache\' | translate }}\n \n \n {{ \'tb.rulenode.tell-failure-if-delta-is-negative\' | translate }}\n \n \n {{ \'tb.rulenode.add-period-between-msgs\' | translate }}\n \n \n tb.rulenode.period-value-key\n \n \n {{ \'tb.rulenode.period-value-key-required\' | translate }}\n \n \n
\n',components:[{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:D.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:V.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:G.MatLabel,selector:"mat-label"},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:G.MatError,selector:"mat-error",inputs:["id"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"}],pipes:{translate:E.TranslatePipe}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Mt,decorators:[{type:t,args:[{selector:"tb-enrichment-node-calculate-delta-config",templateUrl:"./calculate-delta-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class St extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.customerAttributesConfigForm}onConfigurationSet(e){this.customerAttributesConfigForm=this.fb.group({telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[T.required]]})}}St.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:St,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),St.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:St,selector:"tb-enrichment-node-customer-attributes-config",usesInheritance:!0,ngImport:e,template:'
\n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
\n',components:[{type:D.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:rt,selector:"tb-kv-map-config",inputs:["disabled","requiredText","keyText","keyRequiredText","valText","valRequiredText","required"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]}],pipes:{translate:E.TranslatePipe}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:St,decorators:[{type:t,args:[{selector:"tb-enrichment-node-customer-attributes-config",templateUrl:"./customer-attributes-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class At extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.separatorKeysCodes=[Y,J,Z]}configForm(){return this.deviceAttributesConfigForm}onConfigurationSet(e){this.deviceAttributesConfigForm=this.fb.group({deviceRelationsQuery:[e?e.deviceRelationsQuery:null,[T.required]],tellFailureIfAbsent:[!!e&&e.tellFailureIfAbsent,[]],clientAttributeNames:[e?e.clientAttributeNames:null,[]],sharedAttributeNames:[e?e.sharedAttributeNames:null,[]],serverAttributeNames:[e?e.serverAttributeNames:null,[]],latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],getLatestValueWithTs:[!!e&&e.getLatestValueWithTs,[]]})}removeKey(e,t){const o=this.deviceAttributesConfigForm.get(t).value,r=o.indexOf(e);r>=0&&(o.splice(r,1),this.deviceAttributesConfigForm.get(t).setValue(o,{emitEvent:!0}))}addKey(e,t){const o=e.input;let r=e.value;if((r||"").trim()){r=r.trim();let e=this.deviceAttributesConfigForm.get(t).value;e&&-1!==e.indexOf(r)||(e||(e=[]),e.push(r),this.deviceAttributesConfigForm.get(t).setValue(e,{emitEvent:!0}))}o&&(o.value="")}}At.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:At,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),At.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:At,selector:"tb-enrichment-node-device-attributes-config",usesInheritance:!0,ngImport:e,template:'
\n \n \n \n \n {{ \'tb.rulenode.tell-failure-if-absent\' | translate }}\n \n
tb.rulenode.tell-failure-if-absent-hint
\n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n {{ \'tb.rulenode.get-latest-value-with-ts\' | translate }}\n \n
\n
\n',styles:[":host label.tb-title{margin-bottom:-10px}\n"],components:[{type:It,selector:"tb-device-relations-query-config",inputs:["disabled","required"]},{type:D.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:X.MatChipList,selector:"mat-chip-list",inputs:["aria-orientation","multiple","compareWith","value","required","placeholder","disabled","selectable","tabIndex","errorStateMatcher"],outputs:["change","valueChange"],exportAs:["matChipList"]},{type:ee.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:G.MatLabel,selector:"mat-label"},{type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:X.MatChip,selector:"mat-basic-chip, [mat-basic-chip], mat-chip, [mat-chip]",inputs:["color","disableRipple","tabIndex","selected","value","selectable","disabled","removable"],outputs:["selectionChange","destroyed","removed"],exportAs:["matChip"]},{type:X.MatChipRemove,selector:"[matChipRemove]"},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:X.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputSeparatorKeyCodes","placeholder","id","matChipInputFor","matChipInputAddOnBlur","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]}],pipes:{translate:E.TranslatePipe,safeHtml:Ie}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:At,decorators:[{type:t,args:[{selector:"tb-enrichment-node-device-attributes-config",templateUrl:"./device-attributes-config.component.html",styleUrls:["./device-attributes-config.component.scss"]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class Gt extends s{constructor(e,t,o){super(e),this.store=e,this.translate=t,this.fb=o,this.entityDetailsTranslationsMap=Pe,this.entityDetailsList=[],this.searchText="",this.displayDetailsFn=this.displayDetails.bind(this);for(const e of Object.keys(Ee))this.entityDetailsList.push(Ee[e]);this.detailsFormControl=new A(""),this.filteredEntityDetails=this.detailsFormControl.valueChanges.pipe(se(""),me((e=>e||"")),ue((e=>this.fetchEntityDetails(e))),pe())}ngOnInit(){super.ngOnInit()}configForm(){return this.entityDetailsConfigForm}prepareInputConfig(e){return this.searchText="",this.detailsFormControl.patchValue("",{emitEvent:!0}),e}onConfigurationSet(e){this.entityDetailsConfigForm=this.fb.group({detailsList:[e?e.detailsList:null,[T.required]],addToMetadata:[!!e&&e.addToMetadata,[]]})}displayDetails(e){return e?this.translate.instant(Pe.get(e)):void 0}fetchEntityDetails(e){if(this.searchText=e,this.searchText&&this.searchText.length){const e=this.searchText.toUpperCase();return be(this.entityDetailsList.filter((t=>this.translate.instant(Pe.get(Ee[t])).toUpperCase().includes(e))))}return be(this.entityDetailsList)}detailsFieldSelected(e){this.addDetailsField(e.option.value),this.clear("")}removeDetailsField(e){const t=this.entityDetailsConfigForm.get("detailsList").value;if(t){const o=t.indexOf(e);o>=0&&(t.splice(o,1),this.entityDetailsConfigForm.get("detailsList").setValue(t))}}addDetailsField(e){let t=this.entityDetailsConfigForm.get("detailsList").value;t||(t=[]);-1===t.indexOf(e)&&(t.push(e),this.entityDetailsConfigForm.get("detailsList").setValue(t))}onEntityDetailsInputFocus(){this.detailsFormControl.updateValueAndValidity({onlySelf:!0,emitEvent:!0})}clear(e=""){this.detailsInput.nativeElement.value=e,this.detailsFormControl.patchValue(null,{emitEvent:!0}),setTimeout((()=>{this.detailsInput.nativeElement.blur(),this.detailsInput.nativeElement.focus()}),0)}}Gt.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Gt,deps:[{token:N.Store},{token:E.TranslateService},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),Gt.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Gt,selector:"tb-enrichment-node-entity-details-config",viewQueries:[{propertyName:"detailsInput",first:!0,predicate:["detailsInput"],descendants:!0}],usesInheritance:!0,ngImport:e,template:'
\n \n tb.rulenode.entity-details\n \n \n \n {{entityDetailsTranslationsMap.get(details) | translate}}\n \n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-entity-details-matching\n
\n
\n
\n
\n
\n \n \n {{ \'tb.rulenode.add-to-metadata\' | translate }}\n \n
tb.rulenode.add-to-metadata-hint
\n
\n',styles:[":host ::ng-deep mat-form-field.entity-fields-list .mat-form-field-wrapper{margin-bottom:-1.25em}\n"],components:[{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:X.MatChipList,selector:"mat-chip-list",inputs:["aria-orientation","multiple","compareWith","value","required","placeholder","disabled","selectable","tabIndex","errorStateMatcher"],outputs:["change","valueChange"],exportAs:["matChipList"]},{type:ee.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{type:he.MatAutocomplete,selector:"mat-autocomplete",inputs:["disableRipple"],exportAs:["matAutocomplete"]},{type:U.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:ae.TbErrorComponent,selector:"tb-error",inputs:["error"]},{type:D.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:G.MatLabel,selector:"mat-label"},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:X.MatChip,selector:"mat-basic-chip, [mat-basic-chip], mat-chip, [mat-chip]",inputs:["color","disableRipple","tabIndex","selected","value","selectable","disabled","removable"],outputs:["selectionChange","destroyed","removed"],exportAs:["matChip"]},{type:X.MatChipRemove,selector:"[matChipRemove]"},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:he.MatAutocompleteTrigger,selector:"input[matAutocomplete], textarea[matAutocomplete]",exportAs:["matAutocompleteTrigger"]},{type:X.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputSeparatorKeyCodes","placeholder","id","matChipInputFor","matChipInputAddOnBlur","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{type:he.MatAutocompleteOrigin,selector:"[matAutocompleteOrigin]",exportAs:["matAutocompleteOrigin"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlDirective,selector:"[formControl]",inputs:["disabled","formControl","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]}],pipes:{translate:E.TranslatePipe,async:R.AsyncPipe,highlight:Fe.HighlightPipe}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Gt,decorators:[{type:t,args:[{selector:"tb-enrichment-node-entity-details-config",templateUrl:"./entity-details-config.component.html",styleUrls:["./entity-details-config.component.scss"]}]}],ctorParameters:function(){return[{type:N.Store},{type:E.TranslateService},{type:q.FormBuilder}]},propDecorators:{detailsInput:[{type:r,args:["detailsInput",{static:!1}]}]}});class Dt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.separatorKeysCodes=[Y,J,Z],this.aggregationTypes=C,this.aggregations=Object.keys(C),this.aggregationTypesTranslations=L,this.fetchMode=Re,this.fetchModes=Object.keys(Re),this.samplingOrders=Object.keys(we),this.timeUnits=Object.values(Ae),this.timeUnitsTranslationMap=Ge}configForm(){return this.getTelemetryFromDatabaseConfigForm}onConfigurationSet(e){this.getTelemetryFromDatabaseConfigForm=this.fb.group({latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],aggregation:[e?e.aggregation:null,[T.required]],fetchMode:[e?e.fetchMode:null,[T.required]],orderBy:[e?e.orderBy:null,[]],limit:[e?e.limit:null,[]],useMetadataIntervalPatterns:[!!e&&e.useMetadataIntervalPatterns,[]],startInterval:[e?e.startInterval:null,[]],startIntervalTimeUnit:[e?e.startIntervalTimeUnit:null,[]],endInterval:[e?e.endInterval:null,[]],endIntervalTimeUnit:[e?e.endIntervalTimeUnit:null,[]],startIntervalPattern:[e?e.startIntervalPattern:null,[]],endIntervalPattern:[e?e.endIntervalPattern:null,[]]})}validatorTriggers(){return["fetchMode","useMetadataIntervalPatterns"]}updateValidators(e){const t=this.getTelemetryFromDatabaseConfigForm.get("fetchMode").value,o=this.getTelemetryFromDatabaseConfigForm.get("useMetadataIntervalPatterns").value;t&&t===Re.ALL?(this.getTelemetryFromDatabaseConfigForm.get("aggregation").setValidators([T.required]),this.getTelemetryFromDatabaseConfigForm.get("orderBy").setValidators([T.required]),this.getTelemetryFromDatabaseConfigForm.get("limit").setValidators([T.required,T.min(2),T.max(1e3)])):(this.getTelemetryFromDatabaseConfigForm.get("aggregation").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("orderBy").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("limit").setValidators([])),o?(this.getTelemetryFromDatabaseConfigForm.get("startInterval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endInterval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").setValidators([T.required]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").setValidators([T.required])):(this.getTelemetryFromDatabaseConfigForm.get("startInterval").setValidators([T.required,T.min(1),T.max(2147483647)]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").setValidators([T.required]),this.getTelemetryFromDatabaseConfigForm.get("endInterval").setValidators([T.required,T.min(1),T.max(2147483647)]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").setValidators([T.required]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").setValidators([])),this.getTelemetryFromDatabaseConfigForm.get("aggregation").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("orderBy").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("limit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startInterval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endInterval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").updateValueAndValidity({emitEvent:e})}removeKey(e,t){const o=this.getTelemetryFromDatabaseConfigForm.get(t).value,r=o.indexOf(e);r>=0&&(o.splice(r,1),this.getTelemetryFromDatabaseConfigForm.get(t).setValue(o,{emitEvent:!0}))}addKey(e,t){const o=e.input;let r=e.value;if((r||"").trim()){r=r.trim();let e=this.getTelemetryFromDatabaseConfigForm.get(t).value;e&&-1!==e.indexOf(r)||(e||(e=[]),e.push(r),this.getTelemetryFromDatabaseConfigForm.get(t).setValue(e,{emitEvent:!0}))}o&&(o.value="")}}Dt.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Dt,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),Dt.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Dt,selector:"tb-enrichment-node-get-telemetry-from-database",usesInheritance:!0,ngImport:e,template:'
\n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.fetch-mode\n \n \n {{ mode }}\n \n \n tb.rulenode.fetch-mode-hint\n \n
\n \n aggregation.function\n \n \n {{ aggregationTypesTranslations.get(aggregationTypes[aggregation]) | translate }}\n \n \n \n \n tb.rulenode.order-by\n \n \n {{ order }}\n \n \n tb.rulenode.order-by-hint\n \n \n tb.rulenode.limit\n \n tb.rulenode.limit-hint\n \n
\n \n {{ \'tb.rulenode.use-metadata-interval-patterns\' | translate }}\n \n
tb.rulenode.use-metadata-interval-patterns-hint
\n
\n
\n \n tb.rulenode.start-interval\n \n \n {{ \'tb.rulenode.start-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.start-interval-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n tb.rulenode.end-interval\n \n \n {{ \'tb.rulenode.end-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.end-interval-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n \n tb.rulenode.start-interval-pattern\n \n \n {{ \'tb.rulenode.start-interval-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.end-interval-pattern\n \n \n {{ \'tb.rulenode.end-interval-pattern-required\' | translate }}\n \n \n \n \n
\n',styles:[":host label.tb-title{margin-bottom:-10px}\n"],components:[{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:X.MatChipList,selector:"mat-chip-list",inputs:["aria-orientation","multiple","compareWith","value","required","placeholder","disabled","selectable","tabIndex","errorStateMatcher"],outputs:["change","valueChange"],exportAs:["matChipList"]},{type:ee.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{type:H.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:U.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:D.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:G.MatLabel,selector:"mat-label"},{type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:X.MatChip,selector:"mat-basic-chip, [mat-basic-chip], mat-chip, [mat-chip]",inputs:["color","disableRipple","tabIndex","selected","value","selectable","disabled","removable"],outputs:["selectionChange","destroyed","removed"],exportAs:["matChip"]},{type:X.MatChipRemove,selector:"[matChipRemove]"},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:X.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputSeparatorKeyCodes","placeholder","id","matChipInputFor","matChipInputAddOnBlur","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{type:G.MatHint,selector:"mat-hint",inputs:["align","id"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:V.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:G.MatError,selector:"mat-error",inputs:["id"]}],pipes:{translate:E.TranslatePipe,safeHtml:Ie}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Dt,decorators:[{type:t,args:[{selector:"tb-enrichment-node-get-telemetry-from-database",templateUrl:"./get-telemetry-from-database-config.component.html",styleUrls:["./get-telemetry-from-database-config.component.scss"]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class Vt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.separatorKeysCodes=[Y,J,Z]}configForm(){return this.originatorAttributesConfigForm}onConfigurationSet(e){this.originatorAttributesConfigForm=this.fb.group({tellFailureIfAbsent:[!!e&&e.tellFailureIfAbsent,[]],clientAttributeNames:[e?e.clientAttributeNames:null,[]],sharedAttributeNames:[e?e.sharedAttributeNames:null,[]],serverAttributeNames:[e?e.serverAttributeNames:null,[]],latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],getLatestValueWithTs:[!!e&&e.getLatestValueWithTs,[]]})}removeKey(e,t){const o=this.originatorAttributesConfigForm.get(t).value,r=o.indexOf(e);r>=0&&(o.splice(r,1),this.originatorAttributesConfigForm.get(t).setValue(o,{emitEvent:!0}))}addKey(e,t){const o=e.input;let r=e.value;if((r||"").trim()){r=r.trim();let e=this.originatorAttributesConfigForm.get(t).value;e&&-1!==e.indexOf(r)||(e||(e=[]),e.push(r),this.originatorAttributesConfigForm.get(t).setValue(e,{emitEvent:!0}))}o&&(o.value="")}}Vt.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Vt,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),Vt.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Vt,selector:"tb-enrichment-node-originator-attributes-config",usesInheritance:!0,ngImport:e,template:'
\n \n {{ \'tb.rulenode.tell-failure-if-absent\' | translate }}\n \n
tb.rulenode.tell-failure-if-absent-hint
\n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n {{ \'tb.rulenode.get-latest-value-with-ts\' | translate }}\n \n
\n
\n',styles:[":host label.tb-title{margin-bottom:-10px}\n"],components:[{type:D.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:X.MatChipList,selector:"mat-chip-list",inputs:["aria-orientation","multiple","compareWith","value","required","placeholder","disabled","selectable","tabIndex","errorStateMatcher"],outputs:["change","valueChange"],exportAs:["matChipList"]},{type:ee.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:G.MatLabel,selector:"mat-label"},{type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:X.MatChip,selector:"mat-basic-chip, [mat-basic-chip], mat-chip, [mat-chip]",inputs:["color","disableRipple","tabIndex","selected","value","selectable","disabled","removable"],outputs:["selectionChange","destroyed","removed"],exportAs:["matChip"]},{type:X.MatChipRemove,selector:"[matChipRemove]"},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:X.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputSeparatorKeyCodes","placeholder","id","matChipInputFor","matChipInputAddOnBlur","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{type:G.MatHint,selector:"mat-hint",inputs:["align","id"]}],pipes:{translate:E.TranslatePipe,safeHtml:Ie}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Vt,decorators:[{type:t,args:[{selector:"tb-enrichment-node-originator-attributes-config",templateUrl:"./originator-attributes-config.component.html",styleUrls:["./originator-attributes-config.component.scss"]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class Et extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.originatorFieldsConfigForm}onConfigurationSet(e){this.originatorFieldsConfigForm=this.fb.group({fieldsMapping:[e?e.fieldsMapping:null,[T.required]]})}}Et.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Et,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),Et.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Et,selector:"tb-enrichment-node-originator-fields-config",usesInheritance:!0,ngImport:e,template:'
\n \n \n \n
\n',components:[{type:rt,selector:"tb-kv-map-config",inputs:["disabled","requiredText","keyText","keyRequiredText","valText","valRequiredText","required"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]}]}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Et,decorators:[{type:t,args:[{selector:"tb-enrichment-node-originator-fields-config",templateUrl:"./originator-fields-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class Pt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.relatedAttributesConfigForm}onConfigurationSet(e){this.relatedAttributesConfigForm=this.fb.group({relationsQuery:[e?e.relationsQuery:null,[T.required]],telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[T.required]]})}}Pt.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Pt,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),Pt.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Pt,selector:"tb-enrichment-node-related-attributes-config",usesInheritance:!0,ngImport:e,template:'
\n \n \n \n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
\n',components:[{type:Nt,selector:"tb-relations-query-config",inputs:["disabled","required"]},{type:D.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:rt,selector:"tb-kv-map-config",inputs:["disabled","requiredText","keyText","keyRequiredText","valText","valRequiredText","required"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]}],pipes:{translate:E.TranslatePipe}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Pt,decorators:[{type:t,args:[{selector:"tb-enrichment-node-related-attributes-config",templateUrl:"./related-attributes-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class Rt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.tenantAttributesConfigForm}onConfigurationSet(e){this.tenantAttributesConfigForm=this.fb.group({telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[T.required]]})}}Rt.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Rt,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),Rt.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Rt,selector:"tb-enrichment-node-tenant-attributes-config",usesInheritance:!0,ngImport:e,template:'
\n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
\n',components:[{type:D.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:rt,selector:"tb-kv-map-config",inputs:["disabled","requiredText","keyText","keyRequiredText","valText","valRequiredText","required"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]}],pipes:{translate:E.TranslatePipe}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Rt,decorators:[{type:t,args:[{selector:"tb-enrichment-node-tenant-attributes-config",templateUrl:"./tenant-attributes-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class wt{}wt.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:wt,deps:[],target:e.ɵɵFactoryTarget.NgModule}),wt.ɵmod=e.ɵɵngDeclareNgModule({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:wt,declarations:[St,Gt,At,Vt,Et,Dt,Pt,Rt,Mt],imports:[w,F,Tt],exports:[St,Gt,At,Vt,Et,Dt,Pt,Rt,Mt]}),wt.ɵinj=e.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:wt,imports:[[w,F,Tt]]}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:wt,decorators:[{type:l,args:[{declarations:[St,Gt,At,Vt,Et,Dt,Pt,Rt,Mt],imports:[w,F,Tt],exports:[St,Gt,At,Vt,Et,Dt,Pt,Rt,Mt]}]}]});class Ot extends s{constructor(e,t,o){super(e),this.store=e,this.translate=t,this.fb=o,this.alarmStatusTranslationsMap=v,this.alarmStatusList=[],this.searchText="",this.displayStatusFn=this.displayStatus.bind(this);for(const e of Object.keys(I))this.alarmStatusList.push(I[e]);this.statusFormControl=new A(""),this.filteredAlarmStatus=this.statusFormControl.valueChanges.pipe(se(""),me((e=>e||"")),ue((e=>this.fetchAlarmStatus(e))),pe())}ngOnInit(){super.ngOnInit()}configForm(){return this.alarmStatusConfigForm}prepareInputConfig(e){return this.searchText="",this.statusFormControl.patchValue("",{emitEvent:!0}),e}onConfigurationSet(e){this.alarmStatusConfigForm=this.fb.group({alarmStatusList:[e?e.alarmStatusList:null,[T.required]]})}displayStatus(e){return e?this.translate.instant(v.get(e)):void 0}fetchAlarmStatus(e){const t=this.getAlarmStatusList();if(this.searchText=e,this.searchText&&this.searchText.length){const e=this.searchText.toUpperCase();return be(t.filter((t=>this.translate.instant(v.get(I[t])).toUpperCase().includes(e))))}return be(t)}alarmStatusSelected(e){this.addAlarmStatus(e.option.value),this.clear("")}removeAlarmStatus(e){const t=this.alarmStatusConfigForm.get("alarmStatusList").value;if(t){const o=t.indexOf(e);o>=0&&(t.splice(o,1),this.alarmStatusConfigForm.get("alarmStatusList").setValue(t))}}addAlarmStatus(e){let t=this.alarmStatusConfigForm.get("alarmStatusList").value;t||(t=[]);-1===t.indexOf(e)&&(t.push(e),this.alarmStatusConfigForm.get("alarmStatusList").setValue(t))}getAlarmStatusList(){return this.alarmStatusList.filter((e=>-1===this.alarmStatusConfigForm.get("alarmStatusList").value.indexOf(e)))}onAlarmStatusInputFocus(){this.statusFormControl.updateValueAndValidity({onlySelf:!0,emitEvent:!0})}clear(e=""){this.alarmStatusInput.nativeElement.value=e,this.statusFormControl.patchValue(null,{emitEvent:!0}),setTimeout((()=>{this.alarmStatusInput.nativeElement.blur(),this.alarmStatusInput.nativeElement.focus()}),0)}}Ot.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Ot,deps:[{token:N.Store},{token:E.TranslateService},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),Ot.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Ot,selector:"tb-filter-node-check-alarm-status-config",viewQueries:[{propertyName:"alarmStatusInput",first:!0,predicate:["alarmStatusInput"],descendants:!0}],usesInheritance:!0,ngImport:e,template:'
\n \n tb.rulenode.alarm-status-filter\n \n \n \n {{alarmStatusTranslationsMap.get(alarmStatus) | translate}}\n \n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-alarm-status-matching\n
\n
\n
\n
\n
\n \n
\n\n\n\n',components:[{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:X.MatChipList,selector:"mat-chip-list",inputs:["aria-orientation","multiple","compareWith","value","required","placeholder","disabled","selectable","tabIndex","errorStateMatcher"],outputs:["change","valueChange"],exportAs:["matChipList"]},{type:ee.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{type:he.MatAutocomplete,selector:"mat-autocomplete",inputs:["disableRipple"],exportAs:["matAutocomplete"]},{type:U.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:ae.TbErrorComponent,selector:"tb-error",inputs:["error"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:G.MatLabel,selector:"mat-label"},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:X.MatChip,selector:"mat-basic-chip, [mat-basic-chip], mat-chip, [mat-chip]",inputs:["color","disableRipple","tabIndex","selected","value","selectable","disabled","removable"],outputs:["selectionChange","destroyed","removed"],exportAs:["matChip"]},{type:X.MatChipRemove,selector:"[matChipRemove]"},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:he.MatAutocompleteTrigger,selector:"input[matAutocomplete], textarea[matAutocomplete]",exportAs:["matAutocompleteTrigger"]},{type:X.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputSeparatorKeyCodes","placeholder","id","matChipInputFor","matChipInputAddOnBlur","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{type:he.MatAutocompleteOrigin,selector:"[matAutocompleteOrigin]",exportAs:["matAutocompleteOrigin"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlDirective,selector:"[formControl]",inputs:["disabled","formControl","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]}],pipes:{translate:E.TranslatePipe,async:R.AsyncPipe,highlight:Fe.HighlightPipe}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Ot,decorators:[{type:t,args:[{selector:"tb-filter-node-check-alarm-status-config",templateUrl:"./check-alarm-status.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:E.TranslateService},{type:q.FormBuilder}]},propDecorators:{alarmStatusInput:[{type:r,args:["alarmStatusInput",{static:!1}]}]}});class Ht extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.separatorKeysCodes=[Y,J,Z]}configForm(){return this.checkMessageConfigForm}onConfigurationSet(e){this.checkMessageConfigForm=this.fb.group({messageNames:[e?e.messageNames:null,[]],metadataNames:[e?e.metadataNames:null,[]],checkAllKeys:[!!e&&e.checkAllKeys,[]]})}validateConfig(){const e=this.checkMessageConfigForm.get("messageNames").value,t=this.checkMessageConfigForm.get("metadataNames").value;return e.length>0||t.length>0}removeMessageName(e){const t=this.checkMessageConfigForm.get("messageNames").value,o=t.indexOf(e);o>=0&&(t.splice(o,1),this.checkMessageConfigForm.get("messageNames").setValue(t,{emitEvent:!0}))}removeMetadataName(e){const t=this.checkMessageConfigForm.get("metadataNames").value,o=t.indexOf(e);o>=0&&(t.splice(o,1),this.checkMessageConfigForm.get("metadataNames").setValue(t,{emitEvent:!0}))}addMessageName(e){const t=e.input;let o=e.value;if((o||"").trim()){o=o.trim();let e=this.checkMessageConfigForm.get("messageNames").value;e&&-1!==e.indexOf(o)||(e||(e=[]),e.push(o),this.checkMessageConfigForm.get("messageNames").setValue(e,{emitEvent:!0}))}t&&(t.value="")}addMetadataName(e){const t=e.input;let o=e.value;if((o||"").trim()){o=o.trim();let e=this.checkMessageConfigForm.get("metadataNames").value;e&&-1!==e.indexOf(o)||(e||(e=[]),e.push(o),this.checkMessageConfigForm.get("metadataNames").setValue(e,{emitEvent:!0}))}t&&(t.value="")}}Ht.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Ht,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),Ht.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Ht,selector:"tb-filter-node-check-message-config",usesInheritance:!0,ngImport:e,template:'
\n \n \n \n \n \n {{messageName}}\n close\n \n \n \n \n
tb.rulenode.separator-hint
\n \n \n \n \n \n {{metadataName}}\n close\n \n \n \n \n
tb.rulenode.separator-hint
\n \n {{ \'tb.rulenode.check-all-keys\' | translate }}\n \n
tb.rulenode.check-all-keys-hint
\n
\n',styles:[":host label.tb-title{margin-bottom:-10px}\n"],components:[{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:X.MatChipList,selector:"mat-chip-list",inputs:["aria-orientation","multiple","compareWith","value","required","placeholder","disabled","selectable","tabIndex","errorStateMatcher"],outputs:["change","valueChange"],exportAs:["matChipList"]},{type:ee.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{type:D.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:G.MatLabel,selector:"mat-label"},{type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:X.MatChip,selector:"mat-basic-chip, [mat-basic-chip], mat-chip, [mat-chip]",inputs:["color","disableRipple","tabIndex","selected","value","selectable","disabled","removable"],outputs:["selectionChange","destroyed","removed"],exportAs:["matChip"]},{type:X.MatChipRemove,selector:"[matChipRemove]"},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:X.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputSeparatorKeyCodes","placeholder","id","matChipInputFor","matChipInputAddOnBlur","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]}],pipes:{translate:E.TranslatePipe}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Ht,decorators:[{type:t,args:[{selector:"tb-filter-node-check-message-config",templateUrl:"./check-message-config.component.html",styleUrls:["./check-message-config.component.scss"]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class Ut extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.entitySearchDirection=Object.keys(c),this.entitySearchDirectionTranslationsMap=g}configForm(){return this.checkRelationConfigForm}onConfigurationSet(e){this.checkRelationConfigForm=this.fb.group({checkForSingleEntity:[!!e&&e.checkForSingleEntity,[]],direction:[e?e.direction:null,[]],entityType:[e?e.entityType:null,e&&e.checkForSingleEntity?[T.required]:[]],entityId:[e?e.entityId:null,e&&e.checkForSingleEntity?[T.required]:[]],relationType:[e?e.relationType:null,[T.required]]})}validatorTriggers(){return["checkForSingleEntity"]}updateValidators(e){const t=this.checkRelationConfigForm.get("checkForSingleEntity").value;this.checkRelationConfigForm.get("entityType").setValidators(t?[T.required]:[]),this.checkRelationConfigForm.get("entityType").updateValueAndValidity({emitEvent:e}),this.checkRelationConfigForm.get("entityId").setValidators(t?[T.required]:[]),this.checkRelationConfigForm.get("entityId").updateValueAndValidity({emitEvent:e})}}Ut.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Ut,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),Ut.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Ut,selector:"tb-filter-node-check-relation-config",usesInheritance:!0,ngImport:e,template:'
\n \n {{ \'tb.rulenode.check-relation-to-specific-entity\' | translate }}\n \n
tb.rulenode.check-relation-hint
\n \n relation.direction\n \n \n {{ entitySearchDirectionTranslationsMap.get(direction) | translate }}\n \n \n \n
\n \n \n \n \n
\n \n \n
\n',components:[{type:D.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:H.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:U.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:te.EntityTypeSelectComponent,selector:"tb-entity-type-select",inputs:["allowedEntityTypes","useAliasEntityTypes","showLabel","required","disabled"]},{type:Ce.EntityAutocompleteComponent,selector:"tb-entity-autocomplete",inputs:["entityType","entitySubtype","excludeEntityIds","labelText","requiredText","required","disabled"],outputs:["entityChanged"]},{type:ge.RelationTypeAutocompleteComponent,selector:"tb-relation-type-autocomplete",inputs:["required","disabled"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:G.MatLabel,selector:"mat-label"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]}],pipes:{translate:E.TranslatePipe}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Ut,decorators:[{type:t,args:[{selector:"tb-filter-node-check-relation-config",templateUrl:"./check-relation-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class Bt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.perimeterType=Me,this.perimeterTypes=Object.keys(Me),this.perimeterTypeTranslationMap=Se,this.rangeUnits=Object.keys(De),this.rangeUnitTranslationMap=Ve}configForm(){return this.geoFilterConfigForm}onConfigurationSet(e){this.geoFilterConfigForm=this.fb.group({latitudeKeyName:[e?e.latitudeKeyName:null,[T.required]],longitudeKeyName:[e?e.longitudeKeyName:null,[T.required]],fetchPerimeterInfoFromMessageMetadata:[!!e&&e.fetchPerimeterInfoFromMessageMetadata,[]],perimeterType:[e?e.perimeterType:null,[]],centerLatitude:[e?e.centerLatitude:null,[]],centerLongitude:[e?e.centerLatitude:null,[]],range:[e?e.range:null,[]],rangeUnit:[e?e.rangeUnit:null,[]],polygonsDefinition:[e?e.polygonsDefinition:null,[]]})}validatorTriggers(){return["fetchPerimeterInfoFromMessageMetadata","perimeterType"]}updateValidators(e){const t=this.geoFilterConfigForm.get("fetchPerimeterInfoFromMessageMetadata").value,o=this.geoFilterConfigForm.get("perimeterType").value;t?this.geoFilterConfigForm.get("perimeterType").setValidators([]):this.geoFilterConfigForm.get("perimeterType").setValidators([T.required]),t||o!==Me.CIRCLE?(this.geoFilterConfigForm.get("centerLatitude").setValidators([]),this.geoFilterConfigForm.get("centerLongitude").setValidators([]),this.geoFilterConfigForm.get("range").setValidators([]),this.geoFilterConfigForm.get("rangeUnit").setValidators([])):(this.geoFilterConfigForm.get("centerLatitude").setValidators([T.required,T.min(-90),T.max(90)]),this.geoFilterConfigForm.get("centerLongitude").setValidators([T.required,T.min(-180),T.max(180)]),this.geoFilterConfigForm.get("range").setValidators([T.required,T.min(0)]),this.geoFilterConfigForm.get("rangeUnit").setValidators([T.required])),t||o!==Me.POLYGON?this.geoFilterConfigForm.get("polygonsDefinition").setValidators([]):this.geoFilterConfigForm.get("polygonsDefinition").setValidators([T.required]),this.geoFilterConfigForm.get("perimeterType").updateValueAndValidity({emitEvent:!1}),this.geoFilterConfigForm.get("centerLatitude").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("centerLongitude").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("range").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("rangeUnit").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("polygonsDefinition").updateValueAndValidity({emitEvent:e})}}Bt.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Bt,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),Bt.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Bt,selector:"tb-filter-node-gps-geofencing-config",usesInheritance:!0,ngImport:e,template:'
\n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n
\n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n
\n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
\n
\n
\n',components:[{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:D.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:H.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:U.MatOption,selector:"mat-option",exportAs:["matOption"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:G.MatLabel,selector:"mat-label"},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:G.MatError,selector:"mat-error",inputs:["id"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:V.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"}],pipes:{translate:E.TranslatePipe}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Bt,decorators:[{type:t,args:[{selector:"tb-filter-node-gps-geofencing-config",templateUrl:"./gps-geo-filter-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class Kt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.messageTypeConfigForm}onConfigurationSet(e){this.messageTypeConfigForm=this.fb.group({messageTypes:[e?e.messageTypes:null,[T.required]]})}}Kt.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Kt,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),Kt.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Kt,selector:"tb-filter-node-message-type-config",usesInheritance:!0,ngImport:e,template:'
\n \n
\n',components:[{type:qt,selector:"tb-message-types-config",inputs:["required","label","placeholder","disabled"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]}]}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Kt,decorators:[{type:t,args:[{selector:"tb-filter-node-message-type-config",templateUrl:"./message-type-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class jt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.allowedEntityTypes=[x.DEVICE,x.ASSET,x.ENTITY_VIEW,x.TENANT,x.CUSTOMER,x.USER,x.DASHBOARD,x.RULE_CHAIN,x.RULE_NODE]}configForm(){return this.originatorTypeConfigForm}onConfigurationSet(e){this.originatorTypeConfigForm=this.fb.group({originatorTypes:[e?e.originatorTypes:null,[T.required]]})}}jt.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:jt,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),jt.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:jt,selector:"tb-filter-node-originator-type-config",usesInheritance:!0,ngImport:e,template:'
\n \n \n \n
\n',styles:[":host ::ng-deep tb-entity-type-list .mat-form-field-flex{padding-top:0}:host ::ng-deep tb-entity-type-list .mat-form-field-infix{border-top:0}\n"],components:[{type:Le.EntityTypeListComponent,selector:"tb-entity-type-list",inputs:["required","disabled","allowedEntityTypes","ignoreAuthorityFilter"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]}]}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:jt,decorators:[{type:t,args:[{selector:"tb-filter-node-originator-type-config",templateUrl:"./originator-type-config.component.html",styleUrls:["./originator-type-config.component.scss"]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class zt extends s{constructor(e,t,o,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=o,this.translate=r}configForm(){return this.scriptConfigForm}onConfigurationSet(e){this.scriptConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[T.required]]})}testScript(){const e=this.scriptConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(e,"filter",this.translate.instant("tb.rulenode.filter"),"Filter",["msg","metadata","msgType"],this.ruleNodeId,"rulenode/filter_node_script_fn").subscribe((e=>{e&&this.scriptConfigForm.get("jsScript").setValue(e)}))}onValidate(){this.jsFuncComponent.validateOnSubmit()}}zt.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:zt,deps:[{token:N.Store},{token:q.FormBuilder},{token:_.NodeScriptTestService},{token:E.TranslateService}],target:e.ɵɵFactoryTarget.Component}),zt.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:zt,selector:"tb-filter-node-script-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0,static:!0}],usesInheritance:!0,ngImport:e,template:'
\n \n \n \n
\n \n
\n
\n',components:[{type:$.JsFuncComponent,selector:"tb-js-func",inputs:["functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","noValidate","required"]},{type:W.MatButton,selector:"button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]}],pipes:{translate:E.TranslatePipe}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:zt,decorators:[{type:t,args:[{selector:"tb-filter-node-script-config",templateUrl:"./script-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder},{type:_.NodeScriptTestService},{type:E.TranslateService}]},propDecorators:{jsFuncComponent:[{type:r,args:["jsFuncComponent",{static:!0}]}]}});class _t extends s{constructor(e,t,o,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=o,this.translate=r}configForm(){return this.switchConfigForm}onConfigurationSet(e){this.switchConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[T.required]]})}testScript(){const e=this.switchConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(e,"switch",this.translate.instant("tb.rulenode.switch"),"Switch",["msg","metadata","msgType"],this.ruleNodeId,"rulenode/switch_node_script_fn").subscribe((e=>{e&&this.switchConfigForm.get("jsScript").setValue(e)}))}onValidate(){this.jsFuncComponent.validateOnSubmit()}}_t.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:_t,deps:[{token:N.Store},{token:q.FormBuilder},{token:_.NodeScriptTestService},{token:E.TranslateService}],target:e.ɵɵFactoryTarget.Component}),_t.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:_t,selector:"tb-filter-node-switch-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0,static:!0}],usesInheritance:!0,ngImport:e,template:'
\n \n \n \n
\n \n
\n
\n',components:[{type:$.JsFuncComponent,selector:"tb-js-func",inputs:["functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","noValidate","required"]},{type:W.MatButton,selector:"button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]}],pipes:{translate:E.TranslatePipe}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:_t,decorators:[{type:t,args:[{selector:"tb-filter-node-switch-config",templateUrl:"./switch-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder},{type:_.NodeScriptTestService},{type:E.TranslateService}]},propDecorators:{jsFuncComponent:[{type:r,args:["jsFuncComponent",{static:!0}]}]}});class Qt{}Qt.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Qt,deps:[],target:e.ɵɵFactoryTarget.NgModule}),Qt.ɵmod=e.ɵɵngDeclareNgModule({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Qt,declarations:[Ht,Ut,Bt,Kt,jt,zt,_t,Ot],imports:[w,F,Tt],exports:[Ht,Ut,Bt,Kt,jt,zt,_t,Ot]}),Qt.ɵinj=e.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Qt,imports:[[w,F,Tt]]}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Qt,decorators:[{type:l,args:[{declarations:[Ht,Ut,Bt,Kt,jt,zt,_t,Ot],imports:[w,F,Tt],exports:[Ht,Ut,Bt,Kt,jt,zt,_t,Ot]}]}]});class $t extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.originatorSource=Te,this.originatorSources=Object.keys(Te),this.originatorSourceTranslationMap=ke}configForm(){return this.changeOriginatorConfigForm}onConfigurationSet(e){this.changeOriginatorConfigForm=this.fb.group({originatorSource:[e?e.originatorSource:null,[T.required]],relationsQuery:[e?e.relationsQuery:null,[]]})}validatorTriggers(){return["originatorSource"]}updateValidators(e){const t=this.changeOriginatorConfigForm.get("originatorSource").value;t&&t===Te.RELATED?this.changeOriginatorConfigForm.get("relationsQuery").setValidators([T.required]):this.changeOriginatorConfigForm.get("relationsQuery").setValidators([]),this.changeOriginatorConfigForm.get("relationsQuery").updateValueAndValidity({emitEvent:e})}}$t.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:$t,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),$t.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:$t,selector:"tb-transformation-node-change-originator-config",usesInheritance:!0,ngImport:e,template:'
\n \n tb.rulenode.originator-source\n \n \n {{ originatorSourceTranslationMap.get(source) | translate }}\n \n \n \n
\n \n \n \n
\n
\n',components:[{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:H.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:U.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:Nt,selector:"tb-relations-query-config",inputs:["disabled","required"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:G.MatLabel,selector:"mat-label"},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]}],pipes:{translate:E.TranslatePipe}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:$t,decorators:[{type:t,args:[{selector:"tb-transformation-node-change-originator-config",templateUrl:"./change-originator-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class Wt extends s{constructor(e,t,o,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=o,this.translate=r}configForm(){return this.scriptConfigForm}onConfigurationSet(e){this.scriptConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[T.required]]})}testScript(){const e=this.scriptConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(e,"update",this.translate.instant("tb.rulenode.transformer"),"Transform",["msg","metadata","msgType"],this.ruleNodeId,"rulenode/transformation_node_script_fn").subscribe((e=>{e&&this.scriptConfigForm.get("jsScript").setValue(e)}))}onValidate(){this.jsFuncComponent.validateOnSubmit()}}Wt.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Wt,deps:[{token:N.Store},{token:q.FormBuilder},{token:_.NodeScriptTestService},{token:E.TranslateService}],target:e.ɵɵFactoryTarget.Component}),Wt.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Wt,selector:"tb-transformation-node-script-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0,static:!0}],usesInheritance:!0,ngImport:e,template:'
\n \n \n \n
\n \n
\n
\n',components:[{type:$.JsFuncComponent,selector:"tb-js-func",inputs:["functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","noValidate","required"]},{type:W.MatButton,selector:"button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]}],pipes:{translate:E.TranslatePipe}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Wt,decorators:[{type:t,args:[{selector:"tb-transformation-node-script-config",templateUrl:"./script-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder},{type:_.NodeScriptTestService},{type:E.TranslateService}]},propDecorators:{jsFuncComponent:[{type:r,args:["jsFuncComponent",{static:!0}]}]}});class Yt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.mailBodyTypes=[{name:"tb.mail-body-type.plain-text",value:"false"},{name:"tb.mail-body-type.html",value:"true"},{name:"tb.mail-body-type.dynamic",value:"dynamic"}]}configForm(){return this.toEmailConfigForm}onConfigurationSet(e){this.toEmailConfigForm=this.fb.group({fromTemplate:[e?e.fromTemplate:null,[T.required]],toTemplate:[e?e.toTemplate:null,[T.required]],ccTemplate:[e?e.ccTemplate:null,[]],bccTemplate:[e?e.bccTemplate:null,[]],subjectTemplate:[e?e.subjectTemplate:null,[T.required]],mailBodyType:[e?e.mailBodyType:null],isHtmlTemplate:[e?e.isHtmlTemplate:null],bodyTemplate:[e?e.bodyTemplate:null,[T.required]]}),this.toEmailConfigForm.get("mailBodyType").valueChanges.pipe(se([null==e?void 0:e.subjectTemplate])).subscribe((e=>{"dynamic"===e?(this.toEmailConfigForm.get("isHtmlTemplate").patchValue("",{emitEvent:!1}),this.toEmailConfigForm.get("isHtmlTemplate").setValidators(T.required)):this.toEmailConfigForm.get("isHtmlTemplate").clearValidators(),this.toEmailConfigForm.get("isHtmlTemplate").updateValueAndValidity()}))}}Yt.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Yt,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),Yt.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Yt,selector:"tb-transformation-node-to-email-config",usesInheritance:!0,ngImport:e,template:'
\n \n tb.rulenode.from-template\n \n \n {{ \'tb.rulenode.from-template-required\' | translate }}\n \n \n \n \n tb.rulenode.to-template\n \n \n {{ \'tb.rulenode.to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.cc-template\n \n \n \n \n tb.rulenode.bcc-template\n \n \n \n \n tb.rulenode.subject-template\n \n \n {{ \'tb.rulenode.subject-template-required\' | translate }}\n \n \n \n \n tb.rulenode.mail-body-type\n \n \n {{ type.name | translate }}\n \n \n \n \n tb.rulenode.dynamic-mail-body-type\n \n \n \n \n tb.rulenode.body-template\n \n \n {{ \'tb.rulenode.body-template-required\' | translate }}\n \n \n \n
\n',components:[{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:H.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:U.MatOption,selector:"mat-option",exportAs:["matOption"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:G.MatLabel,selector:"mat-label"},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:G.MatError,selector:"mat-error",inputs:["id"]},{type:G.MatHint,selector:"mat-hint",inputs:["align","id"]},{type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]}],pipes:{translate:E.TranslatePipe,safeHtml:Ie}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Yt,decorators:[{type:t,args:[{selector:"tb-transformation-node-to-email-config",templateUrl:"./to-email-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class Jt{}Jt.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Jt,deps:[],target:e.ɵɵFactoryTarget.NgModule}),Jt.ɵmod=e.ɵɵngDeclareNgModule({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Jt,declarations:[$t,Wt,Yt],imports:[w,F,Tt],exports:[$t,Wt,Yt]}),Jt.ɵinj=e.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Jt,imports:[[w,F,Tt]]}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Jt,decorators:[{type:l,args:[{declarations:[$t,Wt,Yt],imports:[w,F,Tt],exports:[$t,Wt,Yt]}]}]});class Zt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.entityType=x}configForm(){return this.ruleChainInputConfigForm}onConfigurationSet(e){this.ruleChainInputConfigForm=this.fb.group({ruleChainId:[e?e.ruleChainId:null,[T.required]]})}}Zt.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Zt,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),Zt.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Zt,selector:"tb-flow-node-rule-chain-input-config",usesInheritance:!0,ngImport:e,template:'
\n \n \n
\n',components:[{type:Ce.EntityAutocompleteComponent,selector:"tb-entity-autocomplete",inputs:["entityType","entitySubtype","excludeEntityIds","labelText","requiredText","required","disabled"],outputs:["entityChanged"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]}]}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Zt,decorators:[{type:t,args:[{selector:"tb-flow-node-rule-chain-input-config",templateUrl:"./rule-chain-input.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class Xt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.ruleChainOutputConfigForm}onConfigurationSet(e){this.ruleChainOutputConfigForm=this.fb.group({})}}Xt.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Xt,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),Xt.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Xt,selector:"tb-flow-node-rule-chain-output-config",usesInheritance:!0,ngImport:e,template:'
\n
\n
\n',directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]}],pipes:{translate:E.TranslatePipe}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Xt,decorators:[{type:t,args:[{selector:"tb-flow-node-rule-chain-output-config",templateUrl:"./rule-chain-output.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class eo{}eo.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:eo,deps:[],target:e.ɵɵFactoryTarget.NgModule}),eo.ɵmod=e.ɵɵngDeclareNgModule({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:eo,declarations:[Zt,Xt],imports:[w,F,Tt],exports:[Zt,Xt]}),eo.ɵinj=e.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:eo,imports:[[w,F,Tt]]}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:eo,decorators:[{type:l,args:[{declarations:[Zt,Xt],imports:[w,F,Tt],exports:[Zt,Xt]}]}]});class to{constructor(e){!function(e){e.setTranslation("en_US",{tb:{rulenode:{"create-entity-if-not-exists":"Create new entity if not exists","create-entity-if-not-exists-hint":"Create a new entity set above if it does not exist.","entity-name-pattern":"Name pattern","entity-name-pattern-required":"Name pattern is required","entity-type-pattern":"Type pattern","entity-type-pattern-required":"Type pattern is required","entity-cache-expiration":"Entities cache expiration time (sec)","entity-cache-expiration-hint":"Specifies maximum time interval allowed to store found entity records. 0 value means that records will never expire.","entity-cache-expiration-required":"Entities cache expiration time is required.","entity-cache-expiration-range":"Entities cache expiration time should be greater than or equal to 0.","customer-name-pattern":"Customer name pattern","customer-name-pattern-required":"Customer name pattern is required","create-customer-if-not-exists":"Create new customer if not exists","customer-cache-expiration":"Customers cache expiration time (sec)","customer-cache-expiration-hint":"Specifies maximum time interval allowed to store found customer records. 0 value means that records will never expire.","customer-cache-expiration-required":"Customers cache expiration time is required.","customer-cache-expiration-range":"Customers cache expiration time should be greater than or equal to 0.","start-interval":"Start Interval","end-interval":"End Interval","start-interval-time-unit":"Start Interval Time Unit","end-interval-time-unit":"End Interval Time Unit","fetch-mode":"Fetch mode","fetch-mode-hint":"If selected fetch mode 'ALL' you able to choose telemetry sampling order.","order-by":"Order by","order-by-hint":"Select to choose telemetry sampling order.",limit:"Limit","limit-hint":"Min limit value is 2, max - 1000. In case you want to fetch a single entry, select fetch mode 'FIRST' or 'LAST'.","time-unit-milliseconds":"Milliseconds","time-unit-seconds":"Seconds","time-unit-minutes":"Minutes","time-unit-hours":"Hours","time-unit-days":"Days","time-value-range":"Time value should be in a range from 1 to 2147483647.","start-interval-value-required":"Start interval value is required.","end-interval-value-required":"End interval value is required.",filter:"Filter",switch:"Switch","message-type":"Message type","message-type-required":"Message type is required.","message-types-filter":"Message types filter","no-message-types-found":"No message types found","no-message-type-matching":"'{{messageType}}' not found.","create-new-message-type":"Create a new one!","message-types-required":"Message types are required.","client-attributes":"Client attributes","shared-attributes":"Shared attributes","server-attributes":"Server attributes","notify-device":"Notify Device","notify-device-hint":"If the message arrives from the device, we will push it back to the device by default.","latest-timeseries":"Latest timeseries","timeseries-key":"Timeseries key","data-keys":"Message data","metadata-keys":"Message metadata","relations-query":"Relations query","device-relations-query":"Device relations query","max-relation-level":"Max relation level","relation-type-pattern":"Relation type pattern","relation-type-pattern-required":"Relation type pattern is required","relation-types-list":"Relation types to propagate","relation-types-list-hint":"If Propagate relation types are not selected, alarms will be propagated without filtering by relation type.","unlimited-level":"Unlimited level","latest-telemetry":"Latest telemetry","attr-mapping":"Attributes mapping","source-attribute":"Source attribute","source-attribute-required":"Source attribute is required.","source-telemetry":"Source telemetry","source-telemetry-required":"Source telemetry is required.","target-attribute":"Target attribute","target-attribute-required":"Target attribute is required.","attr-mapping-required":"At least one attribute mapping should be specified.","fields-mapping":"Fields mapping","fields-mapping-required":"At least one field mapping should be specified.","source-field":"Source field","source-field-required":"Source field is required.","originator-source":"Originator source","originator-customer":"Customer","originator-tenant":"Tenant","originator-related":"Related","originator-alarm-originator":"Alarm Originator","clone-message":"Clone message",transform:"Transform","default-ttl":"Default TTL in seconds","default-ttl-required":"Default TTL is required.","min-default-ttl-message":"Only 0 minimum TTL is allowed.","message-count":"Message count (0 - unlimited)","message-count-required":"Message count is required.","min-message-count-message":"Only 0 minimum message count is allowed.","period-seconds":"Period in seconds","period-seconds-required":"Period is required.","use-metadata-period-in-seconds-patterns":"Use period in seconds pattern","use-metadata-period-in-seconds-patterns-hint":"If selected, rule node use period in seconds interval pattern from message metadata or data assuming that intervals are in the seconds.","period-in-seconds-pattern":"Period in seconds pattern","period-in-seconds-pattern-required":"Period in seconds pattern is required","min-period-seconds-message":"Only 1 second minimum period is allowed.",originator:"Originator","message-body":"Message body","message-metadata":"Message metadata",generate:"Generate","test-generator-function":"Test generator function",generator:"Generator","test-filter-function":"Test filter function","test-switch-function":"Test switch function","test-transformer-function":"Test transformer function",transformer:"Transformer","alarm-create-condition":"Alarm create condition","test-condition-function":"Test condition function","alarm-clear-condition":"Alarm clear condition","alarm-details-builder":"Alarm details builder","test-details-function":"Test details function","alarm-type":"Alarm type","alarm-type-required":"Alarm type is required.","alarm-severity":"Alarm severity","alarm-severity-required":"Alarm severity is required","alarm-status-filter":"Alarm status filter","alarm-status-list-empty":"Alarm status list is empty","no-alarm-status-matching":"No alarm status matching were found.",propagate:"Propagate",condition:"Condition",details:"Details","to-string":"To string","test-to-string-function":"Test to string function","from-template":"From Template","from-template-required":"From Template is required","to-template":"To Template","to-template-required":"To Template is required","mail-address-list-template-hint":'Comma separated address list, use ${metadataKey} for value from metadata, $[messageKey] for value from message body',"cc-template":"Cc Template","bcc-template":"Bcc Template","subject-template":"Subject Template","subject-template-required":"Subject Template is required","body-template":"Body Template","body-template-required":"Body Template is required","dynamic-mail-body-type":"Dynamic mail body type","mail-body-type":"Mail body type","request-id-metadata-attribute":"Request Id Metadata attribute name","timeout-sec":"Timeout in seconds","timeout-required":"Timeout is required","min-timeout-message":"Only 0 minimum timeout value is allowed.","endpoint-url-pattern":"Endpoint URL pattern","endpoint-url-pattern-required":"Endpoint URL pattern is required","request-method":"Request method","use-simple-client-http-factory":"Use simple client HTTP factory","ignore-request-body":"Without request body","read-timeout":"Read timeout in millis","read-timeout-hint":"The value of 0 means an infinite timeout","max-parallel-requests-count":"Max number of parallel requests","max-parallel-requests-count-hint":"The value of 0 specifies no limit in parallel processing",headers:"Headers","headers-hint":'Use ${metadataKey} for value from metadata, $[messageKey] for value from message body in header/value fields',header:"Header","header-required":"Header is required",value:"Value","value-required":"Value is required","topic-pattern":"Topic pattern","topic-pattern-required":"Topic pattern is required",topic:"Topic","topic-required":"Topic is required","bootstrap-servers":"Bootstrap servers","bootstrap-servers-required":"Bootstrap servers value is required","other-properties":"Other properties",key:"Key","key-required":"Key is required",retries:"Automatically retry times if fails","min-retries-message":"Only 0 minimum retries is allowed.","batch-size-bytes":"Produces batch size in bytes","min-batch-size-bytes-message":"Only 0 minimum batch size is allowed.","linger-ms":"Time to buffer locally (ms)","min-linger-ms-message":"Only 0 ms minimum value is allowed.","buffer-memory-bytes":"Client buffer max size in bytes","min-buffer-memory-message":"Only 0 minimum buffer size is allowed.",acks:"Number of acknowledgments","key-serializer":"Key serializer","key-serializer-required":"Key serializer is required","value-serializer":"Value serializer","value-serializer-required":"Value serializer is required","topic-arn-pattern":"Topic ARN pattern","topic-arn-pattern-required":"Topic ARN pattern is required","aws-access-key-id":"AWS Access Key ID","aws-access-key-id-required":"AWS Access Key ID is required","aws-secret-access-key":"AWS Secret Access Key","aws-secret-access-key-required":"AWS Secret Access Key is required","aws-region":"AWS Region","aws-region-required":"AWS Region is required","exchange-name-pattern":"Exchange name pattern","routing-key-pattern":"Routing key pattern","message-properties":"Message properties",host:"Host","host-required":"Host is required",port:"Port","port-required":"Port is required","port-range":"Port should be in a range from 1 to 65535.","virtual-host":"Virtual host",username:"Username",password:"Password","automatic-recovery":"Automatic recovery","connection-timeout-ms":"Connection timeout (ms)","min-connection-timeout-ms-message":"Only 0 ms minimum value is allowed.","handshake-timeout-ms":"Handshake timeout (ms)","min-handshake-timeout-ms-message":"Only 0 ms minimum value is allowed.","client-properties":"Client properties","queue-url-pattern":"Queue URL pattern","queue-url-pattern-required":"Queue URL pattern is required","delay-seconds":"Delay (seconds)","min-delay-seconds-message":"Only 0 seconds minimum value is allowed.","max-delay-seconds-message":"Only 900 seconds maximum value is allowed.",name:"Name","name-required":"Name is required","queue-type":"Queue type","sqs-queue-standard":"Standard","sqs-queue-fifo":"FIFO","gcp-project-id":"GCP project ID","gcp-project-id-required":"GCP project ID is required","gcp-service-account-key":"GCP service account key file","gcp-service-account-key-required":"GCP service account key file is required","pubsub-topic-name":"Topic name","pubsub-topic-name-required":"Topic name is required","message-attributes":"Message attributes","message-attributes-hint":'Use ${metadataKey} for value from metadata, $[messageKey] for value from message body in name/value fields',"connect-timeout":"Connection timeout (sec)","connect-timeout-required":"Connection timeout is required.","connect-timeout-range":"Connection timeout should be in a range from 1 to 200.","client-id":"Client ID","client-id-hint":"Hint: Optional. Leave empty for auto-generated client id. Be careful when specifying the Client ID.Majority of the MQTT brokers will not allow multiple connections with the same client id. To connect to such brokers, your mqtt client id must be unique. When platform is running in a micro-services mode, the copy of rule nodeis launched in each micro-service. This will automatically lead to multiple mqtt clients with the same id and may cause failures of the rule node.","device-id":"Device ID","device-id-required":"Device ID is required.","clean-session":"Clean session","enable-ssl":"Enable SSL",credentials:"Credentials","credentials-type":"Credentials type","credentials-type-required":"Credentials type is required.","credentials-anonymous":"Anonymous","credentials-basic":"Basic","credentials-pem":"PEM","credentials-pem-hint":"At least Server CA certificate file or a pair of Client certificate and Client private key files are required","credentials-sas":"Shared Access Signature","sas-key":"SAS Key","sas-key-required":"SAS Key is required.",hostname:"Hostname","hostname-required":"Hostname is required.","azure-ca-cert":"CA certificate file","username-required":"Username is required.","password-required":"Password is required.","ca-cert":"Server CA certificate file *","private-key":"Client private key file *",cert:"Client certificate file *","no-file":"No file selected.","drop-file":"Drop a file or click to select a file to upload.","private-key-password":"Private key password","use-system-smtp-settings":"Use system SMTP settings","use-metadata-interval-patterns":"Use interval patterns","use-metadata-interval-patterns-hint":"If selected, rule node use start and end interval patterns from message metadata or data assuming that intervals are in the milliseconds.","use-message-alarm-data":"Use message alarm data","use-dynamically-change-the-severity-of-alar":"Use dynamically change the severity of alarm","check-all-keys":"Check that all selected keys are present","check-all-keys-hint":"If selected, checks that all specified keys are present in the message data and metadata.","check-relation-to-specific-entity":"Check relation to specific entity","check-relation-hint":"Checks existence of relation to specific entity or to any entity based on direction and relation type.","delete-relation-to-specific-entity":"Delete relation to specific entity","delete-relation-hint":"Deletes relation from the originator of the incoming message to the specified entity or list of entities based on direction and type.","remove-current-relations":"Remove current relations","remove-current-relations-hint":"Removes current relations from the originator of the incoming message based on direction and type.","change-originator-to-related-entity":"Change originator to related entity","change-originator-to-related-entity-hint":"Used to process submitted message as a message from another entity.","start-interval-pattern":"Start interval pattern","end-interval-pattern":"End interval pattern","start-interval-pattern-required":"Start interval pattern is required","end-interval-pattern-required":"End interval pattern is required","smtp-protocol":"Protocol","smtp-host":"SMTP host","smtp-host-required":"SMTP host is required.","smtp-port":"SMTP port","smtp-port-required":"You must supply a smtp port.","smtp-port-range":"SMTP port should be in a range from 1 to 65535.","timeout-msec":"Timeout ms","min-timeout-msec-message":"Only 0 ms minimum value is allowed.","enter-username":"Enter username","enter-password":"Enter password","enable-tls":"Enable TLS","tls-version":"TLS version","enable-proxy":"Enable proxy","use-system-proxy-properties":"Use system proxy properties","proxy-host":"Proxy host","proxy-host-required":"Proxy host is required.","proxy-port":"Proxy port","proxy-port-required":"Proxy port is required.","proxy-port-range":"Proxy port should be in a range from 1 to 65535.","proxy-user":"Proxy user","proxy-password":"Proxy password","proxy-scheme":"Proxy scheme","numbers-to-template":"Phone Numbers To Template","numbers-to-template-required":"Phone Numbers To Template is required","numbers-to-template-hint":'Comma separated Phone Numbers, use ${metadataKey} for value from metadata, $[messageKey] for value from message body',"sms-message-template":"SMS message Template","sms-message-template-required":"SMS message Template is required","use-system-sms-settings":"Use system SMS provider settings","min-period-0-seconds-message":"Only 0 second minimum period is allowed.","max-pending-messages":"Maximum pending messages","max-pending-messages-required":"Maximum pending messages is required.","max-pending-messages-range":"Maximum pending messages should be in a range from 1 to 100000.","originator-types-filter":"Originator types filter","interval-seconds":"Interval in seconds","interval-seconds-required":"Interval is required.","min-interval-seconds-message":"Only 1 second minimum interval is allowed.","output-timeseries-key-prefix":"Output timeseries key prefix","output-timeseries-key-prefix-required":"Output timeseries key prefix required.","separator-hint":'You should press "enter" to complete field input.',"entity-details":"Select entity details:","entity-details-title":"Title","entity-details-country":"Country","entity-details-state":"State","entity-details-city":"City","entity-details-zip":"Zip","entity-details-address":"Address","entity-details-address2":"Address2","entity-details-additional_info":"Additional Info","entity-details-phone":"Phone","entity-details-email":"Email","add-to-metadata":"Add selected details to message metadata","add-to-metadata-hint":"If selected, adds the selected details keys to the message metadata instead of message data.","entity-details-list-empty":"No entity details selected.","no-entity-details-matching":"No entity details matching were found.","custom-table-name":"Custom table name","custom-table-name-required":"Table Name is required","custom-table-hint":"You should enter the table name without prefix 'cs_tb_'.","message-field":"Message field","message-field-required":"Message field is required.","table-col":"Table column","table-col-required":"Table column is required.","latitude-key-name":"Latitude key name","longitude-key-name":"Longitude key name","latitude-key-name-required":"Latitude key name is required.","longitude-key-name-required":"Longitude key name is required.","fetch-perimeter-info-from-message-metadata":"Fetch perimeter information from message metadata","perimeter-circle":"Circle","perimeter-polygon":"Polygon","perimeter-type":"Perimeter type","circle-center-latitude":"Center latitude","circle-center-latitude-required":"Center latitude is required.","circle-center-longitude":"Center longitude","circle-center-longitude-required":"Center longitude is required.","range-unit-meter":"Meter","range-unit-kilometer":"Kilometer","range-unit-foot":"Foot","range-unit-mile":"Mile","range-unit-nautical-mile":"Nautical mile","range-units":"Range units",range:"Range","range-required":"Range is required.","polygon-definition":"Polygon definition","polygon-definition-required":"Polygon definition is required.","polygon-definition-hint":"Please, use the following format for manual definition of polygon: [[lat1,lon1],[lat2,lon2], ... ,[latN,lonN]].","min-inside-duration":"Minimal inside duration","min-inside-duration-value-required":"Minimal inside duration is required","min-inside-duration-time-unit":"Minimal inside duration time unit","min-outside-duration":"Minimal outside duration","min-outside-duration-value-required":"Minimal outside duration is required","min-outside-duration-time-unit":"Minimal outside duration time unit","tell-failure-if-absent":"Tell Failure","tell-failure-if-absent-hint":'If at least one selected key doesn\'t exist the outbound message will report "Failure".',"get-latest-value-with-ts":"Fetch Latest telemetry with Timestamp","get-latest-value-with-ts-hint":'If selected, latest telemetry values will be added to the outbound message metadata with timestamp, e.g: "temp": "{"ts":1574329385897, "value":42}"',"use-redis-queue":"Use redis queue for message persistence","trim-redis-queue":"Trim redis queue","redis-queue-max-size":"Redis queue max size","add-metadata-key-values-as-kafka-headers":"Add Message metadata key-value pairs to Kafka record headers","add-metadata-key-values-as-kafka-headers-hint":"If selected, key-value pairs from message metadata will be added to the outgoing records headers as byte arrays with predefined charset encoding.","charset-encoding":"Charset encoding","charset-encoding-required":"Charset encoding is required.","charset-us-ascii":"US-ASCII","charset-iso-8859-1":"ISO-8859-1","charset-utf-8":"UTF-8","charset-utf-16be":"UTF-16BE","charset-utf-16le":"UTF-16LE","charset-utf-16":"UTF-16","select-queue-hint":"The queue name can be selected from a drop-down list or add a custom name.","persist-alarm-rules":"Persist state of alarm rules","fetch-alarm-rules":"Fetch state of alarm rules","input-value-key":"Input value key","input-value-key-required":"Input value key is required.","output-value-key":"Output value key","output-value-key-required":"Output value key is required.",round:"Decimals","round-range":"Decimals should be in a range from 0 to 15.","use-cache":"Use cache for latest value","tell-failure-if-delta-is-negative":"Tell Failure if delta is negative","add-period-between-msgs":"Add period between messages","period-value-key":"Period value key","period-key-required":"Period value key is required.","general-pattern-hint":'Hint: use ${metadataKey} for value from metadata, $[messageKey] for value from message body',"alarm-severity-pattern-hint":'Hint: use ${metadataKey} for value from metadata, $[messageKey] for value from message body. Alarm severity should be system (CRITICAL, MAJOR etc.)',"output-node-name-hint":"The rule node name corresponds to the relation type of the output message, and it is used to forward messages to other rule nodes in the caller rule chain."},"key-val":{key:"Key",value:"Value","remove-entry":"Remove entry","add-entry":"Add entry"},"mail-body-type":{"plain-text":"Plain Text",html:"HTML",dynamic:"Dynamic"}}},!0)}(e)}}to.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:to,deps:[{token:E.TranslateService}],target:e.ɵɵFactoryTarget.NgModule}),to.ɵmod=e.ɵɵngDeclareNgModule({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:to,declarations:[ve],imports:[w,F],exports:[kt,Qt,wt,Jt,eo,ve]}),to.ɵinj=e.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:to,imports:[[w,F],kt,Qt,wt,Jt,eo]}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:to,decorators:[{type:l,args:[{declarations:[ve],imports:[w,F],exports:[kt,Qt,wt,Jt,eo,ve]}]}],ctorParameters:function(){return[{type:E.TranslateService}]}});export{Ne as AssignCustomerConfigComponent,qe as AttributesConfigComponent,$e as AzureIotHubConfigComponent,Mt as CalculateDeltaConfigComponent,$t as ChangeOriginatorConfigComponent,Ot as CheckAlarmStatusComponent,Ht as CheckMessageConfigComponent,We as CheckPointConfigComponent,Ut as CheckRelationConfigComponent,Ye as ClearAlarmConfigComponent,Je as CreateAlarmConfigComponent,Ze as CreateRelationConfigComponent,lt as CredentialsConfigComponent,St as CustomerAttributesConfigComponent,Xe as DeleteRelationConfigComponent,At as DeviceAttributesConfigComponent,et as DeviceProfileConfigComponent,It as DeviceRelationsQueryConfigComponent,ve as EmptyConfigComponent,Gt as EntityDetailsConfigComponent,tt as GeneratorConfigComponent,Dt as GetTelemetryFromDatabaseConfigComponent,ot as GpsGeoActionConfigComponent,Bt as GpsGeoFilterConfigComponent,at as KafkaConfigComponent,rt as KvMapConfigComponent,nt as LogConfigComponent,Kt as MessageTypeConfigComponent,qt as MessageTypesConfigComponent,it as MqttConfigComponent,st as MsgCountConfigComponent,mt as MsgDelayConfigComponent,Vt as OriginatorAttributesConfigComponent,Et as OriginatorFieldsConfigComponent,jt as OriginatorTypeConfigComponent,ut as PubSubConfigComponent,pt as PushToCloudConfigComponent,dt as PushToEdgeConfigComponent,ft as RabbitMqConfigComponent,Pt as RelatedAttributesConfigComponent,Nt as RelationsQueryConfigComponent,ct as RestApiCallConfigComponent,gt as RpcReplyConfigComponent,xt as RpcRequestConfigComponent,Zt as RuleChainInputComponent,Xt as RuleChainOutputComponent,kt as RuleNodeCoreConfigActionModule,Qt as RuleNodeCoreConfigFilterModule,eo as RuleNodeCoreConfigFlowModule,to as RuleNodeCoreConfigModule,Tt as RulenodeCoreConfigCommonModule,wt as RulenodeCoreConfigEnrichmentModule,Jt as RulenodeCoreConfigTransformModule,Ie as SafeHtmlPipe,yt as SaveToCustomTableConfigComponent,zt as ScriptConfigComponent,bt as SendEmailConfigComponent,ht as SendSmsConfigComponent,Ft as SnsConfigComponent,Ct as SqsConfigComponent,_t as SwitchConfigComponent,Rt as TenantAttributesConfigComponent,Lt as TimeseriesConfigComponent,Yt as ToEmailConfigComponent,Wt as TransformScriptConfigComponent,vt as UnassignCustomerConfigComponent};//# sourceMappingURL=rulenode-core-config.js.map +import*as e from"@angular/core";import{Component as t,Pipe as o,ViewChild as r,forwardRef as a,Input as n,NgModule as l}from"@angular/core";import*as i from"@shared/public-api";import{RuleNodeConfigurationComponent as s,AttributeScope as m,telemetryTypeTranslations as u,ServiceType as p,AlarmSeverity as d,alarmSeverityTranslations as f,EntitySearchDirection as c,entitySearchDirectionTranslations as g,EntityType as x,PageComponent as y,MessageType as b,messageTypeNames as h,SharedModule as F,AggregationType as C,aggregationTranslations as L,alarmStatusTranslations as v,AlarmStatus as I}from"@shared/public-api";import*as N from"@ngrx/store";import*as q from"@angular/forms";import{Validators as T,NgControl as k,NG_VALUE_ACCESSOR as M,NG_VALIDATORS as S,FormControl as A}from"@angular/forms";import*as G from"@angular/material/form-field";import*as D from"@angular/material/checkbox";import*as V from"@angular/flex-layout/flex";import*as E from"@ngx-translate/core";import*as P from"@angular/material/input";import*as R from"@angular/common";import{CommonModule as w}from"@angular/common";import*as O from"@angular/platform-browser";import*as H from"@angular/material/select";import*as U from"@angular/material/core";import*as B from"@angular/material/expansion";import*as K from"@shared/components/button/toggle-password.component";import*as j from"@shared/components/file-input.component";import*as z from"@shared/components/queue/queue-type-list.component";import*as _ from"@core/public-api";import{isDefinedAndNotNull as Q}from"@core/public-api";import*as $ from"@shared/components/js-func.component";import*as W from"@angular/material/button";import{ENTER as Y,COMMA as J,SEMICOLON as Z}from"@angular/cdk/keycodes";import*as X from"@angular/material/chips";import*as ee from"@angular/material/icon";import*as te from"@shared/components/entity/entity-type-select.component";import*as oe from"@shared/components/entity/entity-select.component";import{coerceBooleanProperty as re}from"@angular/cdk/coercion";import*as ae from"@shared/components/tb-error.component";import*as ne from"@angular/flex-layout/extended";import*as le from"@angular/material/tooltip";import{distinctUntilChanged as ie,startWith as se,map as me,mergeMap as ue,share as pe}from"rxjs/operators";import*as de from"@shared/components/tb-checkbox.component";import*as fe from"@home/components/sms/sms-provider-configuration.component";import{HomeComponentsModule as ce}from"@home/components/public-api";import*as ge from"@shared/components/relation/relation-type-autocomplete.component";import*as xe from"@shared/components/entity/entity-subtype-list.component";import*as ye from"@home/components/relation/relation-filters.component";import{of as be}from"rxjs";import*as he from"@angular/material/autocomplete";import*as Fe from"@shared/pipe/highlight.pipe";import*as Ce from"@shared/components/entity/entity-autocomplete.component";import*as Le from"@shared/components/entity/entity-type-list.component";class ve extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.emptyConfigForm}onConfigurationSet(e){this.emptyConfigForm=this.fb.group({})}}ve.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:ve,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),ve.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:ve,selector:"tb-node-empty-config",usesInheritance:!0,ngImport:e,template:"
",isInline:!0}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:ve,decorators:[{type:t,args:[{selector:"tb-node-empty-config",template:"
",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class Ie{constructor(e){this.sanitizer=e}transform(e){return this.sanitizer.bypassSecurityTrustHtml(e)}}Ie.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Ie,deps:[{token:O.DomSanitizer}],target:e.ɵɵFactoryTarget.Pipe}),Ie.ɵpipe=e.ɵɵngDeclarePipe({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Ie,name:"safeHtml"}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Ie,decorators:[{type:o,args:[{name:"safeHtml"}]}],ctorParameters:function(){return[{type:O.DomSanitizer}]}});class Ne extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.assignCustomerConfigForm}onConfigurationSet(e){this.assignCustomerConfigForm=this.fb.group({customerNamePattern:[e?e.customerNamePattern:null,[T.required,T.pattern(/.*\S.*/)]],createCustomerIfNotExists:[!!e&&e.createCustomerIfNotExists,[]],customerCacheExpiration:[e?e.customerCacheExpiration:null,[T.required,T.min(0)]]})}prepareOutputConfig(e){return e.customerNamePattern=e.customerNamePattern.trim(),e}}Ne.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Ne,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),Ne.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Ne,selector:"tb-action-node-assign-to-customer-config",usesInheritance:!0,ngImport:e,template:'
\n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.create-customer-if-not-exists\' | translate }}\n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n tb.rulenode.customer-cache-expiration-hint\n \n
\n',components:[{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:D.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:G.MatLabel,selector:"mat-label"},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:G.MatError,selector:"mat-error",inputs:["id"]},{type:G.MatHint,selector:"mat-hint",inputs:["align","id"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"}],pipes:{translate:E.TranslatePipe,safeHtml:Ie}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Ne,decorators:[{type:t,args:[{selector:"tb-action-node-assign-to-customer-config",templateUrl:"./assign-customer-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class qe extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.attributeScopes=Object.keys(m),this.telemetryTypeTranslationsMap=u}configForm(){return this.attributesConfigForm}onConfigurationSet(e){this.attributesConfigForm=this.fb.group({scope:[e?e.scope:null,[T.required]],notifyDevice:[!e||e.scope,[]]})}}var Te;qe.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:qe,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),qe.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:qe,selector:"tb-action-node-attributes-config",usesInheritance:!0,ngImport:e,template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.notify-device\' | translate }}\n \n
tb.rulenode.notify-device-hint
\n
\n
\n',components:[{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:H.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:U.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:D.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:G.MatLabel,selector:"mat-label"},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]}],pipes:{translate:E.TranslatePipe}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:qe,decorators:[{type:t,args:[{selector:"tb-action-node-attributes-config",templateUrl:"./attributes-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}}),function(e){e.CUSTOMER="CUSTOMER",e.TENANT="TENANT",e.RELATED="RELATED",e.ALARM_ORIGINATOR="ALARM_ORIGINATOR"}(Te||(Te={}));const ke=new Map([[Te.CUSTOMER,"tb.rulenode.originator-customer"],[Te.TENANT,"tb.rulenode.originator-tenant"],[Te.RELATED,"tb.rulenode.originator-related"],[Te.ALARM_ORIGINATOR,"tb.rulenode.originator-alarm-originator"]]);var Me;!function(e){e.CIRCLE="CIRCLE",e.POLYGON="POLYGON"}(Me||(Me={}));const Se=new Map([[Me.CIRCLE,"tb.rulenode.perimeter-circle"],[Me.POLYGON,"tb.rulenode.perimeter-polygon"]]);var Ae;!function(e){e.MILLISECONDS="MILLISECONDS",e.SECONDS="SECONDS",e.MINUTES="MINUTES",e.HOURS="HOURS",e.DAYS="DAYS"}(Ae||(Ae={}));const Ge=new Map([[Ae.MILLISECONDS,"tb.rulenode.time-unit-milliseconds"],[Ae.SECONDS,"tb.rulenode.time-unit-seconds"],[Ae.MINUTES,"tb.rulenode.time-unit-minutes"],[Ae.HOURS,"tb.rulenode.time-unit-hours"],[Ae.DAYS,"tb.rulenode.time-unit-days"]]);var De;!function(e){e.METER="METER",e.KILOMETER="KILOMETER",e.FOOT="FOOT",e.MILE="MILE",e.NAUTICAL_MILE="NAUTICAL_MILE"}(De||(De={}));const Ve=new Map([[De.METER,"tb.rulenode.range-unit-meter"],[De.KILOMETER,"tb.rulenode.range-unit-kilometer"],[De.FOOT,"tb.rulenode.range-unit-foot"],[De.MILE,"tb.rulenode.range-unit-mile"],[De.NAUTICAL_MILE,"tb.rulenode.range-unit-nautical-mile"]]);var Ee;!function(e){e.TITLE="TITLE",e.COUNTRY="COUNTRY",e.STATE="STATE",e.CITY="CITY",e.ZIP="ZIP",e.ADDRESS="ADDRESS",e.ADDRESS2="ADDRESS2",e.PHONE="PHONE",e.EMAIL="EMAIL",e.ADDITIONAL_INFO="ADDITIONAL_INFO"}(Ee||(Ee={}));const Pe=new Map([[Ee.TITLE,"tb.rulenode.entity-details-title"],[Ee.COUNTRY,"tb.rulenode.entity-details-country"],[Ee.STATE,"tb.rulenode.entity-details-state"],[Ee.CITY,"tb.rulenode.entity-details-city"],[Ee.ZIP,"tb.rulenode.entity-details-zip"],[Ee.ADDRESS,"tb.rulenode.entity-details-address"],[Ee.ADDRESS2,"tb.rulenode.entity-details-address2"],[Ee.PHONE,"tb.rulenode.entity-details-phone"],[Ee.EMAIL,"tb.rulenode.entity-details-email"],[Ee.ADDITIONAL_INFO,"tb.rulenode.entity-details-additional_info"]]);var Re,we,Oe;!function(e){e.FIRST="FIRST",e.LAST="LAST",e.ALL="ALL"}(Re||(Re={})),function(e){e.ASC="ASC",e.DESC="DESC"}(we||(we={})),function(e){e.STANDARD="STANDARD",e.FIFO="FIFO"}(Oe||(Oe={}));const He=new Map([[Oe.STANDARD,"tb.rulenode.sqs-queue-standard"],[Oe.FIFO,"tb.rulenode.sqs-queue-fifo"]]),Ue=["anonymous","basic","cert.PEM"],Be=new Map([["anonymous","tb.rulenode.credentials-anonymous"],["basic","tb.rulenode.credentials-basic"],["cert.PEM","tb.rulenode.credentials-pem"]]),Ke=["sas","cert.PEM"],je=new Map([["sas","tb.rulenode.credentials-sas"],["cert.PEM","tb.rulenode.credentials-pem"]]);var ze;!function(e){e.GET="GET",e.POST="POST",e.PUT="PUT",e.DELETE="DELETE"}(ze||(ze={}));const _e=["US-ASCII","ISO-8859-1","UTF-8","UTF-16BE","UTF-16LE","UTF-16"],Qe=new Map([["US-ASCII","tb.rulenode.charset-us-ascii"],["ISO-8859-1","tb.rulenode.charset-iso-8859-1"],["UTF-8","tb.rulenode.charset-utf-8"],["UTF-16BE","tb.rulenode.charset-utf-16be"],["UTF-16LE","tb.rulenode.charset-utf-16le"],["UTF-16","tb.rulenode.charset-utf-16"]]);class $e extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.allAzureIotHubCredentialsTypes=Ke,this.azureIotHubCredentialsTypeTranslationsMap=je}configForm(){return this.azureIotHubConfigForm}onConfigurationSet(e){this.azureIotHubConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[T.required]],host:[e?e.host:null,[T.required]],port:[e?e.port:null,[T.required,T.min(1),T.max(65535)]],connectTimeoutSec:[e?e.connectTimeoutSec:null,[T.required,T.min(1),T.max(200)]],clientId:[e?e.clientId:null,[T.required]],cleanSession:[!!e&&e.cleanSession,[]],ssl:[!!e&&e.ssl,[]],credentials:this.fb.group({type:[e&&e.credentials?e.credentials.type:null,[T.required]],sasKey:[e&&e.credentials?e.credentials.sasKey:null,[]],caCert:[e&&e.credentials?e.credentials.caCert:null,[]],caCertFileName:[e&&e.credentials?e.credentials.caCertFileName:null,[]],privateKey:[e&&e.credentials?e.credentials.privateKey:null,[]],privateKeyFileName:[e&&e.credentials?e.credentials.privateKeyFileName:null,[]],cert:[e&&e.credentials?e.credentials.cert:null,[]],certFileName:[e&&e.credentials?e.credentials.certFileName:null,[]],password:[e&&e.credentials?e.credentials.password:null,[]]})})}prepareOutputConfig(e){const t=e.credentials.type;return"sas"===t&&(e.credentials={type:t,sasKey:e.credentials.sasKey,caCert:e.credentials.caCert,caCertFileName:e.credentials.caCertFileName}),e}validatorTriggers(){return["credentials.type"]}updateValidators(e){const t=this.azureIotHubConfigForm.get("credentials"),o=t.get("type").value;switch(e&&t.reset({type:o},{emitEvent:!1}),t.get("sasKey").setValidators([]),t.get("privateKey").setValidators([]),t.get("privateKeyFileName").setValidators([]),t.get("cert").setValidators([]),t.get("certFileName").setValidators([]),o){case"sas":t.get("sasKey").setValidators([T.required]);break;case"cert.PEM":t.get("privateKey").setValidators([T.required]),t.get("privateKeyFileName").setValidators([T.required]),t.get("cert").setValidators([T.required]),t.get("certFileName").setValidators([T.required])}t.get("sasKey").updateValueAndValidity({emitEvent:e}),t.get("privateKey").updateValueAndValidity({emitEvent:e}),t.get("privateKeyFileName").updateValueAndValidity({emitEvent:e}),t.get("cert").updateValueAndValidity({emitEvent:e}),t.get("certFileName").updateValueAndValidity({emitEvent:e})}}$e.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:$e,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),$e.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:$e,selector:"tb-action-node-azure-iot-hub-config",usesInheritance:!0,ngImport:e,template:'
\n \n tb.rulenode.topic\n \n \n {{ \'tb.rulenode.topic-required\' | translate }}\n \n \n \n \n tb.rulenode.hostname\n \n \n {{ \'tb.rulenode.hostname-required\' | translate }}\n \n \n \n tb.rulenode.device-id\n \n \n {{ \'tb.rulenode.device-id-required\' | translate }}\n \n \n \n \n \n tb.rulenode.credentials\n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(azureIotHubConfigForm.get(\'credentials.type\').value) | translate }}\n \n \n
\n \n tb.rulenode.credentials-type\n \n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
\n \n \n \n \n tb.rulenode.sas-key\n \n \n \n {{ \'tb.rulenode.sas-key-required\' | translate }}\n \n \n \n \n \n \n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n \n
\n
\n
\n
\n
\n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}:host .tb-hint.client-id{margin-top:-1.25em;max-width:-moz-fit-content;max-width:fit-content}\n"],components:[{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:B.MatExpansionPanel,selector:"mat-expansion-panel",inputs:["disabled","expanded","hideToggle","togglePosition"],outputs:["opened","closed","expandedChange","afterExpand","afterCollapse"],exportAs:["matExpansionPanel"]},{type:B.MatExpansionPanelHeader,selector:"mat-expansion-panel-header",inputs:["tabIndex","expandedHeight","collapsedHeight"]},{type:H.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:U.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:K.TogglePasswordComponent,selector:"tb-toggle-password"},{type:j.FileInputComponent,selector:"tb-file-input",inputs:["label","accept","noFileText","inputId","allowedExtensions","dropLabel","contentConvertFunction","required","requiredAsError","disabled","existingFileName","readAsBinary","workFromFileObj","multipleFile"],outputs:["fileNameChanged"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:G.MatLabel,selector:"mat-label"},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:G.MatError,selector:"mat-error",inputs:["id"]},{type:G.MatHint,selector:"mat-hint",inputs:["align","id"]},{type:B.MatAccordion,selector:"mat-accordion",inputs:["multi","displayMode","togglePosition","hideToggle"],exportAs:["matAccordion"]},{type:B.MatExpansionPanelTitle,selector:"mat-panel-title"},{type:B.MatExpansionPanelDescription,selector:"mat-panel-description"},{type:q.FormGroupName,selector:"[formGroupName]",inputs:["formGroupName"]},{type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:R.NgSwitch,selector:"[ngSwitch]",inputs:["ngSwitch"]},{type:R.NgSwitchCase,selector:"[ngSwitchCase]",inputs:["ngSwitchCase"]},{type:G.MatSuffix,selector:"[matSuffix]"}],pipes:{translate:E.TranslatePipe,safeHtml:Ie}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:$e,decorators:[{type:t,args:[{selector:"tb-action-node-azure-iot-hub-config",templateUrl:"./azure-iot-hub-config.component.html",styleUrls:["./mqtt-config.component.scss"]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class We extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.serviceType=p.TB_RULE_ENGINE}configForm(){return this.checkPointConfigForm}onConfigurationSet(e){this.checkPointConfigForm=this.fb.group({queueName:[e?e.queueName:null,[T.required]]})}}We.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:We,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),We.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:We,selector:"tb-action-node-check-point-config",usesInheritance:!0,ngImport:e,template:'
\n \n \n
\n',components:[{type:z.QueueTypeListComponent,selector:"tb-queue-type-list",inputs:["required","disabled","queueType"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]}]}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:We,decorators:[{type:t,args:[{selector:"tb-action-node-check-point-config",templateUrl:"./check-point-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class Ye extends s{constructor(e,t,o,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=o,this.translate=r}configForm(){return this.clearAlarmConfigForm}onConfigurationSet(e){this.clearAlarmConfigForm=this.fb.group({alarmDetailsBuildJs:[e?e.alarmDetailsBuildJs:null,[T.required]],alarmType:[e?e.alarmType:null,[T.required]]})}testScript(){const e=this.clearAlarmConfigForm.get("alarmDetailsBuildJs").value;this.nodeScriptTestService.testNodeScript(e,"json",this.translate.instant("tb.rulenode.details"),"Details",["msg","metadata","msgType"],this.ruleNodeId,"rulenode/clear_alarm_node_script_fn").subscribe((e=>{e&&this.clearAlarmConfigForm.get("alarmDetailsBuildJs").setValue(e)}))}onValidate(){this.jsFuncComponent.validateOnSubmit()}}Ye.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Ye,deps:[{token:N.Store},{token:q.FormBuilder},{token:_.NodeScriptTestService},{token:E.TranslateService}],target:e.ɵɵFactoryTarget.Component}),Ye.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Ye,selector:"tb-action-node-clear-alarm-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0,static:!0}],usesInheritance:!0,ngImport:e,template:'
\n \n \n \n
\n \n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n
\n',components:[{type:$.JsFuncComponent,selector:"tb-js-func",inputs:["functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","noValidate","required"]},{type:W.MatButton,selector:"button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:G.MatLabel,selector:"mat-label"},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:G.MatError,selector:"mat-error",inputs:["id"]},{type:G.MatHint,selector:"mat-hint",inputs:["align","id"]}],pipes:{translate:E.TranslatePipe,safeHtml:Ie}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Ye,decorators:[{type:t,args:[{selector:"tb-action-node-clear-alarm-config",templateUrl:"./clear-alarm-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder},{type:_.NodeScriptTestService},{type:E.TranslateService}]},propDecorators:{jsFuncComponent:[{type:r,args:["jsFuncComponent",{static:!0}]}]}});class Je extends s{constructor(e,t,o,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=o,this.translate=r,this.alarmSeverities=Object.keys(d),this.alarmSeverityTranslationMap=f,this.separatorKeysCodes=[Y,J,Z]}configForm(){return this.createAlarmConfigForm}onConfigurationSet(e){this.createAlarmConfigForm=this.fb.group({alarmDetailsBuildJs:[e?e.alarmDetailsBuildJs:null,[T.required]],useMessageAlarmData:[!!e&&e.useMessageAlarmData,[]],alarmType:[e?e.alarmType:null,[]],severity:[e?e.severity:null,[]],propagate:[!!e&&e.propagate,[]],relationTypes:[e?e.relationTypes:null,[]],dynamicSeverity:!1}),this.createAlarmConfigForm.get("dynamicSeverity").valueChanges.subscribe((e=>{e?this.createAlarmConfigForm.get("severity").patchValue("",{emitEvent:!1}):this.createAlarmConfigForm.get("severity").patchValue(this.alarmSeverities[0],{emitEvent:!1})}))}validatorTriggers(){return["useMessageAlarmData"]}updateValidators(e){this.createAlarmConfigForm.get("useMessageAlarmData").value?(this.createAlarmConfigForm.get("alarmType").setValidators([]),this.createAlarmConfigForm.get("severity").setValidators([])):(this.createAlarmConfigForm.get("alarmType").setValidators([T.required]),this.createAlarmConfigForm.get("severity").setValidators([T.required])),this.createAlarmConfigForm.get("alarmType").updateValueAndValidity({emitEvent:e}),this.createAlarmConfigForm.get("severity").updateValueAndValidity({emitEvent:e})}testScript(){const e=this.createAlarmConfigForm.get("alarmDetailsBuildJs").value;this.nodeScriptTestService.testNodeScript(e,"json",this.translate.instant("tb.rulenode.details"),"Details",["msg","metadata","msgType"],this.ruleNodeId,"rulenode/create_alarm_node_script_fn").subscribe((e=>{e&&this.createAlarmConfigForm.get("alarmDetailsBuildJs").setValue(e)}))}removeKey(e,t){const o=this.createAlarmConfigForm.get(t).value,r=o.indexOf(e);r>=0&&(o.splice(r,1),this.createAlarmConfigForm.get(t).setValue(o,{emitEvent:!0}))}addKey(e,t){const o=e.input;let r=e.value;if((r||"").trim()){r=r.trim();let e=this.createAlarmConfigForm.get(t).value;e&&-1!==e.indexOf(r)||(e||(e=[]),e.push(r),this.createAlarmConfigForm.get(t).setValue(e,{emitEvent:!0}))}o&&(o.value="")}onValidate(){this.jsFuncComponent.validateOnSubmit()}}Je.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Je,deps:[{token:N.Store},{token:q.FormBuilder},{token:_.NodeScriptTestService},{token:E.TranslateService}],target:e.ɵɵFactoryTarget.Component}),Je.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Je,selector:"tb-action-node-create-alarm-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0,static:!0}],usesInheritance:!0,ngImport:e,template:'
\n \n \n \n
\n \n
\n
\n \n {{ \'tb.rulenode.use-message-alarm-data\' | translate }}\n \n \n {{ \'tb.rulenode.use-dynamically-change-the-severity-of-alar\' | translate }}\n \n
\n
\n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n \n tb.rulenode.alarm-severity\n \n \n {{ alarmSeverityTranslationMap.get(severity) | translate }}\n \n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.alarm-severity\' | translate }}\n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.propagate\' | translate }}\n \n
\n \n tb.rulenode.relation-types-list\n \n \n {{key}}\n close\n \n \n \n tb.rulenode.relation-types-list-hint\n \n
\n
\n
\n',components:[{type:$.JsFuncComponent,selector:"tb-js-func",inputs:["functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","noValidate","required"]},{type:W.MatButton,selector:"button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{type:D.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:H.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:U.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:X.MatChipList,selector:"mat-chip-list",inputs:["aria-orientation","multiple","compareWith","value","required","placeholder","disabled","selectable","tabIndex","errorStateMatcher"],outputs:["change","valueChange"],exportAs:["matChipList"]},{type:ee.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:V.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:G.MatLabel,selector:"mat-label"},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:G.MatError,selector:"mat-error",inputs:["id"]},{type:G.MatHint,selector:"mat-hint",inputs:["align","id"]},{type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:X.MatChip,selector:"mat-basic-chip, [mat-basic-chip], mat-chip, [mat-chip]",inputs:["color","disableRipple","tabIndex","selected","value","selectable","disabled","removable"],outputs:["selectionChange","destroyed","removed"],exportAs:["matChip"]},{type:X.MatChipRemove,selector:"[matChipRemove]"},{type:X.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputSeparatorKeyCodes","placeholder","id","matChipInputFor","matChipInputAddOnBlur","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]}],pipes:{translate:E.TranslatePipe,safeHtml:Ie}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Je,decorators:[{type:t,args:[{selector:"tb-action-node-create-alarm-config",templateUrl:"./create-alarm-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder},{type:_.NodeScriptTestService},{type:E.TranslateService}]},propDecorators:{jsFuncComponent:[{type:r,args:["jsFuncComponent",{static:!0}]}]}});class Ze extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.keys(c),this.directionTypeTranslations=g,this.entityType=x}configForm(){return this.createRelationConfigForm}onConfigurationSet(e){this.createRelationConfigForm=this.fb.group({direction:[e?e.direction:null,[T.required]],entityType:[e?e.entityType:null,[T.required]],entityNamePattern:[e?e.entityNamePattern:null,[]],entityTypePattern:[e?e.entityTypePattern:null,[]],relationType:[e?e.relationType:null,[T.required]],createEntityIfNotExists:[!!e&&e.createEntityIfNotExists,[]],removeCurrentRelations:[!!e&&e.removeCurrentRelations,[]],changeOriginatorToRelatedEntity:[!!e&&e.changeOriginatorToRelatedEntity,[]],entityCacheExpiration:[e?e.entityCacheExpiration:null,[T.required,T.min(0)]]})}validatorTriggers(){return["entityType"]}updateValidators(e){const t=this.createRelationConfigForm.get("entityType").value;t?this.createRelationConfigForm.get("entityNamePattern").setValidators([T.required,T.pattern(/.*\S.*/)]):this.createRelationConfigForm.get("entityNamePattern").setValidators([]),!t||t!==x.DEVICE&&t!==x.ASSET?this.createRelationConfigForm.get("entityTypePattern").setValidators([]):this.createRelationConfigForm.get("entityTypePattern").setValidators([T.required,T.pattern(/.*\S.*/)]),this.createRelationConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e}),this.createRelationConfigForm.get("entityTypePattern").updateValueAndValidity({emitEvent:e})}prepareOutputConfig(e){return e.entityNamePattern=e.entityNamePattern?e.entityNamePattern.trim():null,e.entityTypePattern=e.entityTypePattern?e.entityTypePattern.trim():null,e}}Ze.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Ze,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),Ze.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Ze,selector:"tb-action-node-create-relation-config",usesInheritance:!0,ngImport:e,template:'
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-type-pattern\n \n \n {{ \'tb.rulenode.entity-type-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.create-entity-if-not-exists\' | translate }}\n \n
tb.rulenode.create-entity-if-not-exists-hint
\n
\n \n {{ \'tb.rulenode.remove-current-relations\' | translate }}\n \n
tb.rulenode.remove-current-relations-hint
\n \n {{ \'tb.rulenode.change-originator-to-related-entity\' | translate }}\n \n
tb.rulenode.change-originator-to-related-entity-hint
\n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n tb.rulenode.entity-cache-expiration-hint\n \n
\n',components:[{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:H.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:U.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:te.EntityTypeSelectComponent,selector:"tb-entity-type-select",inputs:["allowedEntityTypes","useAliasEntityTypes","showLabel","required","disabled"]},{type:D.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:G.MatLabel,selector:"mat-label"},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:V.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:G.MatError,selector:"mat-error",inputs:["id"]},{type:G.MatHint,selector:"mat-hint",inputs:["align","id"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"}],pipes:{translate:E.TranslatePipe,safeHtml:Ie}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Ze,decorators:[{type:t,args:[{selector:"tb-action-node-create-relation-config",templateUrl:"./create-relation-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class Xe extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.keys(c),this.directionTypeTranslations=g,this.entityType=x}configForm(){return this.deleteRelationConfigForm}onConfigurationSet(e){this.deleteRelationConfigForm=this.fb.group({deleteForSingleEntity:[!!e&&e.deleteForSingleEntity,[]],direction:[e?e.direction:null,[T.required]],entityType:[e?e.entityType:null,[]],entityNamePattern:[e?e.entityNamePattern:null,[]],relationType:[e?e.relationType:null,[T.required]],entityCacheExpiration:[e?e.entityCacheExpiration:null,[T.required,T.min(0)]]})}validatorTriggers(){return["deleteForSingleEntity","entityType"]}updateValidators(e){const t=this.deleteRelationConfigForm.get("deleteForSingleEntity").value,o=this.deleteRelationConfigForm.get("entityType").value;t?this.deleteRelationConfigForm.get("entityType").setValidators([T.required]):this.deleteRelationConfigForm.get("entityType").setValidators([]),t&&o?this.deleteRelationConfigForm.get("entityNamePattern").setValidators([T.required,T.pattern(/.*\S.*/)]):this.deleteRelationConfigForm.get("entityNamePattern").setValidators([]),this.deleteRelationConfigForm.get("entityType").updateValueAndValidity({emitEvent:!1}),this.deleteRelationConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e})}prepareOutputConfig(e){return e.entityNamePattern=e.entityNamePattern?e.entityNamePattern.trim():null,e}}Xe.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Xe,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),Xe.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Xe,selector:"tb-action-node-delete-relation-config",usesInheritance:!0,ngImport:e,template:'
\n \n {{ \'tb.rulenode.delete-relation-to-specific-entity\' | translate }}\n \n
tb.rulenode.delete-relation-hint
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n tb.rulenode.entity-cache-expiration-hint\n \n
\n',components:[{type:D.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:H.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:U.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:te.EntityTypeSelectComponent,selector:"tb-entity-type-select",inputs:["allowedEntityTypes","useAliasEntityTypes","showLabel","required","disabled"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:G.MatLabel,selector:"mat-label"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:V.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:G.MatError,selector:"mat-error",inputs:["id"]},{type:G.MatHint,selector:"mat-hint",inputs:["align","id"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"}],pipes:{translate:E.TranslatePipe,safeHtml:Ie}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Xe,decorators:[{type:t,args:[{selector:"tb-action-node-delete-relation-config",templateUrl:"./delete-relation-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class et extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.deviceProfile}onConfigurationSet(e){this.deviceProfile=this.fb.group({persistAlarmRulesState:[!!e&&e.persistAlarmRulesState,T.required],fetchAlarmRulesStateOnStart:[!!e&&e.fetchAlarmRulesStateOnStart,T.required]})}}et.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:et,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),et.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:et,selector:"tb-device-profile-config",usesInheritance:!0,ngImport:e,template:'
\n \n {{ \'tb.rulenode.persist-alarm-rules\' | translate }}\n \n \n {{ \'tb.rulenode.fetch-alarm-rules\' | translate }}\n \n
\n',components:[{type:D.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]}],pipes:{translate:E.TranslatePipe}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:et,decorators:[{type:t,args:[{selector:"tb-device-profile-config",templateUrl:"./device-profile-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class tt extends s{constructor(e,t,o,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=o,this.translate=r}configForm(){return this.generatorConfigForm}onConfigurationSet(e){this.generatorConfigForm=this.fb.group({msgCount:[e?e.msgCount:null,[T.required,T.min(0)]],periodInSeconds:[e?e.periodInSeconds:null,[T.required,T.min(1)]],originator:[e?e.originator:null,[]],jsScript:[e?e.jsScript:null,[T.required]]})}prepareInputConfig(e){return e&&(e.originatorId&&e.originatorType?e.originator={id:e.originatorId,entityType:e.originatorType}:e.originator=null,delete e.originatorId,delete e.originatorType),e}prepareOutputConfig(e){return e.originator?(e.originatorId=e.originator.id,e.originatorType=e.originator.entityType):(e.originatorId=null,e.originatorType=null),delete e.originator,e}testScript(){const e=this.generatorConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(e,"generate",this.translate.instant("tb.rulenode.generator"),"Generate",["prevMsg","prevMetadata","prevMsgType"],this.ruleNodeId,"rulenode/generator_node_script_fn").subscribe((e=>{e&&this.generatorConfigForm.get("jsScript").setValue(e)}))}onValidate(){this.jsFuncComponent.validateOnSubmit()}}tt.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:tt,deps:[{token:N.Store},{token:q.FormBuilder},{token:_.NodeScriptTestService},{token:E.TranslateService}],target:e.ɵɵFactoryTarget.Component}),tt.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:tt,selector:"tb-action-node-generator-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0,static:!0}],usesInheritance:!0,ngImport:e,template:'
\n \n tb.rulenode.message-count\n \n \n {{ \'tb.rulenode.message-count-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-message-count-message\' | translate }}\n \n \n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-seconds-message\' | translate }}\n \n \n
\n \n \n \n
\n \n \n \n
\n \n
\n
\n',components:[{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:oe.EntitySelectComponent,selector:"tb-entity-select",inputs:["allowedEntityTypes","useAliasEntityTypes","required","disabled"]},{type:$.JsFuncComponent,selector:"tb-js-func",inputs:["functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","noValidate","required"]},{type:W.MatButton,selector:"button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:G.MatLabel,selector:"mat-label"},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:G.MatError,selector:"mat-error",inputs:["id"]}],pipes:{translate:E.TranslatePipe}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:tt,decorators:[{type:t,args:[{selector:"tb-action-node-generator-config",templateUrl:"./generator-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder},{type:_.NodeScriptTestService},{type:E.TranslateService}]},propDecorators:{jsFuncComponent:[{type:r,args:["jsFuncComponent",{static:!0}]}]}});class ot extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.perimeterType=Me,this.perimeterTypes=Object.keys(Me),this.perimeterTypeTranslationMap=Se,this.rangeUnits=Object.keys(De),this.rangeUnitTranslationMap=Ve,this.timeUnits=Object.keys(Ae),this.timeUnitsTranslationMap=Ge}configForm(){return this.geoActionConfigForm}onConfigurationSet(e){this.geoActionConfigForm=this.fb.group({latitudeKeyName:[e?e.latitudeKeyName:null,[T.required]],longitudeKeyName:[e?e.longitudeKeyName:null,[T.required]],fetchPerimeterInfoFromMessageMetadata:[!!e&&e.fetchPerimeterInfoFromMessageMetadata,[]],perimeterType:[e?e.perimeterType:null,[]],centerLatitude:[e?e.centerLatitude:null,[]],centerLongitude:[e?e.centerLatitude:null,[]],range:[e?e.range:null,[]],rangeUnit:[e?e.rangeUnit:null,[]],polygonsDefinition:[e?e.polygonsDefinition:null,[]],minInsideDuration:[e?e.minInsideDuration:null,[T.required,T.min(1),T.max(2147483647)]],minInsideDurationTimeUnit:[e?e.minInsideDurationTimeUnit:null,[T.required]],minOutsideDuration:[e?e.minOutsideDuration:null,[T.required,T.min(1),T.max(2147483647)]],minOutsideDurationTimeUnit:[e?e.minOutsideDurationTimeUnit:null,[T.required]]})}validatorTriggers(){return["fetchPerimeterInfoFromMessageMetadata","perimeterType"]}updateValidators(e){const t=this.geoActionConfigForm.get("fetchPerimeterInfoFromMessageMetadata").value,o=this.geoActionConfigForm.get("perimeterType").value;t?this.geoActionConfigForm.get("perimeterType").setValidators([]):this.geoActionConfigForm.get("perimeterType").setValidators([T.required]),t||o!==Me.CIRCLE?(this.geoActionConfigForm.get("centerLatitude").setValidators([]),this.geoActionConfigForm.get("centerLongitude").setValidators([]),this.geoActionConfigForm.get("range").setValidators([]),this.geoActionConfigForm.get("rangeUnit").setValidators([])):(this.geoActionConfigForm.get("centerLatitude").setValidators([T.required,T.min(-90),T.max(90)]),this.geoActionConfigForm.get("centerLongitude").setValidators([T.required,T.min(-180),T.max(180)]),this.geoActionConfigForm.get("range").setValidators([T.required,T.min(0)]),this.geoActionConfigForm.get("rangeUnit").setValidators([T.required])),t||o!==Me.POLYGON?this.geoActionConfigForm.get("polygonsDefinition").setValidators([]):this.geoActionConfigForm.get("polygonsDefinition").setValidators([T.required]),this.geoActionConfigForm.get("perimeterType").updateValueAndValidity({emitEvent:!1}),this.geoActionConfigForm.get("centerLatitude").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("centerLongitude").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("range").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("rangeUnit").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("polygonsDefinition").updateValueAndValidity({emitEvent:e})}}ot.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:ot,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),ot.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:ot,selector:"tb-action-node-gps-geofencing-config",usesInheritance:!0,ngImport:e,template:'
\n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n
\n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.min-inside-duration\n \n \n {{ \'tb.rulenode.min-inside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-inside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n tb.rulenode.min-outside-duration\n \n \n {{ \'tb.rulenode.min-outside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-outside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n',components:[{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:D.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:H.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:U.MatOption,selector:"mat-option",exportAs:["matOption"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:G.MatLabel,selector:"mat-label"},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:G.MatError,selector:"mat-error",inputs:["id"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:V.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"}],pipes:{translate:E.TranslatePipe}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:ot,decorators:[{type:t,args:[{selector:"tb-action-node-gps-geofencing-config",templateUrl:"./gps-geo-action-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class rt extends y{constructor(e,t,o,r){super(e),this.store=e,this.translate=t,this.injector=o,this.fb=r,this.propagateChange=null,this.valueChangeSubscription=null}get required(){return this.requiredValue}set required(e){this.requiredValue=re(e)}ngOnInit(){this.ngControl=this.injector.get(k),null!=this.ngControl&&(this.ngControl.valueAccessor=this),this.kvListFormGroup=this.fb.group({}),this.kvListFormGroup.addControl("keyVals",this.fb.array([]))}keyValsFormArray(){return this.kvListFormGroup.get("keyVals")}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.kvListFormGroup.disable({emitEvent:!1}):this.kvListFormGroup.enable({emitEvent:!1})}writeValue(e){this.valueChangeSubscription&&this.valueChangeSubscription.unsubscribe();const t=[];if(e)for(const o of Object.keys(e))Object.prototype.hasOwnProperty.call(e,o)&&t.push(this.fb.group({key:[o,[T.required]],value:[e[o],[T.required]]}));this.kvListFormGroup.setControl("keyVals",this.fb.array(t)),this.valueChangeSubscription=this.kvListFormGroup.valueChanges.subscribe((()=>{this.updateModel()}))}removeKeyVal(e){this.kvListFormGroup.get("keyVals").removeAt(e)}addKeyVal(){this.kvListFormGroup.get("keyVals").push(this.fb.group({key:["",[T.required]],value:["",[T.required]]}))}validate(e){return!this.kvListFormGroup.get("keyVals").value.length&&this.required?{kvMapRequired:!0}:this.kvListFormGroup.valid?null:{kvFieldsRequired:!0}}updateModel(){const e=this.kvListFormGroup.get("keyVals").value;if(this.required&&!e.length||!this.kvListFormGroup.valid)this.propagateChange(null);else{const t={};e.forEach((e=>{t[e.key]=e.value})),this.propagateChange(t)}}}rt.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:rt,deps:[{token:N.Store},{token:E.TranslateService},{token:e.Injector},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),rt.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:rt,selector:"tb-kv-map-config",inputs:{disabled:"disabled",requiredText:"requiredText",keyText:"keyText",keyRequiredText:"keyRequiredText",valText:"valText",valRequiredText:"valRequiredText",required:"required"},providers:[{provide:M,useExisting:a((()=>rt)),multi:!0},{provide:S,useExisting:a((()=>rt)),multi:!0}],usesInheritance:!0,ngImport:e,template:'
\n
\n {{ keyText | translate }}\n {{ valText | translate }}\n \n
\n
\n
\n \n \n \n \n {{ keyRequiredText | translate }}\n \n \n \n \n \n \n {{ valRequiredText | translate }}\n \n \n \n
\n
\n \n
\n \n
\n
\n',styles:[":host .tb-kv-map-config{margin-bottom:16px}:host .tb-kv-map-config .header{padding-left:5px;padding-right:5px;padding-bottom:5px}:host .tb-kv-map-config .header .cell{padding-left:5px;padding-right:5px;color:#0000008a;font-size:12px;font-weight:700;white-space:nowrap}:host .tb-kv-map-config .body{padding-left:5px;padding-right:5px;padding-bottom:20px;max-height:300px;overflow:auto}:host .tb-kv-map-config .body .row{padding-top:5px;max-height:40px}:host .tb-kv-map-config .body .cell{padding-left:5px;padding-right:5px}:host ::ng-deep .tb-kv-map-config .body mat-form-field.cell{margin:0;max-height:40px}:host ::ng-deep .tb-kv-map-config .body mat-form-field.cell .mat-form-field-infix{border-top:0}:host ::ng-deep .tb-kv-map-config .body button.mat-button{margin:0}\n"],components:[{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:W.MatButton,selector:"button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{type:ee.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{type:ae.TbErrorComponent,selector:"tb-error",inputs:["error"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:V.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{type:ne.DefaultShowHideDirective,selector:" [fxShow], [fxShow.print], [fxShow.xs], [fxShow.sm], [fxShow.md], [fxShow.lg], [fxShow.xl], [fxShow.lt-sm], [fxShow.lt-md], [fxShow.lt-lg], [fxShow.lt-xl], [fxShow.gt-xs], [fxShow.gt-sm], [fxShow.gt-md], [fxShow.gt-lg], [fxHide], [fxHide.print], [fxHide.xs], [fxHide.sm], [fxHide.md], [fxHide.lg], [fxHide.xl], [fxHide.lt-sm], [fxHide.lt-md], [fxHide.lt-lg], [fxHide.lt-xl], [fxHide.gt-xs], [fxHide.gt-sm], [fxHide.gt-md], [fxHide.gt-lg]",inputs:["fxShow","fxShow.print","fxShow.xs","fxShow.sm","fxShow.md","fxShow.lg","fxShow.xl","fxShow.lt-sm","fxShow.lt-md","fxShow.lt-lg","fxShow.lt-xl","fxShow.gt-xs","fxShow.gt-sm","fxShow.gt-md","fxShow.gt-lg","fxHide","fxHide.print","fxHide.xs","fxHide.sm","fxHide.md","fxHide.lg","fxHide.xl","fxHide.lt-sm","fxHide.lt-md","fxHide.lt-lg","fxHide.lt-xl","fxHide.gt-xs","fxHide.gt-sm","fxHide.gt-md","fxHide.gt-lg"]},{type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:V.DefaultLayoutAlignDirective,selector:" [fxLayoutAlign], [fxLayoutAlign.xs], [fxLayoutAlign.sm], [fxLayoutAlign.md], [fxLayoutAlign.lg], [fxLayoutAlign.xl], [fxLayoutAlign.lt-sm], [fxLayoutAlign.lt-md], [fxLayoutAlign.lt-lg], [fxLayoutAlign.lt-xl], [fxLayoutAlign.gt-xs], [fxLayoutAlign.gt-sm], [fxLayoutAlign.gt-md], [fxLayoutAlign.gt-lg]",inputs:["fxLayoutAlign","fxLayoutAlign.xs","fxLayoutAlign.sm","fxLayoutAlign.md","fxLayoutAlign.lg","fxLayoutAlign.xl","fxLayoutAlign.lt-sm","fxLayoutAlign.lt-md","fxLayoutAlign.lt-lg","fxLayoutAlign.lt-xl","fxLayoutAlign.gt-xs","fxLayoutAlign.gt-sm","fxLayoutAlign.gt-md","fxLayoutAlign.gt-lg"]},{type:q.FormArrayName,selector:"[formArrayName]",inputs:["formArrayName"]},{type:G.MatLabel,selector:"mat-label"},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlDirective,selector:"[formControl]",inputs:["disabled","formControl","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:G.MatError,selector:"mat-error",inputs:["id"]},{type:le.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]}],pipes:{translate:E.TranslatePipe,async:R.AsyncPipe}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:rt,decorators:[{type:t,args:[{selector:"tb-kv-map-config",templateUrl:"./kv-map-config.component.html",styleUrls:["./kv-map-config.component.scss"],providers:[{provide:M,useExisting:a((()=>rt)),multi:!0},{provide:S,useExisting:a((()=>rt)),multi:!0}]}]}],ctorParameters:function(){return[{type:N.Store},{type:E.TranslateService},{type:e.Injector},{type:q.FormBuilder}]},propDecorators:{disabled:[{type:n}],requiredText:[{type:n}],keyText:[{type:n}],keyRequiredText:[{type:n}],valText:[{type:n}],valRequiredText:[{type:n}],required:[{type:n}]}});class at extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.ackValues=["all","-1","0","1"],this.ToByteStandartCharsetTypesValues=_e,this.ToByteStandartCharsetTypeTranslationMap=Qe}configForm(){return this.kafkaConfigForm}onConfigurationSet(e){this.kafkaConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[T.required]],bootstrapServers:[e?e.bootstrapServers:null,[T.required]],retries:[e?e.retries:null,[T.min(0)]],batchSize:[e?e.batchSize:null,[T.min(0)]],linger:[e?e.linger:null,[T.min(0)]],bufferMemory:[e?e.bufferMemory:null,[T.min(0)]],acks:[e?e.acks:null,[T.required]],keySerializer:[e?e.keySerializer:null,[T.required]],valueSerializer:[e?e.valueSerializer:null,[T.required]],otherProperties:[e?e.otherProperties:null,[]],addMetadataKeyValuesAsKafkaHeaders:[!!e&&e.addMetadataKeyValuesAsKafkaHeaders,[]],kafkaHeadersCharset:[e?e.kafkaHeadersCharset:null,[]]})}validatorTriggers(){return["addMetadataKeyValuesAsKafkaHeaders"]}updateValidators(e){this.kafkaConfigForm.get("addMetadataKeyValuesAsKafkaHeaders").value?this.kafkaConfigForm.get("kafkaHeadersCharset").setValidators([T.required]):this.kafkaConfigForm.get("kafkaHeadersCharset").setValidators([]),this.kafkaConfigForm.get("kafkaHeadersCharset").updateValueAndValidity({emitEvent:e})}}at.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:at,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),at.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:at,selector:"tb-action-node-kafka-config",usesInheritance:!0,ngImport:e,template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.bootstrap-servers\n \n \n {{ \'tb.rulenode.bootstrap-servers-required\' | translate }}\n \n \n \n tb.rulenode.retries\n \n \n {{ \'tb.rulenode.min-retries-message\' | translate }}\n \n \n \n tb.rulenode.batch-size-bytes\n \n \n {{ \'tb.rulenode.min-batch-size-bytes-message\' | translate }}\n \n \n \n tb.rulenode.linger-ms\n \n \n {{ \'tb.rulenode.min-linger-ms-message\' | translate }}\n \n \n \n tb.rulenode.buffer-memory-bytes\n \n \n {{ \'tb.rulenode.min-buffer-memory-bytes-message\' | translate }}\n \n \n \n tb.rulenode.acks\n \n \n {{ ackValue }}\n \n \n \n \n tb.rulenode.key-serializer\n \n \n {{ \'tb.rulenode.key-serializer-required\' | translate }}\n \n \n \n tb.rulenode.value-serializer\n \n \n {{ \'tb.rulenode.value-serializer-required\' | translate }}\n \n \n \n \n \n \n {{ \'tb.rulenode.add-metadata-key-values-as-kafka-headers\' | translate }}\n \n
tb.rulenode.add-metadata-key-values-as-kafka-headers-hint
\n \n tb.rulenode.charset-encoding\n \n \n {{ ToByteStandartCharsetTypeTranslationMap.get(charset) | translate }}\n \n \n \n
\n',components:[{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:H.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:U.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:rt,selector:"tb-kv-map-config",inputs:["disabled","requiredText","keyText","keyRequiredText","valText","valRequiredText","required"]},{type:D.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:G.MatLabel,selector:"mat-label"},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:G.MatError,selector:"mat-error",inputs:["id"]},{type:G.MatHint,selector:"mat-hint",inputs:["align","id"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]}],pipes:{translate:E.TranslatePipe,safeHtml:Ie}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:at,decorators:[{type:t,args:[{selector:"tb-action-node-kafka-config",templateUrl:"./kafka-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class nt extends s{constructor(e,t,o,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=o,this.translate=r}configForm(){return this.logConfigForm}onConfigurationSet(e){this.logConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[T.required]]})}testScript(){const e=this.logConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(e,"string",this.translate.instant("tb.rulenode.to-string"),"ToString",["msg","metadata","msgType"],this.ruleNodeId,"rulenode/log_node_script_fn").subscribe((e=>{e&&this.logConfigForm.get("jsScript").setValue(e)}))}onValidate(){this.jsFuncComponent.validateOnSubmit()}}nt.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:nt,deps:[{token:N.Store},{token:q.FormBuilder},{token:_.NodeScriptTestService},{token:E.TranslateService}],target:e.ɵɵFactoryTarget.Component}),nt.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:nt,selector:"tb-action-node-log-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0,static:!0}],usesInheritance:!0,ngImport:e,template:'
\n \n \n \n
\n \n
\n
\n',components:[{type:$.JsFuncComponent,selector:"tb-js-func",inputs:["functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","noValidate","required"]},{type:W.MatButton,selector:"button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]}],pipes:{translate:E.TranslatePipe}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:nt,decorators:[{type:t,args:[{selector:"tb-action-node-log-config",templateUrl:"./log-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder},{type:_.NodeScriptTestService},{type:E.TranslateService}]},propDecorators:{jsFuncComponent:[{type:r,args:["jsFuncComponent",{static:!0}]}]}});class lt extends y{constructor(e,t){super(e),this.store=e,this.fb=t,this.subscriptions=[],this.disableCertPemCredentials=!1,this.passwordFieldRquired=!0,this.allCredentialsTypes=Ue,this.credentialsTypeTranslationsMap=Be,this.propagateChange=null}get required(){return this.requiredValue}set required(e){this.requiredValue=re(e)}ngOnInit(){this.credentialsConfigFormGroup=this.fb.group({type:[null,[T.required]],username:[null,[]],password:[null,[]],caCert:[null,[]],caCertFileName:[null,[]],privateKey:[null,[]],privateKeyFileName:[null,[]],cert:[null,[]],certFileName:[null,[]]}),this.subscriptions.push(this.credentialsConfigFormGroup.valueChanges.pipe(ie()).subscribe((()=>{this.updateView()}))),this.subscriptions.push(this.credentialsConfigFormGroup.get("type").valueChanges.subscribe((()=>{this.credentialsTypeChanged()})))}ngOnChanges(e){for(const t of Object.keys(e)){const o=e[t];if(!o.firstChange&&o.currentValue!==o.previousValue&&o.currentValue&&"disableCertPemCredentials"===t){"cert.PEM"===this.credentialsConfigFormGroup.get("type").value&&setTimeout((()=>{this.credentialsConfigFormGroup.get("type").patchValue("anonymous",{emitEvent:!0})}))}}}ngOnDestroy(){this.subscriptions.forEach((e=>e.unsubscribe()))}writeValue(e){Q(e)&&(this.credentialsConfigFormGroup.reset(e,{emitEvent:!1}),this.updateValidators(!1))}setDisabledState(e){e?this.credentialsConfigFormGroup.disable():(this.credentialsConfigFormGroup.enable(),this.updateValidators())}updateView(){let e=this.credentialsConfigFormGroup.value;const t=e.type;switch(t){case"anonymous":e={type:t};break;case"basic":e={type:t,username:e.username,password:e.password};break;case"cert.PEM":delete e.username}this.propagateChange(e)}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}validate(e){return this.credentialsConfigFormGroup.valid?null:{credentialsConfig:{valid:!1}}}credentialsTypeChanged(){this.credentialsConfigFormGroup.patchValue({username:null,password:null,caCert:null,caCertFileName:null,privateKey:null,privateKeyFileName:null,cert:null,certFileName:null}),this.updateValidators()}updateValidators(e=!1){const t=this.credentialsConfigFormGroup.get("type").value;switch(e&&this.credentialsConfigFormGroup.reset({type:t},{emitEvent:!1}),this.credentialsConfigFormGroup.setValidators([]),this.credentialsConfigFormGroup.get("username").setValidators([]),this.credentialsConfigFormGroup.get("password").setValidators([]),t){case"anonymous":break;case"basic":this.credentialsConfigFormGroup.get("username").setValidators([T.required]),this.credentialsConfigFormGroup.get("password").setValidators(this.passwordFieldRquired?[T.required]:[]);break;case"cert.PEM":this.credentialsConfigFormGroup.setValidators([this.requiredFilesSelected(T.required,[["caCert","caCertFileName"],["privateKey","privateKeyFileName","cert","certFileName"]])])}this.credentialsConfigFormGroup.get("username").updateValueAndValidity({emitEvent:e}),this.credentialsConfigFormGroup.get("password").updateValueAndValidity({emitEvent:e}),this.credentialsConfigFormGroup.updateValueAndValidity({emitEvent:e})}requiredFilesSelected(e,t=null){return o=>{t||(t=[Object.keys(o.controls)]);return(null==o?void 0:o.controls)&&t.some((t=>t.every((t=>!e(o.controls[t])))))?null:{notAllRequiredFilesSelected:!0}}}}lt.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:lt,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),lt.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:lt,selector:"tb-credentials-config",inputs:{required:"required",disableCertPemCredentials:"disableCertPemCredentials",passwordFieldRquired:"passwordFieldRquired"},providers:[{provide:M,useExisting:a((()=>lt)),multi:!0},{provide:S,useExisting:a((()=>lt)),multi:!0}],usesInheritance:!0,usesOnChanges:!0,ngImport:e,template:'
\n \n \n tb.rulenode.credentials\n \n {{ credentialsTypeTranslationsMap.get(credentialsConfigFormGroup.get(\'type\').value) | translate }}\n \n \n \n \n tb.rulenode.credentials-type\n \n \n {{ credentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
\n \n \n \n \n tb.rulenode.username\n \n \n {{ \'tb.rulenode.username-required\' | translate }}\n \n \n \n tb.rulenode.password\n \n \n \n {{ \'tb.rulenode.password-required\' | translate }}\n \n \n \n \n
{{ \'tb.rulenode.credentials-pem-hint\' | translate }}
\n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n
\n
\n
\n
\n
\n',components:[{type:B.MatExpansionPanel,selector:"mat-expansion-panel",inputs:["disabled","expanded","hideToggle","togglePosition"],outputs:["opened","closed","expandedChange","afterExpand","afterCollapse"],exportAs:["matExpansionPanel"]},{type:B.MatExpansionPanelHeader,selector:"mat-expansion-panel-header",inputs:["tabIndex","expandedHeight","collapsedHeight"]},{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:H.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:U.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:K.TogglePasswordComponent,selector:"tb-toggle-password"},{type:j.FileInputComponent,selector:"tb-file-input",inputs:["label","accept","noFileText","inputId","allowedExtensions","dropLabel","contentConvertFunction","required","requiredAsError","disabled","existingFileName","readAsBinary","workFromFileObj","multipleFile"],outputs:["fileNameChanged"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:B.MatExpansionPanelTitle,selector:"mat-panel-title"},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:B.MatExpansionPanelDescription,selector:"mat-panel-description"},{type:B.MatExpansionPanelContent,selector:"ng-template[matExpansionPanelContent]"},{type:G.MatLabel,selector:"mat-label"},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:G.MatError,selector:"mat-error",inputs:["id"]},{type:R.NgSwitch,selector:"[ngSwitch]",inputs:["ngSwitch"]},{type:R.NgSwitchCase,selector:"[ngSwitchCase]",inputs:["ngSwitchCase"]},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:G.MatSuffix,selector:"[matSuffix]"}],pipes:{translate:E.TranslatePipe}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:lt,decorators:[{type:t,args:[{selector:"tb-credentials-config",templateUrl:"./credentials-config.component.html",styleUrls:[],providers:[{provide:M,useExisting:a((()=>lt)),multi:!0},{provide:S,useExisting:a((()=>lt)),multi:!0}]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]},propDecorators:{required:[{type:n}],disableCertPemCredentials:[{type:n}],passwordFieldRquired:[{type:n}]}});class it extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.mqttConfigForm}onConfigurationSet(e){this.mqttConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[T.required]],host:[e?e.host:null,[T.required]],port:[e?e.port:null,[T.required,T.min(1),T.max(65535)]],connectTimeoutSec:[e?e.connectTimeoutSec:null,[T.required,T.min(1),T.max(200)]],clientId:[e?e.clientId:null,[]],cleanSession:[!!e&&e.cleanSession,[]],ssl:[!!e&&e.ssl,[]],credentials:[e?e.credentials:null,[]]})}}it.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:it,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),it.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:it,selector:"tb-action-node-mqtt-config",usesInheritance:!0,ngImport:e,template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n \n tb.rulenode.connect-timeout\n \n \n {{ \'tb.rulenode.connect-timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n
\n \n tb.rulenode.client-id\n \n \n
tb.rulenode.client-id-hint
\n \n {{ \'tb.rulenode.clean-session\' | translate }}\n \n \n {{ \'tb.rulenode.enable-ssl\' | translate }}\n \n \n
\n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}:host .tb-hint.client-id{margin-top:-1.25em;max-width:-moz-fit-content;max-width:fit-content}\n"],components:[{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:D.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:lt,selector:"tb-credentials-config",inputs:["required","disableCertPemCredentials","passwordFieldRquired"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:G.MatLabel,selector:"mat-label"},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:G.MatError,selector:"mat-error",inputs:["id"]},{type:G.MatHint,selector:"mat-hint",inputs:["align","id"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:V.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"}],pipes:{translate:E.TranslatePipe,safeHtml:Ie}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:it,decorators:[{type:t,args:[{selector:"tb-action-node-mqtt-config",templateUrl:"./mqtt-config.component.html",styleUrls:["./mqtt-config.component.scss"]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class st extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.msgCountConfigForm}onConfigurationSet(e){this.msgCountConfigForm=this.fb.group({interval:[e?e.interval:null,[T.required,T.min(1)]],telemetryPrefix:[e?e.telemetryPrefix:null,[T.required]]})}}st.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:st,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),st.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:st,selector:"tb-action-node-msg-count-config",usesInheritance:!0,ngImport:e,template:'
\n \n tb.rulenode.interval-seconds\n \n \n {{ \'tb.rulenode.interval-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-interval-seconds-message\' | translate }}\n \n \n \n tb.rulenode.output-timeseries-key-prefix\n \n \n {{ \'tb.rulenode.output-timeseries-key-prefix-required\' | translate }}\n \n \n
\n',components:[{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:G.MatLabel,selector:"mat-label"},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:G.MatError,selector:"mat-error",inputs:["id"]}],pipes:{translate:E.TranslatePipe}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:st,decorators:[{type:t,args:[{selector:"tb-action-node-msg-count-config",templateUrl:"./msg-count-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class mt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.msgDelayConfigForm}onConfigurationSet(e){this.msgDelayConfigForm=this.fb.group({useMetadataPeriodInSecondsPatterns:[!!e&&e.useMetadataPeriodInSecondsPatterns,[]],periodInSeconds:[e?e.periodInSeconds:null,[]],periodInSecondsPattern:[e?e.periodInSecondsPattern:null,[]],maxPendingMsgs:[e?e.maxPendingMsgs:null,[T.required,T.min(1),T.max(1e5)]]})}validatorTriggers(){return["useMetadataPeriodInSecondsPatterns"]}updateValidators(e){this.msgDelayConfigForm.get("useMetadataPeriodInSecondsPatterns").value?(this.msgDelayConfigForm.get("periodInSecondsPattern").setValidators([T.required]),this.msgDelayConfigForm.get("periodInSeconds").setValidators([])):(this.msgDelayConfigForm.get("periodInSecondsPattern").setValidators([]),this.msgDelayConfigForm.get("periodInSeconds").setValidators([T.required,T.min(0)])),this.msgDelayConfigForm.get("periodInSecondsPattern").updateValueAndValidity({emitEvent:e}),this.msgDelayConfigForm.get("periodInSeconds").updateValueAndValidity({emitEvent:e})}}mt.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:mt,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),mt.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:mt,selector:"tb-action-node-msg-delay-config",usesInheritance:!0,ngImport:e,template:'
\n \n {{ \'tb.rulenode.use-metadata-period-in-seconds-patterns\' | translate }}\n \n
tb.rulenode.use-metadata-period-in-seconds-patterns-hint
\n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-0-seconds-message\' | translate }}\n \n \n \n \n tb.rulenode.period-in-seconds-pattern\n \n \n {{ \'tb.rulenode.period-in-seconds-pattern-required\' | translate }}\n \n \n \n \n \n tb.rulenode.max-pending-messages\n \n \n {{ \'tb.rulenode.max-pending-messages-required\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n
\n',components:[{type:D.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:G.MatLabel,selector:"mat-label"},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:G.MatError,selector:"mat-error",inputs:["id"]},{type:G.MatHint,selector:"mat-hint",inputs:["align","id"]},{type:q.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]}],pipes:{translate:E.TranslatePipe,safeHtml:Ie}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:mt,decorators:[{type:t,args:[{selector:"tb-action-node-msg-delay-config",templateUrl:"./msg-delay-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class ut extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.pubSubConfigForm}onConfigurationSet(e){this.pubSubConfigForm=this.fb.group({projectId:[e?e.projectId:null,[T.required]],topicName:[e?e.topicName:null,[T.required]],serviceAccountKey:[e?e.serviceAccountKey:null,[T.required]],serviceAccountKeyFileName:[e?e.serviceAccountKeyFileName:null,[T.required]],messageAttributes:[e?e.messageAttributes:null,[]]})}}ut.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:ut,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),ut.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:ut,selector:"tb-action-node-pub-sub-config",usesInheritance:!0,ngImport:e,template:'
\n \n tb.rulenode.gcp-project-id\n \n \n {{ \'tb.rulenode.gcp-project-id-required\' | translate }}\n \n \n \n tb.rulenode.pubsub-topic-name\n \n \n {{ \'tb.rulenode.pubsub-topic-name-required\' | translate }}\n \n \n \n \n \n
\n \n \n
\n',components:[{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:j.FileInputComponent,selector:"tb-file-input",inputs:["label","accept","noFileText","inputId","allowedExtensions","dropLabel","contentConvertFunction","required","requiredAsError","disabled","existingFileName","readAsBinary","workFromFileObj","multipleFile"],outputs:["fileNameChanged"]},{type:rt,selector:"tb-kv-map-config",inputs:["disabled","requiredText","keyText","keyRequiredText","valText","valRequiredText","required"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:G.MatLabel,selector:"mat-label"},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:G.MatError,selector:"mat-error",inputs:["id"]}],pipes:{translate:E.TranslatePipe,safeHtml:Ie}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:ut,decorators:[{type:t,args:[{selector:"tb-action-node-pub-sub-config",templateUrl:"./pubsub-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class pt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.attributeScopes=Object.keys(m),this.telemetryTypeTranslationsMap=u}configForm(){return this.pushToCloudConfigForm}onConfigurationSet(e){this.pushToCloudConfigForm=this.fb.group({scope:[e?e.scope:null,[T.required]]})}}pt.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:pt,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),pt.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:pt,selector:"tb-action-node-push-to-cloud-config",usesInheritance:!0,ngImport:e,template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n',components:[{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:H.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:U.MatOption,selector:"mat-option",exportAs:["matOption"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:G.MatLabel,selector:"mat-label"},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]}],pipes:{translate:E.TranslatePipe}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:pt,decorators:[{type:t,args:[{selector:"tb-action-node-push-to-cloud-config",templateUrl:"./push-to-cloud-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class dt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.attributeScopes=Object.keys(m),this.telemetryTypeTranslationsMap=u}configForm(){return this.pushToEdgeConfigForm}onConfigurationSet(e){this.pushToEdgeConfigForm=this.fb.group({scope:[e?e.scope:null,[T.required]]})}}dt.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:dt,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),dt.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:dt,selector:"tb-action-node-push-to-edge-config",usesInheritance:!0,ngImport:e,template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n',components:[{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:H.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:U.MatOption,selector:"mat-option",exportAs:["matOption"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:G.MatLabel,selector:"mat-label"},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]}],pipes:{translate:E.TranslatePipe}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:dt,decorators:[{type:t,args:[{selector:"tb-action-node-push-to-edge-config",templateUrl:"./push-to-edge-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class ft extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.messageProperties=[null,"BASIC","TEXT_PLAIN","MINIMAL_BASIC","MINIMAL_PERSISTENT_BASIC","PERSISTENT_BASIC","PERSISTENT_TEXT_PLAIN"]}configForm(){return this.rabbitMqConfigForm}onConfigurationSet(e){this.rabbitMqConfigForm=this.fb.group({exchangeNamePattern:[e?e.exchangeNamePattern:null,[]],routingKeyPattern:[e?e.routingKeyPattern:null,[]],messageProperties:[e?e.messageProperties:null,[]],host:[e?e.host:null,[T.required]],port:[e?e.port:null,[T.required,T.min(1),T.max(65535)]],virtualHost:[e?e.virtualHost:null,[]],username:[e?e.username:null,[]],password:[e?e.password:null,[]],automaticRecoveryEnabled:[!!e&&e.automaticRecoveryEnabled,[]],connectionTimeout:[e?e.connectionTimeout:null,[T.min(0)]],handshakeTimeout:[e?e.handshakeTimeout:null,[T.min(0)]],clientProperties:[e?e.clientProperties:null,[]]})}}ft.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:ft,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),ft.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:ft,selector:"tb-action-node-rabbit-mq-config",usesInheritance:!0,ngImport:e,template:'
\n \n tb.rulenode.exchange-name-pattern\n \n \n \n tb.rulenode.routing-key-pattern\n \n \n \n tb.rulenode.message-properties\n \n \n {{ property }}\n \n \n \n
\n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n
\n \n tb.rulenode.virtual-host\n \n \n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n \n {{ \'tb.rulenode.automatic-recovery\' | translate }}\n \n \n tb.rulenode.connection-timeout-ms\n \n \n {{ \'tb.rulenode.min-connection-timeout-ms-message\' | translate }}\n \n \n \n tb.rulenode.handshake-timeout-ms\n \n \n {{ \'tb.rulenode.min-handshake-timeout-ms-message\' | translate }}\n \n \n \n \n \n
\n',components:[{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:H.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:U.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:K.TogglePasswordComponent,selector:"tb-toggle-password"},{type:D.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:rt,selector:"tb-kv-map-config",inputs:["disabled","requiredText","keyText","keyRequiredText","valText","valRequiredText","required"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:G.MatLabel,selector:"mat-label"},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:V.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:G.MatError,selector:"mat-error",inputs:["id"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{type:G.MatSuffix,selector:"[matSuffix]"}],pipes:{translate:E.TranslatePipe}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:ft,decorators:[{type:t,args:[{selector:"tb-action-node-rabbit-mq-config",templateUrl:"./rabbit-mq-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class ct extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.proxySchemes=["http","https"],this.httpRequestTypes=Object.keys(ze)}configForm(){return this.restApiCallConfigForm}onConfigurationSet(e){this.restApiCallConfigForm=this.fb.group({restEndpointUrlPattern:[e?e.restEndpointUrlPattern:null,[T.required]],requestMethod:[e?e.requestMethod:null,[T.required]],useSimpleClientHttpFactory:[!!e&&e.useSimpleClientHttpFactory,[]],ignoreRequestBody:[!!e&&e.ignoreRequestBody,[]],enableProxy:[!!e&&e.enableProxy,[]],useSystemProxyProperties:[!!e&&e.enableProxy,[]],proxyScheme:[e?e.proxyHost:null,[]],proxyHost:[e?e.proxyHost:null,[]],proxyPort:[e?e.proxyPort:null,[]],proxyUser:[e?e.proxyUser:null,[]],proxyPassword:[e?e.proxyPassword:null,[]],readTimeoutMs:[e?e.readTimeoutMs:null,[]],maxParallelRequestsCount:[e?e.maxParallelRequestsCount:null,[T.min(0)]],headers:[e?e.headers:null,[]],useRedisQueueForMsgPersistence:[!!e&&e.useRedisQueueForMsgPersistence,[]],trimQueue:[!!e&&e.trimQueue,[]],maxQueueSize:[e?e.maxQueueSize:null,[]],credentials:[e?e.credentials:null,[]]})}validatorTriggers(){return["useSimpleClientHttpFactory","useRedisQueueForMsgPersistence","enableProxy","useSystemProxyProperties"]}updateValidators(e){const t=this.restApiCallConfigForm.get("useSimpleClientHttpFactory").value,o=this.restApiCallConfigForm.get("useRedisQueueForMsgPersistence").value,r=this.restApiCallConfigForm.get("enableProxy").value,a=this.restApiCallConfigForm.get("useSystemProxyProperties").value;r&&!a?(this.restApiCallConfigForm.get("proxyHost").setValidators(r?[T.required]:[]),this.restApiCallConfigForm.get("proxyPort").setValidators(r?[T.required,T.min(1),T.max(65535)]:[])):(this.restApiCallConfigForm.get("proxyHost").setValidators([]),this.restApiCallConfigForm.get("proxyPort").setValidators([]),t?this.restApiCallConfigForm.get("readTimeoutMs").setValidators([]):this.restApiCallConfigForm.get("readTimeoutMs").setValidators([T.min(0)])),o?this.restApiCallConfigForm.get("maxQueueSize").setValidators([T.min(0)]):this.restApiCallConfigForm.get("maxQueueSize").setValidators([]),this.restApiCallConfigForm.get("readTimeoutMs").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("maxQueueSize").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("proxyHost").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("proxyPort").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("credentials").updateValueAndValidity({emitEvent:e})}}ct.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:ct,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),ct.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:ct,selector:"tb-action-node-rest-api-call-config",usesInheritance:!0,ngImport:e,template:'
\n \n tb.rulenode.endpoint-url-pattern\n \n \n {{ \'tb.rulenode.endpoint-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.request-method\n \n \n {{ requestType }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n \n {{ \'tb.rulenode.use-simple-client-http-factory\' | translate }}\n \n \n {{ \'tb.rulenode.ignore-request-body\' | translate }}\n \n
\n \n {{ \'tb.rulenode.use-system-proxy-properties\' | translate }}\n \n
\n
\n \n tb.rulenode.proxy-scheme\n \n \n {{ proxyScheme }}\n \n \n \n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
\n
\n \n tb.rulenode.read-timeout\n \n tb.rulenode.read-timeout-hint\n \n \n tb.rulenode.max-parallel-requests-count\n \n tb.rulenode.max-parallel-requests-count-hint\n \n \n
\n \n \n \n {{ \'tb.rulenode.use-redis-queue\' | translate }}\n \n
\n \n {{ \'tb.rulenode.trim-redis-queue\' | translate }}\n \n \n tb.rulenode.redis-queue-max-size\n \n \n
\n \n
\n',components:[{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:H.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:U.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:D.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:rt,selector:"tb-kv-map-config",inputs:["disabled","requiredText","keyText","keyRequiredText","valText","valRequiredText","required"]},{type:lt,selector:"tb-credentials-config",inputs:["required","disableCertPemCredentials","passwordFieldRquired"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:G.MatLabel,selector:"mat-label"},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:G.MatError,selector:"mat-error",inputs:["id"]},{type:G.MatHint,selector:"mat-hint",inputs:["align","id"]},{type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:V.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]}],pipes:{translate:E.TranslatePipe,safeHtml:Ie}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:ct,decorators:[{type:t,args:[{selector:"tb-action-node-rest-api-call-config",templateUrl:"./rest-api-call-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class gt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.rpcReplyConfigForm}onConfigurationSet(e){this.rpcReplyConfigForm=this.fb.group({requestIdMetaDataAttribute:[e?e.requestIdMetaDataAttribute:null,[]]})}}gt.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:gt,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),gt.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:gt,selector:"tb-action-node-rpc-reply-config",usesInheritance:!0,ngImport:e,template:'
\n \n tb.rulenode.request-id-metadata-attribute\n \n \n
\n',components:[{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:G.MatLabel,selector:"mat-label"},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]}]}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:gt,decorators:[{type:t,args:[{selector:"tb-action-node-rpc-reply-config",templateUrl:"./rpc-reply-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class xt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.rpcRequestConfigForm}onConfigurationSet(e){this.rpcRequestConfigForm=this.fb.group({timeoutInSeconds:[e?e.timeoutInSeconds:null,[T.required,T.min(0)]]})}}xt.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:xt,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),xt.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:xt,selector:"tb-action-node-rpc-request-config",usesInheritance:!0,ngImport:e,template:'
\n \n tb.rulenode.timeout-sec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-message\' | translate }}\n \n \n
\n',components:[{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:G.MatLabel,selector:"mat-label"},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:G.MatError,selector:"mat-error",inputs:["id"]}],pipes:{translate:E.TranslatePipe}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:xt,decorators:[{type:t,args:[{selector:"tb-action-node-rpc-request-config",templateUrl:"./rpc-request-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class yt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.saveToCustomTableConfigForm}onConfigurationSet(e){this.saveToCustomTableConfigForm=this.fb.group({tableName:[e?e.tableName:null,[T.required,T.pattern(/.*\S.*/)]],fieldsMapping:[e?e.fieldsMapping:null,[T.required]]})}prepareOutputConfig(e){return e.tableName=e.tableName.trim(),e}}yt.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:yt,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),yt.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:yt,selector:"tb-action-node-custom-table-config",usesInheritance:!0,ngImport:e,template:'
\n \n tb.rulenode.custom-table-name\n \n \n {{ \'tb.rulenode.custom-table-name-required\' | translate }}\n \n tb.rulenode.custom-table-hint\n \n \n \n \n
\n',components:[{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:rt,selector:"tb-kv-map-config",inputs:["disabled","requiredText","keyText","keyRequiredText","valText","valRequiredText","required"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:G.MatLabel,selector:"mat-label"},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:G.MatError,selector:"mat-error",inputs:["id"]},{type:G.MatHint,selector:"mat-hint",inputs:["align","id"]}],pipes:{translate:E.TranslatePipe}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:yt,decorators:[{type:t,args:[{selector:"tb-action-node-custom-table-config",templateUrl:"./save-to-custom-table-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class bt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.smtpProtocols=["smtp","smtps"],this.tlsVersions=["TLSv1","TLSv1.1","TLSv1.2","TLSv1.3"]}configForm(){return this.sendEmailConfigForm}onConfigurationSet(e){this.sendEmailConfigForm=this.fb.group({useSystemSmtpSettings:[!!e&&e.useSystemSmtpSettings,[]],smtpProtocol:[e?e.smtpProtocol:null,[]],smtpHost:[e?e.smtpHost:null,[]],smtpPort:[e?e.smtpPort:null,[]],timeout:[e?e.timeout:null,[]],enableTls:[!!e&&e.enableTls,[]],tlsVersion:[e?e.tlsVersion:null,[]],enableProxy:[!!e&&e.enableProxy,[]],proxyHost:[e?e.proxyHost:null,[]],proxyPort:[e?e.proxyPort:null,[]],proxyUser:[e?e.proxyUser:null,[]],proxyPassword:[e?e.proxyPassword:null,[]],username:[e?e.username:null,[]],password:[e?e.password:null,[]]})}validatorTriggers(){return["useSystemSmtpSettings","enableProxy"]}updateValidators(e){const t=this.sendEmailConfigForm.get("useSystemSmtpSettings").value,o=this.sendEmailConfigForm.get("enableProxy").value;t?(this.sendEmailConfigForm.get("smtpProtocol").setValidators([]),this.sendEmailConfigForm.get("smtpHost").setValidators([]),this.sendEmailConfigForm.get("smtpPort").setValidators([]),this.sendEmailConfigForm.get("timeout").setValidators([]),this.sendEmailConfigForm.get("proxyHost").setValidators([]),this.sendEmailConfigForm.get("proxyPort").setValidators([])):(this.sendEmailConfigForm.get("smtpProtocol").setValidators([T.required]),this.sendEmailConfigForm.get("smtpHost").setValidators([T.required]),this.sendEmailConfigForm.get("smtpPort").setValidators([T.required,T.min(1),T.max(65535)]),this.sendEmailConfigForm.get("timeout").setValidators([T.required,T.min(0)]),this.sendEmailConfigForm.get("proxyHost").setValidators(o?[T.required]:[]),this.sendEmailConfigForm.get("proxyPort").setValidators(o?[T.required,T.min(1),T.max(65535)]:[])),this.sendEmailConfigForm.get("smtpProtocol").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("smtpHost").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("smtpPort").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("timeout").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("proxyHost").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("proxyPort").updateValueAndValidity({emitEvent:e})}}bt.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:bt,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),bt.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:bt,selector:"tb-action-node-send-email-config",usesInheritance:!0,ngImport:e,template:'
\n \n {{ \'tb.rulenode.use-system-smtp-settings\' | translate }}\n \n
\n \n tb.rulenode.smtp-protocol\n \n \n {{ smtpProtocol.toUpperCase() }}\n \n \n \n
\n \n tb.rulenode.smtp-host\n \n \n {{ \'tb.rulenode.smtp-host-required\' | translate }}\n \n \n \n tb.rulenode.smtp-port\n \n \n {{ \'tb.rulenode.smtp-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.timeout-msec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-msec-message\' | translate }}\n \n \n \n {{ \'tb.rulenode.enable-tls\' | translate }}\n \n \n tb.rulenode.tls-version\n \n \n {{ tlsVersion }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n
\n
\n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
\n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n
\n
\n',components:[{type:D.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:H.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:U.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:de.TbCheckboxComponent,selector:"tb-checkbox",inputs:["disabled","trueValue","falseValue"],outputs:["valueChange"]},{type:K.TogglePasswordComponent,selector:"tb-toggle-password"}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:G.MatLabel,selector:"mat-label"},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:V.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:G.MatError,selector:"mat-error",inputs:["id"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{type:G.MatSuffix,selector:"[matSuffix]"}],pipes:{translate:E.TranslatePipe}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:bt,decorators:[{type:t,args:[{selector:"tb-action-node-send-email-config",templateUrl:"./send-email-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class ht extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.sendSmsConfigForm}onConfigurationSet(e){this.sendSmsConfigForm=this.fb.group({numbersToTemplate:[e?e.numbersToTemplate:null,[T.required]],smsMessageTemplate:[e?e.smsMessageTemplate:null,[T.required]],useSystemSmsSettings:[!!e&&e.useSystemSmsSettings,[]],smsProviderConfiguration:[e?e.smsProviderConfiguration:null,[]]})}validatorTriggers(){return["useSystemSmsSettings"]}updateValidators(e){this.sendSmsConfigForm.get("useSystemSmsSettings").value?this.sendSmsConfigForm.get("smsProviderConfiguration").setValidators([]):this.sendSmsConfigForm.get("smsProviderConfiguration").setValidators([T.required]),this.sendSmsConfigForm.get("smsProviderConfiguration").updateValueAndValidity({emitEvent:e})}}ht.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:ht,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),ht.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:ht,selector:"tb-action-node-send-sms-config",usesInheritance:!0,ngImport:e,template:'
\n \n tb.rulenode.numbers-to-template\n \n \n {{ \'tb.rulenode.numbers-to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.sms-message-template\n \n \n {{ \'tb.rulenode.sms-message-template-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-system-sms-settings\' | translate }}\n \n \n \n
\n',components:[{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:D.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:fe.SmsProviderConfigurationComponent,selector:"tb-sms-provider-configuration",inputs:["required","disabled"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:G.MatLabel,selector:"mat-label"},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:G.MatError,selector:"mat-error",inputs:["id"]},{type:G.MatHint,selector:"mat-hint",inputs:["align","id"]}],pipes:{translate:E.TranslatePipe,safeHtml:Ie}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:ht,decorators:[{type:t,args:[{selector:"tb-action-node-send-sms-config",templateUrl:"./send-sms-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class Ft extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.snsConfigForm}onConfigurationSet(e){this.snsConfigForm=this.fb.group({topicArnPattern:[e?e.topicArnPattern:null,[T.required]],accessKeyId:[e?e.accessKeyId:null,[T.required]],secretAccessKey:[e?e.secretAccessKey:null,[T.required]],region:[e?e.region:null,[T.required]]})}}Ft.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Ft,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),Ft.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Ft,selector:"tb-action-node-sns-config",usesInheritance:!0,ngImport:e,template:'
\n \n tb.rulenode.topic-arn-pattern\n \n \n {{ \'tb.rulenode.topic-arn-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
\n',components:[{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:G.MatLabel,selector:"mat-label"},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:G.MatError,selector:"mat-error",inputs:["id"]},{type:G.MatHint,selector:"mat-hint",inputs:["align","id"]}],pipes:{translate:E.TranslatePipe,safeHtml:Ie}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Ft,decorators:[{type:t,args:[{selector:"tb-action-node-sns-config",templateUrl:"./sns-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class Ct extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.sqsQueueType=Oe,this.sqsQueueTypes=Object.keys(Oe),this.sqsQueueTypeTranslationsMap=He}configForm(){return this.sqsConfigForm}onConfigurationSet(e){this.sqsConfigForm=this.fb.group({queueType:[e?e.queueType:null,[T.required]],queueUrlPattern:[e?e.queueUrlPattern:null,[T.required]],delaySeconds:[e?e.delaySeconds:null,[T.min(0),T.max(900)]],messageAttributes:[e?e.messageAttributes:null,[]],accessKeyId:[e?e.accessKeyId:null,[T.required]],secretAccessKey:[e?e.secretAccessKey:null,[T.required]],region:[e?e.region:null,[T.required]]})}}Ct.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Ct,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),Ct.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Ct,selector:"tb-action-node-sqs-config",usesInheritance:!0,ngImport:e,template:'
\n \n tb.rulenode.queue-type\n \n \n {{ sqsQueueTypeTranslationsMap.get(type) | translate }}\n \n \n \n \n tb.rulenode.queue-url-pattern\n \n \n {{ \'tb.rulenode.queue-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.delay-seconds\n \n \n {{ \'tb.rulenode.min-delay-seconds-message\' | translate }}\n \n \n {{ \'tb.rulenode.max-delay-seconds-message\' | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
\n',components:[{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:H.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:U.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:rt,selector:"tb-kv-map-config",inputs:["disabled","requiredText","keyText","keyRequiredText","valText","valRequiredText","required"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:G.MatLabel,selector:"mat-label"},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:G.MatError,selector:"mat-error",inputs:["id"]},{type:G.MatHint,selector:"mat-hint",inputs:["align","id"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"}],pipes:{translate:E.TranslatePipe,safeHtml:Ie}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Ct,decorators:[{type:t,args:[{selector:"tb-action-node-sqs-config",templateUrl:"./sqs-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class Lt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.timeseriesConfigForm}onConfigurationSet(e){this.timeseriesConfigForm=this.fb.group({defaultTTL:[e?e.defaultTTL:null,[T.required,T.min(0)]],skipLatestPersistence:[!!e&&e.skipLatestPersistence,[]]})}}Lt.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Lt,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),Lt.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Lt,selector:"tb-action-node-timeseries-config",usesInheritance:!0,ngImport:e,template:'
\n \n tb.rulenode.default-ttl\n \n \n {{ \'tb.rulenode.default-ttl-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-default-ttl-message\' | translate }}\n \n \n \n {{ \'tb.rulenode.skip-latest-persistence\' | translate }}\n \n
\n',components:[{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:D.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:G.MatLabel,selector:"mat-label"},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:G.MatError,selector:"mat-error",inputs:["id"]}],pipes:{translate:E.TranslatePipe}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Lt,decorators:[{type:t,args:[{selector:"tb-action-node-timeseries-config",templateUrl:"./timeseries-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class vt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.unassignCustomerConfigForm}onConfigurationSet(e){this.unassignCustomerConfigForm=this.fb.group({customerNamePattern:[e?e.customerNamePattern:null,[T.required,T.pattern(/.*\S.*/)]],customerCacheExpiration:[e?e.customerCacheExpiration:null,[T.required,T.min(0)]]})}prepareOutputConfig(e){return e.customerNamePattern=e.customerNamePattern.trim(),e}}vt.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:vt,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),vt.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:vt,selector:"tb-action-node-un-assign-to-customer-config",usesInheritance:!0,ngImport:e,template:'
\n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n tb.rulenode.customer-cache-expiration-hint\n \n
\n',components:[{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:G.MatLabel,selector:"mat-label"},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:G.MatError,selector:"mat-error",inputs:["id"]},{type:G.MatHint,selector:"mat-hint",inputs:["align","id"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"}],pipes:{translate:E.TranslatePipe,safeHtml:Ie}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:vt,decorators:[{type:t,args:[{selector:"tb-action-node-un-assign-to-customer-config",templateUrl:"./unassign-customer-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class It extends y{constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.keys(c),this.directionTypeTranslations=g,this.entityType=x,this.propagateChange=null}get required(){return this.requiredValue}set required(e){this.requiredValue=re(e)}ngOnInit(){this.deviceRelationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[T.required]],maxLevel:[null,[]],relationType:[null],deviceTypes:[null,[T.required]]}),this.deviceRelationsQueryFormGroup.valueChanges.subscribe((e=>{this.deviceRelationsQueryFormGroup.valid?this.propagateChange(e):this.propagateChange(null)}))}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.deviceRelationsQueryFormGroup.disable({emitEvent:!1}):this.deviceRelationsQueryFormGroup.enable({emitEvent:!1})}writeValue(e){this.deviceRelationsQueryFormGroup.reset(e,{emitEvent:!1})}}It.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:It,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),It.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:It,selector:"tb-device-relations-query-config",inputs:{disabled:"disabled",required:"required"},providers:[{provide:M,useExisting:a((()=>It)),multi:!0}],usesInheritance:!0,ngImport:e,template:'
\n \n {{ \'alias.last-level-relation\' | translate }}\n \n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n
\n
relation.relation-type
\n \n \n
device.device-types
\n \n \n
\n',components:[{type:D.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:H.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:U.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:ge.RelationTypeAutocompleteComponent,selector:"tb-relation-type-autocomplete",inputs:["required","disabled"]},{type:xe.EntitySubTypeListComponent,selector:"tb-entity-subtype-list",inputs:["required","disabled","entityType"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:V.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{type:G.MatLabel,selector:"mat-label"},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"}],pipes:{translate:E.TranslatePipe}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:It,decorators:[{type:t,args:[{selector:"tb-device-relations-query-config",templateUrl:"./device-relations-query-config.component.html",styleUrls:[],providers:[{provide:M,useExisting:a((()=>It)),multi:!0}]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]},propDecorators:{disabled:[{type:n}],required:[{type:n}]}});class Nt extends y{constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.keys(c),this.directionTypeTranslations=g,this.propagateChange=null}get required(){return this.requiredValue}set required(e){this.requiredValue=re(e)}ngOnInit(){this.relationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[T.required]],maxLevel:[null,[]],filters:[null]}),this.relationsQueryFormGroup.valueChanges.subscribe((e=>{this.relationsQueryFormGroup.valid?this.propagateChange(e):this.propagateChange(null)}))}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.relationsQueryFormGroup.disable({emitEvent:!1}):this.relationsQueryFormGroup.enable({emitEvent:!1})}writeValue(e){this.relationsQueryFormGroup.reset(e||{},{emitEvent:!1})}}Nt.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Nt,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),Nt.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Nt,selector:"tb-relations-query-config",inputs:{disabled:"disabled",required:"required"},providers:[{provide:M,useExisting:a((()=>Nt)),multi:!0}],usesInheritance:!0,ngImport:e,template:'
\n \n {{ \'alias.last-level-relation\' | translate }}\n \n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n
\n
relation.relation-filters
\n \n
\n',components:[{type:D.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:H.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:U.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:ye.RelationFiltersComponent,selector:"tb-relation-filters",inputs:["disabled","allowedEntityTypes"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:V.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{type:G.MatLabel,selector:"mat-label"},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"}],pipes:{translate:E.TranslatePipe}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Nt,decorators:[{type:t,args:[{selector:"tb-relations-query-config",templateUrl:"./relations-query-config.component.html",styleUrls:[],providers:[{provide:M,useExisting:a((()=>Nt)),multi:!0}]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]},propDecorators:{disabled:[{type:n}],required:[{type:n}]}});class qt extends y{constructor(e,t,o,r){super(e),this.store=e,this.translate=t,this.truncate=o,this.fb=r,this.placeholder="tb.rulenode.message-type",this.separatorKeysCodes=[Y,J,Z],this.messageTypes=[],this.messageTypesList=[],this.searchText="",this.propagateChange=e=>{},this.messageTypeConfigForm=this.fb.group({messageType:[null]});for(const e of Object.keys(b))this.messageTypesList.push({name:h.get(b[e]),value:e})}get required(){return this.requiredValue}set required(e){this.requiredValue=re(e)}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}ngOnInit(){this.filteredMessageTypes=this.messageTypeConfigForm.get("messageType").valueChanges.pipe(se(""),me((e=>e||"")),ue((e=>this.fetchMessageTypes(e))),pe())}ngAfterViewInit(){}setDisabledState(e){this.disabled=e,this.disabled?this.messageTypeConfigForm.disable({emitEvent:!1}):this.messageTypeConfigForm.enable({emitEvent:!1})}writeValue(e){this.searchText="",this.messageTypes.length=0,e&&e.forEach((e=>{const t=this.messageTypesList.find((t=>t.value===e));t?this.messageTypes.push({name:t.name,value:t.value}):this.messageTypes.push({name:e,value:e})}))}displayMessageTypeFn(e){return e?e.name:void 0}textIsNotEmpty(e){return!!(e&&null!=e&&e.length>0)}createMessageType(e,t){e.preventDefault(),this.transformMessageType(t)}add(e){this.transformMessageType(e.value)}fetchMessageTypes(e){if(this.searchText=e,this.searchText&&this.searchText.length){const e=this.searchText.toUpperCase();return be(this.messageTypesList.filter((t=>t.name.toUpperCase().includes(e))))}return be(this.messageTypesList)}transformMessageType(e){if((e||"").trim()){let t=null;const o=e.trim(),r=this.messageTypesList.find((e=>e.name===o));t=r?{name:r.name,value:r.value}:{name:o,value:o},t&&this.addMessageType(t)}this.clear("")}remove(e){const t=this.messageTypes.indexOf(e);t>=0&&(this.messageTypes.splice(t,1),this.updateModel())}selected(e){this.addMessageType(e.option.value),this.clear("")}addMessageType(e){-1===this.messageTypes.findIndex((t=>t.value===e.value))&&(this.messageTypes.push(e),this.updateModel())}onFocus(){this.messageTypeConfigForm.get("messageType").updateValueAndValidity({onlySelf:!0,emitEvent:!0})}clear(e=""){this.messageTypeInput.nativeElement.value=e,this.messageTypeConfigForm.get("messageType").patchValue(null,{emitEvent:!0}),setTimeout((()=>{this.messageTypeInput.nativeElement.blur(),this.messageTypeInput.nativeElement.focus()}),0)}updateModel(){const e=this.messageTypes.map((e=>e.value));this.required?(this.chipList.errorState=!e.length,this.propagateChange(e.length>0?e:null)):(this.chipList.errorState=!1,this.propagateChange(e))}}qt.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:qt,deps:[{token:N.Store},{token:E.TranslateService},{token:i.TruncatePipe},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),qt.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:qt,selector:"tb-message-types-config",inputs:{required:"required",label:"label",placeholder:"placeholder",disabled:"disabled"},providers:[{provide:M,useExisting:a((()=>qt)),multi:!0}],viewQueries:[{propertyName:"chipList",first:!0,predicate:["chipList"],descendants:!0},{propertyName:"matAutocomplete",first:!0,predicate:["messageTypeAutocomplete"],descendants:!0},{propertyName:"messageTypeInput",first:!0,predicate:["messageTypeInput"],descendants:!0}],usesInheritance:!0,ngImport:e,template:'\n {{ label }}\n \n \n {{messageType.name}}\n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-message-types-found\n
\n \n \n {{ translate.get(\'tb.rulenode.no-message-type-matching\',\n {messageType: truncate.transform(searchText, true, 6, '...')}) | async }}\n \n \n \n tb.rulenode.create-new-message-type\n \n
\n
\n
\n \n {{ \'tb.rulenode.message-types-required\' | translate }}\n \n
\n',components:[{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:X.MatChipList,selector:"mat-chip-list",inputs:["aria-orientation","multiple","compareWith","value","required","placeholder","disabled","selectable","tabIndex","errorStateMatcher"],outputs:["change","valueChange"],exportAs:["matChipList"]},{type:ee.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{type:he.MatAutocomplete,selector:"mat-autocomplete",inputs:["disableRipple"],exportAs:["matAutocomplete"]},{type:U.MatOption,selector:"mat-option",exportAs:["matOption"]}],directives:[{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:G.MatLabel,selector:"mat-label"},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:X.MatChip,selector:"mat-basic-chip, [mat-basic-chip], mat-chip, [mat-chip]",inputs:["color","disableRipple","tabIndex","selected","value","selectable","disabled","removable"],outputs:["selectionChange","destroyed","removed"],exportAs:["matChip"]},{type:X.MatChipRemove,selector:"[matChipRemove]"},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:he.MatAutocompleteTrigger,selector:"input[matAutocomplete], textarea[matAutocomplete]",exportAs:["matAutocompleteTrigger"]},{type:X.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputSeparatorKeyCodes","placeholder","id","matChipInputFor","matChipInputAddOnBlur","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:he.MatAutocompleteOrigin,selector:"[matAutocompleteOrigin]",exportAs:["matAutocompleteOrigin"]},{type:G.MatError,selector:"mat-error",inputs:["id"]}],pipes:{translate:E.TranslatePipe,async:R.AsyncPipe,highlight:Fe.HighlightPipe}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:qt,decorators:[{type:t,args:[{selector:"tb-message-types-config",templateUrl:"./message-types-config.component.html",styleUrls:[],providers:[{provide:M,useExisting:a((()=>qt)),multi:!0}]}]}],ctorParameters:function(){return[{type:N.Store},{type:E.TranslateService},{type:i.TruncatePipe},{type:q.FormBuilder}]},propDecorators:{required:[{type:n}],label:[{type:n}],placeholder:[{type:n}],disabled:[{type:n}],chipList:[{type:r,args:["chipList",{static:!1}]}],matAutocomplete:[{type:r,args:["messageTypeAutocomplete",{static:!1}]}],messageTypeInput:[{type:r,args:["messageTypeInput",{static:!1}]}]}});class Tt{}Tt.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Tt,deps:[],target:e.ɵɵFactoryTarget.NgModule}),Tt.ɵmod=e.ɵɵngDeclareNgModule({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Tt,declarations:[rt,It,Nt,qt,lt,Ie],imports:[w,F,ce],exports:[rt,It,Nt,qt,lt,Ie]}),Tt.ɵinj=e.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Tt,imports:[[w,F,ce]]}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Tt,decorators:[{type:l,args:[{declarations:[rt,It,Nt,qt,lt,Ie],imports:[w,F,ce],exports:[rt,It,Nt,qt,lt,Ie]}]}]});class kt{}kt.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:kt,deps:[],target:e.ɵɵFactoryTarget.NgModule}),kt.ɵmod=e.ɵɵngDeclareNgModule({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:kt,declarations:[qe,Lt,xt,nt,Ne,Ye,Je,Ze,mt,Xe,tt,ot,st,gt,yt,vt,Ft,Ct,ut,at,it,ft,ct,bt,We,$e,et,ht,dt,pt],imports:[w,F,ce,Tt],exports:[qe,Lt,xt,nt,Ne,Ye,Je,Ze,mt,Xe,tt,ot,st,gt,yt,vt,Ft,Ct,ut,at,it,ft,ct,bt,We,$e,et,ht,dt,pt]}),kt.ɵinj=e.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:kt,imports:[[w,F,ce,Tt]]}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:kt,decorators:[{type:l,args:[{declarations:[qe,Lt,xt,nt,Ne,Ye,Je,Ze,mt,Xe,tt,ot,st,gt,yt,vt,Ft,Ct,ut,at,it,ft,ct,bt,We,$e,et,ht,dt,pt],imports:[w,F,ce,Tt],exports:[qe,Lt,xt,nt,Ne,Ye,Je,Ze,mt,Xe,tt,ot,st,gt,yt,vt,Ft,Ct,ut,at,it,ft,ct,bt,We,$e,et,ht,dt,pt]}]}]});class Mt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.separatorKeysCodes=[Y,J,Z]}configForm(){return this.calculateDeltaConfigForm}onConfigurationSet(e){this.calculateDeltaConfigForm=this.fb.group({inputValueKey:[e?e.inputValueKey:null,[T.required]],outputValueKey:[e?e.outputValueKey:null,[T.required]],useCache:[e?e.useCache:null,[]],addPeriodBetweenMsgs:[!!e&&e.addPeriodBetweenMsgs,[]],periodValueKey:[e?e.periodValueKey:null,[]],round:[e?e.round:null,[T.min(0),T.max(15)]],tellFailureIfDeltaIsNegative:[e?e.tellFailureIfDeltaIsNegative:null,[]]})}updateValidators(e){this.calculateDeltaConfigForm.get("addPeriodBetweenMsgs").value?this.calculateDeltaConfigForm.get("periodValueKey").setValidators([T.required]):this.calculateDeltaConfigForm.get("periodValueKey").setValidators([]),this.calculateDeltaConfigForm.get("periodValueKey").updateValueAndValidity({emitEvent:e})}validatorTriggers(){return["addPeriodBetweenMsgs"]}}Mt.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Mt,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),Mt.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Mt,selector:"tb-enrichment-node-calculate-delta-config",usesInheritance:!0,ngImport:e,template:'
\n
\n \n tb.rulenode.input-value-key\n \n \n {{ \'tb.rulenode.input-value-key-required\' | translate }}\n \n \n \n tb.rulenode.output-value-key\n \n \n {{ \'tb.rulenode.output-value-key-required\' | translate }}\n \n \n \n tb.rulenode.round\n \n \n {{ \'tb.rulenode.round-range\' | translate }}\n \n \n {{ \'tb.rulenode.round-range\' | translate }}\n \n \n
\n \n {{ \'tb.rulenode.use-cache\' | translate }}\n \n \n {{ \'tb.rulenode.tell-failure-if-delta-is-negative\' | translate }}\n \n \n {{ \'tb.rulenode.add-period-between-msgs\' | translate }}\n \n \n tb.rulenode.period-value-key\n \n \n {{ \'tb.rulenode.period-value-key-required\' | translate }}\n \n \n
\n',components:[{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:D.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:V.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:G.MatLabel,selector:"mat-label"},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:G.MatError,selector:"mat-error",inputs:["id"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"}],pipes:{translate:E.TranslatePipe}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Mt,decorators:[{type:t,args:[{selector:"tb-enrichment-node-calculate-delta-config",templateUrl:"./calculate-delta-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class St extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.customerAttributesConfigForm}onConfigurationSet(e){this.customerAttributesConfigForm=this.fb.group({telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[T.required]]})}}St.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:St,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),St.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:St,selector:"tb-enrichment-node-customer-attributes-config",usesInheritance:!0,ngImport:e,template:'
\n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
\n',components:[{type:D.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:rt,selector:"tb-kv-map-config",inputs:["disabled","requiredText","keyText","keyRequiredText","valText","valRequiredText","required"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]}],pipes:{translate:E.TranslatePipe}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:St,decorators:[{type:t,args:[{selector:"tb-enrichment-node-customer-attributes-config",templateUrl:"./customer-attributes-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class At extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.separatorKeysCodes=[Y,J,Z]}configForm(){return this.deviceAttributesConfigForm}onConfigurationSet(e){this.deviceAttributesConfigForm=this.fb.group({deviceRelationsQuery:[e?e.deviceRelationsQuery:null,[T.required]],tellFailureIfAbsent:[!!e&&e.tellFailureIfAbsent,[]],clientAttributeNames:[e?e.clientAttributeNames:null,[]],sharedAttributeNames:[e?e.sharedAttributeNames:null,[]],serverAttributeNames:[e?e.serverAttributeNames:null,[]],latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],getLatestValueWithTs:[!!e&&e.getLatestValueWithTs,[]]})}removeKey(e,t){const o=this.deviceAttributesConfigForm.get(t).value,r=o.indexOf(e);r>=0&&(o.splice(r,1),this.deviceAttributesConfigForm.get(t).setValue(o,{emitEvent:!0}))}addKey(e,t){const o=e.input;let r=e.value;if((r||"").trim()){r=r.trim();let e=this.deviceAttributesConfigForm.get(t).value;e&&-1!==e.indexOf(r)||(e||(e=[]),e.push(r),this.deviceAttributesConfigForm.get(t).setValue(e,{emitEvent:!0}))}o&&(o.value="")}}At.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:At,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),At.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:At,selector:"tb-enrichment-node-device-attributes-config",usesInheritance:!0,ngImport:e,template:'
\n \n \n \n \n {{ \'tb.rulenode.tell-failure-if-absent\' | translate }}\n \n
tb.rulenode.tell-failure-if-absent-hint
\n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n {{ \'tb.rulenode.get-latest-value-with-ts\' | translate }}\n \n
\n
\n',styles:[":host label.tb-title{margin-bottom:-10px}\n"],components:[{type:It,selector:"tb-device-relations-query-config",inputs:["disabled","required"]},{type:D.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:X.MatChipList,selector:"mat-chip-list",inputs:["aria-orientation","multiple","compareWith","value","required","placeholder","disabled","selectable","tabIndex","errorStateMatcher"],outputs:["change","valueChange"],exportAs:["matChipList"]},{type:ee.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:G.MatLabel,selector:"mat-label"},{type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:X.MatChip,selector:"mat-basic-chip, [mat-basic-chip], mat-chip, [mat-chip]",inputs:["color","disableRipple","tabIndex","selected","value","selectable","disabled","removable"],outputs:["selectionChange","destroyed","removed"],exportAs:["matChip"]},{type:X.MatChipRemove,selector:"[matChipRemove]"},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:X.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputSeparatorKeyCodes","placeholder","id","matChipInputFor","matChipInputAddOnBlur","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]}],pipes:{translate:E.TranslatePipe,safeHtml:Ie}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:At,decorators:[{type:t,args:[{selector:"tb-enrichment-node-device-attributes-config",templateUrl:"./device-attributes-config.component.html",styleUrls:["./device-attributes-config.component.scss"]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class Gt extends s{constructor(e,t,o){super(e),this.store=e,this.translate=t,this.fb=o,this.entityDetailsTranslationsMap=Pe,this.entityDetailsList=[],this.searchText="",this.displayDetailsFn=this.displayDetails.bind(this);for(const e of Object.keys(Ee))this.entityDetailsList.push(Ee[e]);this.detailsFormControl=new A(""),this.filteredEntityDetails=this.detailsFormControl.valueChanges.pipe(se(""),me((e=>e||"")),ue((e=>this.fetchEntityDetails(e))),pe())}ngOnInit(){super.ngOnInit()}configForm(){return this.entityDetailsConfigForm}prepareInputConfig(e){return this.searchText="",this.detailsFormControl.patchValue("",{emitEvent:!0}),e}onConfigurationSet(e){this.entityDetailsConfigForm=this.fb.group({detailsList:[e?e.detailsList:null,[T.required]],addToMetadata:[!!e&&e.addToMetadata,[]]})}displayDetails(e){return e?this.translate.instant(Pe.get(e)):void 0}fetchEntityDetails(e){if(this.searchText=e,this.searchText&&this.searchText.length){const e=this.searchText.toUpperCase();return be(this.entityDetailsList.filter((t=>this.translate.instant(Pe.get(Ee[t])).toUpperCase().includes(e))))}return be(this.entityDetailsList)}detailsFieldSelected(e){this.addDetailsField(e.option.value),this.clear("")}removeDetailsField(e){const t=this.entityDetailsConfigForm.get("detailsList").value;if(t){const o=t.indexOf(e);o>=0&&(t.splice(o,1),this.entityDetailsConfigForm.get("detailsList").setValue(t))}}addDetailsField(e){let t=this.entityDetailsConfigForm.get("detailsList").value;t||(t=[]);-1===t.indexOf(e)&&(t.push(e),this.entityDetailsConfigForm.get("detailsList").setValue(t))}onEntityDetailsInputFocus(){this.detailsFormControl.updateValueAndValidity({onlySelf:!0,emitEvent:!0})}clear(e=""){this.detailsInput.nativeElement.value=e,this.detailsFormControl.patchValue(null,{emitEvent:!0}),setTimeout((()=>{this.detailsInput.nativeElement.blur(),this.detailsInput.nativeElement.focus()}),0)}}Gt.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Gt,deps:[{token:N.Store},{token:E.TranslateService},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),Gt.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Gt,selector:"tb-enrichment-node-entity-details-config",viewQueries:[{propertyName:"detailsInput",first:!0,predicate:["detailsInput"],descendants:!0}],usesInheritance:!0,ngImport:e,template:'
\n \n tb.rulenode.entity-details\n \n \n \n {{entityDetailsTranslationsMap.get(details) | translate}}\n \n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-entity-details-matching\n
\n
\n
\n
\n
\n \n \n {{ \'tb.rulenode.add-to-metadata\' | translate }}\n \n
tb.rulenode.add-to-metadata-hint
\n
\n',styles:[":host ::ng-deep mat-form-field.entity-fields-list .mat-form-field-wrapper{margin-bottom:-1.25em}\n"],components:[{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:X.MatChipList,selector:"mat-chip-list",inputs:["aria-orientation","multiple","compareWith","value","required","placeholder","disabled","selectable","tabIndex","errorStateMatcher"],outputs:["change","valueChange"],exportAs:["matChipList"]},{type:ee.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{type:he.MatAutocomplete,selector:"mat-autocomplete",inputs:["disableRipple"],exportAs:["matAutocomplete"]},{type:U.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:ae.TbErrorComponent,selector:"tb-error",inputs:["error"]},{type:D.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:G.MatLabel,selector:"mat-label"},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:X.MatChip,selector:"mat-basic-chip, [mat-basic-chip], mat-chip, [mat-chip]",inputs:["color","disableRipple","tabIndex","selected","value","selectable","disabled","removable"],outputs:["selectionChange","destroyed","removed"],exportAs:["matChip"]},{type:X.MatChipRemove,selector:"[matChipRemove]"},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:he.MatAutocompleteTrigger,selector:"input[matAutocomplete], textarea[matAutocomplete]",exportAs:["matAutocompleteTrigger"]},{type:X.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputSeparatorKeyCodes","placeholder","id","matChipInputFor","matChipInputAddOnBlur","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{type:he.MatAutocompleteOrigin,selector:"[matAutocompleteOrigin]",exportAs:["matAutocompleteOrigin"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlDirective,selector:"[formControl]",inputs:["disabled","formControl","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]}],pipes:{translate:E.TranslatePipe,async:R.AsyncPipe,highlight:Fe.HighlightPipe}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Gt,decorators:[{type:t,args:[{selector:"tb-enrichment-node-entity-details-config",templateUrl:"./entity-details-config.component.html",styleUrls:["./entity-details-config.component.scss"]}]}],ctorParameters:function(){return[{type:N.Store},{type:E.TranslateService},{type:q.FormBuilder}]},propDecorators:{detailsInput:[{type:r,args:["detailsInput",{static:!1}]}]}});class Dt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.separatorKeysCodes=[Y,J,Z],this.aggregationTypes=C,this.aggregations=Object.keys(C),this.aggregationTypesTranslations=L,this.fetchMode=Re,this.fetchModes=Object.keys(Re),this.samplingOrders=Object.keys(we),this.timeUnits=Object.values(Ae),this.timeUnitsTranslationMap=Ge}configForm(){return this.getTelemetryFromDatabaseConfigForm}onConfigurationSet(e){this.getTelemetryFromDatabaseConfigForm=this.fb.group({latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],aggregation:[e?e.aggregation:null,[T.required]],fetchMode:[e?e.fetchMode:null,[T.required]],orderBy:[e?e.orderBy:null,[]],limit:[e?e.limit:null,[]],useMetadataIntervalPatterns:[!!e&&e.useMetadataIntervalPatterns,[]],startInterval:[e?e.startInterval:null,[]],startIntervalTimeUnit:[e?e.startIntervalTimeUnit:null,[]],endInterval:[e?e.endInterval:null,[]],endIntervalTimeUnit:[e?e.endIntervalTimeUnit:null,[]],startIntervalPattern:[e?e.startIntervalPattern:null,[]],endIntervalPattern:[e?e.endIntervalPattern:null,[]]})}validatorTriggers(){return["fetchMode","useMetadataIntervalPatterns"]}updateValidators(e){const t=this.getTelemetryFromDatabaseConfigForm.get("fetchMode").value,o=this.getTelemetryFromDatabaseConfigForm.get("useMetadataIntervalPatterns").value;t&&t===Re.ALL?(this.getTelemetryFromDatabaseConfigForm.get("aggregation").setValidators([T.required]),this.getTelemetryFromDatabaseConfigForm.get("orderBy").setValidators([T.required]),this.getTelemetryFromDatabaseConfigForm.get("limit").setValidators([T.required,T.min(2),T.max(1e3)])):(this.getTelemetryFromDatabaseConfigForm.get("aggregation").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("orderBy").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("limit").setValidators([])),o?(this.getTelemetryFromDatabaseConfigForm.get("startInterval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endInterval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").setValidators([T.required]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").setValidators([T.required])):(this.getTelemetryFromDatabaseConfigForm.get("startInterval").setValidators([T.required,T.min(1),T.max(2147483647)]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").setValidators([T.required]),this.getTelemetryFromDatabaseConfigForm.get("endInterval").setValidators([T.required,T.min(1),T.max(2147483647)]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").setValidators([T.required]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").setValidators([])),this.getTelemetryFromDatabaseConfigForm.get("aggregation").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("orderBy").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("limit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startInterval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endInterval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").updateValueAndValidity({emitEvent:e})}removeKey(e,t){const o=this.getTelemetryFromDatabaseConfigForm.get(t).value,r=o.indexOf(e);r>=0&&(o.splice(r,1),this.getTelemetryFromDatabaseConfigForm.get(t).setValue(o,{emitEvent:!0}))}addKey(e,t){const o=e.input;let r=e.value;if((r||"").trim()){r=r.trim();let e=this.getTelemetryFromDatabaseConfigForm.get(t).value;e&&-1!==e.indexOf(r)||(e||(e=[]),e.push(r),this.getTelemetryFromDatabaseConfigForm.get(t).setValue(e,{emitEvent:!0}))}o&&(o.value="")}}Dt.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Dt,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),Dt.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Dt,selector:"tb-enrichment-node-get-telemetry-from-database",usesInheritance:!0,ngImport:e,template:'
\n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.fetch-mode\n \n \n {{ mode }}\n \n \n tb.rulenode.fetch-mode-hint\n \n
\n \n aggregation.function\n \n \n {{ aggregationTypesTranslations.get(aggregationTypes[aggregation]) | translate }}\n \n \n \n \n tb.rulenode.order-by\n \n \n {{ order }}\n \n \n tb.rulenode.order-by-hint\n \n \n tb.rulenode.limit\n \n tb.rulenode.limit-hint\n \n
\n \n {{ \'tb.rulenode.use-metadata-interval-patterns\' | translate }}\n \n
tb.rulenode.use-metadata-interval-patterns-hint
\n
\n
\n \n tb.rulenode.start-interval\n \n \n {{ \'tb.rulenode.start-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.start-interval-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n tb.rulenode.end-interval\n \n \n {{ \'tb.rulenode.end-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.end-interval-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n \n tb.rulenode.start-interval-pattern\n \n \n {{ \'tb.rulenode.start-interval-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.end-interval-pattern\n \n \n {{ \'tb.rulenode.end-interval-pattern-required\' | translate }}\n \n \n \n \n
\n',styles:[":host label.tb-title{margin-bottom:-10px}\n"],components:[{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:X.MatChipList,selector:"mat-chip-list",inputs:["aria-orientation","multiple","compareWith","value","required","placeholder","disabled","selectable","tabIndex","errorStateMatcher"],outputs:["change","valueChange"],exportAs:["matChipList"]},{type:ee.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{type:H.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:U.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:D.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:G.MatLabel,selector:"mat-label"},{type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:X.MatChip,selector:"mat-basic-chip, [mat-basic-chip], mat-chip, [mat-chip]",inputs:["color","disableRipple","tabIndex","selected","value","selectable","disabled","removable"],outputs:["selectionChange","destroyed","removed"],exportAs:["matChip"]},{type:X.MatChipRemove,selector:"[matChipRemove]"},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:X.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputSeparatorKeyCodes","placeholder","id","matChipInputFor","matChipInputAddOnBlur","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{type:G.MatHint,selector:"mat-hint",inputs:["align","id"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:V.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:G.MatError,selector:"mat-error",inputs:["id"]}],pipes:{translate:E.TranslatePipe,safeHtml:Ie}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Dt,decorators:[{type:t,args:[{selector:"tb-enrichment-node-get-telemetry-from-database",templateUrl:"./get-telemetry-from-database-config.component.html",styleUrls:["./get-telemetry-from-database-config.component.scss"]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class Vt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.separatorKeysCodes=[Y,J,Z]}configForm(){return this.originatorAttributesConfigForm}onConfigurationSet(e){this.originatorAttributesConfigForm=this.fb.group({tellFailureIfAbsent:[!!e&&e.tellFailureIfAbsent,[]],clientAttributeNames:[e?e.clientAttributeNames:null,[]],sharedAttributeNames:[e?e.sharedAttributeNames:null,[]],serverAttributeNames:[e?e.serverAttributeNames:null,[]],latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],getLatestValueWithTs:[!!e&&e.getLatestValueWithTs,[]]})}removeKey(e,t){const o=this.originatorAttributesConfigForm.get(t).value,r=o.indexOf(e);r>=0&&(o.splice(r,1),this.originatorAttributesConfigForm.get(t).setValue(o,{emitEvent:!0}))}addKey(e,t){const o=e.input;let r=e.value;if((r||"").trim()){r=r.trim();let e=this.originatorAttributesConfigForm.get(t).value;e&&-1!==e.indexOf(r)||(e||(e=[]),e.push(r),this.originatorAttributesConfigForm.get(t).setValue(e,{emitEvent:!0}))}o&&(o.value="")}}Vt.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Vt,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),Vt.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Vt,selector:"tb-enrichment-node-originator-attributes-config",usesInheritance:!0,ngImport:e,template:'
\n \n {{ \'tb.rulenode.tell-failure-if-absent\' | translate }}\n \n
tb.rulenode.tell-failure-if-absent-hint
\n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n {{ \'tb.rulenode.get-latest-value-with-ts\' | translate }}\n \n
\n
\n',styles:[":host label.tb-title{margin-bottom:-10px}\n"],components:[{type:D.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:X.MatChipList,selector:"mat-chip-list",inputs:["aria-orientation","multiple","compareWith","value","required","placeholder","disabled","selectable","tabIndex","errorStateMatcher"],outputs:["change","valueChange"],exportAs:["matChipList"]},{type:ee.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:G.MatLabel,selector:"mat-label"},{type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:X.MatChip,selector:"mat-basic-chip, [mat-basic-chip], mat-chip, [mat-chip]",inputs:["color","disableRipple","tabIndex","selected","value","selectable","disabled","removable"],outputs:["selectionChange","destroyed","removed"],exportAs:["matChip"]},{type:X.MatChipRemove,selector:"[matChipRemove]"},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:X.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputSeparatorKeyCodes","placeholder","id","matChipInputFor","matChipInputAddOnBlur","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{type:G.MatHint,selector:"mat-hint",inputs:["align","id"]}],pipes:{translate:E.TranslatePipe,safeHtml:Ie}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Vt,decorators:[{type:t,args:[{selector:"tb-enrichment-node-originator-attributes-config",templateUrl:"./originator-attributes-config.component.html",styleUrls:["./originator-attributes-config.component.scss"]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class Et extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.originatorFieldsConfigForm}onConfigurationSet(e){this.originatorFieldsConfigForm=this.fb.group({fieldsMapping:[e?e.fieldsMapping:null,[T.required]]})}}Et.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Et,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),Et.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Et,selector:"tb-enrichment-node-originator-fields-config",usesInheritance:!0,ngImport:e,template:'
\n \n \n \n
\n',components:[{type:rt,selector:"tb-kv-map-config",inputs:["disabled","requiredText","keyText","keyRequiredText","valText","valRequiredText","required"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]}]}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Et,decorators:[{type:t,args:[{selector:"tb-enrichment-node-originator-fields-config",templateUrl:"./originator-fields-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class Pt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.relatedAttributesConfigForm}onConfigurationSet(e){this.relatedAttributesConfigForm=this.fb.group({relationsQuery:[e?e.relationsQuery:null,[T.required]],telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[T.required]]})}}Pt.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Pt,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),Pt.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Pt,selector:"tb-enrichment-node-related-attributes-config",usesInheritance:!0,ngImport:e,template:'
\n \n \n \n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
\n',components:[{type:Nt,selector:"tb-relations-query-config",inputs:["disabled","required"]},{type:D.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:rt,selector:"tb-kv-map-config",inputs:["disabled","requiredText","keyText","keyRequiredText","valText","valRequiredText","required"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]}],pipes:{translate:E.TranslatePipe}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Pt,decorators:[{type:t,args:[{selector:"tb-enrichment-node-related-attributes-config",templateUrl:"./related-attributes-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class Rt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.tenantAttributesConfigForm}onConfigurationSet(e){this.tenantAttributesConfigForm=this.fb.group({telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[T.required]]})}}Rt.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Rt,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),Rt.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Rt,selector:"tb-enrichment-node-tenant-attributes-config",usesInheritance:!0,ngImport:e,template:'
\n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
\n',components:[{type:D.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:rt,selector:"tb-kv-map-config",inputs:["disabled","requiredText","keyText","keyRequiredText","valText","valRequiredText","required"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]}],pipes:{translate:E.TranslatePipe}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Rt,decorators:[{type:t,args:[{selector:"tb-enrichment-node-tenant-attributes-config",templateUrl:"./tenant-attributes-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class wt{}wt.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:wt,deps:[],target:e.ɵɵFactoryTarget.NgModule}),wt.ɵmod=e.ɵɵngDeclareNgModule({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:wt,declarations:[St,Gt,At,Vt,Et,Dt,Pt,Rt,Mt],imports:[w,F,Tt],exports:[St,Gt,At,Vt,Et,Dt,Pt,Rt,Mt]}),wt.ɵinj=e.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:wt,imports:[[w,F,Tt]]}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:wt,decorators:[{type:l,args:[{declarations:[St,Gt,At,Vt,Et,Dt,Pt,Rt,Mt],imports:[w,F,Tt],exports:[St,Gt,At,Vt,Et,Dt,Pt,Rt,Mt]}]}]});class Ot extends s{constructor(e,t,o){super(e),this.store=e,this.translate=t,this.fb=o,this.alarmStatusTranslationsMap=v,this.alarmStatusList=[],this.searchText="",this.displayStatusFn=this.displayStatus.bind(this);for(const e of Object.keys(I))this.alarmStatusList.push(I[e]);this.statusFormControl=new A(""),this.filteredAlarmStatus=this.statusFormControl.valueChanges.pipe(se(""),me((e=>e||"")),ue((e=>this.fetchAlarmStatus(e))),pe())}ngOnInit(){super.ngOnInit()}configForm(){return this.alarmStatusConfigForm}prepareInputConfig(e){return this.searchText="",this.statusFormControl.patchValue("",{emitEvent:!0}),e}onConfigurationSet(e){this.alarmStatusConfigForm=this.fb.group({alarmStatusList:[e?e.alarmStatusList:null,[T.required]]})}displayStatus(e){return e?this.translate.instant(v.get(e)):void 0}fetchAlarmStatus(e){const t=this.getAlarmStatusList();if(this.searchText=e,this.searchText&&this.searchText.length){const e=this.searchText.toUpperCase();return be(t.filter((t=>this.translate.instant(v.get(I[t])).toUpperCase().includes(e))))}return be(t)}alarmStatusSelected(e){this.addAlarmStatus(e.option.value),this.clear("")}removeAlarmStatus(e){const t=this.alarmStatusConfigForm.get("alarmStatusList").value;if(t){const o=t.indexOf(e);o>=0&&(t.splice(o,1),this.alarmStatusConfigForm.get("alarmStatusList").setValue(t))}}addAlarmStatus(e){let t=this.alarmStatusConfigForm.get("alarmStatusList").value;t||(t=[]);-1===t.indexOf(e)&&(t.push(e),this.alarmStatusConfigForm.get("alarmStatusList").setValue(t))}getAlarmStatusList(){return this.alarmStatusList.filter((e=>-1===this.alarmStatusConfigForm.get("alarmStatusList").value.indexOf(e)))}onAlarmStatusInputFocus(){this.statusFormControl.updateValueAndValidity({onlySelf:!0,emitEvent:!0})}clear(e=""){this.alarmStatusInput.nativeElement.value=e,this.statusFormControl.patchValue(null,{emitEvent:!0}),setTimeout((()=>{this.alarmStatusInput.nativeElement.blur(),this.alarmStatusInput.nativeElement.focus()}),0)}}Ot.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Ot,deps:[{token:N.Store},{token:E.TranslateService},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),Ot.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Ot,selector:"tb-filter-node-check-alarm-status-config",viewQueries:[{propertyName:"alarmStatusInput",first:!0,predicate:["alarmStatusInput"],descendants:!0}],usesInheritance:!0,ngImport:e,template:'
\n \n tb.rulenode.alarm-status-filter\n \n \n \n {{alarmStatusTranslationsMap.get(alarmStatus) | translate}}\n \n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-alarm-status-matching\n
\n
\n
\n
\n
\n \n
\n\n\n\n',components:[{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:X.MatChipList,selector:"mat-chip-list",inputs:["aria-orientation","multiple","compareWith","value","required","placeholder","disabled","selectable","tabIndex","errorStateMatcher"],outputs:["change","valueChange"],exportAs:["matChipList"]},{type:ee.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{type:he.MatAutocomplete,selector:"mat-autocomplete",inputs:["disableRipple"],exportAs:["matAutocomplete"]},{type:U.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:ae.TbErrorComponent,selector:"tb-error",inputs:["error"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:G.MatLabel,selector:"mat-label"},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:X.MatChip,selector:"mat-basic-chip, [mat-basic-chip], mat-chip, [mat-chip]",inputs:["color","disableRipple","tabIndex","selected","value","selectable","disabled","removable"],outputs:["selectionChange","destroyed","removed"],exportAs:["matChip"]},{type:X.MatChipRemove,selector:"[matChipRemove]"},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:he.MatAutocompleteTrigger,selector:"input[matAutocomplete], textarea[matAutocomplete]",exportAs:["matAutocompleteTrigger"]},{type:X.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputSeparatorKeyCodes","placeholder","id","matChipInputFor","matChipInputAddOnBlur","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{type:he.MatAutocompleteOrigin,selector:"[matAutocompleteOrigin]",exportAs:["matAutocompleteOrigin"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlDirective,selector:"[formControl]",inputs:["disabled","formControl","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]}],pipes:{translate:E.TranslatePipe,async:R.AsyncPipe,highlight:Fe.HighlightPipe}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Ot,decorators:[{type:t,args:[{selector:"tb-filter-node-check-alarm-status-config",templateUrl:"./check-alarm-status.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:E.TranslateService},{type:q.FormBuilder}]},propDecorators:{alarmStatusInput:[{type:r,args:["alarmStatusInput",{static:!1}]}]}});class Ht extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.separatorKeysCodes=[Y,J,Z]}configForm(){return this.checkMessageConfigForm}onConfigurationSet(e){this.checkMessageConfigForm=this.fb.group({messageNames:[e?e.messageNames:null,[]],metadataNames:[e?e.metadataNames:null,[]],checkAllKeys:[!!e&&e.checkAllKeys,[]]})}validateConfig(){const e=this.checkMessageConfigForm.get("messageNames").value,t=this.checkMessageConfigForm.get("metadataNames").value;return e.length>0||t.length>0}removeMessageName(e){const t=this.checkMessageConfigForm.get("messageNames").value,o=t.indexOf(e);o>=0&&(t.splice(o,1),this.checkMessageConfigForm.get("messageNames").setValue(t,{emitEvent:!0}))}removeMetadataName(e){const t=this.checkMessageConfigForm.get("metadataNames").value,o=t.indexOf(e);o>=0&&(t.splice(o,1),this.checkMessageConfigForm.get("metadataNames").setValue(t,{emitEvent:!0}))}addMessageName(e){const t=e.input;let o=e.value;if((o||"").trim()){o=o.trim();let e=this.checkMessageConfigForm.get("messageNames").value;e&&-1!==e.indexOf(o)||(e||(e=[]),e.push(o),this.checkMessageConfigForm.get("messageNames").setValue(e,{emitEvent:!0}))}t&&(t.value="")}addMetadataName(e){const t=e.input;let o=e.value;if((o||"").trim()){o=o.trim();let e=this.checkMessageConfigForm.get("metadataNames").value;e&&-1!==e.indexOf(o)||(e||(e=[]),e.push(o),this.checkMessageConfigForm.get("metadataNames").setValue(e,{emitEvent:!0}))}t&&(t.value="")}}Ht.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Ht,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),Ht.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Ht,selector:"tb-filter-node-check-message-config",usesInheritance:!0,ngImport:e,template:'
\n \n \n \n \n \n {{messageName}}\n close\n \n \n \n \n
tb.rulenode.separator-hint
\n \n \n \n \n \n {{metadataName}}\n close\n \n \n \n \n
tb.rulenode.separator-hint
\n \n {{ \'tb.rulenode.check-all-keys\' | translate }}\n \n
tb.rulenode.check-all-keys-hint
\n
\n',styles:[":host label.tb-title{margin-bottom:-10px}\n"],components:[{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:X.MatChipList,selector:"mat-chip-list",inputs:["aria-orientation","multiple","compareWith","value","required","placeholder","disabled","selectable","tabIndex","errorStateMatcher"],outputs:["change","valueChange"],exportAs:["matChipList"]},{type:ee.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{type:D.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:G.MatLabel,selector:"mat-label"},{type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:X.MatChip,selector:"mat-basic-chip, [mat-basic-chip], mat-chip, [mat-chip]",inputs:["color","disableRipple","tabIndex","selected","value","selectable","disabled","removable"],outputs:["selectionChange","destroyed","removed"],exportAs:["matChip"]},{type:X.MatChipRemove,selector:"[matChipRemove]"},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:X.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputSeparatorKeyCodes","placeholder","id","matChipInputFor","matChipInputAddOnBlur","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]}],pipes:{translate:E.TranslatePipe}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Ht,decorators:[{type:t,args:[{selector:"tb-filter-node-check-message-config",templateUrl:"./check-message-config.component.html",styleUrls:["./check-message-config.component.scss"]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class Ut extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.entitySearchDirection=Object.keys(c),this.entitySearchDirectionTranslationsMap=g}configForm(){return this.checkRelationConfigForm}onConfigurationSet(e){this.checkRelationConfigForm=this.fb.group({checkForSingleEntity:[!!e&&e.checkForSingleEntity,[]],direction:[e?e.direction:null,[]],entityType:[e?e.entityType:null,e&&e.checkForSingleEntity?[T.required]:[]],entityId:[e?e.entityId:null,e&&e.checkForSingleEntity?[T.required]:[]],relationType:[e?e.relationType:null,[T.required]]})}validatorTriggers(){return["checkForSingleEntity"]}updateValidators(e){const t=this.checkRelationConfigForm.get("checkForSingleEntity").value;this.checkRelationConfigForm.get("entityType").setValidators(t?[T.required]:[]),this.checkRelationConfigForm.get("entityType").updateValueAndValidity({emitEvent:e}),this.checkRelationConfigForm.get("entityId").setValidators(t?[T.required]:[]),this.checkRelationConfigForm.get("entityId").updateValueAndValidity({emitEvent:e})}}Ut.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Ut,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),Ut.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Ut,selector:"tb-filter-node-check-relation-config",usesInheritance:!0,ngImport:e,template:'
\n \n {{ \'tb.rulenode.check-relation-to-specific-entity\' | translate }}\n \n
tb.rulenode.check-relation-hint
\n \n relation.direction\n \n \n {{ entitySearchDirectionTranslationsMap.get(direction) | translate }}\n \n \n \n
\n \n \n \n \n
\n \n \n
\n',components:[{type:D.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:H.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:U.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:te.EntityTypeSelectComponent,selector:"tb-entity-type-select",inputs:["allowedEntityTypes","useAliasEntityTypes","showLabel","required","disabled"]},{type:Ce.EntityAutocompleteComponent,selector:"tb-entity-autocomplete",inputs:["entityType","entitySubtype","excludeEntityIds","labelText","requiredText","required","disabled"],outputs:["entityChanged"]},{type:ge.RelationTypeAutocompleteComponent,selector:"tb-relation-type-autocomplete",inputs:["required","disabled"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:G.MatLabel,selector:"mat-label"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]}],pipes:{translate:E.TranslatePipe}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Ut,decorators:[{type:t,args:[{selector:"tb-filter-node-check-relation-config",templateUrl:"./check-relation-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class Bt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.perimeterType=Me,this.perimeterTypes=Object.keys(Me),this.perimeterTypeTranslationMap=Se,this.rangeUnits=Object.keys(De),this.rangeUnitTranslationMap=Ve}configForm(){return this.geoFilterConfigForm}onConfigurationSet(e){this.geoFilterConfigForm=this.fb.group({latitudeKeyName:[e?e.latitudeKeyName:null,[T.required]],longitudeKeyName:[e?e.longitudeKeyName:null,[T.required]],fetchPerimeterInfoFromMessageMetadata:[!!e&&e.fetchPerimeterInfoFromMessageMetadata,[]],perimeterType:[e?e.perimeterType:null,[]],centerLatitude:[e?e.centerLatitude:null,[]],centerLongitude:[e?e.centerLatitude:null,[]],range:[e?e.range:null,[]],rangeUnit:[e?e.rangeUnit:null,[]],polygonsDefinition:[e?e.polygonsDefinition:null,[]]})}validatorTriggers(){return["fetchPerimeterInfoFromMessageMetadata","perimeterType"]}updateValidators(e){const t=this.geoFilterConfigForm.get("fetchPerimeterInfoFromMessageMetadata").value,o=this.geoFilterConfigForm.get("perimeterType").value;t?this.geoFilterConfigForm.get("perimeterType").setValidators([]):this.geoFilterConfigForm.get("perimeterType").setValidators([T.required]),t||o!==Me.CIRCLE?(this.geoFilterConfigForm.get("centerLatitude").setValidators([]),this.geoFilterConfigForm.get("centerLongitude").setValidators([]),this.geoFilterConfigForm.get("range").setValidators([]),this.geoFilterConfigForm.get("rangeUnit").setValidators([])):(this.geoFilterConfigForm.get("centerLatitude").setValidators([T.required,T.min(-90),T.max(90)]),this.geoFilterConfigForm.get("centerLongitude").setValidators([T.required,T.min(-180),T.max(180)]),this.geoFilterConfigForm.get("range").setValidators([T.required,T.min(0)]),this.geoFilterConfigForm.get("rangeUnit").setValidators([T.required])),t||o!==Me.POLYGON?this.geoFilterConfigForm.get("polygonsDefinition").setValidators([]):this.geoFilterConfigForm.get("polygonsDefinition").setValidators([T.required]),this.geoFilterConfigForm.get("perimeterType").updateValueAndValidity({emitEvent:!1}),this.geoFilterConfigForm.get("centerLatitude").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("centerLongitude").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("range").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("rangeUnit").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("polygonsDefinition").updateValueAndValidity({emitEvent:e})}}Bt.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Bt,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),Bt.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Bt,selector:"tb-filter-node-gps-geofencing-config",usesInheritance:!0,ngImport:e,template:'
\n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n
\n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n
\n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
\n
\n
\n',components:[{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:D.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:H.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:U.MatOption,selector:"mat-option",exportAs:["matOption"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:G.MatLabel,selector:"mat-label"},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:G.MatError,selector:"mat-error",inputs:["id"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:V.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"}],pipes:{translate:E.TranslatePipe}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Bt,decorators:[{type:t,args:[{selector:"tb-filter-node-gps-geofencing-config",templateUrl:"./gps-geo-filter-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class Kt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.messageTypeConfigForm}onConfigurationSet(e){this.messageTypeConfigForm=this.fb.group({messageTypes:[e?e.messageTypes:null,[T.required]]})}}Kt.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Kt,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),Kt.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Kt,selector:"tb-filter-node-message-type-config",usesInheritance:!0,ngImport:e,template:'
\n \n
\n',components:[{type:qt,selector:"tb-message-types-config",inputs:["required","label","placeholder","disabled"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]}]}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Kt,decorators:[{type:t,args:[{selector:"tb-filter-node-message-type-config",templateUrl:"./message-type-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class jt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.allowedEntityTypes=[x.DEVICE,x.ASSET,x.ENTITY_VIEW,x.TENANT,x.CUSTOMER,x.USER,x.DASHBOARD,x.RULE_CHAIN,x.RULE_NODE]}configForm(){return this.originatorTypeConfigForm}onConfigurationSet(e){this.originatorTypeConfigForm=this.fb.group({originatorTypes:[e?e.originatorTypes:null,[T.required]]})}}jt.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:jt,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),jt.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:jt,selector:"tb-filter-node-originator-type-config",usesInheritance:!0,ngImport:e,template:'
\n \n \n \n
\n',styles:[":host ::ng-deep tb-entity-type-list .mat-form-field-flex{padding-top:0}:host ::ng-deep tb-entity-type-list .mat-form-field-infix{border-top:0}\n"],components:[{type:Le.EntityTypeListComponent,selector:"tb-entity-type-list",inputs:["required","disabled","allowedEntityTypes","ignoreAuthorityFilter"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]}]}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:jt,decorators:[{type:t,args:[{selector:"tb-filter-node-originator-type-config",templateUrl:"./originator-type-config.component.html",styleUrls:["./originator-type-config.component.scss"]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class zt extends s{constructor(e,t,o,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=o,this.translate=r}configForm(){return this.scriptConfigForm}onConfigurationSet(e){this.scriptConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[T.required]]})}testScript(){const e=this.scriptConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(e,"filter",this.translate.instant("tb.rulenode.filter"),"Filter",["msg","metadata","msgType"],this.ruleNodeId,"rulenode/filter_node_script_fn").subscribe((e=>{e&&this.scriptConfigForm.get("jsScript").setValue(e)}))}onValidate(){this.jsFuncComponent.validateOnSubmit()}}zt.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:zt,deps:[{token:N.Store},{token:q.FormBuilder},{token:_.NodeScriptTestService},{token:E.TranslateService}],target:e.ɵɵFactoryTarget.Component}),zt.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:zt,selector:"tb-filter-node-script-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0,static:!0}],usesInheritance:!0,ngImport:e,template:'
\n \n \n \n
\n \n
\n
\n',components:[{type:$.JsFuncComponent,selector:"tb-js-func",inputs:["functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","noValidate","required"]},{type:W.MatButton,selector:"button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]}],pipes:{translate:E.TranslatePipe}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:zt,decorators:[{type:t,args:[{selector:"tb-filter-node-script-config",templateUrl:"./script-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder},{type:_.NodeScriptTestService},{type:E.TranslateService}]},propDecorators:{jsFuncComponent:[{type:r,args:["jsFuncComponent",{static:!0}]}]}});class _t extends s{constructor(e,t,o,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=o,this.translate=r}configForm(){return this.switchConfigForm}onConfigurationSet(e){this.switchConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[T.required]]})}testScript(){const e=this.switchConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(e,"switch",this.translate.instant("tb.rulenode.switch"),"Switch",["msg","metadata","msgType"],this.ruleNodeId,"rulenode/switch_node_script_fn").subscribe((e=>{e&&this.switchConfigForm.get("jsScript").setValue(e)}))}onValidate(){this.jsFuncComponent.validateOnSubmit()}}_t.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:_t,deps:[{token:N.Store},{token:q.FormBuilder},{token:_.NodeScriptTestService},{token:E.TranslateService}],target:e.ɵɵFactoryTarget.Component}),_t.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:_t,selector:"tb-filter-node-switch-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0,static:!0}],usesInheritance:!0,ngImport:e,template:'
\n \n \n \n
\n \n
\n
\n',components:[{type:$.JsFuncComponent,selector:"tb-js-func",inputs:["functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","noValidate","required"]},{type:W.MatButton,selector:"button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]}],pipes:{translate:E.TranslatePipe}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:_t,decorators:[{type:t,args:[{selector:"tb-filter-node-switch-config",templateUrl:"./switch-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder},{type:_.NodeScriptTestService},{type:E.TranslateService}]},propDecorators:{jsFuncComponent:[{type:r,args:["jsFuncComponent",{static:!0}]}]}});class Qt{}Qt.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Qt,deps:[],target:e.ɵɵFactoryTarget.NgModule}),Qt.ɵmod=e.ɵɵngDeclareNgModule({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Qt,declarations:[Ht,Ut,Bt,Kt,jt,zt,_t,Ot],imports:[w,F,Tt],exports:[Ht,Ut,Bt,Kt,jt,zt,_t,Ot]}),Qt.ɵinj=e.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Qt,imports:[[w,F,Tt]]}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Qt,decorators:[{type:l,args:[{declarations:[Ht,Ut,Bt,Kt,jt,zt,_t,Ot],imports:[w,F,Tt],exports:[Ht,Ut,Bt,Kt,jt,zt,_t,Ot]}]}]});class $t extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.originatorSource=Te,this.originatorSources=Object.keys(Te),this.originatorSourceTranslationMap=ke}configForm(){return this.changeOriginatorConfigForm}onConfigurationSet(e){this.changeOriginatorConfigForm=this.fb.group({originatorSource:[e?e.originatorSource:null,[T.required]],relationsQuery:[e?e.relationsQuery:null,[]]})}validatorTriggers(){return["originatorSource"]}updateValidators(e){const t=this.changeOriginatorConfigForm.get("originatorSource").value;t&&t===Te.RELATED?this.changeOriginatorConfigForm.get("relationsQuery").setValidators([T.required]):this.changeOriginatorConfigForm.get("relationsQuery").setValidators([]),this.changeOriginatorConfigForm.get("relationsQuery").updateValueAndValidity({emitEvent:e})}}$t.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:$t,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),$t.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:$t,selector:"tb-transformation-node-change-originator-config",usesInheritance:!0,ngImport:e,template:'
\n \n tb.rulenode.originator-source\n \n \n {{ originatorSourceTranslationMap.get(source) | translate }}\n \n \n \n
\n \n \n \n
\n
\n',components:[{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:H.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:U.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:Nt,selector:"tb-relations-query-config",inputs:["disabled","required"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:G.MatLabel,selector:"mat-label"},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]}],pipes:{translate:E.TranslatePipe}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:$t,decorators:[{type:t,args:[{selector:"tb-transformation-node-change-originator-config",templateUrl:"./change-originator-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class Wt extends s{constructor(e,t,o,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=o,this.translate=r}configForm(){return this.scriptConfigForm}onConfigurationSet(e){this.scriptConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[T.required]]})}testScript(){const e=this.scriptConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(e,"update",this.translate.instant("tb.rulenode.transformer"),"Transform",["msg","metadata","msgType"],this.ruleNodeId,"rulenode/transformation_node_script_fn").subscribe((e=>{e&&this.scriptConfigForm.get("jsScript").setValue(e)}))}onValidate(){this.jsFuncComponent.validateOnSubmit()}}Wt.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Wt,deps:[{token:N.Store},{token:q.FormBuilder},{token:_.NodeScriptTestService},{token:E.TranslateService}],target:e.ɵɵFactoryTarget.Component}),Wt.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Wt,selector:"tb-transformation-node-script-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0,static:!0}],usesInheritance:!0,ngImport:e,template:'
\n \n \n \n
\n \n
\n
\n',components:[{type:$.JsFuncComponent,selector:"tb-js-func",inputs:["functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","noValidate","required"]},{type:W.MatButton,selector:"button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]}],pipes:{translate:E.TranslatePipe}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Wt,decorators:[{type:t,args:[{selector:"tb-transformation-node-script-config",templateUrl:"./script-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder},{type:_.NodeScriptTestService},{type:E.TranslateService}]},propDecorators:{jsFuncComponent:[{type:r,args:["jsFuncComponent",{static:!0}]}]}});class Yt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.mailBodyTypes=[{name:"tb.mail-body-type.plain-text",value:"false"},{name:"tb.mail-body-type.html",value:"true"},{name:"tb.mail-body-type.dynamic",value:"dynamic"}]}configForm(){return this.toEmailConfigForm}onConfigurationSet(e){this.toEmailConfigForm=this.fb.group({fromTemplate:[e?e.fromTemplate:null,[T.required]],toTemplate:[e?e.toTemplate:null,[T.required]],ccTemplate:[e?e.ccTemplate:null,[]],bccTemplate:[e?e.bccTemplate:null,[]],subjectTemplate:[e?e.subjectTemplate:null,[T.required]],mailBodyType:[e?e.mailBodyType:null],isHtmlTemplate:[e?e.isHtmlTemplate:null],bodyTemplate:[e?e.bodyTemplate:null,[T.required]]}),this.toEmailConfigForm.get("mailBodyType").valueChanges.pipe(se([null==e?void 0:e.subjectTemplate])).subscribe((e=>{"dynamic"===e?(this.toEmailConfigForm.get("isHtmlTemplate").patchValue("",{emitEvent:!1}),this.toEmailConfigForm.get("isHtmlTemplate").setValidators(T.required)):this.toEmailConfigForm.get("isHtmlTemplate").clearValidators(),this.toEmailConfigForm.get("isHtmlTemplate").updateValueAndValidity()}))}}Yt.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Yt,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),Yt.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Yt,selector:"tb-transformation-node-to-email-config",usesInheritance:!0,ngImport:e,template:'
\n \n tb.rulenode.from-template\n \n \n {{ \'tb.rulenode.from-template-required\' | translate }}\n \n \n \n \n tb.rulenode.to-template\n \n \n {{ \'tb.rulenode.to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.cc-template\n \n \n \n \n tb.rulenode.bcc-template\n \n \n \n \n tb.rulenode.subject-template\n \n \n {{ \'tb.rulenode.subject-template-required\' | translate }}\n \n \n \n \n tb.rulenode.mail-body-type\n \n \n {{ type.name | translate }}\n \n \n \n \n tb.rulenode.dynamic-mail-body-type\n \n \n \n \n tb.rulenode.body-template\n \n \n {{ \'tb.rulenode.body-template-required\' | translate }}\n \n \n \n
\n',components:[{type:G.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:H.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:U.MatOption,selector:"mat-option",exportAs:["matOption"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:G.MatLabel,selector:"mat-label"},{type:E.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:P.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:G.MatError,selector:"mat-error",inputs:["id"]},{type:G.MatHint,selector:"mat-hint",inputs:["align","id"]},{type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]}],pipes:{translate:E.TranslatePipe,safeHtml:Ie}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Yt,decorators:[{type:t,args:[{selector:"tb-transformation-node-to-email-config",templateUrl:"./to-email-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class Jt{}Jt.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Jt,deps:[],target:e.ɵɵFactoryTarget.NgModule}),Jt.ɵmod=e.ɵɵngDeclareNgModule({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Jt,declarations:[$t,Wt,Yt],imports:[w,F,Tt],exports:[$t,Wt,Yt]}),Jt.ɵinj=e.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Jt,imports:[[w,F,Tt]]}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Jt,decorators:[{type:l,args:[{declarations:[$t,Wt,Yt],imports:[w,F,Tt],exports:[$t,Wt,Yt]}]}]});class Zt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.entityType=x}configForm(){return this.ruleChainInputConfigForm}onConfigurationSet(e){this.ruleChainInputConfigForm=this.fb.group({ruleChainId:[e?e.ruleChainId:null,[T.required]]})}}Zt.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Zt,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),Zt.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Zt,selector:"tb-flow-node-rule-chain-input-config",usesInheritance:!0,ngImport:e,template:'
\n \n \n
\n',components:[{type:Ce.EntityAutocompleteComponent,selector:"tb-entity-autocomplete",inputs:["entityType","entitySubtype","excludeEntityIds","labelText","requiredText","required","disabled"],outputs:["entityChanged"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]}]}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Zt,decorators:[{type:t,args:[{selector:"tb-flow-node-rule-chain-input-config",templateUrl:"./rule-chain-input.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class Xt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.ruleChainOutputConfigForm}onConfigurationSet(e){this.ruleChainOutputConfigForm=this.fb.group({})}}Xt.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Xt,deps:[{token:N.Store},{token:q.FormBuilder}],target:e.ɵɵFactoryTarget.Component}),Xt.ɵcmp=e.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Xt,selector:"tb-flow-node-rule-chain-output-config",usesInheritance:!0,ngImport:e,template:'
\n
\n
\n',directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]}],pipes:{translate:E.TranslatePipe}}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:Xt,decorators:[{type:t,args:[{selector:"tb-flow-node-rule-chain-output-config",templateUrl:"./rule-chain-output.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:N.Store},{type:q.FormBuilder}]}});class eo{}eo.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:eo,deps:[],target:e.ɵɵFactoryTarget.NgModule}),eo.ɵmod=e.ɵɵngDeclareNgModule({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:eo,declarations:[Zt,Xt],imports:[w,F,Tt],exports:[Zt,Xt]}),eo.ɵinj=e.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:eo,imports:[[w,F,Tt]]}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:eo,decorators:[{type:l,args:[{declarations:[Zt,Xt],imports:[w,F,Tt],exports:[Zt,Xt]}]}]});class to{constructor(e){!function(e){e.setTranslation("en_US",{tb:{rulenode:{"create-entity-if-not-exists":"Create new entity if not exists","create-entity-if-not-exists-hint":"Create a new entity set above if it does not exist.","entity-name-pattern":"Name pattern","entity-name-pattern-required":"Name pattern is required","entity-type-pattern":"Type pattern","entity-type-pattern-required":"Type pattern is required","entity-cache-expiration":"Entities cache expiration time (sec)","entity-cache-expiration-hint":"Specifies maximum time interval allowed to store found entity records. 0 value means that records will never expire.","entity-cache-expiration-required":"Entities cache expiration time is required.","entity-cache-expiration-range":"Entities cache expiration time should be greater than or equal to 0.","customer-name-pattern":"Customer name pattern","customer-name-pattern-required":"Customer name pattern is required","create-customer-if-not-exists":"Create new customer if not exists","customer-cache-expiration":"Customers cache expiration time (sec)","customer-cache-expiration-hint":"Specifies maximum time interval allowed to store found customer records. 0 value means that records will never expire.","customer-cache-expiration-required":"Customers cache expiration time is required.","customer-cache-expiration-range":"Customers cache expiration time should be greater than or equal to 0.","start-interval":"Start Interval","end-interval":"End Interval","start-interval-time-unit":"Start Interval Time Unit","end-interval-time-unit":"End Interval Time Unit","fetch-mode":"Fetch mode","fetch-mode-hint":"If selected fetch mode 'ALL' you able to choose telemetry sampling order.","order-by":"Order by","order-by-hint":"Select to choose telemetry sampling order.",limit:"Limit","limit-hint":"Min limit value is 2, max - 1000. In case you want to fetch a single entry, select fetch mode 'FIRST' or 'LAST'.","time-unit-milliseconds":"Milliseconds","time-unit-seconds":"Seconds","time-unit-minutes":"Minutes","time-unit-hours":"Hours","time-unit-days":"Days","time-value-range":"Time value should be in a range from 1 to 2147483647.","start-interval-value-required":"Start interval value is required.","end-interval-value-required":"End interval value is required.",filter:"Filter",switch:"Switch","message-type":"Message type","message-type-required":"Message type is required.","message-types-filter":"Message types filter","no-message-types-found":"No message types found","no-message-type-matching":"'{{messageType}}' not found.","create-new-message-type":"Create a new one!","message-types-required":"Message types are required.","client-attributes":"Client attributes","shared-attributes":"Shared attributes","server-attributes":"Server attributes","notify-device":"Notify Device","notify-device-hint":"If the message arrives from the device, we will push it back to the device by default.","latest-timeseries":"Latest timeseries","timeseries-key":"Timeseries key","data-keys":"Message data","metadata-keys":"Message metadata","relations-query":"Relations query","device-relations-query":"Device relations query","max-relation-level":"Max relation level","relation-type-pattern":"Relation type pattern","relation-type-pattern-required":"Relation type pattern is required","relation-types-list":"Relation types to propagate","relation-types-list-hint":"If Propagate relation types are not selected, alarms will be propagated without filtering by relation type.","unlimited-level":"Unlimited level","latest-telemetry":"Latest telemetry","attr-mapping":"Attributes mapping","source-attribute":"Source attribute","source-attribute-required":"Source attribute is required.","source-telemetry":"Source telemetry","source-telemetry-required":"Source telemetry is required.","target-attribute":"Target attribute","target-attribute-required":"Target attribute is required.","attr-mapping-required":"At least one attribute mapping should be specified.","fields-mapping":"Fields mapping","fields-mapping-required":"At least one field mapping should be specified.","source-field":"Source field","source-field-required":"Source field is required.","originator-source":"Originator source","originator-customer":"Customer","originator-tenant":"Tenant","originator-related":"Related","originator-alarm-originator":"Alarm Originator","clone-message":"Clone message",transform:"Transform","default-ttl":"Default TTL in seconds","default-ttl-required":"Default TTL is required.","min-default-ttl-message":"Only 0 minimum TTL is allowed.","message-count":"Message count (0 - unlimited)","message-count-required":"Message count is required.","min-message-count-message":"Only 0 minimum message count is allowed.","period-seconds":"Period in seconds","period-seconds-required":"Period is required.","use-metadata-period-in-seconds-patterns":"Use period in seconds pattern","use-metadata-period-in-seconds-patterns-hint":"If selected, rule node use period in seconds interval pattern from message metadata or data assuming that intervals are in the seconds.","period-in-seconds-pattern":"Period in seconds pattern","period-in-seconds-pattern-required":"Period in seconds pattern is required","min-period-seconds-message":"Only 1 second minimum period is allowed.",originator:"Originator","message-body":"Message body","message-metadata":"Message metadata",generate:"Generate","test-generator-function":"Test generator function",generator:"Generator","test-filter-function":"Test filter function","test-switch-function":"Test switch function","test-transformer-function":"Test transformer function",transformer:"Transformer","alarm-create-condition":"Alarm create condition","test-condition-function":"Test condition function","alarm-clear-condition":"Alarm clear condition","alarm-details-builder":"Alarm details builder","test-details-function":"Test details function","alarm-type":"Alarm type","alarm-type-required":"Alarm type is required.","alarm-severity":"Alarm severity","alarm-severity-required":"Alarm severity is required","alarm-status-filter":"Alarm status filter","alarm-status-list-empty":"Alarm status list is empty","no-alarm-status-matching":"No alarm status matching were found.",propagate:"Propagate",condition:"Condition",details:"Details","to-string":"To string","test-to-string-function":"Test to string function","from-template":"From Template","from-template-required":"From Template is required","to-template":"To Template","to-template-required":"To Template is required","mail-address-list-template-hint":'Comma separated address list, use ${metadataKey} for value from metadata, $[messageKey] for value from message body',"cc-template":"Cc Template","bcc-template":"Bcc Template","subject-template":"Subject Template","subject-template-required":"Subject Template is required","body-template":"Body Template","body-template-required":"Body Template is required","dynamic-mail-body-type":"Dynamic mail body type","mail-body-type":"Mail body type","request-id-metadata-attribute":"Request Id Metadata attribute name","timeout-sec":"Timeout in seconds","timeout-required":"Timeout is required","min-timeout-message":"Only 0 minimum timeout value is allowed.","endpoint-url-pattern":"Endpoint URL pattern","endpoint-url-pattern-required":"Endpoint URL pattern is required","request-method":"Request method","use-simple-client-http-factory":"Use simple client HTTP factory","ignore-request-body":"Without request body","read-timeout":"Read timeout in millis","read-timeout-hint":"The value of 0 means an infinite timeout","max-parallel-requests-count":"Max number of parallel requests","max-parallel-requests-count-hint":"The value of 0 specifies no limit in parallel processing",headers:"Headers","headers-hint":'Use ${metadataKey} for value from metadata, $[messageKey] for value from message body in header/value fields',header:"Header","header-required":"Header is required",value:"Value","value-required":"Value is required","topic-pattern":"Topic pattern","topic-pattern-required":"Topic pattern is required",topic:"Topic","topic-required":"Topic is required","bootstrap-servers":"Bootstrap servers","bootstrap-servers-required":"Bootstrap servers value is required","other-properties":"Other properties",key:"Key","key-required":"Key is required",retries:"Automatically retry times if fails","min-retries-message":"Only 0 minimum retries is allowed.","batch-size-bytes":"Produces batch size in bytes","min-batch-size-bytes-message":"Only 0 minimum batch size is allowed.","linger-ms":"Time to buffer locally (ms)","min-linger-ms-message":"Only 0 ms minimum value is allowed.","buffer-memory-bytes":"Client buffer max size in bytes","min-buffer-memory-message":"Only 0 minimum buffer size is allowed.",acks:"Number of acknowledgments","key-serializer":"Key serializer","key-serializer-required":"Key serializer is required","value-serializer":"Value serializer","value-serializer-required":"Value serializer is required","topic-arn-pattern":"Topic ARN pattern","topic-arn-pattern-required":"Topic ARN pattern is required","aws-access-key-id":"AWS Access Key ID","aws-access-key-id-required":"AWS Access Key ID is required","aws-secret-access-key":"AWS Secret Access Key","aws-secret-access-key-required":"AWS Secret Access Key is required","aws-region":"AWS Region","aws-region-required":"AWS Region is required","exchange-name-pattern":"Exchange name pattern","routing-key-pattern":"Routing key pattern","message-properties":"Message properties",host:"Host","host-required":"Host is required",port:"Port","port-required":"Port is required","port-range":"Port should be in a range from 1 to 65535.","virtual-host":"Virtual host",username:"Username",password:"Password","automatic-recovery":"Automatic recovery","connection-timeout-ms":"Connection timeout (ms)","min-connection-timeout-ms-message":"Only 0 ms minimum value is allowed.","handshake-timeout-ms":"Handshake timeout (ms)","min-handshake-timeout-ms-message":"Only 0 ms minimum value is allowed.","client-properties":"Client properties","queue-url-pattern":"Queue URL pattern","queue-url-pattern-required":"Queue URL pattern is required","delay-seconds":"Delay (seconds)","min-delay-seconds-message":"Only 0 seconds minimum value is allowed.","max-delay-seconds-message":"Only 900 seconds maximum value is allowed.",name:"Name","name-required":"Name is required","queue-type":"Queue type","sqs-queue-standard":"Standard","sqs-queue-fifo":"FIFO","gcp-project-id":"GCP project ID","gcp-project-id-required":"GCP project ID is required","gcp-service-account-key":"GCP service account key file","gcp-service-account-key-required":"GCP service account key file is required","pubsub-topic-name":"Topic name","pubsub-topic-name-required":"Topic name is required","message-attributes":"Message attributes","message-attributes-hint":'Use ${metadataKey} for value from metadata, $[messageKey] for value from message body in name/value fields',"connect-timeout":"Connection timeout (sec)","connect-timeout-required":"Connection timeout is required.","connect-timeout-range":"Connection timeout should be in a range from 1 to 200.","client-id":"Client ID","client-id-hint":"Hint: Optional. Leave empty for auto-generated client id. Be careful when specifying the Client ID.Majority of the MQTT brokers will not allow multiple connections with the same client id. To connect to such brokers, your mqtt client id must be unique. When platform is running in a micro-services mode, the copy of rule nodeis launched in each micro-service. This will automatically lead to multiple mqtt clients with the same id and may cause failures of the rule node.","device-id":"Device ID","device-id-required":"Device ID is required.","clean-session":"Clean session","enable-ssl":"Enable SSL",credentials:"Credentials","credentials-type":"Credentials type","credentials-type-required":"Credentials type is required.","credentials-anonymous":"Anonymous","credentials-basic":"Basic","credentials-pem":"PEM","credentials-pem-hint":"At least Server CA certificate file or a pair of Client certificate and Client private key files are required","credentials-sas":"Shared Access Signature","sas-key":"SAS Key","sas-key-required":"SAS Key is required.",hostname:"Hostname","hostname-required":"Hostname is required.","azure-ca-cert":"CA certificate file","username-required":"Username is required.","password-required":"Password is required.","ca-cert":"Server CA certificate file *","private-key":"Client private key file *",cert:"Client certificate file *","no-file":"No file selected.","drop-file":"Drop a file or click to select a file to upload.","private-key-password":"Private key password","use-system-smtp-settings":"Use system SMTP settings","use-metadata-interval-patterns":"Use interval patterns","use-metadata-interval-patterns-hint":"If selected, rule node use start and end interval patterns from message metadata or data assuming that intervals are in the milliseconds.","use-message-alarm-data":"Use message alarm data","use-dynamically-change-the-severity-of-alar":"Use dynamically change the severity of alarm","check-all-keys":"Check that all selected keys are present","check-all-keys-hint":"If selected, checks that all specified keys are present in the message data and metadata.","check-relation-to-specific-entity":"Check relation to specific entity","check-relation-hint":"Checks existence of relation to specific entity or to any entity based on direction and relation type.","delete-relation-to-specific-entity":"Delete relation to specific entity","delete-relation-hint":"Deletes relation from the originator of the incoming message to the specified entity or list of entities based on direction and type.","remove-current-relations":"Remove current relations","remove-current-relations-hint":"Removes current relations from the originator of the incoming message based on direction and type.","change-originator-to-related-entity":"Change originator to related entity","change-originator-to-related-entity-hint":"Used to process submitted message as a message from another entity.","start-interval-pattern":"Start interval pattern","end-interval-pattern":"End interval pattern","start-interval-pattern-required":"Start interval pattern is required","end-interval-pattern-required":"End interval pattern is required","smtp-protocol":"Protocol","smtp-host":"SMTP host","smtp-host-required":"SMTP host is required.","smtp-port":"SMTP port","smtp-port-required":"You must supply a smtp port.","smtp-port-range":"SMTP port should be in a range from 1 to 65535.","timeout-msec":"Timeout ms","min-timeout-msec-message":"Only 0 ms minimum value is allowed.","enter-username":"Enter username","enter-password":"Enter password","enable-tls":"Enable TLS","tls-version":"TLS version","enable-proxy":"Enable proxy","use-system-proxy-properties":"Use system proxy properties","proxy-host":"Proxy host","proxy-host-required":"Proxy host is required.","proxy-port":"Proxy port","proxy-port-required":"Proxy port is required.","proxy-port-range":"Proxy port should be in a range from 1 to 65535.","proxy-user":"Proxy user","proxy-password":"Proxy password","proxy-scheme":"Proxy scheme","numbers-to-template":"Phone Numbers To Template","numbers-to-template-required":"Phone Numbers To Template is required","numbers-to-template-hint":'Comma separated Phone Numbers, use ${metadataKey} for value from metadata, $[messageKey] for value from message body',"sms-message-template":"SMS message Template","sms-message-template-required":"SMS message Template is required","use-system-sms-settings":"Use system SMS provider settings","min-period-0-seconds-message":"Only 0 second minimum period is allowed.","max-pending-messages":"Maximum pending messages","max-pending-messages-required":"Maximum pending messages is required.","max-pending-messages-range":"Maximum pending messages should be in a range from 1 to 100000.","originator-types-filter":"Originator types filter","interval-seconds":"Interval in seconds","interval-seconds-required":"Interval is required.","min-interval-seconds-message":"Only 1 second minimum interval is allowed.","output-timeseries-key-prefix":"Output timeseries key prefix","output-timeseries-key-prefix-required":"Output timeseries key prefix required.","separator-hint":'You should press "enter" to complete field input.',"entity-details":"Select entity details:","entity-details-title":"Title","entity-details-country":"Country","entity-details-state":"State","entity-details-city":"City","entity-details-zip":"Zip","entity-details-address":"Address","entity-details-address2":"Address2","entity-details-additional_info":"Additional Info","entity-details-phone":"Phone","entity-details-email":"Email","add-to-metadata":"Add selected details to message metadata","add-to-metadata-hint":"If selected, adds the selected details keys to the message metadata instead of message data.","entity-details-list-empty":"No entity details selected.","no-entity-details-matching":"No entity details matching were found.","custom-table-name":"Custom table name","custom-table-name-required":"Table Name is required","custom-table-hint":"You should enter the table name without prefix 'cs_tb_'.","message-field":"Message field","message-field-required":"Message field is required.","table-col":"Table column","table-col-required":"Table column is required.","latitude-key-name":"Latitude key name","longitude-key-name":"Longitude key name","latitude-key-name-required":"Latitude key name is required.","longitude-key-name-required":"Longitude key name is required.","fetch-perimeter-info-from-message-metadata":"Fetch perimeter information from message metadata","perimeter-circle":"Circle","perimeter-polygon":"Polygon","perimeter-type":"Perimeter type","circle-center-latitude":"Center latitude","circle-center-latitude-required":"Center latitude is required.","circle-center-longitude":"Center longitude","circle-center-longitude-required":"Center longitude is required.","range-unit-meter":"Meter","range-unit-kilometer":"Kilometer","range-unit-foot":"Foot","range-unit-mile":"Mile","range-unit-nautical-mile":"Nautical mile","range-units":"Range units",range:"Range","range-required":"Range is required.","polygon-definition":"Polygon definition","polygon-definition-required":"Polygon definition is required.","polygon-definition-hint":"Please, use the following format for manual definition of polygon: [[lat1,lon1],[lat2,lon2], ... ,[latN,lonN]].","min-inside-duration":"Minimal inside duration","min-inside-duration-value-required":"Minimal inside duration is required","min-inside-duration-time-unit":"Minimal inside duration time unit","min-outside-duration":"Minimal outside duration","min-outside-duration-value-required":"Minimal outside duration is required","min-outside-duration-time-unit":"Minimal outside duration time unit","tell-failure-if-absent":"Tell Failure","tell-failure-if-absent-hint":'If at least one selected key doesn\'t exist the outbound message will report "Failure".',"get-latest-value-with-ts":"Fetch Latest telemetry with Timestamp","get-latest-value-with-ts-hint":'If selected, latest telemetry values will be added to the outbound message metadata with timestamp, e.g: "temp": "{"ts":1574329385897, "value":42}"',"use-redis-queue":"Use redis queue for message persistence","trim-redis-queue":"Trim redis queue","redis-queue-max-size":"Redis queue max size","add-metadata-key-values-as-kafka-headers":"Add Message metadata key-value pairs to Kafka record headers","add-metadata-key-values-as-kafka-headers-hint":"If selected, key-value pairs from message metadata will be added to the outgoing records headers as byte arrays with predefined charset encoding.","charset-encoding":"Charset encoding","charset-encoding-required":"Charset encoding is required.","charset-us-ascii":"US-ASCII","charset-iso-8859-1":"ISO-8859-1","charset-utf-8":"UTF-8","charset-utf-16be":"UTF-16BE","charset-utf-16le":"UTF-16LE","charset-utf-16":"UTF-16","select-queue-hint":"The queue name can be selected from a drop-down list or add a custom name.","persist-alarm-rules":"Persist state of alarm rules","fetch-alarm-rules":"Fetch state of alarm rules","input-value-key":"Input value key","input-value-key-required":"Input value key is required.","output-value-key":"Output value key","output-value-key-required":"Output value key is required.",round:"Decimals","round-range":"Decimals should be in a range from 0 to 15.","use-cache":"Use cache for latest value","tell-failure-if-delta-is-negative":"Tell Failure if delta is negative","add-period-between-msgs":"Add period between messages","period-value-key":"Period value key","period-key-required":"Period value key is required.","general-pattern-hint":'Hint: use ${metadataKey} for value from metadata, $[messageKey] for value from message body',"alarm-severity-pattern-hint":'Hint: use ${metadataKey} for value from metadata, $[messageKey] for value from message body. Alarm severity should be system (CRITICAL, MAJOR etc.)',"output-node-name-hint":"The rule node name corresponds to the relation type of the output message, and it is used to forward messages to other rule nodes in the caller rule chain.","skip-latest-persistence":"Skip latest persistence"},"key-val":{key:"Key",value:"Value","remove-entry":"Remove entry","add-entry":"Add entry"},"mail-body-type":{"plain-text":"Plain Text",html:"HTML",dynamic:"Dynamic"}}},!0)}(e)}}to.ɵfac=e.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:to,deps:[{token:E.TranslateService}],target:e.ɵɵFactoryTarget.NgModule}),to.ɵmod=e.ɵɵngDeclareNgModule({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:to,declarations:[ve],imports:[w,F],exports:[kt,Qt,wt,Jt,eo,ve]}),to.ɵinj=e.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:to,imports:[[w,F],kt,Qt,wt,Jt,eo]}),e.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:e,type:to,decorators:[{type:l,args:[{declarations:[ve],imports:[w,F],exports:[kt,Qt,wt,Jt,eo,ve]}]}],ctorParameters:function(){return[{type:E.TranslateService}]}});export{Ne as AssignCustomerConfigComponent,qe as AttributesConfigComponent,$e as AzureIotHubConfigComponent,Mt as CalculateDeltaConfigComponent,$t as ChangeOriginatorConfigComponent,Ot as CheckAlarmStatusComponent,Ht as CheckMessageConfigComponent,We as CheckPointConfigComponent,Ut as CheckRelationConfigComponent,Ye as ClearAlarmConfigComponent,Je as CreateAlarmConfigComponent,Ze as CreateRelationConfigComponent,lt as CredentialsConfigComponent,St as CustomerAttributesConfigComponent,Xe as DeleteRelationConfigComponent,At as DeviceAttributesConfigComponent,et as DeviceProfileConfigComponent,It as DeviceRelationsQueryConfigComponent,ve as EmptyConfigComponent,Gt as EntityDetailsConfigComponent,tt as GeneratorConfigComponent,Dt as GetTelemetryFromDatabaseConfigComponent,ot as GpsGeoActionConfigComponent,Bt as GpsGeoFilterConfigComponent,at as KafkaConfigComponent,rt as KvMapConfigComponent,nt as LogConfigComponent,Kt as MessageTypeConfigComponent,qt as MessageTypesConfigComponent,it as MqttConfigComponent,st as MsgCountConfigComponent,mt as MsgDelayConfigComponent,Vt as OriginatorAttributesConfigComponent,Et as OriginatorFieldsConfigComponent,jt as OriginatorTypeConfigComponent,ut as PubSubConfigComponent,pt as PushToCloudConfigComponent,dt as PushToEdgeConfigComponent,ft as RabbitMqConfigComponent,Pt as RelatedAttributesConfigComponent,Nt as RelationsQueryConfigComponent,ct as RestApiCallConfigComponent,gt as RpcReplyConfigComponent,xt as RpcRequestConfigComponent,Zt as RuleChainInputComponent,Xt as RuleChainOutputComponent,kt as RuleNodeCoreConfigActionModule,Qt as RuleNodeCoreConfigFilterModule,eo as RuleNodeCoreConfigFlowModule,to as RuleNodeCoreConfigModule,Tt as RulenodeCoreConfigCommonModule,wt as RulenodeCoreConfigEnrichmentModule,Jt as RulenodeCoreConfigTransformModule,Ie as SafeHtmlPipe,yt as SaveToCustomTableConfigComponent,zt as ScriptConfigComponent,bt as SendEmailConfigComponent,ht as SendSmsConfigComponent,Ft as SnsConfigComponent,Ct as SqsConfigComponent,_t as SwitchConfigComponent,Rt as TenantAttributesConfigComponent,Lt as TimeseriesConfigComponent,Yt as ToEmailConfigComponent,Wt as TransformScriptConfigComponent,vt as UnassignCustomerConfigComponent};//# sourceMappingURL=rulenode-core-config.js.map From 59070804a78f793aaa3c8bbcb9c2a89dbcb59f92 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Fri, 17 Dec 2021 14:33:58 +0200 Subject: [PATCH 264/432] lwm2m: if error BootstrapRead - update without find Server ID --- .../store/LwM2MBootstrapConfigStoreTaskProvider.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MBootstrapConfigStoreTaskProvider.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MBootstrapConfigStoreTaskProvider.java index 74ca2ca92a..5c4e442875 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MBootstrapConfigStoreTaskProvider.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MBootstrapConfigStoreTaskProvider.java @@ -84,7 +84,7 @@ public class LwM2MBootstrapConfigStoreTaskProvider implements BootstrapTaskProvi this.initAfterBootstrapDiscover(discoverResponse); findSecurityInstanceId(discoverResponse.getObjectLinks()); } else { - log.info( + log.warn( "Bootstrap Discover return error {} : to continue bootstrap session without autoIdForSecurityObject mode. {}", discoverResponse, session); } @@ -100,7 +100,13 @@ public class LwM2MBootstrapConfigStoreTaskProvider implements BootstrapTaskProvi return tasks; } BootstrapReadResponse readResponse = (BootstrapReadResponse) previousResponse.get(0); - findServerInstanceId(readResponse); + if (readResponse.isSuccess()) { + findServerInstanceId(readResponse); + } else { + log.warn( + "Bootstrap ReadResponse return error {} : to continue bootstrap session without find Server Instance Id. {}", + readResponse, session); + } // create requests from config tasks.requestsToSend = this.toRequests(config, config.contentFormat != null ? config.contentFormat : session.getContentFormat()); From b8d49b66a6f6926a3697c9e1ccd67e3c59dca672 Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Fri, 17 Dec 2021 16:36:19 +0200 Subject: [PATCH 265/432] send notifications by rewriteLatestIfDeleted --- .../controller/TelemetryController.java | 2 +- .../AbstractSubscriptionService.java | 2 +- .../DefaultTelemetrySubscriptionService.java | 27 ++++++++++++++----- .../dao/timeseries/TimeseriesService.java | 4 +-- .../dao/sqlts/SqlTimeseriesLatestDao.java | 13 ++++----- .../dao/timeseries/BaseTimeseriesService.java | 14 +++++----- .../CassandraBaseTimeseriesLatestDao.java | 11 ++++---- .../dao/timeseries/TimeseriesLatestDao.java | 2 +- .../api/RuleEngineTelemetryService.java | 2 +- .../models/datasource/attribute-datasource.ts | 10 ++++++- 10 files changed, 55 insertions(+), 32 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/TelemetryController.java b/application/src/main/java/org/thingsboard/server/controller/TelemetryController.java index 70a6b029ed..dfe0701642 100644 --- a/application/src/main/java/org/thingsboard/server/controller/TelemetryController.java +++ b/application/src/main/java/org/thingsboard/server/controller/TelemetryController.java @@ -573,7 +573,7 @@ public class TelemetryController extends BaseController { for (String key : keys) { deleteTsKvQueries.add(new BaseDeleteTsKvQuery(key, deleteFromTs, deleteToTs, rewriteLatestIfDeleted)); } - tsSubService.deleteTimeseriesAndNotify(tenantId, entityId, keys, deleteTsKvQueries, new FutureCallback<>() { + tsSubService.deleteTimeseriesAndNotify(tenantId, entityId, keys, deleteTsKvQueries, rewriteLatestIfDeleted, new FutureCallback<>() { @Override public void onSuccess(@Nullable Void tmp) { logTimeseriesDeleted(user, entityId, keys, deleteFromTs, deleteToTs, null); diff --git a/application/src/main/java/org/thingsboard/server/service/telemetry/AbstractSubscriptionService.java b/application/src/main/java/org/thingsboard/server/service/telemetry/AbstractSubscriptionService.java index bbd3811075..3512c37134 100644 --- a/application/src/main/java/org/thingsboard/server/service/telemetry/AbstractSubscriptionService.java +++ b/application/src/main/java/org/thingsboard/server/service/telemetry/AbstractSubscriptionService.java @@ -90,7 +90,7 @@ public abstract class AbstractSubscriptionService extends TbApplicationEventList Futures.addCallback(saveFuture, new FutureCallback() { @Override public void onSuccess(@Nullable T result) { - callback.accept(null); + callback.accept(result); } @Override diff --git a/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetrySubscriptionService.java b/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetrySubscriptionService.java index dba664013d..8a911962f0 100644 --- a/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetrySubscriptionService.java +++ b/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetrySubscriptionService.java @@ -22,6 +22,7 @@ import com.google.common.util.concurrent.MoreExecutors; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.thingsboard.common.util.ThingsBoardThreadFactory; +import org.thingsboard.server.cluster.TbClusterService; import org.thingsboard.server.common.data.ApiUsageRecordKey; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.EntityView; @@ -46,7 +47,6 @@ import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.queue.discovery.PartitionService; import org.thingsboard.server.queue.usagestats.TbApiUsageClient; import org.thingsboard.server.service.apiusage.TbApiUsageStateService; -import org.thingsboard.server.cluster.TbClusterService; import org.thingsboard.server.service.subscription.TbSubscriptionUtils; import javax.annotation.Nullable; @@ -59,9 +59,12 @@ import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Optional; +import java.util.Set; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import java.util.stream.Collectors; /** * Created by ashvayka on 27.03.18. @@ -252,7 +255,7 @@ public class DefaultTelemetrySubscriptionService extends AbstractSubscriptionSer @Override public void deleteLatestInternal(TenantId tenantId, EntityId entityId, List keys, FutureCallback callback) { - ListenableFuture> deleteFuture = tsService.removeLatest(tenantId, entityId, keys); + ListenableFuture> deleteFuture = tsService.removeLatest(tenantId, entityId, keys); addVoidCallback(deleteFuture, callback); } @@ -273,10 +276,10 @@ public class DefaultTelemetrySubscriptionService extends AbstractSubscriptionSer } @Override - public void deleteTimeseriesAndNotify(TenantId tenantId, EntityId entityId, List keys, List deleteTsKvQueries, FutureCallback callback) { - ListenableFuture> deleteFuture = tsService.remove(tenantId, entityId, deleteTsKvQueries); + public void deleteTimeseriesAndNotify(TenantId tenantId, EntityId entityId, List keys, List deleteTsKvQueries, boolean rewriteLatestIfDeleted, FutureCallback callback) { + ListenableFuture> deleteFuture = tsService.remove(tenantId, entityId, deleteTsKvQueries); addVoidCallback(deleteFuture, callback); - addWsCallback(deleteFuture, success -> onTimeSeriesDelete(tenantId, entityId, keys)); + addWsCallback(deleteFuture, list -> onTimeSeriesDelete(tenantId, entityId, keys, list, rewriteLatestIfDeleted)); } @Override @@ -345,11 +348,21 @@ public class DefaultTelemetrySubscriptionService extends AbstractSubscriptionSer } } - private void onTimeSeriesDelete(TenantId tenantId, EntityId entityId, List keys) { + private void onTimeSeriesDelete(TenantId tenantId, EntityId entityId, List keys, List ts, boolean rewriteLatestIfDeleted) { TopicPartitionInfo tpi = partitionService.resolve(ServiceType.TB_CORE, tenantId, entityId); if (currentPartitions.contains(tpi)) { if (subscriptionManagerService.isPresent()) { - subscriptionManagerService.get().onTimeSeriesDelete(tenantId, entityId, keys, TbCallback.EMPTY); + Set updated; + if (rewriteLatestIfDeleted) { + List filteredTs = ts.stream().filter(Objects::nonNull).collect(Collectors.toList()); + subscriptionManagerService.get().onTimeSeriesUpdate(tenantId, entityId, ts, TbCallback.EMPTY); + updated = filteredTs.stream().map(TsKvEntry::getKey).collect(Collectors.toSet()); + } else { + updated = Collections.emptySet(); + } + + List deleted = keys.stream().filter(key -> updated.isEmpty() || !updated.remove(key)).collect(Collectors.toList()); + subscriptionManagerService.get().onTimeSeriesDelete(tenantId, entityId, deleted, TbCallback.EMPTY); } else { log.warn("Possible misconfiguration because subscriptionManagerService is null!"); } diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/timeseries/TimeseriesService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/timeseries/TimeseriesService.java index b1a2541fc7..4da8c14eeb 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/timeseries/TimeseriesService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/timeseries/TimeseriesService.java @@ -43,9 +43,9 @@ public interface TimeseriesService { ListenableFuture> saveLatest(TenantId tenantId, EntityId entityId, List tsKvEntry); - ListenableFuture> remove(TenantId tenantId, EntityId entityId, List queries); + ListenableFuture> remove(TenantId tenantId, EntityId entityId, List queries); - ListenableFuture> removeLatest(TenantId tenantId, EntityId entityId, Collection keys); + ListenableFuture> removeLatest(TenantId tenantId, EntityId entityId, Collection keys); ListenableFuture> removeAllLatest(TenantId tenantId, EntityId entityId); diff --git a/dao/src/main/java/org/thingsboard/server/dao/sqlts/SqlTimeseriesLatestDao.java b/dao/src/main/java/org/thingsboard/server/dao/sqlts/SqlTimeseriesLatestDao.java index 3937b7c2c5..3534a4c253 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sqlts/SqlTimeseriesLatestDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sqlts/SqlTimeseriesLatestDao.java @@ -147,7 +147,7 @@ public class SqlTimeseriesLatestDao extends BaseAbstractSqlTimeseriesDao impleme } @Override - public ListenableFuture removeLatest(TenantId tenantId, EntityId entityId, DeleteTsKvQuery query) { + public ListenableFuture removeLatest(TenantId tenantId, EntityId entityId, DeleteTsKvQuery query) { return getRemoveLatestFuture(tenantId, entityId, query); } @@ -175,11 +175,12 @@ public class SqlTimeseriesLatestDao extends BaseAbstractSqlTimeseriesDao impleme return tsKvLatestRepository.findAllKeysByEntityIds(entityIds.stream().map(EntityId::getId).collect(Collectors.toList())); } - private ListenableFuture getNewLatestEntryFuture(TenantId tenantId, EntityId entityId, DeleteTsKvQuery query) { + private ListenableFuture getNewLatestEntryFuture(TenantId tenantId, EntityId entityId, DeleteTsKvQuery query) { ListenableFuture> future = findNewLatestEntryFuture(tenantId, entityId, query); return Futures.transformAsync(future, entryList -> { if (entryList.size() == 1) { - return getSaveLatestFuture(entityId, entryList.get(0)); + TsKvEntry entry = entryList.get(0); + return Futures.transform(getSaveLatestFuture(entityId, entry), v -> entry, MoreExecutors.directExecutor()); } else { log.trace("Could not find new latest value for [{}], key - {}", entityId, query.getKey()); } @@ -212,7 +213,7 @@ public class SqlTimeseriesLatestDao extends BaseAbstractSqlTimeseriesDao impleme return Futures.immediateFuture(result); } - protected ListenableFuture getRemoveLatestFuture(TenantId tenantId, EntityId entityId, DeleteTsKvQuery query) { + protected ListenableFuture getRemoveLatestFuture(TenantId tenantId, EntityId entityId, DeleteTsKvQuery query) { ListenableFuture latestFuture = getFindLatestFuture(entityId, query.getKey()); ListenableFuture booleanFuture = Futures.transform(latestFuture, tsKvEntry -> { @@ -233,12 +234,12 @@ public class SqlTimeseriesLatestDao extends BaseAbstractSqlTimeseriesDao impleme return Futures.immediateFuture(null); }, service); - final SimpleListenableFuture resultFuture = new SimpleListenableFuture<>(); + final SimpleListenableFuture resultFuture = new SimpleListenableFuture<>(); Futures.addCallback(removedLatestFuture, new FutureCallback() { @Override public void onSuccess(@Nullable Void result) { if (query.getRewriteLatestIfDeleted()) { - ListenableFuture savedLatestFuture = Futures.transformAsync(booleanFuture, isRemove -> { + ListenableFuture savedLatestFuture = Futures.transformAsync(booleanFuture, isRemove -> { if (isRemove) { return getNewLatestEntryFuture(tenantId, entityId, query); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/timeseries/BaseTimeseriesService.java b/dao/src/main/java/org/thingsboard/server/dao/timeseries/BaseTimeseriesService.java index 3170f6c256..95be63dae7 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/timeseries/BaseTimeseriesService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/timeseries/BaseTimeseriesService.java @@ -195,10 +195,10 @@ public class BaseTimeseriesService implements TimeseriesService { } @Override - public ListenableFuture> remove(TenantId tenantId, EntityId entityId, List deleteTsKvQueries) { + public ListenableFuture> remove(TenantId tenantId, EntityId entityId, List deleteTsKvQueries) { validate(entityId); deleteTsKvQueries.forEach(BaseTimeseriesService::validate); - List> futures = Lists.newArrayListWithExpectedSize(deleteTsKvQueries.size() * DELETES_PER_ENTRY); + List> futures = Lists.newArrayListWithExpectedSize(deleteTsKvQueries.size() * DELETES_PER_ENTRY); for (DeleteTsKvQuery tsKvQuery : deleteTsKvQueries) { deleteAndRegisterFutures(tenantId, futures, entityId, tsKvQuery); } @@ -206,9 +206,9 @@ public class BaseTimeseriesService implements TimeseriesService { } @Override - public ListenableFuture> removeLatest(TenantId tenantId, EntityId entityId, Collection keys) { + public ListenableFuture> removeLatest(TenantId tenantId, EntityId entityId, Collection keys) { validate(entityId); - List> futures = Lists.newArrayListWithExpectedSize(keys.size()); + List> futures = Lists.newArrayListWithExpectedSize(keys.size()); for (String key : keys) { DeleteTsKvQuery query = new BaseDeleteTsKvQuery(key, 0, System.currentTimeMillis(), false); futures.add(timeseriesLatestDao.removeLatest(tenantId, entityId, query)); @@ -229,10 +229,10 @@ public class BaseTimeseriesService implements TimeseriesService { }, MoreExecutors.directExecutor()); } - private void deleteAndRegisterFutures(TenantId tenantId, List> futures, EntityId entityId, DeleteTsKvQuery query) { - futures.add(timeseriesDao.remove(tenantId, entityId, query)); + private void deleteAndRegisterFutures(TenantId tenantId, List> futures, EntityId entityId, DeleteTsKvQuery query) { + futures.add(Futures.transform(timeseriesDao.remove(tenantId, entityId, query), v -> null, MoreExecutors.directExecutor())); futures.add(timeseriesLatestDao.removeLatest(tenantId, entityId, query)); - futures.add(timeseriesDao.removePartition(tenantId, entityId, query)); + futures.add(Futures.transform(timeseriesDao.removePartition(tenantId, entityId, query), v -> null, MoreExecutors.directExecutor())); } private static void validate(EntityId entityId) { diff --git a/dao/src/main/java/org/thingsboard/server/dao/timeseries/CassandraBaseTimeseriesLatestDao.java b/dao/src/main/java/org/thingsboard/server/dao/timeseries/CassandraBaseTimeseriesLatestDao.java index 0b4ae71e85..6e9bea0ecb 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/timeseries/CassandraBaseTimeseriesLatestDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/timeseries/CassandraBaseTimeseriesLatestDao.java @@ -114,7 +114,7 @@ public class CassandraBaseTimeseriesLatestDao extends AbstractCassandraBaseTimes } @Override - public ListenableFuture removeLatest(TenantId tenantId, EntityId entityId, DeleteTsKvQuery query) { + public ListenableFuture removeLatest(TenantId tenantId, EntityId entityId, DeleteTsKvQuery query) { ListenableFuture latestEntryFuture = findLatest(tenantId, entityId, query.getKey()); ListenableFuture booleanFuture = Futures.transform(latestEntryFuture, latestEntry -> { @@ -134,12 +134,12 @@ public class CassandraBaseTimeseriesLatestDao extends AbstractCassandraBaseTimes return Futures.immediateFuture(null); }, readResultsProcessingExecutor); - final SimpleListenableFuture resultFuture = new SimpleListenableFuture<>(); + final SimpleListenableFuture resultFuture = new SimpleListenableFuture<>(); Futures.addCallback(removedLatestFuture, new FutureCallback() { @Override public void onSuccess(@Nullable Void result) { if (query.getRewriteLatestIfDeleted()) { - ListenableFuture savedLatestFuture = Futures.transformAsync(booleanFuture, isRemove -> { + ListenableFuture savedLatestFuture = Futures.transformAsync(booleanFuture, isRemove -> { if (isRemove) { return getNewLatestEntryFuture(tenantId, entityId, query); } @@ -164,7 +164,7 @@ public class CassandraBaseTimeseriesLatestDao extends AbstractCassandraBaseTimes return resultFuture; } - private ListenableFuture getNewLatestEntryFuture(TenantId tenantId, EntityId entityId, DeleteTsKvQuery query) { + private ListenableFuture getNewLatestEntryFuture(TenantId tenantId, EntityId entityId, DeleteTsKvQuery query) { long startTs = 0; long endTs = query.getStartTs() - 1; ReadTsKvQuery findNewLatestQuery = new BaseReadTsKvQuery(query.getKey(), startTs, endTs, endTs - startTs, 1, @@ -173,7 +173,8 @@ public class CassandraBaseTimeseriesLatestDao extends AbstractCassandraBaseTimes return Futures.transformAsync(future, entryList -> { if (entryList.size() == 1) { - return saveLatest(tenantId, entityId, entryList.get(0)); + TsKvEntry entry = entryList.get(0); + return Futures.transform(saveLatest(tenantId, entityId, entryList.get(0)), v -> entry, MoreExecutors.directExecutor()); } else { log.trace("Could not find new latest value for [{}], key - {}", entityId, query.getKey()); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/timeseries/TimeseriesLatestDao.java b/dao/src/main/java/org/thingsboard/server/dao/timeseries/TimeseriesLatestDao.java index f19cc461dc..d0253db0bd 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/timeseries/TimeseriesLatestDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/timeseries/TimeseriesLatestDao.java @@ -32,7 +32,7 @@ public interface TimeseriesLatestDao { ListenableFuture saveLatest(TenantId tenantId, EntityId entityId, TsKvEntry tsKvEntry); - ListenableFuture removeLatest(TenantId tenantId, EntityId entityId, DeleteTsKvQuery query); + ListenableFuture removeLatest(TenantId tenantId, EntityId entityId, DeleteTsKvQuery query); List findAllKeysByDeviceProfileId(TenantId tenantId, DeviceProfileId deviceProfileId); diff --git a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/RuleEngineTelemetryService.java b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/RuleEngineTelemetryService.java index a19d0fad0c..fe0b39c299 100644 --- a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/RuleEngineTelemetryService.java +++ b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/RuleEngineTelemetryService.java @@ -55,5 +55,5 @@ public interface RuleEngineTelemetryService { void deleteAllLatest(TenantId tenantId, EntityId entityId, FutureCallback> callback); - void deleteTimeseriesAndNotify(TenantId tenantId, EntityId entityId, List keys, List deleteTsKvQueries, FutureCallback callback); + void deleteTimeseriesAndNotify(TenantId tenantId, EntityId entityId, List keys, List deleteTsKvQueries, boolean rewriteLatestIfDeleted, FutureCallback callback); } diff --git a/ui-ngx/src/app/modules/home/models/datasource/attribute-datasource.ts b/ui-ngx/src/app/modules/home/models/datasource/attribute-datasource.ts index 89a0c8f5b2..99907bcaa9 100644 --- a/ui-ngx/src/app/modules/home/models/datasource/attribute-datasource.ts +++ b/ui-ngx/src/app/modules/home/models/datasource/attribute-datasource.ts @@ -88,7 +88,15 @@ export class AttributeDatasource implements DataSource { fetchAttributes(entityId: EntityId, attributesScope: TelemetryType, pageLink: PageLink): Observable> { return this.getAllAttributes(entityId, attributesScope).pipe( - map((data) => pageLink.filterData(data)) + map((data) => { + let filteredData = []; + for(let key in filteredData) { + if(data[key]['value'] !== null) { + filteredData.push(data[key]); + } + } + return pageLink.filterData(filteredData); + }) ); } From c0075009a80b77647b99127b33fa7196d204808f Mon Sep 17 00:00:00 2001 From: Larry Diamond <1066589+larrydiamond@users.noreply.github.com> Date: Sat, 18 Dec 2021 16:07:33 -0500 Subject: [PATCH 266/432] remediation for log4shell CVE-2021-45105 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 182491d4f8..b7c873898f 100755 --- a/pom.xml +++ b/pom.xml @@ -47,7 +47,7 @@ 3.3.0 0.7.0 1.7.32 - 2.16.0 + 2.17.0 1.2.6 0.10 4.10.0 From 9464c02f5511eeb1d6c3254c27c1b7ce9c34e4e0 Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Mon, 20 Dec 2021 12:58:14 +0200 Subject: [PATCH 267/432] edge test refactor for CE to assign alias for many asserts --- .../controller/BaseEdgeControllerTest.java | 46 ++++++++++--------- .../thingsboard/server/edge/BaseEdgeTest.java | 2 +- .../server/edge/imitator/EdgeImitator.java | 6 ++- 3 files changed, 29 insertions(+), 25 deletions(-) diff --git a/application/src/test/java/org/thingsboard/server/controller/BaseEdgeControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/BaseEdgeControllerTest.java index 9259f3253d..4a7e362e75 100644 --- a/application/src/test/java/org/thingsboard/server/controller/BaseEdgeControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/BaseEdgeControllerTest.java @@ -48,15 +48,17 @@ import org.thingsboard.server.gen.edge.v1.UserUpdateMsg; import java.util.ArrayList; import java.util.Collections; import java.util.List; -import java.util.Random; +import static org.assertj.core.api.Assertions.assertThat; import static org.hamcrest.Matchers.containsString; -import static org.hamcrest.Matchers.nullValue; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID; public abstract class BaseEdgeControllerTest extends AbstractControllerTest { + public static final String EDGE_HOST = "localhost"; + public static final int EDGE_PORT = 7070; + private IdComparator idComparator = new IdComparator<>(); private Tenant savedTenant; @@ -68,7 +70,7 @@ public abstract class BaseEdgeControllerTest extends AbstractControllerTest { loginSysAdmin(); Tenant tenant = new Tenant(); - tenant.setTitle("My tenant"); + tenant.setTitle("My tenant for Edge"); savedTenant = doPost("/api/tenant", tenant, Tenant.class); tenantId = savedTenant.getId(); Assert.assertNotNull(savedTenant); @@ -666,46 +668,46 @@ public abstract class BaseEdgeControllerTest extends AbstractControllerTest { } @Test - public void testSyncEdge() throws Exception { - Edge edge = doPost("/api/edge", constructEdge("Test Edge", "test"), Edge.class); + public void testSyncEdgeCE() throws Exception { + Edge edge = doPost("/api/edge", constructEdge("Test Sync Edge CE", "test"), Edge.class); Device device = new Device(); - device.setName("Edge Device 1"); + device.setName("Test Sync Edge CE Device 1"); device.setType("default"); Device savedDevice = doPost("/api/device", device, Device.class); doPost("/api/edge/" + edge.getId().getId().toString() + "/device/" + savedDevice.getId().getId().toString(), Device.class); Asset asset = new Asset(); - asset.setName("Edge Asset 1"); + asset.setName("Test Sync Edge CE Asset 1"); asset.setType("test"); Asset savedAsset = doPost("/api/asset", asset, Asset.class); doPost("/api/edge/" + edge.getId().getId().toString() + "/asset/" + savedAsset.getId().getId().toString(), Asset.class); - EdgeImitator edgeImitator = new EdgeImitator("localhost", 7070, edge.getRoutingKey(), edge.getSecret()); + EdgeImitator edgeImitator = new EdgeImitator(EDGE_HOST, EDGE_PORT, edge.getRoutingKey(), edge.getSecret()); edgeImitator.ignoreType(UserCredentialsUpdateMsg.class); edgeImitator.expectMessageAmount(11); edgeImitator.connect(); - Assert.assertTrue(edgeImitator.waitForMessages()); + assertThat(edgeImitator.waitForMessages()).as("await for messages on first connect").isTrue(); - Assert.assertEquals(2, edgeImitator.findAllMessagesByType(RuleChainUpdateMsg.class).size()); // one msg during sync process, another from edge creation - Assert.assertEquals(1, edgeImitator.findAllMessagesByType(DeviceProfileUpdateMsg.class).size()); // one msg during sync process for 'default' device profile - Assert.assertEquals(1, edgeImitator.findAllMessagesByType(DeviceUpdateMsg.class).size()); // one msg once device assigned to edge - Assert.assertEquals(2, edgeImitator.findAllMessagesByType(AssetUpdateMsg.class).size()); // two msgs - one during sync process, and one more once asset assigned to edge - Assert.assertEquals(1, edgeImitator.findAllMessagesByType(UserUpdateMsg.class).size()); // one msg during sync process for tenant admin user - Assert.assertEquals(4, edgeImitator.findAllMessagesByType(AdminSettingsUpdateMsg.class).size()); + assertThat(edgeImitator.findAllMessagesByType(RuleChainUpdateMsg.class)).as("one msg during sync process, another from edge creation").hasSize(2); + assertThat(edgeImitator.findAllMessagesByType(DeviceProfileUpdateMsg.class)).as("one msg during sync process for 'default' device profile").hasSize(1); + assertThat(edgeImitator.findAllMessagesByType(DeviceUpdateMsg.class)).as("one msg once device assigned to edge").hasSize(1); + assertThat(edgeImitator.findAllMessagesByType(AssetUpdateMsg.class)).as("two msgs - one during sync process, and one more once asset assigned to edge").hasSize(2); + assertThat(edgeImitator.findAllMessagesByType(UserUpdateMsg.class)).as("one msg during sync process for tenant admin user").hasSize(1); + assertThat(edgeImitator.findAllMessagesByType(AdminSettingsUpdateMsg.class)).as("admin setting update").hasSize(4); edgeImitator.expectMessageAmount(8); doPost("/api/edge/sync/" + edge.getId()); - Assert.assertTrue(edgeImitator.waitForMessages()); + assertThat(edgeImitator.waitForMessages()).as("await for messages after edge sync rest api call").isTrue(); - Assert.assertEquals(1, edgeImitator.findAllMessagesByType(RuleChainUpdateMsg.class).size()); - Assert.assertEquals(1, edgeImitator.findAllMessagesByType(DeviceProfileUpdateMsg.class).size()); - Assert.assertEquals(1, edgeImitator.findAllMessagesByType(AssetUpdateMsg.class).size()); - Assert.assertEquals(1, edgeImitator.findAllMessagesByType(UserUpdateMsg.class).size()); - Assert.assertEquals(4, edgeImitator.findAllMessagesByType(AdminSettingsUpdateMsg.class).size()); + assertThat(edgeImitator.findAllMessagesByType(RuleChainUpdateMsg.class)).as("rule chain msg").hasSize(1); + assertThat(edgeImitator.findAllMessagesByType(DeviceProfileUpdateMsg.class)).as("device profile msg").hasSize(1); + assertThat(edgeImitator.findAllMessagesByType(AssetUpdateMsg.class)).as("asset update msg").hasSize(1); + assertThat(edgeImitator.findAllMessagesByType(UserUpdateMsg.class)).as("user update msg").hasSize(1); + assertThat(edgeImitator.findAllMessagesByType(AdminSettingsUpdateMsg.class)).as("admin setting update msg").hasSize(4); edgeImitator.allowIgnoredTypes(); try { @@ -720,4 +722,4 @@ public abstract class BaseEdgeControllerTest extends AbstractControllerTest { .andExpect(status().isOk()); } -} \ No newline at end of file +} diff --git a/application/src/test/java/org/thingsboard/server/edge/BaseEdgeTest.java b/application/src/test/java/org/thingsboard/server/edge/BaseEdgeTest.java index 2dea0d2811..c412e86ec6 100644 --- a/application/src/test/java/org/thingsboard/server/edge/BaseEdgeTest.java +++ b/application/src/test/java/org/thingsboard/server/edge/BaseEdgeTest.java @@ -767,7 +767,7 @@ abstract public class BaseEdgeTest extends AbstractControllerTest { edgeImitator.expectMessageAmount(1); doDelete("/api/alarm/" + savedAlarm.getId().getId().toString()) .andExpect(status().isOk()); - Assert.assertTrue(edgeImitator.waitForMessages(1)); + Assert.assertTrue(edgeImitator.waitForMessages()); latestMessage = edgeImitator.getLatestMessage(); Assert.assertTrue(latestMessage instanceof AlarmUpdateMsg); alarmUpdateMsg = (AlarmUpdateMsg) latestMessage; diff --git a/application/src/test/java/org/thingsboard/server/edge/imitator/EdgeImitator.java b/application/src/test/java/org/thingsboard/server/edge/imitator/EdgeImitator.java index e257f5c5d2..46ee981be1 100644 --- a/application/src/test/java/org/thingsboard/server/edge/imitator/EdgeImitator.java +++ b/application/src/test/java/org/thingsboard/server/edge/imitator/EdgeImitator.java @@ -65,6 +65,8 @@ import java.util.stream.Collectors; @Slf4j public class EdgeImitator { + public static final int TIMEOUT_IN_SECONDS = 30; + private String routingKey; private String routingSecret; @@ -293,7 +295,7 @@ public class EdgeImitator { } public boolean waitForMessages() throws InterruptedException { - return waitForMessages(5); + return waitForMessages(TIMEOUT_IN_SECONDS); } public boolean waitForMessages(int timeoutInSeconds) throws InterruptedException { @@ -308,7 +310,7 @@ public class EdgeImitator { } public boolean waitForResponses() throws InterruptedException { - return responsesLatch.await(5, TimeUnit.SECONDS); + return responsesLatch.await(TIMEOUT_IN_SECONDS, TimeUnit.SECONDS); } public void expectResponsesAmount(int messageAmount) { From ded203bd050af7735abe40e9418a47e6edbfa53c Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Mon, 20 Dec 2021 13:16:24 +0200 Subject: [PATCH 268/432] fixed names for edge test --- .../server/controller/BaseEdgeControllerTest.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/application/src/test/java/org/thingsboard/server/controller/BaseEdgeControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/BaseEdgeControllerTest.java index 4a7e362e75..326d1465c1 100644 --- a/application/src/test/java/org/thingsboard/server/controller/BaseEdgeControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/BaseEdgeControllerTest.java @@ -668,18 +668,18 @@ public abstract class BaseEdgeControllerTest extends AbstractControllerTest { } @Test - public void testSyncEdgeCE() throws Exception { - Edge edge = doPost("/api/edge", constructEdge("Test Sync Edge CE", "test"), Edge.class); + public void testSyncEdge() throws Exception { + Edge edge = doPost("/api/edge", constructEdge("Test Sync Edge", "test"), Edge.class); Device device = new Device(); - device.setName("Test Sync Edge CE Device 1"); + device.setName("Test Sync Edge Device 1"); device.setType("default"); Device savedDevice = doPost("/api/device", device, Device.class); doPost("/api/edge/" + edge.getId().getId().toString() + "/device/" + savedDevice.getId().getId().toString(), Device.class); Asset asset = new Asset(); - asset.setName("Test Sync Edge CE Asset 1"); + asset.setName("Test Sync Edge Asset 1"); asset.setType("test"); Asset savedAsset = doPost("/api/asset", asset, Asset.class); doPost("/api/edge/" + edge.getId().getId().toString() From c195fc2c2125769dc3b4e81094599c50d617877e Mon Sep 17 00:00:00 2001 From: dlandiak Date: Mon, 20 Dec 2021 14:23:50 +0200 Subject: [PATCH 269/432] queue factories improvements --- .../provider/AwsSqsMonolithQueueFactory.java | 8 +++---- .../provider/AwsSqsTbCoreQueueFactory.java | 18 +++++++++------- .../AwsSqsTbRuleEngineQueueFactory.java | 14 ++++++++----- .../provider/AwsSqsTransportQueueFactory.java | 17 +++++++++++---- .../provider/KafkaMonolithQueueFactory.java | 7 +++++-- .../provider/KafkaTbCoreQueueFactory.java | 19 +++++++++++------ .../KafkaTbRuleEngineQueueFactory.java | 20 +++++++++++------- .../provider/PubSubMonolithQueueFactory.java | 4 ++-- .../provider/PubSubTbCoreQueueFactory.java | 21 +++++++++++++++---- .../PubSubTbRuleEngineQueueFactory.java | 13 +++++++----- .../RabbitMqMonolithQueueFactory.java | 8 +++---- .../provider/RabbitMqTbCoreQueueFactory.java | 12 +++++++---- .../RabbitMqTbRuleEngineQueueFactory.java | 12 +++++++---- .../RabbitMqTransportQueueFactory.java | 10 ++++++--- .../ServiceBusMonolithQueueFactory.java | 4 ++-- .../ServiceBusTbCoreQueueFactory.java | 12 +++++++---- .../ServiceBusTbRuleEngineQueueFactory.java | 12 +++++++---- .../ServiceBusTransportQueueFactory.java | 11 +++++++++- 18 files changed, 150 insertions(+), 72 deletions(-) diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/AwsSqsMonolithQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/AwsSqsMonolithQueueFactory.java index 026f879c8d..f5a592e1c9 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/AwsSqsMonolithQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/AwsSqsMonolithQueueFactory.java @@ -102,7 +102,7 @@ public class AwsSqsMonolithQueueFactory implements TbCoreQueueFactory, TbRuleEng @Override public TbQueueProducer> createRuleEngineNotificationsMsgProducer() { - return new TbAwsSqsProducerTemplate<>(ruleEngineAdmin, sqsSettings, ruleEngineSettings.getTopic()); + return new TbAwsSqsProducerTemplate<>(notificationAdmin, sqsSettings, ruleEngineSettings.getTopic()); } @Override @@ -112,7 +112,7 @@ public class AwsSqsMonolithQueueFactory implements TbCoreQueueFactory, TbRuleEng @Override public TbQueueProducer> createTbCoreNotificationsMsgProducer() { - return new TbAwsSqsProducerTemplate<>(coreAdmin, sqsSettings, coreSettings.getTopic()); + return new TbAwsSqsProducerTemplate<>(notificationAdmin, sqsSettings, coreSettings.getTopic()); } @Override @@ -182,13 +182,13 @@ public class AwsSqsMonolithQueueFactory implements TbCoreQueueFactory, TbRuleEng @Override public TbQueueConsumer> createToUsageStatsServiceMsgConsumer() { - return new TbAwsSqsConsumerTemplate<>(transportApiAdmin, sqsSettings, coreSettings.getUsageStatsTopic(), + return new TbAwsSqsConsumerTemplate<>(coreAdmin, sqsSettings, coreSettings.getUsageStatsTopic(), msg -> new TbProtoQueueMsg<>(msg.getKey(), ToUsageStatsServiceMsg.parseFrom(msg.getData()), msg.getHeaders())); } @Override public TbQueueConsumer> createToOtaPackageStateServiceMsgConsumer() { - return new TbAwsSqsConsumerTemplate<>(transportApiAdmin, sqsSettings, coreSettings.getOtaPackageTopic(), + return new TbAwsSqsConsumerTemplate<>(coreAdmin, sqsSettings, coreSettings.getOtaPackageTopic(), msg -> new TbProtoQueueMsg<>(msg.getKey(), ToOtaPackageStateServiceMsg.parseFrom(msg.getData()), msg.getHeaders())); } diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/AwsSqsTbCoreQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/AwsSqsTbCoreQueueFactory.java index eaa73bc108..87ebe42024 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/AwsSqsTbCoreQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/AwsSqsTbCoreQueueFactory.java @@ -43,6 +43,7 @@ import org.thingsboard.server.queue.settings.TbQueueCoreSettings; import org.thingsboard.server.queue.settings.TbQueueRemoteJsInvokeSettings; import org.thingsboard.server.queue.settings.TbQueueRuleEngineSettings; import org.thingsboard.server.queue.settings.TbQueueTransportApiSettings; +import org.thingsboard.server.queue.settings.TbQueueTransportNotificationSettings; import org.thingsboard.server.queue.sqs.TbAwsSqsAdmin; import org.thingsboard.server.queue.sqs.TbAwsSqsConsumerTemplate; import org.thingsboard.server.queue.sqs.TbAwsSqsProducerTemplate; @@ -63,6 +64,7 @@ public class AwsSqsTbCoreQueueFactory implements TbCoreQueueFactory { private final PartitionService partitionService; private final TbServiceInfoProvider serviceInfoProvider; private final TbQueueRemoteJsInvokeSettings jsInvokeSettings; + private final TbQueueTransportNotificationSettings transportNotificationSettings; private final TbQueueAdmin coreAdmin; private final TbQueueAdmin ruleEngineAdmin; @@ -77,7 +79,8 @@ public class AwsSqsTbCoreQueueFactory implements TbCoreQueueFactory { PartitionService partitionService, TbServiceInfoProvider serviceInfoProvider, TbQueueRemoteJsInvokeSettings jsInvokeSettings, - TbAwsSqsQueueAttributes sqsQueueAttributes) { + TbAwsSqsQueueAttributes sqsQueueAttributes, + TbQueueTransportNotificationSettings transportNotificationSettings) { this.sqsSettings = sqsSettings; this.coreSettings = coreSettings; this.transportApiSettings = transportApiSettings; @@ -85,6 +88,7 @@ public class AwsSqsTbCoreQueueFactory implements TbCoreQueueFactory { this.partitionService = partitionService; this.serviceInfoProvider = serviceInfoProvider; this.jsInvokeSettings = jsInvokeSettings; + this.transportNotificationSettings = transportNotificationSettings; this.coreAdmin = new TbAwsSqsAdmin(sqsSettings, sqsQueueAttributes.getCoreAttributes()); this.ruleEngineAdmin = new TbAwsSqsAdmin(sqsSettings, sqsQueueAttributes.getRuleEngineAttributes()); @@ -95,7 +99,7 @@ public class AwsSqsTbCoreQueueFactory implements TbCoreQueueFactory { @Override public TbQueueProducer> createTransportNotificationsMsgProducer() { - return new TbAwsSqsProducerTemplate<>(coreAdmin, sqsSettings, coreSettings.getTopic()); + return new TbAwsSqsProducerTemplate<>(notificationAdmin, sqsSettings, transportNotificationSettings.getNotificationsTopic()); } @Override @@ -105,7 +109,7 @@ public class AwsSqsTbCoreQueueFactory implements TbCoreQueueFactory { @Override public TbQueueProducer> createRuleEngineNotificationsMsgProducer() { - return new TbAwsSqsProducerTemplate<>(ruleEngineAdmin, sqsSettings, ruleEngineSettings.getTopic()); + return new TbAwsSqsProducerTemplate<>(notificationAdmin, sqsSettings, ruleEngineSettings.getTopic()); } @Override @@ -115,7 +119,7 @@ public class AwsSqsTbCoreQueueFactory implements TbCoreQueueFactory { @Override public TbQueueProducer> createTbCoreNotificationsMsgProducer() { - return new TbAwsSqsProducerTemplate<>(coreAdmin, sqsSettings, coreSettings.getTopic()); + return new TbAwsSqsProducerTemplate<>(notificationAdmin, sqsSettings, coreSettings.getTopic()); } @Override @@ -139,7 +143,7 @@ public class AwsSqsTbCoreQueueFactory implements TbCoreQueueFactory { @Override public TbQueueProducer> createTransportApiResponseProducer() { - return new TbAwsSqsProducerTemplate<>(coreAdmin, sqsSettings, coreSettings.getTopic()); + return new TbAwsSqsProducerTemplate<>(transportApiAdmin, sqsSettings, transportApiSettings.getResponsesTopic()); } @Override @@ -172,13 +176,13 @@ public class AwsSqsTbCoreQueueFactory implements TbCoreQueueFactory { @Override public TbQueueConsumer> createToUsageStatsServiceMsgConsumer() { - return new TbAwsSqsConsumerTemplate<>(transportApiAdmin, sqsSettings, coreSettings.getUsageStatsTopic(), + return new TbAwsSqsConsumerTemplate<>(coreAdmin, sqsSettings, coreSettings.getUsageStatsTopic(), msg -> new TbProtoQueueMsg<>(msg.getKey(), ToUsageStatsServiceMsg.parseFrom(msg.getData()), msg.getHeaders())); } @Override public TbQueueConsumer> createToOtaPackageStateServiceMsgConsumer() { - return new TbAwsSqsConsumerTemplate<>(transportApiAdmin, sqsSettings, coreSettings.getOtaPackageTopic(), + return new TbAwsSqsConsumerTemplate<>(coreAdmin, sqsSettings, coreSettings.getOtaPackageTopic(), msg -> new TbProtoQueueMsg<>(msg.getKey(), ToOtaPackageStateServiceMsg.parseFrom(msg.getData()), msg.getHeaders())); } diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/AwsSqsTbRuleEngineQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/AwsSqsTbRuleEngineQueueFactory.java index 0e9f1812dd..05274625d3 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/AwsSqsTbRuleEngineQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/AwsSqsTbRuleEngineQueueFactory.java @@ -37,6 +37,7 @@ import org.thingsboard.server.queue.discovery.TbServiceInfoProvider; import org.thingsboard.server.queue.settings.TbQueueCoreSettings; import org.thingsboard.server.queue.settings.TbQueueRemoteJsInvokeSettings; import org.thingsboard.server.queue.settings.TbQueueRuleEngineSettings; +import org.thingsboard.server.queue.settings.TbQueueTransportNotificationSettings; import org.thingsboard.server.queue.settings.TbRuleEngineQueueConfiguration; import org.thingsboard.server.queue.sqs.TbAwsSqsAdmin; import org.thingsboard.server.queue.sqs.TbAwsSqsConsumerTemplate; @@ -57,6 +58,7 @@ public class AwsSqsTbRuleEngineQueueFactory implements TbRuleEngineQueueFactory private final TbQueueRuleEngineSettings ruleEngineSettings; private final TbAwsSqsSettings sqsSettings; private final TbQueueRemoteJsInvokeSettings jsInvokeSettings; + private final TbQueueTransportNotificationSettings transportNotificationSettings; private final TbQueueAdmin coreAdmin; private final TbQueueAdmin ruleEngineAdmin; @@ -68,13 +70,15 @@ public class AwsSqsTbRuleEngineQueueFactory implements TbRuleEngineQueueFactory TbServiceInfoProvider serviceInfoProvider, TbAwsSqsSettings sqsSettings, TbAwsSqsQueueAttributes sqsQueueAttributes, - TbQueueRemoteJsInvokeSettings jsInvokeSettings) { + TbQueueRemoteJsInvokeSettings jsInvokeSettings, + TbQueueTransportNotificationSettings transportNotificationSettings) { this.partitionService = partitionService; this.coreSettings = coreSettings; this.serviceInfoProvider = serviceInfoProvider; this.ruleEngineSettings = ruleEngineSettings; this.sqsSettings = sqsSettings; this.jsInvokeSettings = jsInvokeSettings; + this.transportNotificationSettings = transportNotificationSettings; this.coreAdmin = new TbAwsSqsAdmin(sqsSettings, sqsQueueAttributes.getCoreAttributes()); this.ruleEngineAdmin = new TbAwsSqsAdmin(sqsSettings, sqsQueueAttributes.getRuleEngineAttributes()); @@ -84,17 +88,17 @@ public class AwsSqsTbRuleEngineQueueFactory implements TbRuleEngineQueueFactory @Override public TbQueueProducer> createTransportNotificationsMsgProducer() { - return new TbAwsSqsProducerTemplate<>(coreAdmin, sqsSettings, coreSettings.getTopic()); + return new TbAwsSqsProducerTemplate<>(notificationAdmin, sqsSettings, transportNotificationSettings.getNotificationsTopic()); } @Override public TbQueueProducer> createRuleEngineMsgProducer() { - return new TbAwsSqsProducerTemplate<>(coreAdmin, sqsSettings, coreSettings.getTopic()); + return new TbAwsSqsProducerTemplate<>(ruleEngineAdmin, sqsSettings, ruleEngineSettings.getTopic()); } @Override public TbQueueProducer> createRuleEngineNotificationsMsgProducer() { - return new TbAwsSqsProducerTemplate<>(ruleEngineAdmin, sqsSettings, ruleEngineSettings.getTopic()); + return new TbAwsSqsProducerTemplate<>(notificationAdmin, sqsSettings, ruleEngineSettings.getTopic()); } @Override @@ -104,7 +108,7 @@ public class AwsSqsTbRuleEngineQueueFactory implements TbRuleEngineQueueFactory @Override public TbQueueProducer> createTbCoreNotificationsMsgProducer() { - return new TbAwsSqsProducerTemplate<>(coreAdmin, sqsSettings, coreSettings.getTopic()); + return new TbAwsSqsProducerTemplate<>(notificationAdmin, sqsSettings, coreSettings.getTopic()); } @Override diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/AwsSqsTransportQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/AwsSqsTransportQueueFactory.java index 689f2c041e..80f9e27d1c 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/AwsSqsTransportQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/AwsSqsTransportQueueFactory.java @@ -32,6 +32,7 @@ import org.thingsboard.server.queue.common.DefaultTbQueueRequestTemplate; import org.thingsboard.server.queue.common.TbProtoQueueMsg; import org.thingsboard.server.queue.discovery.TbServiceInfoProvider; import org.thingsboard.server.queue.settings.TbQueueCoreSettings; +import org.thingsboard.server.queue.settings.TbQueueRuleEngineSettings; import org.thingsboard.server.queue.settings.TbQueueTransportApiSettings; import org.thingsboard.server.queue.settings.TbQueueTransportNotificationSettings; import org.thingsboard.server.queue.sqs.TbAwsSqsAdmin; @@ -51,34 +52,39 @@ public class AwsSqsTransportQueueFactory implements TbTransportQueueFactory { private final TbAwsSqsSettings sqsSettings; private final TbQueueCoreSettings coreSettings; private final TbServiceInfoProvider serviceInfoProvider; + private final TbQueueRuleEngineSettings ruleEngineSettings; private final TbQueueAdmin coreAdmin; private final TbQueueAdmin transportApiAdmin; private final TbQueueAdmin notificationAdmin; + private final TbQueueAdmin ruleEngineAdmin; public AwsSqsTransportQueueFactory(TbQueueTransportApiSettings transportApiSettings, TbQueueTransportNotificationSettings transportNotificationSettings, TbAwsSqsSettings sqsSettings, TbServiceInfoProvider serviceInfoProvider, TbQueueCoreSettings coreSettings, - TbAwsSqsQueueAttributes sqsQueueAttributes) { + TbAwsSqsQueueAttributes sqsQueueAttributes, + TbQueueRuleEngineSettings ruleEngineSettings) { this.transportApiSettings = transportApiSettings; this.transportNotificationSettings = transportNotificationSettings; this.sqsSettings = sqsSettings; this.serviceInfoProvider = serviceInfoProvider; this.coreSettings = coreSettings; + this.ruleEngineSettings = ruleEngineSettings; this.coreAdmin = new TbAwsSqsAdmin(sqsSettings, sqsQueueAttributes.getCoreAttributes()); this.transportApiAdmin = new TbAwsSqsAdmin(sqsSettings, sqsQueueAttributes.getTransportApiAttributes()); this.notificationAdmin = new TbAwsSqsAdmin(sqsSettings, sqsQueueAttributes.getNotificationsAttributes()); + this.ruleEngineAdmin = new TbAwsSqsAdmin(sqsSettings, sqsQueueAttributes.getRuleEngineAttributes()); } @Override public TbQueueRequestTemplate, TbProtoQueueMsg> createTransportApiRequestTemplate() { - TbAwsSqsProducerTemplate> producerTemplate = + TbQueueProducer> producerTemplate = new TbAwsSqsProducerTemplate<>(transportApiAdmin, sqsSettings, transportApiSettings.getRequestsTopic()); - TbAwsSqsConsumerTemplate> consumerTemplate = + TbQueueConsumer> consumerTemplate = new TbAwsSqsConsumerTemplate<>(transportApiAdmin, sqsSettings, transportApiSettings.getResponsesTopic() + "_" + serviceInfoProvider.getServiceId(), msg -> new TbProtoQueueMsg<>(msg.getKey(), TransportApiResponseMsg.parseFrom(msg.getData()), msg.getHeaders())); @@ -96,7 +102,7 @@ public class AwsSqsTransportQueueFactory implements TbTransportQueueFactory { @Override public TbQueueProducer> createRuleEngineMsgProducer() { - return new TbAwsSqsProducerTemplate<>(transportApiAdmin, sqsSettings, transportApiSettings.getRequestsTopic()); + return new TbAwsSqsProducerTemplate<>(ruleEngineAdmin, sqsSettings, ruleEngineSettings.getTopic()); } @Override @@ -126,5 +132,8 @@ public class AwsSqsTransportQueueFactory implements TbTransportQueueFactory { if (notificationAdmin != null) { notificationAdmin.destroy(); } + if (ruleEngineAdmin != null) { + ruleEngineAdmin.destroy(); + } } } diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/KafkaMonolithQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/KafkaMonolithQueueFactory.java index e08be485ea..b4dd38217d 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/KafkaMonolithQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/KafkaMonolithQueueFactory.java @@ -131,7 +131,7 @@ public class KafkaMonolithQueueFactory implements TbCoreQueueFactory, TbRuleEngi requestBuilder.settings(kafkaSettings); requestBuilder.clientId("monolith-rule-engine-notifications-" + serviceInfoProvider.getServiceId()); requestBuilder.defaultTopic(ruleEngineSettings.getTopic()); - requestBuilder.admin(ruleEngineAdmin); + requestBuilder.admin(notificationAdmin); return requestBuilder.build(); } @@ -151,7 +151,7 @@ public class KafkaMonolithQueueFactory implements TbCoreQueueFactory, TbRuleEngi requestBuilder.settings(kafkaSettings); requestBuilder.clientId("monolith-core-notifications-" + serviceInfoProvider.getServiceId()); requestBuilder.defaultTopic(coreSettings.getTopic()); - requestBuilder.admin(coreAdmin); + requestBuilder.admin(notificationAdmin); return requestBuilder.build(); } @@ -328,5 +328,8 @@ public class KafkaMonolithQueueFactory implements TbCoreQueueFactory, TbRuleEngi if (notificationAdmin != null) { notificationAdmin.destroy(); } + if (fwUpdatesAdmin != null) { + fwUpdatesAdmin.destroy(); + } } } diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/KafkaTbCoreQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/KafkaTbCoreQueueFactory.java index bec01c7201..f560fcc5f4 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/KafkaTbCoreQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/KafkaTbCoreQueueFactory.java @@ -49,6 +49,7 @@ import org.thingsboard.server.queue.settings.TbQueueCoreSettings; import org.thingsboard.server.queue.settings.TbQueueRemoteJsInvokeSettings; import org.thingsboard.server.queue.settings.TbQueueRuleEngineSettings; import org.thingsboard.server.queue.settings.TbQueueTransportApiSettings; +import org.thingsboard.server.queue.settings.TbQueueTransportNotificationSettings; import javax.annotation.PreDestroy; import java.nio.charset.StandardCharsets; @@ -65,6 +66,7 @@ public class KafkaTbCoreQueueFactory implements TbCoreQueueFactory { private final TbQueueTransportApiSettings transportApiSettings; private final TbQueueRemoteJsInvokeSettings jsInvokeSettings; private final TbKafkaConsumerStatsService consumerStatsService; + private final TbQueueTransportNotificationSettings transportNotificationSettings; private final TbQueueAdmin coreAdmin; private final TbQueueAdmin ruleEngineAdmin; @@ -80,6 +82,7 @@ public class KafkaTbCoreQueueFactory implements TbCoreQueueFactory { TbQueueTransportApiSettings transportApiSettings, TbQueueRemoteJsInvokeSettings jsInvokeSettings, TbKafkaConsumerStatsService consumerStatsService, + TbQueueTransportNotificationSettings transportNotificationSettings, TbKafkaTopicConfigs kafkaTopicConfigs) { this.partitionService = partitionService; this.kafkaSettings = kafkaSettings; @@ -89,6 +92,7 @@ public class KafkaTbCoreQueueFactory implements TbCoreQueueFactory { this.transportApiSettings = transportApiSettings; this.jsInvokeSettings = jsInvokeSettings; this.consumerStatsService = consumerStatsService; + this.transportNotificationSettings = transportNotificationSettings; this.coreAdmin = new TbKafkaAdmin(kafkaSettings, kafkaTopicConfigs.getCoreConfigs()); this.ruleEngineAdmin = new TbKafkaAdmin(kafkaSettings, kafkaTopicConfigs.getRuleEngineConfigs()); @@ -103,8 +107,8 @@ public class KafkaTbCoreQueueFactory implements TbCoreQueueFactory { TbKafkaProducerTemplate.TbKafkaProducerTemplateBuilder> requestBuilder = TbKafkaProducerTemplate.builder(); requestBuilder.settings(kafkaSettings); requestBuilder.clientId("tb-core-transport-notifications-" + serviceInfoProvider.getServiceId()); - requestBuilder.defaultTopic(coreSettings.getTopic()); - requestBuilder.admin(coreAdmin); + requestBuilder.defaultTopic(transportNotificationSettings.getNotificationsTopic()); + requestBuilder.admin(notificationAdmin); return requestBuilder.build(); } @@ -124,7 +128,7 @@ public class KafkaTbCoreQueueFactory implements TbCoreQueueFactory { requestBuilder.settings(kafkaSettings); requestBuilder.clientId("tb-core-rule-engine-notifications-" + serviceInfoProvider.getServiceId()); requestBuilder.defaultTopic(ruleEngineSettings.getTopic()); - requestBuilder.admin(ruleEngineAdmin); + requestBuilder.admin(notificationAdmin); return requestBuilder.build(); } @@ -144,7 +148,7 @@ public class KafkaTbCoreQueueFactory implements TbCoreQueueFactory { requestBuilder.settings(kafkaSettings); requestBuilder.clientId("tb-core-to-core-notifications-" + serviceInfoProvider.getServiceId()); requestBuilder.defaultTopic(coreSettings.getTopic()); - requestBuilder.admin(coreAdmin); + requestBuilder.admin(notificationAdmin); return requestBuilder.build(); } @@ -192,8 +196,8 @@ public class KafkaTbCoreQueueFactory implements TbCoreQueueFactory { TbKafkaProducerTemplate.TbKafkaProducerTemplateBuilder> requestBuilder = TbKafkaProducerTemplate.builder(); requestBuilder.settings(kafkaSettings); requestBuilder.clientId("tb-core-transport-api-producer-" + serviceInfoProvider.getServiceId()); - requestBuilder.defaultTopic(coreSettings.getTopic()); - requestBuilder.admin(coreAdmin); + requestBuilder.defaultTopic(transportApiSettings.getResponsesTopic()); + requestBuilder.admin(transportApiAdmin); return requestBuilder.build(); } @@ -294,5 +298,8 @@ public class KafkaTbCoreQueueFactory implements TbCoreQueueFactory { if (notificationAdmin != null) { notificationAdmin.destroy(); } + if (fwUpdatesAdmin != null) { + fwUpdatesAdmin.destroy(); + } } } diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/KafkaTbRuleEngineQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/KafkaTbRuleEngineQueueFactory.java index 58bc38d3a9..dc3db14ec2 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/KafkaTbRuleEngineQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/KafkaTbRuleEngineQueueFactory.java @@ -46,6 +46,7 @@ import org.thingsboard.server.queue.kafka.TbKafkaTopicConfigs; import org.thingsboard.server.queue.settings.TbQueueCoreSettings; import org.thingsboard.server.queue.settings.TbQueueRemoteJsInvokeSettings; import org.thingsboard.server.queue.settings.TbQueueRuleEngineSettings; +import org.thingsboard.server.queue.settings.TbQueueTransportNotificationSettings; import org.thingsboard.server.queue.settings.TbRuleEngineQueueConfiguration; import javax.annotation.PreDestroy; @@ -63,6 +64,7 @@ public class KafkaTbRuleEngineQueueFactory implements TbRuleEngineQueueFactory { private final TbQueueRuleEngineSettings ruleEngineSettings; private final TbQueueRemoteJsInvokeSettings jsInvokeSettings; private final TbKafkaConsumerStatsService consumerStatsService; + private final TbQueueTransportNotificationSettings transportNotificationSettings; private final TbQueueAdmin coreAdmin; private final TbQueueAdmin ruleEngineAdmin; @@ -77,6 +79,7 @@ public class KafkaTbRuleEngineQueueFactory implements TbRuleEngineQueueFactory { TbQueueRuleEngineSettings ruleEngineSettings, TbQueueRemoteJsInvokeSettings jsInvokeSettings, TbKafkaConsumerStatsService consumerStatsService, + TbQueueTransportNotificationSettings transportNotificationSettings, TbKafkaTopicConfigs kafkaTopicConfigs) { this.partitionService = partitionService; this.kafkaSettings = kafkaSettings; @@ -85,6 +88,7 @@ public class KafkaTbRuleEngineQueueFactory implements TbRuleEngineQueueFactory { this.ruleEngineSettings = ruleEngineSettings; this.jsInvokeSettings = jsInvokeSettings; this.consumerStatsService = consumerStatsService; + this.transportNotificationSettings = transportNotificationSettings; this.coreAdmin = new TbKafkaAdmin(kafkaSettings, kafkaTopicConfigs.getCoreConfigs()); this.ruleEngineAdmin = new TbKafkaAdmin(kafkaSettings, kafkaTopicConfigs.getRuleEngineConfigs()); @@ -98,8 +102,8 @@ public class KafkaTbRuleEngineQueueFactory implements TbRuleEngineQueueFactory { TbKafkaProducerTemplate.TbKafkaProducerTemplateBuilder> requestBuilder = TbKafkaProducerTemplate.builder(); requestBuilder.settings(kafkaSettings); requestBuilder.clientId("tb-rule-engine-transport-notifications-" + serviceInfoProvider.getServiceId()); - requestBuilder.defaultTopic(coreSettings.getTopic()); - requestBuilder.admin(coreAdmin); + requestBuilder.defaultTopic(transportNotificationSettings.getNotificationsTopic()); + requestBuilder.admin(notificationAdmin); return requestBuilder.build(); } @@ -108,8 +112,8 @@ public class KafkaTbRuleEngineQueueFactory implements TbRuleEngineQueueFactory { TbKafkaProducerTemplate.TbKafkaProducerTemplateBuilder> requestBuilder = TbKafkaProducerTemplate.builder(); requestBuilder.settings(kafkaSettings); requestBuilder.clientId("tb-rule-engine-to-rule-engine-" + serviceInfoProvider.getServiceId()); - requestBuilder.defaultTopic(coreSettings.getTopic()); - requestBuilder.admin(coreAdmin); + requestBuilder.defaultTopic(ruleEngineSettings.getTopic()); + requestBuilder.admin(ruleEngineAdmin); return requestBuilder.build(); } @@ -119,11 +123,10 @@ public class KafkaTbRuleEngineQueueFactory implements TbRuleEngineQueueFactory { requestBuilder.settings(kafkaSettings); requestBuilder.clientId("tb-rule-engine-to-rule-engine-notifications-" + serviceInfoProvider.getServiceId()); requestBuilder.defaultTopic(ruleEngineSettings.getTopic()); - requestBuilder.admin(ruleEngineAdmin); + requestBuilder.admin(notificationAdmin); return requestBuilder.build(); } - @Override public TbQueueProducer> createTbCoreMsgProducer() { TbKafkaProducerTemplate.TbKafkaProducerTemplateBuilder> requestBuilder = TbKafkaProducerTemplate.builder(); @@ -150,7 +153,7 @@ public class KafkaTbRuleEngineQueueFactory implements TbRuleEngineQueueFactory { requestBuilder.settings(kafkaSettings); requestBuilder.clientId("tb-rule-engine-to-core-notifications-" + serviceInfoProvider.getServiceId()); requestBuilder.defaultTopic(coreSettings.getTopic()); - requestBuilder.admin(coreAdmin); + requestBuilder.admin(notificationAdmin); return requestBuilder.build(); } @@ -239,5 +242,8 @@ public class KafkaTbRuleEngineQueueFactory implements TbRuleEngineQueueFactory { if (notificationAdmin != null) { notificationAdmin.destroy(); } + if (fwUpdatesAdmin != null) { + fwUpdatesAdmin.destroy(); + } } } diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/PubSubMonolithQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/PubSubMonolithQueueFactory.java index 1d2f36c5c2..d22839b9be 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/PubSubMonolithQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/PubSubMonolithQueueFactory.java @@ -112,7 +112,7 @@ public class PubSubMonolithQueueFactory implements TbCoreQueueFactory, TbRuleEng @Override public TbQueueProducer> createRuleEngineNotificationsMsgProducer() { - return new TbPubSubProducerTemplate<>(ruleEngineAdmin, pubSubSettings, ruleEngineSettings.getTopic()); + return new TbPubSubProducerTemplate<>(notificationAdmin, pubSubSettings, ruleEngineSettings.getTopic()); } @Override @@ -122,7 +122,7 @@ public class PubSubMonolithQueueFactory implements TbCoreQueueFactory, TbRuleEng @Override public TbQueueProducer> createTbCoreNotificationsMsgProducer() { - return new TbPubSubProducerTemplate<>(coreAdmin, pubSubSettings, coreSettings.getTopic()); + return new TbPubSubProducerTemplate<>(notificationAdmin, pubSubSettings, coreSettings.getTopic()); } @Override diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/PubSubTbCoreQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/PubSubTbCoreQueueFactory.java index 65ea183d66..086c4d9420 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/PubSubTbCoreQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/PubSubTbCoreQueueFactory.java @@ -46,7 +46,9 @@ import org.thingsboard.server.queue.pubsub.TbPubSubSettings; import org.thingsboard.server.queue.pubsub.TbPubSubSubscriptionSettings; import org.thingsboard.server.queue.settings.TbQueueCoreSettings; import org.thingsboard.server.queue.settings.TbQueueRemoteJsInvokeSettings; +import org.thingsboard.server.queue.settings.TbQueueRuleEngineSettings; import org.thingsboard.server.queue.settings.TbQueueTransportApiSettings; +import org.thingsboard.server.queue.settings.TbQueueTransportNotificationSettings; import javax.annotation.PreDestroy; import java.nio.charset.StandardCharsets; @@ -61,11 +63,14 @@ public class PubSubTbCoreQueueFactory implements TbCoreQueueFactory { private final PartitionService partitionService; private final TbServiceInfoProvider serviceInfoProvider; private final TbQueueRemoteJsInvokeSettings jsInvokeSettings; + private final TbQueueTransportNotificationSettings transportNotificationSettings; + private final TbQueueRuleEngineSettings ruleEngineSettings; private final TbQueueAdmin coreAdmin; private final TbQueueAdmin jsExecutorAdmin; private final TbQueueAdmin transportApiAdmin; private final TbQueueAdmin notificationAdmin; + private final TbQueueAdmin ruleEngineAdmin; public PubSubTbCoreQueueFactory(TbPubSubSettings pubSubSettings, TbQueueCoreSettings coreSettings, @@ -73,6 +78,8 @@ public class PubSubTbCoreQueueFactory implements TbCoreQueueFactory { PartitionService partitionService, TbServiceInfoProvider serviceInfoProvider, TbQueueRemoteJsInvokeSettings jsInvokeSettings, + TbQueueTransportNotificationSettings transportNotificationSettings, + TbQueueRuleEngineSettings ruleEngineSettings, TbPubSubSubscriptionSettings pubSubSubscriptionSettings) { this.pubSubSettings = pubSubSettings; this.coreSettings = coreSettings; @@ -80,16 +87,19 @@ public class PubSubTbCoreQueueFactory implements TbCoreQueueFactory { this.partitionService = partitionService; this.serviceInfoProvider = serviceInfoProvider; this.jsInvokeSettings = jsInvokeSettings; + this.transportNotificationSettings = transportNotificationSettings; + this.ruleEngineSettings = ruleEngineSettings; this.coreAdmin = new TbPubSubAdmin(pubSubSettings, pubSubSubscriptionSettings.getCoreSettings()); this.jsExecutorAdmin = new TbPubSubAdmin(pubSubSettings, pubSubSubscriptionSettings.getJsExecutorSettings()); this.transportApiAdmin = new TbPubSubAdmin(pubSubSettings, pubSubSubscriptionSettings.getTransportApiSettings()); this.notificationAdmin = new TbPubSubAdmin(pubSubSettings, pubSubSubscriptionSettings.getNotificationsSettings()); + this.ruleEngineAdmin = new TbPubSubAdmin(pubSubSettings, pubSubSubscriptionSettings.getRuleEngineSettings()); } @Override public TbQueueProducer> createTransportNotificationsMsgProducer() { - return new TbPubSubProducerTemplate<>(coreAdmin, pubSubSettings, coreSettings.getTopic()); + return new TbPubSubProducerTemplate<>(notificationAdmin, pubSubSettings, transportNotificationSettings.getNotificationsTopic()); } @Override @@ -99,7 +109,7 @@ public class PubSubTbCoreQueueFactory implements TbCoreQueueFactory { @Override public TbQueueProducer> createRuleEngineNotificationsMsgProducer() { - return new TbPubSubProducerTemplate<>(coreAdmin, pubSubSettings, coreSettings.getTopic()); + return new TbPubSubProducerTemplate<>(notificationAdmin, pubSubSettings, ruleEngineSettings.getTopic()); } @Override @@ -109,7 +119,7 @@ public class PubSubTbCoreQueueFactory implements TbCoreQueueFactory { @Override public TbQueueProducer> createTbCoreNotificationsMsgProducer() { - return new TbPubSubProducerTemplate<>(coreAdmin, pubSubSettings, coreSettings.getTopic()); + return new TbPubSubProducerTemplate<>(notificationAdmin, pubSubSettings, coreSettings.getTopic()); } @Override @@ -133,7 +143,7 @@ public class PubSubTbCoreQueueFactory implements TbCoreQueueFactory { @Override public TbQueueProducer> createTransportApiResponseProducer() { - return new TbPubSubProducerTemplate<>(coreAdmin, pubSubSettings, coreSettings.getTopic()); + return new TbPubSubProducerTemplate<>(transportApiAdmin, pubSubSettings, transportApiSettings.getResponsesTopic()); } @Override @@ -195,5 +205,8 @@ public class PubSubTbCoreQueueFactory implements TbCoreQueueFactory { if (notificationAdmin != null) { notificationAdmin.destroy(); } + if (ruleEngineAdmin != null) { + ruleEngineAdmin.destroy(); + } } } diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/PubSubTbRuleEngineQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/PubSubTbRuleEngineQueueFactory.java index b02322496f..f8f190853d 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/PubSubTbRuleEngineQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/PubSubTbRuleEngineQueueFactory.java @@ -45,6 +45,7 @@ import org.thingsboard.server.queue.pubsub.TbPubSubSubscriptionSettings; import org.thingsboard.server.queue.settings.TbQueueCoreSettings; import org.thingsboard.server.queue.settings.TbQueueRemoteJsInvokeSettings; import org.thingsboard.server.queue.settings.TbQueueRuleEngineSettings; +import org.thingsboard.server.queue.settings.TbQueueTransportNotificationSettings; import org.thingsboard.server.queue.settings.TbRuleEngineQueueConfiguration; import javax.annotation.PreDestroy; @@ -60,6 +61,7 @@ public class PubSubTbRuleEngineQueueFactory implements TbRuleEngineQueueFactory private final PartitionService partitionService; private final TbServiceInfoProvider serviceInfoProvider; private final TbQueueRemoteJsInvokeSettings jsInvokeSettings; + private final TbQueueTransportNotificationSettings transportNotificationSettings; private final TbQueueAdmin coreAdmin; private final TbQueueAdmin ruleEngineAdmin; @@ -72,6 +74,7 @@ public class PubSubTbRuleEngineQueueFactory implements TbRuleEngineQueueFactory PartitionService partitionService, TbServiceInfoProvider serviceInfoProvider, TbQueueRemoteJsInvokeSettings jsInvokeSettings, + TbQueueTransportNotificationSettings transportNotificationSettings, TbPubSubSubscriptionSettings pubSubSubscriptionSettings) { this.pubSubSettings = pubSubSettings; this.coreSettings = coreSettings; @@ -79,6 +82,7 @@ public class PubSubTbRuleEngineQueueFactory implements TbRuleEngineQueueFactory this.partitionService = partitionService; this.serviceInfoProvider = serviceInfoProvider; this.jsInvokeSettings = jsInvokeSettings; + this.transportNotificationSettings = transportNotificationSettings; this.coreAdmin = new TbPubSubAdmin(pubSubSettings, pubSubSubscriptionSettings.getCoreSettings()); this.ruleEngineAdmin = new TbPubSubAdmin(pubSubSettings, pubSubSubscriptionSettings.getRuleEngineSettings()); @@ -88,28 +92,27 @@ public class PubSubTbRuleEngineQueueFactory implements TbRuleEngineQueueFactory @Override public TbQueueProducer> createTransportNotificationsMsgProducer() { - return new TbPubSubProducerTemplate<>(coreAdmin, pubSubSettings, coreSettings.getTopic()); + return new TbPubSubProducerTemplate<>(notificationAdmin, pubSubSettings, transportNotificationSettings.getNotificationsTopic()); } @Override public TbQueueProducer> createRuleEngineMsgProducer() { - return new TbPubSubProducerTemplate<>(coreAdmin, pubSubSettings, coreSettings.getTopic()); + return new TbPubSubProducerTemplate<>(ruleEngineAdmin, pubSubSettings, ruleEngineSettings.getTopic()); } @Override public TbQueueProducer> createRuleEngineNotificationsMsgProducer() { - return new TbPubSubProducerTemplate<>(ruleEngineAdmin, pubSubSettings, ruleEngineSettings.getTopic()); + return new TbPubSubProducerTemplate<>(notificationAdmin, pubSubSettings, ruleEngineSettings.getTopic()); } @Override public TbQueueProducer> createTbCoreMsgProducer() { return new TbPubSubProducerTemplate<>(coreAdmin, pubSubSettings, coreSettings.getTopic()); - } @Override public TbQueueProducer> createTbCoreNotificationsMsgProducer() { - return new TbPubSubProducerTemplate<>(coreAdmin, pubSubSettings, coreSettings.getTopic()); + return new TbPubSubProducerTemplate<>(notificationAdmin, pubSubSettings, coreSettings.getTopic()); } @Override diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/RabbitMqMonolithQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/RabbitMqMonolithQueueFactory.java index 7d48803258..e8ec6e4cff 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/RabbitMqMonolithQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/RabbitMqMonolithQueueFactory.java @@ -66,13 +66,13 @@ public class RabbitMqMonolithQueueFactory implements TbCoreQueueFactory, TbRuleE private final TbQueueTransportApiSettings transportApiSettings; private final TbQueueTransportNotificationSettings transportNotificationSettings; private final TbRabbitMqSettings rabbitMqSettings; + private final TbQueueRemoteJsInvokeSettings jsInvokeSettings; private final TbQueueAdmin coreAdmin; private final TbQueueAdmin ruleEngineAdmin; private final TbQueueAdmin jsExecutorAdmin; private final TbQueueAdmin transportApiAdmin; private final TbQueueAdmin notificationAdmin; - private final TbQueueRemoteJsInvokeSettings jsInvokeSettings; public RabbitMqMonolithQueueFactory(PartitionService partitionService, TbQueueCoreSettings coreSettings, TbQueueRuleEngineSettings ruleEngineSettings, @@ -89,13 +89,13 @@ public class RabbitMqMonolithQueueFactory implements TbCoreQueueFactory, TbRuleE this.transportApiSettings = transportApiSettings; this.transportNotificationSettings = transportNotificationSettings; this.rabbitMqSettings = rabbitMqSettings; + this.jsInvokeSettings = jsInvokeSettings; this.coreAdmin = new TbRabbitMqAdmin(rabbitMqSettings, queueArguments.getCoreArgs()); this.ruleEngineAdmin = new TbRabbitMqAdmin(rabbitMqSettings, queueArguments.getRuleEngineArgs()); this.jsExecutorAdmin = new TbRabbitMqAdmin(rabbitMqSettings, queueArguments.getJsExecutorArgs()); this.transportApiAdmin = new TbRabbitMqAdmin(rabbitMqSettings, queueArguments.getTransportApiArgs()); this.notificationAdmin = new TbRabbitMqAdmin(rabbitMqSettings, queueArguments.getNotificationsArgs()); - this.jsInvokeSettings = jsInvokeSettings; } @Override @@ -110,7 +110,7 @@ public class RabbitMqMonolithQueueFactory implements TbCoreQueueFactory, TbRuleE @Override public TbQueueProducer> createRuleEngineNotificationsMsgProducer() { - return new TbRabbitMqProducerTemplate<>(ruleEngineAdmin, rabbitMqSettings, ruleEngineSettings.getTopic()); + return new TbRabbitMqProducerTemplate<>(notificationAdmin, rabbitMqSettings, ruleEngineSettings.getTopic()); } @Override @@ -120,7 +120,7 @@ public class RabbitMqMonolithQueueFactory implements TbCoreQueueFactory, TbRuleE @Override public TbQueueProducer> createTbCoreNotificationsMsgProducer() { - return new TbRabbitMqProducerTemplate<>(coreAdmin, rabbitMqSettings, coreSettings.getTopic()); + return new TbRabbitMqProducerTemplate<>(notificationAdmin, rabbitMqSettings, coreSettings.getTopic()); } @Override diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/RabbitMqTbCoreQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/RabbitMqTbCoreQueueFactory.java index c0abeab162..303180bad6 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/RabbitMqTbCoreQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/RabbitMqTbCoreQueueFactory.java @@ -48,6 +48,7 @@ import org.thingsboard.server.queue.settings.TbQueueCoreSettings; import org.thingsboard.server.queue.settings.TbQueueRemoteJsInvokeSettings; import org.thingsboard.server.queue.settings.TbQueueRuleEngineSettings; import org.thingsboard.server.queue.settings.TbQueueTransportApiSettings; +import org.thingsboard.server.queue.settings.TbQueueTransportNotificationSettings; import javax.annotation.PreDestroy; import java.nio.charset.StandardCharsets; @@ -63,6 +64,7 @@ public class RabbitMqTbCoreQueueFactory implements TbCoreQueueFactory { private final PartitionService partitionService; private final TbServiceInfoProvider serviceInfoProvider; private final TbQueueRemoteJsInvokeSettings jsInvokeSettings; + private final TbQueueTransportNotificationSettings transportNotificationSettings; private final TbQueueAdmin coreAdmin; private final TbQueueAdmin ruleEngineAdmin; @@ -77,6 +79,7 @@ public class RabbitMqTbCoreQueueFactory implements TbCoreQueueFactory { PartitionService partitionService, TbServiceInfoProvider serviceInfoProvider, TbQueueRemoteJsInvokeSettings jsInvokeSettings, + TbQueueTransportNotificationSettings transportNotificationSettings, TbRabbitMqQueueArguments queueArguments) { this.rabbitMqSettings = rabbitMqSettings; this.coreSettings = coreSettings; @@ -85,6 +88,7 @@ public class RabbitMqTbCoreQueueFactory implements TbCoreQueueFactory { this.partitionService = partitionService; this.serviceInfoProvider = serviceInfoProvider; this.jsInvokeSettings = jsInvokeSettings; + this.transportNotificationSettings = transportNotificationSettings; this.coreAdmin = new TbRabbitMqAdmin(rabbitMqSettings, queueArguments.getCoreArgs()); this.ruleEngineAdmin = new TbRabbitMqAdmin(rabbitMqSettings, queueArguments.getRuleEngineArgs()); @@ -95,7 +99,7 @@ public class RabbitMqTbCoreQueueFactory implements TbCoreQueueFactory { @Override public TbQueueProducer> createTransportNotificationsMsgProducer() { - return new TbRabbitMqProducerTemplate<>(coreAdmin, rabbitMqSettings, coreSettings.getTopic()); + return new TbRabbitMqProducerTemplate<>(notificationAdmin, rabbitMqSettings, transportNotificationSettings.getNotificationsTopic()); } @Override @@ -105,7 +109,7 @@ public class RabbitMqTbCoreQueueFactory implements TbCoreQueueFactory { @Override public TbQueueProducer> createRuleEngineNotificationsMsgProducer() { - return new TbRabbitMqProducerTemplate<>(ruleEngineAdmin, rabbitMqSettings, ruleEngineSettings.getTopic()); + return new TbRabbitMqProducerTemplate<>(notificationAdmin, rabbitMqSettings, ruleEngineSettings.getTopic()); } @Override @@ -115,7 +119,7 @@ public class RabbitMqTbCoreQueueFactory implements TbCoreQueueFactory { @Override public TbQueueProducer> createTbCoreNotificationsMsgProducer() { - return new TbRabbitMqProducerTemplate<>(coreAdmin, rabbitMqSettings, coreSettings.getTopic()); + return new TbRabbitMqProducerTemplate<>(notificationAdmin, rabbitMqSettings, coreSettings.getTopic()); } @Override @@ -139,7 +143,7 @@ public class RabbitMqTbCoreQueueFactory implements TbCoreQueueFactory { @Override public TbQueueProducer> createTransportApiResponseProducer() { - return new TbRabbitMqProducerTemplate<>(coreAdmin, rabbitMqSettings, coreSettings.getTopic()); + return new TbRabbitMqProducerTemplate<>(transportApiAdmin, rabbitMqSettings, transportApiSettings.getResponsesTopic()); } @Override diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/RabbitMqTbRuleEngineQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/RabbitMqTbRuleEngineQueueFactory.java index 2f8a3ed655..470e4a8785 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/RabbitMqTbRuleEngineQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/RabbitMqTbRuleEngineQueueFactory.java @@ -45,6 +45,7 @@ import org.thingsboard.server.queue.rabbitmq.TbRabbitMqSettings; import org.thingsboard.server.queue.settings.TbQueueCoreSettings; import org.thingsboard.server.queue.settings.TbQueueRemoteJsInvokeSettings; import org.thingsboard.server.queue.settings.TbQueueRuleEngineSettings; +import org.thingsboard.server.queue.settings.TbQueueTransportNotificationSettings; import org.thingsboard.server.queue.settings.TbRuleEngineQueueConfiguration; import javax.annotation.PreDestroy; @@ -60,6 +61,7 @@ public class RabbitMqTbRuleEngineQueueFactory implements TbRuleEngineQueueFactor private final TbQueueRuleEngineSettings ruleEngineSettings; private final TbRabbitMqSettings rabbitMqSettings; private final TbQueueRemoteJsInvokeSettings jsInvokeSettings; + private final TbQueueTransportNotificationSettings transportNotificationSettings; private final TbQueueAdmin coreAdmin; private final TbQueueAdmin ruleEngineAdmin; @@ -71,6 +73,7 @@ public class RabbitMqTbRuleEngineQueueFactory implements TbRuleEngineQueueFactor TbServiceInfoProvider serviceInfoProvider, TbRabbitMqSettings rabbitMqSettings, TbQueueRemoteJsInvokeSettings jsInvokeSettings, + TbQueueTransportNotificationSettings transportNotificationSettings, TbRabbitMqQueueArguments queueArguments) { this.partitionService = partitionService; this.coreSettings = coreSettings; @@ -78,6 +81,7 @@ public class RabbitMqTbRuleEngineQueueFactory implements TbRuleEngineQueueFactor this.ruleEngineSettings = ruleEngineSettings; this.rabbitMqSettings = rabbitMqSettings; this.jsInvokeSettings = jsInvokeSettings; + this.transportNotificationSettings = transportNotificationSettings; this.coreAdmin = new TbRabbitMqAdmin(rabbitMqSettings, queueArguments.getCoreArgs()); this.ruleEngineAdmin = new TbRabbitMqAdmin(rabbitMqSettings, queueArguments.getRuleEngineArgs()); @@ -87,17 +91,17 @@ public class RabbitMqTbRuleEngineQueueFactory implements TbRuleEngineQueueFactor @Override public TbQueueProducer> createTransportNotificationsMsgProducer() { - return new TbRabbitMqProducerTemplate<>(coreAdmin, rabbitMqSettings, coreSettings.getTopic()); + return new TbRabbitMqProducerTemplate<>(notificationAdmin, rabbitMqSettings, transportNotificationSettings.getNotificationsTopic()); } @Override public TbQueueProducer> createRuleEngineMsgProducer() { - return new TbRabbitMqProducerTemplate<>(coreAdmin, rabbitMqSettings, coreSettings.getTopic()); + return new TbRabbitMqProducerTemplate<>(ruleEngineAdmin, rabbitMqSettings, ruleEngineSettings.getTopic()); } @Override public TbQueueProducer> createRuleEngineNotificationsMsgProducer() { - return new TbRabbitMqProducerTemplate<>(ruleEngineAdmin, rabbitMqSettings, ruleEngineSettings.getTopic()); + return new TbRabbitMqProducerTemplate<>(notificationAdmin, rabbitMqSettings, ruleEngineSettings.getTopic()); } @Override @@ -107,7 +111,7 @@ public class RabbitMqTbRuleEngineQueueFactory implements TbRuleEngineQueueFactor @Override public TbQueueProducer> createTbCoreNotificationsMsgProducer() { - return new TbRabbitMqProducerTemplate<>(coreAdmin, rabbitMqSettings, coreSettings.getTopic()); + return new TbRabbitMqProducerTemplate<>(notificationAdmin, rabbitMqSettings, coreSettings.getTopic()); } @Override diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/RabbitMqTransportQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/RabbitMqTransportQueueFactory.java index ec27a3ed04..e40816b242 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/RabbitMqTransportQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/RabbitMqTransportQueueFactory.java @@ -37,6 +37,7 @@ import org.thingsboard.server.queue.rabbitmq.TbRabbitMqProducerTemplate; import org.thingsboard.server.queue.rabbitmq.TbRabbitMqQueueArguments; import org.thingsboard.server.queue.rabbitmq.TbRabbitMqSettings; import org.thingsboard.server.queue.settings.TbQueueCoreSettings; +import org.thingsboard.server.queue.settings.TbQueueRuleEngineSettings; import org.thingsboard.server.queue.settings.TbQueueTransportApiSettings; import org.thingsboard.server.queue.settings.TbQueueTransportNotificationSettings; @@ -51,6 +52,7 @@ public class RabbitMqTransportQueueFactory implements TbTransportQueueFactory { private final TbRabbitMqSettings rabbitMqSettings; private final TbServiceInfoProvider serviceInfoProvider; private final TbQueueCoreSettings coreSettings; + private final TbQueueRuleEngineSettings ruleEngineSettings; private final TbQueueAdmin coreAdmin; private final TbQueueAdmin ruleEngineAdmin; @@ -62,12 +64,14 @@ public class RabbitMqTransportQueueFactory implements TbTransportQueueFactory { TbRabbitMqSettings rabbitMqSettings, TbServiceInfoProvider serviceInfoProvider, TbQueueCoreSettings coreSettings, + TbQueueRuleEngineSettings ruleEngineSettings, TbRabbitMqQueueArguments queueArguments) { this.transportApiSettings = transportApiSettings; this.transportNotificationSettings = transportNotificationSettings; this.rabbitMqSettings = rabbitMqSettings; this.serviceInfoProvider = serviceInfoProvider; this.coreSettings = coreSettings; + this.ruleEngineSettings = ruleEngineSettings; this.coreAdmin = new TbRabbitMqAdmin(rabbitMqSettings, queueArguments.getCoreArgs()); this.ruleEngineAdmin = new TbRabbitMqAdmin(rabbitMqSettings, queueArguments.getRuleEngineArgs()); @@ -77,10 +81,10 @@ public class RabbitMqTransportQueueFactory implements TbTransportQueueFactory { @Override public TbQueueRequestTemplate, TbProtoQueueMsg> createTransportApiRequestTemplate() { - TbRabbitMqProducerTemplate> producerTemplate = + TbQueueProducer> producerTemplate = new TbRabbitMqProducerTemplate<>(transportApiAdmin, rabbitMqSettings, transportApiSettings.getRequestsTopic()); - TbRabbitMqConsumerTemplate> consumerTemplate = + TbQueueConsumer> consumerTemplate = new TbRabbitMqConsumerTemplate<>(transportApiAdmin, rabbitMqSettings, transportApiSettings.getResponsesTopic() + "." + serviceInfoProvider.getServiceId(), msg -> new TbProtoQueueMsg<>(msg.getKey(), TransportApiResponseMsg.parseFrom(msg.getData()), msg.getHeaders())); @@ -98,7 +102,7 @@ public class RabbitMqTransportQueueFactory implements TbTransportQueueFactory { @Override public TbQueueProducer> createRuleEngineMsgProducer() { - return new TbRabbitMqProducerTemplate<>(transportApiAdmin, rabbitMqSettings, transportApiSettings.getRequestsTopic()); + return new TbRabbitMqProducerTemplate<>(ruleEngineAdmin, rabbitMqSettings, ruleEngineSettings.getTopic()); } @Override diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/ServiceBusMonolithQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/ServiceBusMonolithQueueFactory.java index 3731a56aee..39f41e8faf 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/ServiceBusMonolithQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/ServiceBusMonolithQueueFactory.java @@ -109,7 +109,7 @@ public class ServiceBusMonolithQueueFactory implements TbCoreQueueFactory, TbRul @Override public TbQueueProducer> createRuleEngineNotificationsMsgProducer() { - return new TbServiceBusProducerTemplate<>(ruleEngineAdmin, serviceBusSettings, ruleEngineSettings.getTopic()); + return new TbServiceBusProducerTemplate<>(notificationAdmin, serviceBusSettings, ruleEngineSettings.getTopic()); } @Override @@ -119,7 +119,7 @@ public class ServiceBusMonolithQueueFactory implements TbCoreQueueFactory, TbRul @Override public TbQueueProducer> createTbCoreNotificationsMsgProducer() { - return new TbServiceBusProducerTemplate<>(coreAdmin, serviceBusSettings, coreSettings.getTopic()); + return new TbServiceBusProducerTemplate<>(notificationAdmin, serviceBusSettings, coreSettings.getTopic()); } @Override diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/ServiceBusTbCoreQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/ServiceBusTbCoreQueueFactory.java index 7a9da236ed..0280012008 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/ServiceBusTbCoreQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/ServiceBusTbCoreQueueFactory.java @@ -48,6 +48,7 @@ import org.thingsboard.server.queue.settings.TbQueueCoreSettings; import org.thingsboard.server.queue.settings.TbQueueRemoteJsInvokeSettings; import org.thingsboard.server.queue.settings.TbQueueRuleEngineSettings; import org.thingsboard.server.queue.settings.TbQueueTransportApiSettings; +import org.thingsboard.server.queue.settings.TbQueueTransportNotificationSettings; import javax.annotation.PreDestroy; import java.nio.charset.StandardCharsets; @@ -63,6 +64,7 @@ public class ServiceBusTbCoreQueueFactory implements TbCoreQueueFactory { private final PartitionService partitionService; private final TbServiceInfoProvider serviceInfoProvider; private final TbQueueRemoteJsInvokeSettings jsInvokeSettings; + private final TbQueueTransportNotificationSettings transportNotificationSettings; private final TbQueueAdmin coreAdmin; private final TbQueueAdmin ruleEngineAdmin; @@ -77,6 +79,7 @@ public class ServiceBusTbCoreQueueFactory implements TbCoreQueueFactory { PartitionService partitionService, TbServiceInfoProvider serviceInfoProvider, TbQueueRemoteJsInvokeSettings jsInvokeSettings, + TbQueueTransportNotificationSettings transportNotificationSettings, TbServiceBusQueueConfigs serviceBusQueueConfigs) { this.serviceBusSettings = serviceBusSettings; this.coreSettings = coreSettings; @@ -85,6 +88,7 @@ public class ServiceBusTbCoreQueueFactory implements TbCoreQueueFactory { this.partitionService = partitionService; this.serviceInfoProvider = serviceInfoProvider; this.jsInvokeSettings = jsInvokeSettings; + this.transportNotificationSettings = transportNotificationSettings; this.coreAdmin = new TbServiceBusAdmin(serviceBusSettings, serviceBusQueueConfigs.getCoreConfigs()); this.ruleEngineAdmin = new TbServiceBusAdmin(serviceBusSettings, serviceBusQueueConfigs.getRuleEngineConfigs()); @@ -95,7 +99,7 @@ public class ServiceBusTbCoreQueueFactory implements TbCoreQueueFactory { @Override public TbQueueProducer> createTransportNotificationsMsgProducer() { - return new TbServiceBusProducerTemplate<>(coreAdmin, serviceBusSettings, coreSettings.getTopic()); + return new TbServiceBusProducerTemplate<>(notificationAdmin, serviceBusSettings, transportNotificationSettings.getNotificationsTopic()); } @Override @@ -105,7 +109,7 @@ public class ServiceBusTbCoreQueueFactory implements TbCoreQueueFactory { @Override public TbQueueProducer> createRuleEngineNotificationsMsgProducer() { - return new TbServiceBusProducerTemplate<>(ruleEngineAdmin, serviceBusSettings, ruleEngineSettings.getTopic()); + return new TbServiceBusProducerTemplate<>(notificationAdmin, serviceBusSettings, ruleEngineSettings.getTopic()); } @Override @@ -115,7 +119,7 @@ public class ServiceBusTbCoreQueueFactory implements TbCoreQueueFactory { @Override public TbQueueProducer> createTbCoreNotificationsMsgProducer() { - return new TbServiceBusProducerTemplate<>(coreAdmin, serviceBusSettings, coreSettings.getTopic()); + return new TbServiceBusProducerTemplate<>(notificationAdmin, serviceBusSettings, coreSettings.getTopic()); } @Override @@ -139,7 +143,7 @@ public class ServiceBusTbCoreQueueFactory implements TbCoreQueueFactory { @Override public TbQueueProducer> createTransportApiResponseProducer() { - return new TbServiceBusProducerTemplate<>(coreAdmin, serviceBusSettings, coreSettings.getTopic()); + return new TbServiceBusProducerTemplate<>(transportApiAdmin, serviceBusSettings, transportApiSettings.getResponsesTopic()); } @Override diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/ServiceBusTbRuleEngineQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/ServiceBusTbRuleEngineQueueFactory.java index be11736ad2..d653c8aa17 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/ServiceBusTbRuleEngineQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/ServiceBusTbRuleEngineQueueFactory.java @@ -45,6 +45,7 @@ import org.thingsboard.server.queue.discovery.TbServiceInfoProvider; import org.thingsboard.server.queue.settings.TbQueueCoreSettings; import org.thingsboard.server.queue.settings.TbQueueRemoteJsInvokeSettings; import org.thingsboard.server.queue.settings.TbQueueRuleEngineSettings; +import org.thingsboard.server.queue.settings.TbQueueTransportNotificationSettings; import org.thingsboard.server.queue.settings.TbRuleEngineQueueConfiguration; import javax.annotation.PreDestroy; @@ -60,6 +61,7 @@ public class ServiceBusTbRuleEngineQueueFactory implements TbRuleEngineQueueFact private final TbQueueRuleEngineSettings ruleEngineSettings; private final TbServiceBusSettings serviceBusSettings; private final TbQueueRemoteJsInvokeSettings jsInvokeSettings; + private final TbQueueTransportNotificationSettings transportNotificationSettings; private final TbQueueAdmin coreAdmin; private final TbQueueAdmin ruleEngineAdmin; @@ -71,6 +73,7 @@ public class ServiceBusTbRuleEngineQueueFactory implements TbRuleEngineQueueFact TbServiceInfoProvider serviceInfoProvider, TbServiceBusSettings serviceBusSettings, TbQueueRemoteJsInvokeSettings jsInvokeSettings, + TbQueueTransportNotificationSettings transportNotificationSettings, TbServiceBusQueueConfigs serviceBusQueueConfigs) { this.partitionService = partitionService; this.coreSettings = coreSettings; @@ -78,6 +81,7 @@ public class ServiceBusTbRuleEngineQueueFactory implements TbRuleEngineQueueFact this.ruleEngineSettings = ruleEngineSettings; this.serviceBusSettings = serviceBusSettings; this.jsInvokeSettings = jsInvokeSettings; + this.transportNotificationSettings = transportNotificationSettings; this.coreAdmin = new TbServiceBusAdmin(serviceBusSettings, serviceBusQueueConfigs.getCoreConfigs()); this.ruleEngineAdmin = new TbServiceBusAdmin(serviceBusSettings, serviceBusQueueConfigs.getRuleEngineConfigs()); @@ -87,17 +91,17 @@ public class ServiceBusTbRuleEngineQueueFactory implements TbRuleEngineQueueFact @Override public TbQueueProducer> createTransportNotificationsMsgProducer() { - return new TbServiceBusProducerTemplate<>(coreAdmin, serviceBusSettings, coreSettings.getTopic()); + return new TbServiceBusProducerTemplate<>(notificationAdmin, serviceBusSettings, transportNotificationSettings.getNotificationsTopic()); } @Override public TbQueueProducer> createRuleEngineMsgProducer() { - return new TbServiceBusProducerTemplate<>(coreAdmin, serviceBusSettings, coreSettings.getTopic()); + return new TbServiceBusProducerTemplate<>(ruleEngineAdmin, serviceBusSettings, ruleEngineSettings.getTopic()); } @Override public TbQueueProducer> createRuleEngineNotificationsMsgProducer() { - return new TbServiceBusProducerTemplate<>(ruleEngineAdmin, serviceBusSettings, ruleEngineSettings.getTopic()); + return new TbServiceBusProducerTemplate<>(notificationAdmin, serviceBusSettings, ruleEngineSettings.getTopic()); } @Override @@ -107,7 +111,7 @@ public class ServiceBusTbRuleEngineQueueFactory implements TbRuleEngineQueueFact @Override public TbQueueProducer> createTbCoreNotificationsMsgProducer() { - return new TbServiceBusProducerTemplate<>(coreAdmin, serviceBusSettings, coreSettings.getTopic()); + return new TbServiceBusProducerTemplate<>(notificationAdmin, serviceBusSettings, coreSettings.getTopic()); } @Override diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/ServiceBusTransportQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/ServiceBusTransportQueueFactory.java index 3befd52729..85ecdd2643 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/ServiceBusTransportQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/ServiceBusTransportQueueFactory.java @@ -37,6 +37,7 @@ import org.thingsboard.server.queue.common.DefaultTbQueueRequestTemplate; import org.thingsboard.server.queue.common.TbProtoQueueMsg; import org.thingsboard.server.queue.discovery.TbServiceInfoProvider; import org.thingsboard.server.queue.settings.TbQueueCoreSettings; +import org.thingsboard.server.queue.settings.TbQueueRuleEngineSettings; import org.thingsboard.server.queue.settings.TbQueueTransportApiSettings; import org.thingsboard.server.queue.settings.TbQueueTransportNotificationSettings; @@ -51,14 +52,17 @@ public class ServiceBusTransportQueueFactory implements TbTransportQueueFactory private final TbServiceBusSettings serviceBusSettings; private final TbServiceInfoProvider serviceInfoProvider; private final TbQueueCoreSettings coreSettings; + private final TbQueueRuleEngineSettings ruleEngineSettings; private final TbQueueAdmin coreAdmin; private final TbQueueAdmin transportApiAdmin; private final TbQueueAdmin notificationAdmin; + private final TbQueueAdmin ruleEngineAdmin; public ServiceBusTransportQueueFactory(TbQueueTransportApiSettings transportApiSettings, TbQueueTransportNotificationSettings transportNotificationSettings, TbServiceBusSettings serviceBusSettings, + TbQueueRuleEngineSettings ruleEngineSettings, TbServiceInfoProvider serviceInfoProvider, TbQueueCoreSettings coreSettings, TbServiceBusQueueConfigs serviceBusQueueConfigs) { @@ -67,10 +71,12 @@ public class ServiceBusTransportQueueFactory implements TbTransportQueueFactory this.serviceBusSettings = serviceBusSettings; this.serviceInfoProvider = serviceInfoProvider; this.coreSettings = coreSettings; + this.ruleEngineSettings = ruleEngineSettings; this.coreAdmin = new TbServiceBusAdmin(serviceBusSettings, serviceBusQueueConfigs.getCoreConfigs()); this.transportApiAdmin = new TbServiceBusAdmin(serviceBusSettings, serviceBusQueueConfigs.getTransportApiConfigs()); this.notificationAdmin = new TbServiceBusAdmin(serviceBusSettings, serviceBusQueueConfigs.getNotificationsConfigs()); + this.ruleEngineAdmin = new TbServiceBusAdmin(serviceBusSettings, serviceBusQueueConfigs.getRuleEngineConfigs()); } @Override @@ -96,7 +102,7 @@ public class ServiceBusTransportQueueFactory implements TbTransportQueueFactory @Override public TbQueueProducer> createRuleEngineMsgProducer() { - return new TbServiceBusProducerTemplate<>(transportApiAdmin, serviceBusSettings, transportApiSettings.getRequestsTopic()); + return new TbServiceBusProducerTemplate<>(ruleEngineAdmin, serviceBusSettings, ruleEngineSettings.getTopic()); } @Override @@ -127,5 +133,8 @@ public class ServiceBusTransportQueueFactory implements TbTransportQueueFactory if (notificationAdmin != null) { notificationAdmin.destroy(); } + if (ruleEngineAdmin != null) { + ruleEngineAdmin.destroy(); + } } } From 6d61b249e57d3ff3c2079cd9849ae295bbec9fd4 Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Mon, 20 Dec 2021 15:23:28 +0200 Subject: [PATCH 270/432] improvements (not notify if lates ts has not been deleted) --- .../controller/TelemetryController.java | 2 +- .../DefaultTelemetrySubscriptionService.java | 35 +++++++------ .../dao/timeseries/TimeseriesService.java | 5 +- .../data/kv/TsKvLatestRemovingResult.java | 36 +++++++++++++ .../dao/sqlts/SqlTimeseriesLatestDao.java | 51 +++++-------------- .../dao/timeseries/BaseTimeseriesService.java | 11 ++-- .../CassandraBaseTimeseriesLatestDao.java | 45 +++++----------- .../dao/timeseries/TimeseriesLatestDao.java | 3 +- .../api/RuleEngineTelemetryService.java | 2 +- .../models/datasource/attribute-datasource.ts | 2 +- 10 files changed, 94 insertions(+), 98 deletions(-) create mode 100644 common/data/src/main/java/org/thingsboard/server/common/data/kv/TsKvLatestRemovingResult.java diff --git a/application/src/main/java/org/thingsboard/server/controller/TelemetryController.java b/application/src/main/java/org/thingsboard/server/controller/TelemetryController.java index dfe0701642..70a6b029ed 100644 --- a/application/src/main/java/org/thingsboard/server/controller/TelemetryController.java +++ b/application/src/main/java/org/thingsboard/server/controller/TelemetryController.java @@ -573,7 +573,7 @@ public class TelemetryController extends BaseController { for (String key : keys) { deleteTsKvQueries.add(new BaseDeleteTsKvQuery(key, deleteFromTs, deleteToTs, rewriteLatestIfDeleted)); } - tsSubService.deleteTimeseriesAndNotify(tenantId, entityId, keys, deleteTsKvQueries, rewriteLatestIfDeleted, new FutureCallback<>() { + tsSubService.deleteTimeseriesAndNotify(tenantId, entityId, keys, deleteTsKvQueries, new FutureCallback<>() { @Override public void onSuccess(@Nullable Void tmp) { logTimeseriesDeleted(user, entityId, keys, deleteFromTs, deleteToTs, null); diff --git a/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetrySubscriptionService.java b/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetrySubscriptionService.java index 8a911962f0..8100b12464 100644 --- a/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetrySubscriptionService.java +++ b/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetrySubscriptionService.java @@ -37,6 +37,7 @@ import org.thingsboard.server.common.data.kv.DoubleDataEntry; import org.thingsboard.server.common.data.kv.LongDataEntry; import org.thingsboard.server.common.data.kv.StringDataEntry; import org.thingsboard.server.common.data.kv.TsKvEntry; +import org.thingsboard.server.common.data.kv.TsKvLatestRemovingResult; import org.thingsboard.server.common.msg.queue.ServiceType; import org.thingsboard.server.common.msg.queue.TbCallback; import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; @@ -61,10 +62,8 @@ import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Optional; -import java.util.Set; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; -import java.util.stream.Collectors; /** * Created by ashvayka on 27.03.18. @@ -255,7 +254,7 @@ public class DefaultTelemetrySubscriptionService extends AbstractSubscriptionSer @Override public void deleteLatestInternal(TenantId tenantId, EntityId entityId, List keys, FutureCallback callback) { - ListenableFuture> deleteFuture = tsService.removeLatest(tenantId, entityId, keys); + ListenableFuture> deleteFuture = tsService.removeLatest(tenantId, entityId, keys); addVoidCallback(deleteFuture, callback); } @@ -276,10 +275,10 @@ public class DefaultTelemetrySubscriptionService extends AbstractSubscriptionSer } @Override - public void deleteTimeseriesAndNotify(TenantId tenantId, EntityId entityId, List keys, List deleteTsKvQueries, boolean rewriteLatestIfDeleted, FutureCallback callback) { - ListenableFuture> deleteFuture = tsService.remove(tenantId, entityId, deleteTsKvQueries); + public void deleteTimeseriesAndNotify(TenantId tenantId, EntityId entityId, List keys, List deleteTsKvQueries, FutureCallback callback) { + ListenableFuture> deleteFuture = tsService.remove(tenantId, entityId, deleteTsKvQueries); addVoidCallback(deleteFuture, callback); - addWsCallback(deleteFuture, list -> onTimeSeriesDelete(tenantId, entityId, keys, list, rewriteLatestIfDeleted)); + addWsCallback(deleteFuture, list -> onTimeSeriesDelete(tenantId, entityId, keys, list)); } @Override @@ -348,20 +347,24 @@ public class DefaultTelemetrySubscriptionService extends AbstractSubscriptionSer } } - private void onTimeSeriesDelete(TenantId tenantId, EntityId entityId, List keys, List ts, boolean rewriteLatestIfDeleted) { + private void onTimeSeriesDelete(TenantId tenantId, EntityId entityId, List keys, List ts) { TopicPartitionInfo tpi = partitionService.resolve(ServiceType.TB_CORE, tenantId, entityId); if (currentPartitions.contains(tpi)) { if (subscriptionManagerService.isPresent()) { - Set updated; - if (rewriteLatestIfDeleted) { - List filteredTs = ts.stream().filter(Objects::nonNull).collect(Collectors.toList()); - subscriptionManagerService.get().onTimeSeriesUpdate(tenantId, entityId, ts, TbCallback.EMPTY); - updated = filteredTs.stream().map(TsKvEntry::getKey).collect(Collectors.toSet()); - } else { - updated = Collections.emptySet(); - } + List updated = new ArrayList<>(); + List deleted = new ArrayList<>(); + + ts.stream().filter(Objects::nonNull).forEach(res -> { + if (res.isRemoved()) { + if (res.getData() != null) { + updated.add(res.getData()); + } else { + deleted.add(res.getKey()); + } + } + }); - List deleted = keys.stream().filter(key -> updated.isEmpty() || !updated.remove(key)).collect(Collectors.toList()); + subscriptionManagerService.get().onTimeSeriesUpdate(tenantId, entityId, updated, TbCallback.EMPTY); subscriptionManagerService.get().onTimeSeriesDelete(tenantId, entityId, deleted, TbCallback.EMPTY); } else { log.warn("Possible misconfiguration because subscriptionManagerService is null!"); diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/timeseries/TimeseriesService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/timeseries/TimeseriesService.java index 4da8c14eeb..c707e12a46 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/timeseries/TimeseriesService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/timeseries/TimeseriesService.java @@ -21,6 +21,7 @@ import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.kv.DeleteTsKvQuery; import org.thingsboard.server.common.data.kv.ReadTsKvQuery; +import org.thingsboard.server.common.data.kv.TsKvLatestRemovingResult; import org.thingsboard.server.common.data.kv.TsKvEntry; import java.util.Collection; @@ -43,9 +44,9 @@ public interface TimeseriesService { ListenableFuture> saveLatest(TenantId tenantId, EntityId entityId, List tsKvEntry); - ListenableFuture> remove(TenantId tenantId, EntityId entityId, List queries); + ListenableFuture> remove(TenantId tenantId, EntityId entityId, List queries); - ListenableFuture> removeLatest(TenantId tenantId, EntityId entityId, Collection keys); + ListenableFuture> removeLatest(TenantId tenantId, EntityId entityId, Collection keys); ListenableFuture> removeAllLatest(TenantId tenantId, EntityId entityId); diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/kv/TsKvLatestRemovingResult.java b/common/data/src/main/java/org/thingsboard/server/common/data/kv/TsKvLatestRemovingResult.java new file mode 100644 index 0000000000..4c67dea2aa --- /dev/null +++ b/common/data/src/main/java/org/thingsboard/server/common/data/kv/TsKvLatestRemovingResult.java @@ -0,0 +1,36 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.common.data.kv; + +import lombok.Data; + +@Data +public class TsKvLatestRemovingResult { + private String key; + private TsKvEntry data; + private boolean removed; + + public TsKvLatestRemovingResult(TsKvEntry data) { + this.key = data.getKey(); + this.data = data; + this.removed = true; + } + + public TsKvLatestRemovingResult(String key, boolean removed) { + this.key = key; + this.removed = removed; + } +} diff --git a/dao/src/main/java/org/thingsboard/server/dao/sqlts/SqlTimeseriesLatestDao.java b/dao/src/main/java/org/thingsboard/server/dao/sqlts/SqlTimeseriesLatestDao.java index 3534a4c253..1c5d28b715 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sqlts/SqlTimeseriesLatestDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sqlts/SqlTimeseriesLatestDao.java @@ -16,7 +16,6 @@ package org.thingsboard.server.dao.sqlts; import com.google.common.collect.Lists; -import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.MoreExecutors; @@ -34,6 +33,7 @@ import org.thingsboard.server.common.data.kv.DeleteTsKvQuery; import org.thingsboard.server.common.data.kv.ReadTsKvQuery; import org.thingsboard.server.common.data.kv.StringDataEntry; import org.thingsboard.server.common.data.kv.TsKvEntry; +import org.thingsboard.server.common.data.kv.TsKvLatestRemovingResult; import org.thingsboard.server.common.stats.StatsFactory; import org.thingsboard.server.dao.DaoUtil; import org.thingsboard.server.dao.model.sql.AbstractTsKvEntity; @@ -45,11 +45,9 @@ import org.thingsboard.server.dao.sql.TbSqlBlockingQueueWrapper; import org.thingsboard.server.dao.sqlts.insert.latest.InsertLatestTsRepository; import org.thingsboard.server.dao.sqlts.latest.SearchTsKvLatestRepository; import org.thingsboard.server.dao.sqlts.latest.TsKvLatestRepository; -import org.thingsboard.server.dao.timeseries.SimpleListenableFuture; import org.thingsboard.server.dao.timeseries.TimeseriesLatestDao; import org.thingsboard.server.dao.util.SqlTsLatestAnyDao; -import javax.annotation.Nullable; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; import java.util.ArrayList; @@ -59,7 +57,6 @@ import java.util.List; import java.util.Map; import java.util.Optional; import java.util.UUID; -import java.util.concurrent.ExecutionException; import java.util.function.Function; import java.util.stream.Collectors; @@ -147,7 +144,7 @@ public class SqlTimeseriesLatestDao extends BaseAbstractSqlTimeseriesDao impleme } @Override - public ListenableFuture removeLatest(TenantId tenantId, EntityId entityId, DeleteTsKvQuery query) { + public ListenableFuture removeLatest(TenantId tenantId, EntityId entityId, DeleteTsKvQuery query) { return getRemoveLatestFuture(tenantId, entityId, query); } @@ -175,16 +172,16 @@ public class SqlTimeseriesLatestDao extends BaseAbstractSqlTimeseriesDao impleme return tsKvLatestRepository.findAllKeysByEntityIds(entityIds.stream().map(EntityId::getId).collect(Collectors.toList())); } - private ListenableFuture getNewLatestEntryFuture(TenantId tenantId, EntityId entityId, DeleteTsKvQuery query) { + private ListenableFuture getNewLatestEntryFuture(TenantId tenantId, EntityId entityId, DeleteTsKvQuery query) { ListenableFuture> future = findNewLatestEntryFuture(tenantId, entityId, query); return Futures.transformAsync(future, entryList -> { if (entryList.size() == 1) { TsKvEntry entry = entryList.get(0); - return Futures.transform(getSaveLatestFuture(entityId, entry), v -> entry, MoreExecutors.directExecutor()); + return Futures.transform(getSaveLatestFuture(entityId, entry), v -> new TsKvLatestRemovingResult(entry), MoreExecutors.directExecutor()); } else { log.trace("Could not find new latest value for [{}], key - {}", entityId, query.getKey()); } - return Futures.immediateFuture(null); + return Futures.immediateFuture(new TsKvLatestRemovingResult(query.getKey(), true)); }, service); } @@ -213,7 +210,7 @@ public class SqlTimeseriesLatestDao extends BaseAbstractSqlTimeseriesDao impleme return Futures.immediateFuture(result); } - protected ListenableFuture getRemoveLatestFuture(TenantId tenantId, EntityId entityId, DeleteTsKvQuery query) { + protected ListenableFuture getRemoveLatestFuture(TenantId tenantId, EntityId entityId, DeleteTsKvQuery query) { ListenableFuture latestFuture = getFindLatestFuture(entityId, query.getKey()); ListenableFuture booleanFuture = Futures.transform(latestFuture, tsKvEntry -> { @@ -221,47 +218,25 @@ public class SqlTimeseriesLatestDao extends BaseAbstractSqlTimeseriesDao impleme return ts > query.getStartTs() && ts <= query.getEndTs(); }, service); - ListenableFuture removedLatestFuture = Futures.transformAsync(booleanFuture, isRemove -> { + ListenableFuture removedLatestFuture = Futures.transformAsync(booleanFuture, isRemove -> { if (isRemove) { TsKvLatestEntity latestEntity = new TsKvLatestEntity(); latestEntity.setEntityId(entityId.getId()); latestEntity.setKey(getOrSaveKeyId(query.getKey())); return service.submit(() -> { tsKvLatestRepository.delete(latestEntity); - return null; + return true; }); } - return Futures.immediateFuture(null); + return Futures.immediateFuture(false); }, service); - final SimpleListenableFuture resultFuture = new SimpleListenableFuture<>(); - Futures.addCallback(removedLatestFuture, new FutureCallback() { - @Override - public void onSuccess(@Nullable Void result) { - if (query.getRewriteLatestIfDeleted()) { - ListenableFuture savedLatestFuture = Futures.transformAsync(booleanFuture, isRemove -> { - if (isRemove) { - return getNewLatestEntryFuture(tenantId, entityId, query); - } - return Futures.immediateFuture(null); - }, service); - - try { - resultFuture.set(savedLatestFuture.get()); - } catch (InterruptedException | ExecutionException e) { - log.warn("Could not get latest saved value for [{}], {}", entityId, query.getKey(), e); - } - } else { - resultFuture.set(null); - } - } - - @Override - public void onFailure(Throwable t) { - log.warn("[{}] Failed to process remove of the latest value", entityId, t); + return Futures.transformAsync(removedLatestFuture, isRemoved -> { + if (isRemoved && query.getRewriteLatestIfDeleted()) { + return getNewLatestEntryFuture(tenantId, entityId, query); } + return Futures.immediateFuture(new TsKvLatestRemovingResult(query.getKey(), isRemoved)); }, MoreExecutors.directExecutor()); - return resultFuture; } protected ListenableFuture> getFindAllLatestFuture(EntityId entityId) { diff --git a/dao/src/main/java/org/thingsboard/server/dao/timeseries/BaseTimeseriesService.java b/dao/src/main/java/org/thingsboard/server/dao/timeseries/BaseTimeseriesService.java index 95be63dae7..39bed5359d 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/timeseries/BaseTimeseriesService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/timeseries/BaseTimeseriesService.java @@ -36,6 +36,7 @@ import org.thingsboard.server.common.data.kv.BaseDeleteTsKvQuery; import org.thingsboard.server.common.data.kv.BaseReadTsKvQuery; import org.thingsboard.server.common.data.kv.DeleteTsKvQuery; import org.thingsboard.server.common.data.kv.ReadTsKvQuery; +import org.thingsboard.server.common.data.kv.TsKvLatestRemovingResult; import org.thingsboard.server.common.data.kv.TsKvEntry; import org.thingsboard.server.dao.entityview.EntityViewService; import org.thingsboard.server.dao.exception.IncorrectParameterException; @@ -195,10 +196,10 @@ public class BaseTimeseriesService implements TimeseriesService { } @Override - public ListenableFuture> remove(TenantId tenantId, EntityId entityId, List deleteTsKvQueries) { + public ListenableFuture> remove(TenantId tenantId, EntityId entityId, List deleteTsKvQueries) { validate(entityId); deleteTsKvQueries.forEach(BaseTimeseriesService::validate); - List> futures = Lists.newArrayListWithExpectedSize(deleteTsKvQueries.size() * DELETES_PER_ENTRY); + List> futures = Lists.newArrayListWithExpectedSize(deleteTsKvQueries.size() * DELETES_PER_ENTRY); for (DeleteTsKvQuery tsKvQuery : deleteTsKvQueries) { deleteAndRegisterFutures(tenantId, futures, entityId, tsKvQuery); } @@ -206,9 +207,9 @@ public class BaseTimeseriesService implements TimeseriesService { } @Override - public ListenableFuture> removeLatest(TenantId tenantId, EntityId entityId, Collection keys) { + public ListenableFuture> removeLatest(TenantId tenantId, EntityId entityId, Collection keys) { validate(entityId); - List> futures = Lists.newArrayListWithExpectedSize(keys.size()); + List> futures = Lists.newArrayListWithExpectedSize(keys.size()); for (String key : keys) { DeleteTsKvQuery query = new BaseDeleteTsKvQuery(key, 0, System.currentTimeMillis(), false); futures.add(timeseriesLatestDao.removeLatest(tenantId, entityId, query)); @@ -229,7 +230,7 @@ public class BaseTimeseriesService implements TimeseriesService { }, MoreExecutors.directExecutor()); } - private void deleteAndRegisterFutures(TenantId tenantId, List> futures, EntityId entityId, DeleteTsKvQuery query) { + private void deleteAndRegisterFutures(TenantId tenantId, List> futures, EntityId entityId, DeleteTsKvQuery query) { futures.add(Futures.transform(timeseriesDao.remove(tenantId, entityId, query), v -> null, MoreExecutors.directExecutor())); futures.add(timeseriesLatestDao.removeLatest(tenantId, entityId, query)); futures.add(Futures.transform(timeseriesDao.removePartition(tenantId, entityId, query), v -> null, MoreExecutors.directExecutor())); diff --git a/dao/src/main/java/org/thingsboard/server/dao/timeseries/CassandraBaseTimeseriesLatestDao.java b/dao/src/main/java/org/thingsboard/server/dao/timeseries/CassandraBaseTimeseriesLatestDao.java index 6e9bea0ecb..5b1a4d2eb0 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/timeseries/CassandraBaseTimeseriesLatestDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/timeseries/CassandraBaseTimeseriesLatestDao.java @@ -34,6 +34,7 @@ import org.thingsboard.server.common.data.kv.Aggregation; import org.thingsboard.server.common.data.kv.BaseReadTsKvQuery; import org.thingsboard.server.common.data.kv.DeleteTsKvQuery; import org.thingsboard.server.common.data.kv.ReadTsKvQuery; +import org.thingsboard.server.common.data.kv.TsKvLatestRemovingResult; import org.thingsboard.server.common.data.kv.TsKvEntry; import org.thingsboard.server.dao.model.ModelConstants; import org.thingsboard.server.dao.nosql.TbResultSet; @@ -114,7 +115,7 @@ public class CassandraBaseTimeseriesLatestDao extends AbstractCassandraBaseTimes } @Override - public ListenableFuture removeLatest(TenantId tenantId, EntityId entityId, DeleteTsKvQuery query) { + public ListenableFuture removeLatest(TenantId tenantId, EntityId entityId, DeleteTsKvQuery query) { ListenableFuture latestEntryFuture = findLatest(tenantId, entityId, query.getKey()); ListenableFuture booleanFuture = Futures.transform(latestEntryFuture, latestEntry -> { @@ -127,44 +128,22 @@ public class CassandraBaseTimeseriesLatestDao extends AbstractCassandraBaseTimes return false; }, readResultsProcessingExecutor); - ListenableFuture removedLatestFuture = Futures.transformAsync(booleanFuture, isRemove -> { + ListenableFuture removedLatestFuture = Futures.transformAsync(booleanFuture, isRemove -> { if (isRemove) { - return deleteLatest(tenantId, entityId, query.getKey()); + return Futures.transform(deleteLatest(tenantId, entityId, query.getKey()), res -> true, MoreExecutors.directExecutor()); } - return Futures.immediateFuture(null); + return Futures.immediateFuture(false); }, readResultsProcessingExecutor); - final SimpleListenableFuture resultFuture = new SimpleListenableFuture<>(); - Futures.addCallback(removedLatestFuture, new FutureCallback() { - @Override - public void onSuccess(@Nullable Void result) { - if (query.getRewriteLatestIfDeleted()) { - ListenableFuture savedLatestFuture = Futures.transformAsync(booleanFuture, isRemove -> { - if (isRemove) { - return getNewLatestEntryFuture(tenantId, entityId, query); - } - return Futures.immediateFuture(null); - }, readResultsProcessingExecutor); - - try { - resultFuture.set(savedLatestFuture.get()); - } catch (InterruptedException | ExecutionException e) { - log.warn("Could not get latest saved value for [{}], {}", entityId, query.getKey(), e); - } - } else { - resultFuture.set(null); - } - } - - @Override - public void onFailure(Throwable t) { - log.warn("[{}] Failed to process remove of the latest value", entityId, t); + return Futures.transformAsync(removedLatestFuture, isRemoved -> { + if (isRemoved && query.getRewriteLatestIfDeleted()) { + return getNewLatestEntryFuture(tenantId, entityId, query); } + return Futures.immediateFuture(new TsKvLatestRemovingResult(query.getKey(), isRemoved)); }, MoreExecutors.directExecutor()); - return resultFuture; } - private ListenableFuture getNewLatestEntryFuture(TenantId tenantId, EntityId entityId, DeleteTsKvQuery query) { + private ListenableFuture getNewLatestEntryFuture(TenantId tenantId, EntityId entityId, DeleteTsKvQuery query) { long startTs = 0; long endTs = query.getStartTs() - 1; ReadTsKvQuery findNewLatestQuery = new BaseReadTsKvQuery(query.getKey(), startTs, endTs, endTs - startTs, 1, @@ -174,11 +153,11 @@ public class CassandraBaseTimeseriesLatestDao extends AbstractCassandraBaseTimes return Futures.transformAsync(future, entryList -> { if (entryList.size() == 1) { TsKvEntry entry = entryList.get(0); - return Futures.transform(saveLatest(tenantId, entityId, entryList.get(0)), v -> entry, MoreExecutors.directExecutor()); + return Futures.transform(saveLatest(tenantId, entityId, entryList.get(0)), v -> new TsKvLatestRemovingResult(entry), MoreExecutors.directExecutor()); } else { log.trace("Could not find new latest value for [{}], key - {}", entityId, query.getKey()); } - return Futures.immediateFuture(null); + return Futures.immediateFuture(new TsKvLatestRemovingResult(query.getKey(), true)); }, readResultsProcessingExecutor); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/timeseries/TimeseriesLatestDao.java b/dao/src/main/java/org/thingsboard/server/dao/timeseries/TimeseriesLatestDao.java index d0253db0bd..f83a41c010 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/timeseries/TimeseriesLatestDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/timeseries/TimeseriesLatestDao.java @@ -20,6 +20,7 @@ import org.thingsboard.server.common.data.id.DeviceProfileId; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.kv.DeleteTsKvQuery; +import org.thingsboard.server.common.data.kv.TsKvLatestRemovingResult; import org.thingsboard.server.common.data.kv.TsKvEntry; import java.util.List; @@ -32,7 +33,7 @@ public interface TimeseriesLatestDao { ListenableFuture saveLatest(TenantId tenantId, EntityId entityId, TsKvEntry tsKvEntry); - ListenableFuture removeLatest(TenantId tenantId, EntityId entityId, DeleteTsKvQuery query); + ListenableFuture removeLatest(TenantId tenantId, EntityId entityId, DeleteTsKvQuery query); List findAllKeysByDeviceProfileId(TenantId tenantId, DeviceProfileId deviceProfileId); diff --git a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/RuleEngineTelemetryService.java b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/RuleEngineTelemetryService.java index fe0b39c299..a19d0fad0c 100644 --- a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/RuleEngineTelemetryService.java +++ b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/RuleEngineTelemetryService.java @@ -55,5 +55,5 @@ public interface RuleEngineTelemetryService { void deleteAllLatest(TenantId tenantId, EntityId entityId, FutureCallback> callback); - void deleteTimeseriesAndNotify(TenantId tenantId, EntityId entityId, List keys, List deleteTsKvQueries, boolean rewriteLatestIfDeleted, FutureCallback callback); + void deleteTimeseriesAndNotify(TenantId tenantId, EntityId entityId, List keys, List deleteTsKvQueries, FutureCallback callback); } diff --git a/ui-ngx/src/app/modules/home/models/datasource/attribute-datasource.ts b/ui-ngx/src/app/modules/home/models/datasource/attribute-datasource.ts index 99907bcaa9..6e6c937a8e 100644 --- a/ui-ngx/src/app/modules/home/models/datasource/attribute-datasource.ts +++ b/ui-ngx/src/app/modules/home/models/datasource/attribute-datasource.ts @@ -90,7 +90,7 @@ export class AttributeDatasource implements DataSource { return this.getAllAttributes(entityId, attributesScope).pipe( map((data) => { let filteredData = []; - for(let key in filteredData) { + for(let key in data) { if(data[key]['value'] !== null) { filteredData.push(data[key]); } From 57b09b2328aa6c97b41eb48ca87141a97b1adebe Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Mon, 20 Dec 2021 15:35:23 +0200 Subject: [PATCH 271/432] device delete transactional and cache evict refactor --- .../server/dao/device/DeviceServiceImpl.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java index 3255bf75b4..f70d1c1ffe 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java @@ -336,12 +336,14 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe return savedDevice; } + @Transactional @Override - public void deleteDevice(TenantId tenantId, DeviceId deviceId) { + public void deleteDevice(final TenantId tenantId, final DeviceId deviceId) { log.trace("Executing deleteDevice [{}]", deviceId); validateId(deviceId, INCORRECT_DEVICE_ID + deviceId); Device device = deviceDao.findById(tenantId, deviceId.getId()); + final String deviceName = device.getName(); try { List entityViews = entityViewService.findEntityViewsByTenantIdAndEntityIdAsync(device.getTenantId(), deviceId).get(); if (entityViews != null && !entityViews.isEmpty()) { @@ -358,10 +360,10 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe } deleteEntityRelations(tenantId, deviceId); - removeDeviceFromCacheByName(tenantId, device.getName()); - removeDeviceFromCacheById(tenantId, device.getId()); - deviceDao.removeById(tenantId, deviceId.getId()); + + removeDeviceFromCacheByName(tenantId, deviceName); + removeDeviceFromCacheById(tenantId, deviceId); } private void removeDeviceFromCacheByName(TenantId tenantId, String name) { From 07824ed50c89205aa0df5afdae4eb0164f7dcccf Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Mon, 20 Dec 2021 15:38:08 +0200 Subject: [PATCH 272/432] refactored --- .../thingsboard/server/common/data/kv/BaseDeleteTsKvQuery.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/kv/BaseDeleteTsKvQuery.java b/common/data/src/main/java/org/thingsboard/server/common/data/kv/BaseDeleteTsKvQuery.java index 3ffedaa69a..161883313d 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/kv/BaseDeleteTsKvQuery.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/kv/BaseDeleteTsKvQuery.java @@ -31,7 +31,4 @@ public class BaseDeleteTsKvQuery extends BaseTsKvQuery implements DeleteTsKvQuer this(key, startTs, endTs, false); } - public Boolean getRewriteLatestIfDeleted() { - return rewriteLatestIfDeleted; - } } From c14bba5b1eb82ee96ad0ebbb2404afd8ed2975da Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Mon, 20 Dec 2021 16:49:05 +0200 Subject: [PATCH 273/432] dao util: PageLink unsorted replaced with ORDER BY is ASC --- dao/src/main/java/org/thingsboard/server/dao/DaoUtil.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/dao/src/main/java/org/thingsboard/server/dao/DaoUtil.java b/dao/src/main/java/org/thingsboard/server/dao/DaoUtil.java index 44bdc7f5d9..19f613bd30 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/DaoUtil.java +++ b/dao/src/main/java/org/thingsboard/server/dao/DaoUtil.java @@ -36,6 +36,9 @@ import java.util.stream.Collectors; public abstract class DaoUtil { + public static final String DEFAULT_SORT_PROPERTY = "id"; + public static final Sort DEFAULT_SORT = Sort.by(Sort.Direction.ASC, DEFAULT_SORT_PROPERTY); + private DaoUtil() { } @@ -70,7 +73,7 @@ public abstract class DaoUtil { public static Sort toSort(SortOrder sortOrder, Map columnMap) { if (sortOrder == null) { - return Sort.unsorted(); + return DEFAULT_SORT; } else { String property = sortOrder.getProperty(); if (columnMap.containsKey(property)) { From 0583880ec7dea2a27756c20c9bc964e10b70afa0 Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Mon, 20 Dec 2021 16:50:29 +0200 Subject: [PATCH 274/432] test: ota package refactored to get better output on assertion --- .../server/dao/service/BaseOtaPackageServiceTest.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseOtaPackageServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseOtaPackageServiceTest.java index ed6b14dd10..8fcadcd812 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseOtaPackageServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseOtaPackageServiceTest.java @@ -44,6 +44,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; +import static org.assertj.core.api.Assertions.assertThat; import static org.thingsboard.server.common.data.ota.OtaPackageType.FIRMWARE; public abstract class BaseOtaPackageServiceTest extends AbstractServiceTest { @@ -58,7 +59,7 @@ public abstract class BaseOtaPackageServiceTest extends AbstractServiceTest { private static final ByteBuffer DATA = ByteBuffer.wrap(new byte[]{(int) DATA_SIZE}); private static final String URL = "http://firmware.test.org"; - private IdComparator idComparator = new IdComparator<>(); + private final IdComparator idComparator = new IdComparator<>(); private TenantId tenantId; @@ -565,7 +566,7 @@ public abstract class BaseOtaPackageServiceTest extends AbstractServiceTest { Collections.sort(firmwares, idComparator); Collections.sort(loadedFirmwares, idComparator); - Assert.assertEquals(firmwares, loadedFirmwares); + assertThat(firmwares).isEqualTo(loadedFirmwares); otaPackageService.deleteOtaPackagesByTenantId(tenantId); @@ -620,7 +621,7 @@ public abstract class BaseOtaPackageServiceTest extends AbstractServiceTest { Collections.sort(firmwares, idComparator); Collections.sort(loadedFirmwares, idComparator); - Assert.assertEquals(firmwares, loadedFirmwares); + assertThat(firmwares).isEqualTo(loadedFirmwares); otaPackageService.deleteOtaPackagesByTenantId(tenantId); From 66d6b8d687aa99122ffeb2cea80b26b60005064e Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Mon, 20 Dec 2021 17:52:19 +0200 Subject: [PATCH 275/432] Map rectangles support --- .../components/widget/lib/maps/leaflet-map.ts | 25 +++- .../components/widget/lib/maps/map-models.ts | 10 ++ .../components/widget/lib/maps/map-widget2.ts | 3 + .../components/widget/lib/maps/markers.scss | 9 ++ .../components/widget/lib/maps/polygon.ts | 108 ++++++++++++++---- .../components/widget/lib/maps/schemes.ts | 50 ++++++++ 6 files changed, 179 insertions(+), 26 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts index 27d6fb5edc..f4247d152e 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts @@ -69,6 +69,8 @@ export default abstract class LeafletMap { loading = false; replaceInfoLabelMarker: Array = []; markerLabelText: string; + polygonLabelText: string; + replaceInfoLabelPolygon: Array = []; replaceInfoTooltipMarker: Array = []; markerTooltipText: string; drawRoutes: boolean; @@ -248,8 +250,16 @@ export default abstract class LeafletMap { this.saveLocation(this.selectedEntity, this.convertToCustomFormat(e.layer.getLatLng())).subscribe(() => { }); } else if (e.shape === 'tbRectangle' || e.shape === 'tbPolygon') { - // @ts-ignore - this.saveLocation(this.selectedEntity, this.convertPolygonToCustomFormat(e.layer.getLatLngs()[0])).subscribe(() => { + let coordinates; + if (e.shape === 'tbRectangle') { + // @ts-ignore + const bounds: L.LatLngBounds = e.layer.getBounds(); + coordinates = [bounds.getNorthWest(), bounds.getSouthEast()]; + } else { + // @ts-ignore + coordinates = e.layer.getLatLngs()[0]; + } + this.saveLocation(this.selectedEntity, this.convertPolygonToCustomFormat(coordinates)).subscribe(() => { }); } // @ts-ignore @@ -281,7 +291,7 @@ export default abstract class LeafletMap { result = iterator.next(); } this.saveLocation(result.value.data, this.convertToCustomFormat(null)).subscribe(() => {}); - } else if (e.shape === 'Polygon') { + } else if (e.shape === 'Polygon' || e.shape === 'Rectangle') { const iterator = this.polygons.values(); let result = iterator.next(); while (!result.done && e.layer !== result.value.leafletPoly) { @@ -333,6 +343,7 @@ export default abstract class LeafletMap { this.map.scrollWheelZoom.disable(); } if (this.options.draggableMarker || this.editPolygons) { + map.pm.setGlobalOptions({ snappable: false } as L.PM.GlobalOptions); this.addEditControl(); } else { this.map.pm.disableDraw(); @@ -764,6 +775,14 @@ export default abstract class LeafletMap { if (coordinates.length === 1) { coordinates = coordinates[0]; } + if (e.shape === 'Rectangle') { + // @ts-ignore + const bounds: L.LatLngBounds = e.layer.getBounds(); + const boundsArray = [bounds.getNorthWest(), bounds.getNorthEast(), bounds.getSouthWest(), bounds.getSouthEast()]; + if (coordinates.every(point => boundsArray.find(boundPoint => boundPoint.equals(point)) !== undefined)) { + coordinates = [bounds.getNorthWest(), bounds.getSouthEast()]; + } + } this.saveLocation(data, this.convertPolygonToCustomFormat(coordinates)).subscribe(() => {}); } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-models.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-models.ts index 5b99b792e9..a472a99915 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-models.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-models.ts @@ -131,6 +131,11 @@ export type PolygonSettings = { polygonStrokeWeight: number; polygonStrokeColor: string; polygonColor: string; + showPolygonLabel?: boolean; + polygonLabel: string; + polygonLabelColor: string; + polygonLabelText: string; + usePolygonLabelFunction: boolean; showPolygonTooltip: boolean; autocloseTooltip: boolean; showTooltipAction: string; @@ -139,8 +144,11 @@ export type PolygonSettings = { usePolygonTooltipFunction: boolean; polygonClick: { [name: string]: actionsHandler }; usePolygonColorFunction: boolean; + usePolygonStrokeColorFunction: boolean; polygonTooltipFunction: GenericFunction; polygonColorFunction?: GenericFunction; + polygonStrokeColorFunction?: GenericFunction; + polygonLabelFunction?: GenericFunction; editablePolygon: boolean; }; @@ -227,8 +235,10 @@ export const defaultSettings: any = { showPolygon: false, labelColor: '#000000', color: '#FE7569', + showPolygonLabel: false, polygonColor: '#0000ff', polygonStrokeColor: '#fe0001', + polygonLabelColor: '#000000', polygonOpacity: 0.5, polygonStrokeOpacity: 1, polygonStrokeWeight: 1, diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-widget2.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-widget2.ts index a2385b2877..f755754eca 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-widget2.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-widget2.ts @@ -265,10 +265,13 @@ export class MapWidgetController implements MapWidgetInterface { tooltipFunction: parseFunction(settings.tooltipFunction, functionParams), colorFunction: parseFunction(settings.colorFunction, functionParams), colorPointFunction: parseFunction(settings.colorPointFunction, functionParams), + polygonLabelFunction: parseFunction(settings.polygonLabelFunction, functionParams), polygonColorFunction: parseFunction(settings.polygonColorFunction, functionParams), + polygonStrokeColorFunction: parseFunction(settings.polygonStrokeColorFunction, functionParams), polygonTooltipFunction: parseFunction(settings.polygonTooltipFunction, functionParams), markerImageFunction: parseFunction(settings.markerImageFunction, ['data', 'images', 'dsData', 'dsIndex']), labelColor: this.ctx.widgetConfig.color, + polygonLabelColor: this.ctx.widgetConfig.color, polygonKeyName: settings.polKeyName ? settings.polKeyName : settings.polygonKeyName, tooltipPattern: settings.tooltipPattern || '${entityName}

Latitude: ${' + diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/markers.scss b/ui-ngx/src/app/modules/home/components/widget/lib/maps/markers.scss index 147386685c..f45d08f9e9 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/markers.scss +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/markers.scss @@ -29,6 +29,15 @@ box-shadow: none; } +.tb-polygon-label { + border: none; + background: none; + box-shadow: none; + &:before { + content: none; + } +} + .leaflet-container { background-color: white; } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/polygon.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/polygon.ts index d87d764d0a..ab3abc7f7f 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/polygon.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/polygon.ts @@ -16,8 +16,14 @@ import L, { LatLngExpression, LeafletMouseEvent } from 'leaflet'; import { createTooltip } from './maps-utils'; -import { functionValueCalculator, parseWithTranslation, safeExecute } from './common-maps-utils'; -import { FormattedData, PolygonSettings } from './map-models'; +import { + fillPattern, + functionValueCalculator, + parseWithTranslation, + processPattern, + safeExecute +} from './common-maps-utils'; +import { FormattedData, MarkerSettings, PolygonSettings } from './map-models'; export class Polygon { @@ -26,38 +32,47 @@ export class Polygon { data: FormattedData; dataSources: FormattedData[]; - constructor(public map, polyData: FormattedData, dataSources: FormattedData[], private settings: PolygonSettings, onDragendListener?) { + constructor(public map, data: FormattedData, dataSources: FormattedData[], private settings: PolygonSettings, + private onDragendListener?) { this.dataSources = dataSources; - this.data = polyData; + this.data = data; const polygonColor = this.getPolygonColor(settings); - this.leafletPoly = L.polygon(polyData[this.settings.polygonKeyName], { + const polygonStrokeColor = this.getPolygonStrokeColor(settings); + const polyData = data[this.settings.polygonKeyName]; + const polyConstructor = polyData.length > 2 ? L.polygon : L.rectangle; + this.leafletPoly = polyConstructor(polyData, { fill: true, fillColor: polygonColor, - color: settings.polygonStrokeColor, + color: polygonStrokeColor, weight: settings.polygonStrokeWeight, fillOpacity: settings.polygonOpacity, opacity: settings.polygonStrokeOpacity, pmIgnore: !settings.editablePolygon }).addTo(this.map); - if (settings.editablePolygon && onDragendListener) { - this.leafletPoly.on('pm:edit', (e) => onDragendListener(e, this.data)); - } - + this.updateLabel(settings); if (settings.showPolygonTooltip) { - this.tooltip = createTooltip(this.leafletPoly, settings, polyData.$datasource); - this.updateTooltip(polyData); - } - if (settings.polygonClick) { - this.leafletPoly.on('click', (event: LeafletMouseEvent) => { - for (const action in this.settings.polygonClick) { - if (typeof (this.settings.polygonClick[action]) === 'function') { - this.settings.polygonClick[action](event.originalEvent, polyData.$datasource); - } - } - }); + this.tooltip = createTooltip(this.leafletPoly, settings, data.$datasource); + this.updateTooltip(data); } + this.createEventListeners(); + } + + private createEventListeners() { + if (this.settings.editablePolygon && this.onDragendListener) { + this.leafletPoly.on('pm:edit', (e) => this.onDragendListener(e, this.data)); + } + + if (this.settings.polygonClick) { + this.leafletPoly.on('click', (event: LeafletMouseEvent) => { + for (const action in this.settings.polygonClick) { + if (typeof (this.settings.polygonClick[action]) === 'function') { + this.settings.polygonClick[action](event.originalEvent, this.data.$datasource); + } + } + }); + } } updateTooltip(data: FormattedData) { @@ -67,13 +82,54 @@ export class Polygon { this.tooltip.setContent(parseWithTranslation.parseTemplate(pattern, data, true)); } + updateLabel(settings: PolygonSettings) { + this.leafletPoly.unbindTooltip(); + if (settings.showPolygonLabel) { + if (!this.map.polygonLabelText || settings.usePolygonLabelFunction) { + const pattern = settings.usePolygonLabelFunction ? + safeExecute(settings.polygonLabelFunction, [this.data, this.dataSources, this.data.dsIndex]) : settings.polygonLabel; + this.map.polygonLabelText = parseWithTranslation.prepareProcessPattern(pattern, true); + this.map.replaceInfoLabelPolygon = processPattern(this.map.polygonLabelText, this.data); + } + settings.polygonLabelText = fillPattern(this.map.polygonLabelText, this.map.replaceInfoLabelPolygon, this.data); + this.leafletPoly.bindTooltip(`
${settings.polygonLabelText}
`, + { className: 'tb-polygon-label', permanent: true, sticky: true, direction: 'center' }) + .openTooltip(this.leafletPoly.getBounds().getCenter()); + } + } + updatePolygon(data: FormattedData, dataSources: FormattedData[], settings: PolygonSettings) { this.data = data; this.dataSources = dataSources; - this.leafletPoly.setLatLngs(data[this.settings.polygonKeyName]); + const polyData = data[this.settings.polygonKeyName]; + if (polyData.length > 2) { + if (this.leafletPoly instanceof L.Rectangle) { + this.map.removeLayer(this.leafletPoly); + const polygonColor = this.getPolygonColor(settings); + const polygonStrokeColor = this.getPolygonStrokeColor(settings); + this.leafletPoly = L.polygon(polyData, { + fill: true, + fillColor: polygonColor, + color: polygonStrokeColor, + weight: settings.polygonStrokeWeight, + fillOpacity: settings.polygonOpacity, + opacity: settings.polygonStrokeOpacity, + pmIgnore: !settings.editablePolygon + }).addTo(this.map); + } else { + this.leafletPoly.setLatLngs(polyData); + } + } else if (polyData.length === 2) { + const bounds = new L.LatLngBounds(polyData); + // @ts-ignore + this.leafletPoly.setBounds(bounds); + } if (settings.showPolygonTooltip) { this.updateTooltip(this.data); } + if (settings.showPolygonLabel) { + this.updateLabel(settings); + } this.updatePolygonColor(settings); } @@ -83,10 +139,11 @@ export class Polygon { updatePolygonColor(settings: PolygonSettings) { const polygonColor = this.getPolygonColor(settings); + const polygonStrokeColor = this.getPolygonStrokeColor(settings); const style: L.PathOptions = { fill: true, fillColor: polygonColor, - color: settings.polygonStrokeColor, + color: polygonStrokeColor, weight: settings.polygonStrokeWeight, fillOpacity: settings.polygonOpacity, opacity: settings.polygonStrokeOpacity @@ -107,4 +164,9 @@ export class Polygon { return functionValueCalculator(settings.usePolygonColorFunction, settings.polygonColorFunction, [this.data, this.dataSources, this.data.dsIndex], settings.polygonColor); } + + private getPolygonStrokeColor(settings: PolygonSettings): string | null { + return functionValueCalculator(settings.usePolygonStrokeColorFunction, settings.polygonStrokeColorFunction, + [this.data, this.dataSources, this.data.dsIndex], settings.polygonStrokeColor); + } } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/schemes.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/schemes.ts index ff52ece929..b42da7d8b0 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/schemes.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/schemes.ts @@ -556,6 +556,25 @@ export const mapPolygonSchema = type: 'boolean', default: false }, + showPolygonLabel: { + title: 'Show polygon label', + type: 'boolean', + default: false + }, + polygonLabel: { + title: 'Polygon label (pattern examples: \'${entityName}\', \'${entityName}: (Text ${keyName} units.)\' )', + type: 'string', + default: '${entityName}' + }, + usePolygonLabelFunction: { + title: 'Use polygon label function', + type: 'boolean', + default: false + }, + polygonLabelFunction: { + title: 'Polygon label function: f(data, dsData, dsIndex)', + type: 'string' + }, polygonColor: { title: 'Polygon color', type: 'string' @@ -607,6 +626,15 @@ export const mapPolygonSchema = title: 'Polygon Color function: f(data, dsData, dsIndex)', type: 'string' }, + usePolygonStrokeColorFunction: { + title: 'Use polygon stroke color function', + type: 'boolean', + default: false + }, + polygonStrokeColorFunction: { + title: 'Polygon Stroke Color function: f(data, dsData, dsIndex)', + type: 'string' + } }, required: [] }, @@ -614,6 +642,21 @@ export const mapPolygonSchema = 'showPolygon', 'polygonKeyName', 'editablePolygon', + 'showPolygonLabel', + { + key: 'usePolygonLabelFunction', + condition: 'model.showPolygonLabel === true' + }, + { + key: 'polygonLabel', + condition: 'model.showPolygonLabel === true && model.usePolygonLabelFunction !== true' + }, + { + key: 'polygonLabelFunction', + type: 'javascript', + helpId: 'widget/lib/map/label_fn', + condition: 'model.showPolygonLabel === true && model.usePolygonLabelFunction === true' + }, { key: 'polygonColor', type: 'color' @@ -630,6 +673,13 @@ export const mapPolygonSchema = key: 'polygonStrokeColor', type: 'color' }, + 'usePolygonStrokeColorFunction', + { + key: 'polygonStrokeColorFunction', + helpId: 'widget/lib/map/polygon_color_fn', + type: 'javascript', + condition: 'model.usePolygonStrokeColorFunction === true' + }, 'polygonStrokeOpacity', 'polygonStrokeWeight', 'showPolygonTooltip', From 38bc05100e8c26fe4318ab2f55ffe25637ebf368 Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Mon, 20 Dec 2021 18:35:18 +0200 Subject: [PATCH 276/432] UI: Fixed incorrect work edit rectangle with cut --- .../modules/home/components/widget/lib/maps/leaflet-map.ts | 2 +- .../modules/home/components/widget/lib/maps/maps-utils.ts | 7 +++++++ .../app/modules/home/components/widget/lib/maps/polygon.ts | 6 +++--- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts index f4247d152e..1abd64093d 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts @@ -775,7 +775,7 @@ export default abstract class LeafletMap { if (coordinates.length === 1) { coordinates = coordinates[0]; } - if (e.shape === 'Rectangle') { + if (e.shape === 'Rectangle' && coordinates.length === 1) { // @ts-ignore const bounds: L.LatLngBounds = e.layer.getBounds(); const boundsArray = [bounds.getNorthWest(), bounds.getNorthEast(), bounds.getSouthWest(), bounds.getSouthEast()]; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/maps-utils.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/maps-utils.ts index c76a6de48e..9c2fbcdcd5 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/maps-utils.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/maps-utils.ts @@ -56,3 +56,10 @@ export function bindPopupActions(popup: L.Popup, settings: MarkerSettings | Poly } }); } + +export function isCutPolygon(data): boolean { + if (Array.isArray(data[0]) && Array.isArray(data[0][0])) { + return true; + } + return false; +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/polygon.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/polygon.ts index ab3abc7f7f..908952e7d2 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/polygon.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/polygon.ts @@ -15,7 +15,7 @@ /// import L, { LatLngExpression, LeafletMouseEvent } from 'leaflet'; -import { createTooltip } from './maps-utils'; +import { createTooltip, isCutPolygon } from './maps-utils'; import { fillPattern, functionValueCalculator, @@ -39,7 +39,7 @@ export class Polygon { const polygonColor = this.getPolygonColor(settings); const polygonStrokeColor = this.getPolygonStrokeColor(settings); const polyData = data[this.settings.polygonKeyName]; - const polyConstructor = polyData.length > 2 ? L.polygon : L.rectangle; + const polyConstructor = isCutPolygon(polyData) || polyData.length > 2 ? L.polygon : L.rectangle; this.leafletPoly = polyConstructor(polyData, { fill: true, fillColor: polygonColor, @@ -102,7 +102,7 @@ export class Polygon { this.data = data; this.dataSources = dataSources; const polyData = data[this.settings.polygonKeyName]; - if (polyData.length > 2) { + if (isCutPolygon(polyData) || polyData.length > 2) { if (this.leafletPoly instanceof L.Rectangle) { this.map.removeLayer(this.leafletPoly); const polygonColor = this.getPolygonColor(settings); From 3950b58845b96bb475b8b4c5908e8d49eb3bfbcc Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Tue, 21 Dec 2021 09:47:37 +0200 Subject: [PATCH 277/432] Add tooltip offset settings for map widgets. Improve default values handling by json schema form component. --- .../components/widget/lib/maps/map-models.ts | 4 ++++ .../components/widget/lib/maps/markers.ts | 14 +++++++---- .../components/widget/lib/maps/schemes.ts | 24 ++++++++++++++----- .../react/json-form-base-component.tsx | 16 ++++++------- 4 files changed, 40 insertions(+), 18 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-models.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-models.ts index a472a99915..981e71d787 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-models.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-models.ts @@ -104,6 +104,8 @@ export type MarkerSettings = { markerImageFunction?: MarkerImageFunction; markerOffsetX: number; markerOffsetY: number; + tooltipOffsetX: number; + tooltipOffsetY: number; }; export interface FormattedData { @@ -223,6 +225,8 @@ export const defaultSettings: any = { yPosKeyName: 'yPos', markerOffsetX: 0.5, markerOffsetY: 1, + tooltipOffsetX: 0, + tooltipOffsetY: -1, latKeyName: 'latitude', lngKeyName: 'longitude', polygonKeyName: 'coordinates', diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/markers.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/markers.ts index 5550706402..f2fae19ab0 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/markers.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/markers.ts @@ -33,6 +33,7 @@ import LeafletMap from './leaflet-map'; export class Marker { leafletMarker: L.Marker; + labelOffset: L.LatLngTuple; tooltipOffset: L.LatLngTuple; markerOffset: L.LatLngTuple; tooltip: L.Popup; @@ -49,9 +50,14 @@ export class Marker { isDefined(settings.markerOffsetY) ? settings.markerOffsetY : 1, ]; + this.tooltipOffset = [ + isDefined(settings.tooltipOffsetX) ? settings.tooltipOffsetX : 0, + isDefined(settings.tooltipOffsetY) ? settings.tooltipOffsetY : -1, + ]; + this.createMarkerIcon((iconInfo) => { this.leafletMarker.setIcon(iconInfo.icon); - this.tooltipOffset = [0, -iconInfo.size[1] * this.markerOffset[1] + 10]; + this.labelOffset = [0, -iconInfo.size[1] * this.markerOffset[1] + 10]; this.updateMarkerLabel(settings); }); @@ -111,7 +117,7 @@ export class Marker { } settings.labelText = fillPattern(this.map.markerLabelText, this.map.replaceInfoLabelMarker, this.data); this.leafletMarker.bindTooltip(`
${settings.labelText}
`, - { className: 'tb-marker-label', permanent: true, direction: 'top', offset: this.tooltipOffset }); + { className: 'tb-marker-label', permanent: true, direction: 'top', offset: this.labelOffset }); } } @@ -124,7 +130,7 @@ export class Marker { updateMarkerIcon(settings: MarkerSettings) { this.createMarkerIcon((iconInfo) => { this.leafletMarker.setIcon(iconInfo.icon); - this.tooltipOffset = [0, -iconInfo.size[1] * this.markerOffset[1] + 10]; + this.labelOffset = [0, -iconInfo.size[1] * this.markerOffset[1] + 10]; this.updateMarkerLabel(settings); }); } @@ -165,7 +171,7 @@ export class Marker { iconUrl: currentImage.url, iconSize: [width, height], iconAnchor: [width * this.markerOffset[0], height * this.markerOffset[1]], - popupAnchor: [0, -height] + popupAnchor: [width * this.tooltipOffset[0], height * this.tooltipOffset[1]] }); const iconInfo = { size: [width, height], diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/schemes.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/schemes.ts index b42da7d8b0..2924ff688e 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/schemes.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/schemes.ts @@ -343,15 +343,25 @@ export const commonMapSettingsSchema = default: 'return {x: origXPos, y: origYPos};' }, markerOffsetX: { - title: 'Marker X offset relative to position', + title: 'Marker X offset relative to position multiplied by marker width', type: 'number', default: 0.5 }, markerOffsetY: { - title: 'Marker Y offset relative to position', + title: 'Marker Y offset relative to position multiplied by marker height', type: 'number', default: 1 }, + tooltipOffsetX: { + title: 'Tooltip X offset relative to marker anchor multiplied by marker width', + type: 'number', + default: 0 + }, + tooltipOffsetY: { + title: 'Tooltip Y offset relative to marker anchor multiplied by marker height', + type: 'number', + default: -1 + }, color: { title: 'Color', type: 'string' @@ -482,13 +492,15 @@ export const commonMapSettingsSchema = condition: 'model.showTooltip === true && model.useTooltipFunction === true' }, { - key: 'markerOffsetX', - condition: 'model.provider === "image-map"' + key: 'tooltipOffsetX', + condition: 'model.showTooltip === true' }, { - key: 'markerOffsetY', - condition: 'model.provider === "image-map"' + key: 'tooltipOffsetY', + condition: 'model.showTooltip === true' }, + 'markerOffsetX', + 'markerOffsetY', { key: 'posFunction', type: 'javascript', diff --git a/ui-ngx/src/app/shared/components/json-form/react/json-form-base-component.tsx b/ui-ngx/src/app/shared/components/json-form/react/json-form-base-component.tsx index ce1f570f7f..17885e7c50 100644 --- a/ui-ngx/src/app/shared/components/json-form/react/json-form-base-component.tsx +++ b/ui-ngx/src/app/shared/components/json-form/react/json-form-base-component.tsx @@ -67,10 +67,10 @@ export default ThingsboardBaseComponent => class

defaultValue() { let value = JsonFormUtils.selectOrSet(this.props.form.key, this.props.model); if (this.props.form.schema.type === 'boolean') { - if (typeof value !== 'boolean' && this.props.form.default) { + if (typeof value !== 'boolean' && typeof this.props.form.default === 'boolean') { value = this.props.form.default; } - if (typeof value !== 'boolean' && this.props.form.schema && this.props.form.schema.default) { + if (typeof value !== 'boolean' && this.props.form.schema && typeof this.props.form.schema.default === 'boolean') { value = this.props.form.schema.default; } if (typeof value !== 'boolean' && @@ -79,13 +79,13 @@ export default ThingsboardBaseComponent => class

value = false; } } else if (this.props.form.schema.type === 'integer' || this.props.form.schema.type === 'number') { - if (typeof value !== 'number' && this.props.form.default) { + if (typeof value !== 'number' && typeof this.props.form.default === 'number') { value = this.props.form.default; } - if (typeof value !== 'number' && this.props.form.schema && this.props.form.schema.default) { + if (typeof value !== 'number' && this.props.form.schema && typeof this.props.form.schema.default === 'number') { value = this.props.form.schema.default; } - if (typeof value !== 'number' && this.props.form.titleMap && this.props.form.titleMap[0].value) { + if (typeof value !== 'number' && this.props.form.titleMap && typeof this.props.form.titleMap[0].value === 'number') { value = this.props.form.titleMap[0].value; } if (value && typeof value === 'string') { @@ -96,13 +96,13 @@ export default ThingsboardBaseComponent => class

} } } else { - if (!value && this.props.form.default) { + if (!value && typeof this.props.form.default !== 'undefined') { value = this.props.form.default; } - if (!value && this.props.form.schema && this.props.form.schema.default) { + if (!value && this.props.form.schema && typeof this.props.form.schema.default !== 'undefined') { value = this.props.form.schema.default; } - if (!value && this.props.form.titleMap && this.props.form.titleMap[0].value) { + if (!value && this.props.form.titleMap && typeof this.props.form.titleMap[0].value !== 'undefined') { value = this.props.form.titleMap[0].value; } } From 017c4f072e785b7c1eaa98221938ff97a56e3519 Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Tue, 21 Dec 2021 12:30:29 +0200 Subject: [PATCH 278/432] fixed removing fw/sw attributes if fw/sw is not set --- .../ota/DefaultOtaPackageStateService.java | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/ota/DefaultOtaPackageStateService.java b/application/src/main/java/org/thingsboard/server/service/ota/DefaultOtaPackageStateService.java index 0c372fdfd6..c239dd78b3 100644 --- a/application/src/main/java/org/thingsboard/server/service/ota/DefaultOtaPackageStateService.java +++ b/application/src/main/java/org/thingsboard/server/service/ota/DefaultOtaPackageStateService.java @@ -122,17 +122,17 @@ public class DefaultOtaPackageStateService implements OtaPackageStateService { newFirmwareId = newDeviceProfile.getFirmwareId(); } if (oldDevice != null) { + OtaPackageId oldFirmwareId = oldDevice.getFirmwareId(); + if (oldFirmwareId == null) { + DeviceProfile oldDeviceProfile = deviceProfileService.findDeviceProfileById(oldDevice.getTenantId(), oldDevice.getDeviceProfileId()); + oldFirmwareId = oldDeviceProfile.getFirmwareId(); + } if (newFirmwareId != null) { - OtaPackageId oldFirmwareId = oldDevice.getFirmwareId(); - if (oldFirmwareId == null) { - DeviceProfile oldDeviceProfile = deviceProfileService.findDeviceProfileById(oldDevice.getTenantId(), oldDevice.getDeviceProfileId()); - oldFirmwareId = oldDeviceProfile.getFirmwareId(); - } if (!newFirmwareId.equals(oldFirmwareId)) { // Device was updated and new firmware is different from previous firmware. send(device.getTenantId(), device.getId(), newFirmwareId, System.currentTimeMillis(), FIRMWARE); } - } else { + } else if (oldFirmwareId != null){ // Device was updated and new firmware is not set. remove(device, FIRMWARE); } @@ -149,17 +149,17 @@ public class DefaultOtaPackageStateService implements OtaPackageStateService { newSoftwareId = newDeviceProfile.getSoftwareId(); } if (oldDevice != null) { + OtaPackageId oldSoftwareId = oldDevice.getSoftwareId(); + if (oldSoftwareId == null) { + DeviceProfile oldDeviceProfile = deviceProfileService.findDeviceProfileById(oldDevice.getTenantId(), oldDevice.getDeviceProfileId()); + oldSoftwareId = oldDeviceProfile.getSoftwareId(); + } if (newSoftwareId != null) { - OtaPackageId oldSoftwareId = oldDevice.getSoftwareId(); - if (oldSoftwareId == null) { - DeviceProfile oldDeviceProfile = deviceProfileService.findDeviceProfileById(oldDevice.getTenantId(), oldDevice.getDeviceProfileId()); - oldSoftwareId = oldDeviceProfile.getSoftwareId(); - } if (!newSoftwareId.equals(oldSoftwareId)) { // Device was updated and new firmware is different from previous firmware. send(device.getTenantId(), device.getId(), newSoftwareId, System.currentTimeMillis(), SOFTWARE); } - } else { + } else if (oldSoftwareId != null){ // Device was updated and new firmware is not set. remove(device, SOFTWARE); } From 49a9a3136f61eb1c92a016818c4e6ed15aa82db8 Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Tue, 21 Dec 2021 11:50:05 +0200 Subject: [PATCH 279/432] UI: Improvement multiple attribute widget --- .../system/widget_bundles/input_widgets.json | 2 +- ui-ngx/src/app/core/utils.ts | 4 + .../lib/multiple-input-widget.component.html | 21 +++- .../lib/multiple-input-widget.component.scss | 14 +++ .../lib/multiple-input-widget.component.ts | 114 ++++++++++++++++-- 5 files changed, 141 insertions(+), 14 deletions(-) diff --git a/application/src/main/data/json/system/widget_bundles/input_widgets.json b/application/src/main/data/json/system/widget_bundles/input_widgets.json index 1b085be999..3d81c0e5fe 100644 --- a/application/src/main/data/json/system/widget_bundles/input_widgets.json +++ b/application/src/main/data/json/system/widget_bundles/input_widgets.json @@ -38,7 +38,7 @@ "templateCss": ".tb-toast {\n min-width: 0;\n font-size: 14px !important;\n}", "controllerScript": "self.onInit = function() {\r\n}\r\n\r\nself.onDataUpdated = function() {\r\n self.ctx.$scope.multipleInputWidget.onDataUpdated();\r\n}\r\n", "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"MultipleInput\",\n \"properties\": {\n \"widgetTitle\": {\n \"title\": \"Widget title\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"showActionButtons\":{\n \"title\":\"Show action buttons\",\n \"type\":\"boolean\",\n \"default\": true\n },\n \"updateAllValues\": {\n \"title\":\"Update all values, not only modified\",\n \"type\":\"boolean\",\n \"default\": false\n },\n \"saveButtonLabel\": {\n \"title\": \"'SAVE' button label\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"resetButtonLabel\": {\n \"title\": \"'UNDO' button label\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"showResultMessage\":{\n \"title\":\"Show result message\",\n \"type\":\"boolean\",\n \"default\": true\n },\n \"showGroupTitle\": {\n \"title\":\"Show title for group of fields, related to different entities\",\n \"type\":\"boolean\",\n \"default\": false\n },\n \"groupTitle\": {\n \"title\": \"Group title\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"fieldsAlignment\": {\n \"title\": \"Fields alignment\",\n \"type\": \"string\",\n \"default\": \"row\"\n },\n \"fieldsInRow\": {\n \"title\": \"Number of fields in the row\",\n \"type\": \"number\",\n \"default\": \"2\"\n }\n },\n \"required\": []\n },\n \"form\": [\n \"widgetTitle\",\n \"showActionButtons\",\n {\n \"key\": \"updateAllValues\",\n \"condition\": \"model.showActionButtons === true\"\n },\n {\n \"key\": \"saveButtonLabel\",\n \"condition\": \"model.showActionButtons === true\"\n },\n {\n \"key\": \"resetButtonLabel\",\n \"condition\": \"model.showActionButtons === true\"\n },\n \"showResultMessage\",\n \"showGroupTitle\",\n \"groupTitle\",\n {\n \"key\": \"fieldsAlignment\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"row\",\n \"label\": \"Row (default)\"\n },\n {\n \"value\": \"column\",\n \"label\": \"Column\"\n }\n ]\n },\n {\n \"key\": \"fieldsInRow\",\n \"condition\": \"model.fieldsAlignment === 'row'\"\n }\n ]\n}", - "dataKeySettingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"DataKeySettings\",\n \"properties\": {\n \"dataKeyType\": {\n \"title\": \"Datakey type\",\n \"type\": \"string\",\n \"default\": \"server\"\n },\n \"dataKeyValueType\": {\n \"title\": \"Datakey value type\",\n \"type\": \"string\",\n \"default\": \"string\"\n },\n \"selectOptions\": {\n \"title\": \"Select options\",\n \"type\": \"array\",\n \"default\": [],\n \"items\": {\n \"type\": \"object\",\n \"properties\": {\n \"value\": {\n \"title\": \"Value (write 'null' for create empty option)\",\n \"type\": \"string\"\n },\n \"label\": {\n \"title\": \"Label\",\n \"type\": \"string\"\n }\n },\n \"required\": [\"value\"]\n }\n },\n \"step\": {\n \"title\": \"Step interval between values\",\n \"type\": \"number\",\n \"default\": \"1\"\n },\n \"minValue\": {\n \"title\": \"Minimum value\",\n \"type\": \"number\"\n },\n \"maxValue\": {\n \"title\": \"Maximum value\",\n \"type\": \"number\"\n },\n \"required\": {\n \"title\": \"Value is required\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"requiredErrorMessage\": {\n \"title\": \"'Required' error message\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"minValueErrorMessage\": {\n \"title\": \"'Min Value' error message\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"maxValueErrorMessage\": {\n \"title\": \"'Max Value' error message\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"invalidDateErrorMessage\": {\n \"title\": \"'Invalid Date' error message\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"isEditable\": {\n \"title\": \"Ability to edit attribute\",\n \"type\": \"string\",\n \"default\": \"editable\"\n },\n \"disabledOnDataKey\": {\n \"title\": \"Disable on false value of another datakey (specify datakey name)\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"dataKeyHidden\": {\n \"title\": \"Hide input field\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"icon\": {\n \"title\": \"Icon to show before input cell\",\n \"type\": \"string\",\n \"default\": \"\"\n }\n },\n \"required\": []\n },\n \"form\": [\n {\n \"key\": \"dataKeyType\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"server\",\n \"label\": \"Server attribute (default)\"\n },\n {\n \"value\": \"shared\",\n \"label\": \"Shared attribute\"\n },\n {\n \"value\": \"timeseries\",\n \"label\": \"Timeseries\"\n }\n ]\n },\n {\n \"key\": \"dataKeyValueType\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"string\",\n \"label\": \"String\"\n },\n {\n \"value\": \"double\",\n \"label\": \"Double\"\n },\n {\n \"value\": \"integer\",\n \"label\": \"Integer\"\n },\n {\n \"value\": \"booleanCheckbox\",\n \"label\": \"Boolean (Checkbox)\"\n },\n {\n \"value\": \"booleanSwitch\",\n \"label\": \"Boolean (Switch)\"\n },\n {\n \"value\": \"dateTime\",\n \"label\": \"Date & Time\"\n },\n {\n \"value\": \"date\",\n \"label\": \"Date\"\n },\n {\n \"value\": \"time\",\n \"label\": \"Time\"\n },\n {\n \"value\": \"select\",\n \"label\": \"Select\"\n }\n ]\n },\n {\n \"key\": \"selectOptions\",\n \"condition\": \"model.dataKeyValueType === 'select'\",\n \"items\": [\"selectOptions[].value\", \"selectOptions[].label\"]\n },\n {\n \"key\": \"step\",\n \"condition\": \"model.dataKeyValueType === 'double' || model.dataKeyValueType === 'integer'\"\n },\n {\n \"key\": \"minValue\",\n \"condition\": \"model.dataKeyValueType === 'double' || model.dataKeyValueType === 'integer'\"\n },\n {\n \"key\": \"maxValue\",\n \"condition\": \"model.dataKeyValueType === 'double' || model.dataKeyValueType === 'integer'\"\n },\n \"required\",\n {\n \"key\": \"requiredErrorMessage\",\n \"condition\": \"model.required === true\"\n },\n {\n \"key\": \"invalidDateErrorMessage\",\n \"condition\": \"model.dataKeyValueType === 'dateTime' || model.dataKeyValueType === 'date' || model.dataKeyValueType === 'time'\"\n },\n {\n \"key\": \"minValueErrorMessage\",\n \"condition\": \"model.dataKeyValueType === 'double' || model.dataKeyValueType === 'integer'\"\n },\n {\n \"key\": \"maxValueErrorMessage\",\n \"condition\": \"model.dataKeyValueType === 'double' || model.dataKeyValueType === 'integer'\"\n },\n {\n \"key\": \"isEditable\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"editable\",\n \"label\": \"Editable (default)\"\n },\n {\n \"value\": \"disabled\",\n \"label\": \"Disabled\"\n },\n {\n \"value\": \"readonly\",\n \"label\": \"Read-only\"\n }\n ]\n },\n \"disabledOnDataKey\",\n \"dataKeyHidden\",\n\t\t{\n \t\t\"key\": \"icon\",\n\t\t\t\"type\": \"icon\"\n\t\t}\n ]\n}\n", + "dataKeySettingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"DataKeySettings\",\n \"properties\": {\n \"dataKeyType\": {\n \"title\": \"Datakey type\",\n \"type\": \"string\",\n \"default\": \"server\"\n },\n \"dataKeyValueType\": {\n \"title\": \"Datakey value type\",\n \"type\": \"string\",\n \"default\": \"string\"\n },\n \"slideToggleLabelPosition\": {\n \"title\": \"Label appears after or before the slide-toggle\",\n \"type\": \"string\",\n \"default\": \"after\"\n },\n \"selectOptions\": {\n \"title\": \"Select options\",\n \"type\": \"array\",\n \"default\": [],\n \"items\": {\n \"type\": \"object\",\n \"properties\": {\n \"value\": {\n \"title\": \"Value (write 'null' for create empty option)\",\n \"type\": \"string\"\n },\n \"label\": {\n \"title\": \"Label\",\n \"type\": \"string\"\n }\n },\n \"required\": [\"value\"]\n }\n },\n \"step\": {\n \"title\": \"Step interval between values\",\n \"type\": \"number\",\n \"default\": \"1\"\n },\n \"minValue\": {\n \"title\": \"Minimum value\",\n \"type\": \"number\"\n },\n \"maxValue\": {\n \"title\": \"Maximum value\",\n \"type\": \"number\"\n },\n \"required\": {\n \"title\": \"Value is required\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"requiredErrorMessage\": {\n \"title\": \"'Required' error message\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"minValueErrorMessage\": {\n \"title\": \"'Min Value' error message\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"maxValueErrorMessage\": {\n \"title\": \"'Max Value' error message\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"invalidDateErrorMessage\": {\n \"title\": \"'Invalid Date' error message\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"isEditable\": {\n \"title\": \"Ability to edit attribute\",\n \"type\": \"string\",\n \"default\": \"editable\"\n },\n \"disabledOnDataKey\": {\n \"title\": \"Disable on false value of another datakey (specify datakey name)\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"dataKeyHidden\": {\n \"title\": \"Hide input field\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"useCustomIcon\": {\n \"title\": \"Use custom icon\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"icon\": {\n \"title\": \"Icon to show before input cell\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"customIcon\": {\n \"title\": \"Icon to show before input cell\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"useGetValueFunction\": {\n \"title\": \"use getValue function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"getValueFunctionBody\": {\n \"title\": \"getValue function: f(value, ctx)\",\n \"type\": \"string\"\n },\n \"useSetValueFunction\": {\n \"title\": \"use setValue function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"setValueFunctionBody\": {\n \"title\": \"setValue function: f(value, originValue, ctx)\",\n \"type\": \"string\"\n }\n },\n \"required\": []\n },\n \"form\": [\n {\n \"key\": \"dataKeyType\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"server\",\n \"label\": \"Server attribute (default)\"\n },\n {\n \"value\": \"shared\",\n \"label\": \"Shared attribute\"\n },\n {\n \"value\": \"timeseries\",\n \"label\": \"Timeseries\"\n }\n ]\n },\n {\n \"key\": \"dataKeyValueType\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"string\",\n \"label\": \"String\"\n },\n {\n \"value\": \"double\",\n \"label\": \"Double\"\n },\n {\n \"value\": \"integer\",\n \"label\": \"Integer\"\n },\n {\n \"value\": \"booleanCheckbox\",\n \"label\": \"Boolean (Checkbox)\"\n },\n {\n \"value\": \"booleanSwitch\",\n \"label\": \"Boolean (Switch)\"\n },\n {\n \"value\": \"dateTime\",\n \"label\": \"Date & Time\"\n },\n {\n \"value\": \"date\",\n \"label\": \"Date\"\n },\n {\n \"value\": \"time\",\n \"label\": \"Time\"\n },\n {\n \"value\": \"select\",\n \"label\": \"Select\"\n }\n ]\n },\n {\n \"key\": \"slideToggleLabelPosition\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"condition\": \"model.dataKeyValueType === 'booleanSwitch'\",\n \"items\": [\n {\n \"value\": \"after\",\n \"label\": \"After\"\n },\n {\n \"value\": \"before\",\n \"label\": \"Before\"\n }\n ]\n },\n {\n \"key\": \"selectOptions\",\n \"condition\": \"model.dataKeyValueType === 'select'\",\n \"items\": [\"selectOptions[].value\", \"selectOptions[].label\"]\n },\n {\n \"key\": \"step\",\n \"condition\": \"model.dataKeyValueType === 'double' || model.dataKeyValueType === 'integer'\"\n },\n {\n \"key\": \"minValue\",\n \"condition\": \"model.dataKeyValueType === 'double' || model.dataKeyValueType === 'integer'\"\n },\n {\n \"key\": \"maxValue\",\n \"condition\": \"model.dataKeyValueType === 'double' || model.dataKeyValueType === 'integer'\"\n },\n \"required\",\n {\n \"key\": \"requiredErrorMessage\",\n \"condition\": \"model.required === true\"\n },\n {\n \"key\": \"invalidDateErrorMessage\",\n \"condition\": \"model.dataKeyValueType === 'dateTime' || model.dataKeyValueType === 'date' || model.dataKeyValueType === 'time'\"\n },\n {\n \"key\": \"minValueErrorMessage\",\n \"condition\": \"model.dataKeyValueType === 'double' || model.dataKeyValueType === 'integer'\"\n },\n {\n \"key\": \"maxValueErrorMessage\",\n \"condition\": \"model.dataKeyValueType === 'double' || model.dataKeyValueType === 'integer'\"\n },\n {\n \"key\": \"isEditable\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"editable\",\n \"label\": \"Editable (default)\"\n },\n {\n \"value\": \"disabled\",\n \"label\": \"Disabled\"\n },\n {\n \"value\": \"readonly\",\n \"label\": \"Read-only\"\n }\n ]\n },\n \"disabledOnDataKey\",\n \"dataKeyHidden\",\n \"useCustomIcon\",\n\t\t{\n \t\t\"key\": \"icon\",\n\t\t\t\"type\": \"icon\",\n\t\t\t\"condition\": \"model.useCustomIcon !== true\"\n\t\t},\n\t\t{\n \t\t\"key\": \"customIcon\",\n\t\t\t\"type\": \"image\",\n\t\t\t\"condition\": \"model.useCustomIcon === true\"\n\t\t},\n\t\t\"useGetValueFunction\",\n\t\t{\n\t\t \"key\": \"getValueFunctionBody\",\n\t\t \"type\": \"javascript\",\n\t\t \"condition\": \"model.useGetValueFunction === true\"\n\t\t},\n\t\t\"useSetValueFunction\",\n\t\t{\n\t\t \"key\": \"setValueFunctionBody\",\n\t\t \"type\": \"javascript\",\n\t\t \"condition\": \"model.useSetValueFunction === true\"\n\t\t}\n ]\n}\n", "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Sin\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.23592248334107624,\"funcBody\":\"return Math.round(1000*Math.sin(time/5000));\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{},\"title\":\"Update Multiple Attributes\",\"dropShadow\":true,\"enableFullscreen\":false,\"enableDataExport\":false,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"useDashboardTimewindow\":true,\"showLegend\":false,\"actions\":{}}" } }, diff --git a/ui-ngx/src/app/core/utils.ts b/ui-ngx/src/app/core/utils.ts index aa52c55cbe..b986583171 100644 --- a/ui-ngx/src/app/core/utils.ts +++ b/ui-ngx/src/app/core/utils.ts @@ -114,6 +114,10 @@ export function isNumeric(value: any): boolean { return (value - parseFloat(value) + 1) >= 0; } +export function isBoolean(value: any): boolean { + return typeof value === 'boolean'; +} + export function isString(value: any): boolean { return typeof value === 'string'; } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.html index ce0bdc4acd..6907a8afbf 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.html @@ -37,7 +37,12 @@ type="text" (focus)="key.isFocused = true; focusInputElement($event)" (blur)="key.isFocused = false; inputChanged(source, key)"> - {{key.settings.icon}} + + {{key.settings.icon}} + + icon + + {{ getErrorMessageText(key.settings, 'required') }} @@ -57,7 +62,12 @@ max="{{key.settings.maxValue}}" (focus)="key.isFocused = true; focusInputElement($event)" (blur)="key.isFocused = false; inputChanged(source, key)"> - {{key.settings.icon}} + + {{key.settings.icon}} + + icon + + {{ getErrorMessageText(key.settings,'required') }} @@ -77,7 +87,14 @@

+ + {{key.settings.icon}} + + icon + + {{key.label}}
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.scss b/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.scss index cdf83e2e38..eaec893836 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.scss +++ b/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.scss @@ -64,3 +64,17 @@ } } } + +:host ::ng-deep { + .tb-multiple-input { + .mat-slide-toggle-content { + width: 100%; + display: flex; + align-items: center; + + .mat-icon { + margin-right: 8px; + } + } + } +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.ts index 016e04392e..cac977dd4c 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.ts @@ -24,7 +24,14 @@ import { UtilsService } from '@core/services/utils.service'; import { TranslateService } from '@ngx-translate/core'; import { DataKey, Datasource, DatasourceData, DatasourceType, WidgetConfig } from '@shared/models/widget.models'; import { IWidgetSubscription } from '@core/api/widget-api.models'; -import { createLabelFromDatasource, isDefinedAndNotNull, isEqual, isNotEmptyStr, isUndefined } from '@core/utils'; +import { + createLabelFromDatasource, + isBoolean, isDefined, + isDefinedAndNotNull, + isEqual, + isNotEmptyStr, + isUndefined +} from '@core/utils'; import { EntityType } from '@shared/models/entity-type.models'; import * as _moment from 'moment'; import { FormBuilder, FormGroup, ValidatorFn, Validators } from '@angular/forms'; @@ -35,6 +42,7 @@ import { forkJoin, Observable, Subject } from 'rxjs'; import { EntityId } from '@shared/models/id/entity-id'; import { ResizeObserver } from '@juggle/resize-observer'; import { takeUntil } from 'rxjs/operators'; +import { DomSanitizer, SafeUrl } from '@angular/platform-browser'; type FieldAlignment = 'row' | 'column'; @@ -44,6 +52,9 @@ type MultipleInputWidgetDataKeyValueType = 'string' | 'double' | 'integer' | 'dateTime' | 'date' | 'time' | 'select'; type MultipleInputWidgetDataKeyEditableType = 'editable' | 'disabled' | 'readonly'; +type ConvertGetValueFunction = (value: any, ctx: WidgetContext) => any; +type ConvertSetValueFunction = (value: any, originValue: any, ctx: WidgetContext) => any; + interface MultipleInputWidgetSettings { widgetTitle: string; showActionButtons: boolean; @@ -66,6 +77,7 @@ interface MultipleInputWidgetSelectOption { interface MultipleInputWidgetDataKeySettings { dataKeyType: MultipleInputWidgetDataKeyType; dataKeyValueType: MultipleInputWidgetDataKeyValueType; + slideToggleLabelPosition?: 'after' | 'before'; selectOptions: MultipleInputWidgetSelectOption[]; required: boolean; isEditable: MultipleInputWidgetDataKeyEditableType; @@ -78,10 +90,19 @@ interface MultipleInputWidgetDataKeySettings { invalidDateErrorMessage?: string; minValueErrorMessage?: string; maxValueErrorMessage?: string; + useCustomIcon: boolean; icon: string; + customIcon: string ; + safeCustomIcon?: SafeUrl; inputTypeNumber?: boolean; readOnly?: boolean; disabledOnCondition?: boolean; + useGetValueFunction?: boolean; + getValueFunctionBody?: string; + getValueFunction?: ConvertGetValueFunction; + useSetValueFunction?: boolean; + setValueFunctionBody?: string; + setValueFunction?: ConvertSetValueFunction; } interface MultipleInputWidgetDataKey extends DataKey { @@ -139,7 +160,8 @@ export class MultipleInputWidgetComponent extends PageComponent implements OnIni private utils: UtilsService, private fb: FormBuilder, private attributeService: AttributeService, - private translate: TranslateService) { + private translate: TranslateService, + private sanitizer: DomSanitizer) { super(store); } @@ -265,6 +287,34 @@ export class MultipleInputWidgetComponent extends PageComponent implements OnIni }); } + if (dataKey.settings.dataKeyValueType === 'booleanSwitch' && isUndefined(dataKey.settings.slideToggleLabelPosition)) { + dataKey.settings.slideToggleLabelPosition = 'after'; + } + + if (dataKey.settings.useCustomIcon && isDefinedAndNotNull(dataKey.settings.customIcon)) { + dataKey.settings.safeCustomIcon = this.sanitizer.bypassSecurityTrustUrl(dataKey.settings.customIcon); + } + + if (dataKey.settings.useGetValueFunction && dataKey.settings.getValueFunctionBody.length) { + try { + dataKey.settings.getValueFunction = + new Function('value, ctx', dataKey.settings.getValueFunctionBody) as ConvertGetValueFunction; + } catch (e) { + console.warn(`Parse getValue function in key ${dataKey.label}`, e); + dataKey.settings.getValueFunction = null; + } + } + + if (dataKey.settings.useSetValueFunction && dataKey.settings.setValueFunctionBody.length) { + try { + dataKey.settings.setValueFunction = + new Function('value, originValue, ctx', dataKey.settings.setValueFunctionBody) as ConvertSetValueFunction; + } catch (e) { + console.warn(`Parse setValue function in key ${dataKey.label}`, e); + dataKey.settings.setValueFunction = null; + } + } + source.keys.push(dataKey); }); } else { @@ -342,28 +392,41 @@ export class MultipleInputWidgetComponent extends PageComponent implements OnIni source.keys.forEach((key) => { const keyData = data[dataIndex].data; if (keyData && keyData.length) { - let value; + let value = keyData[0][1]; + const keyValue = this.getKeyValue(value, key.settings); switch (key.settings.dataKeyValueType) { case 'dateTime': case 'date': - if (isDefinedAndNotNull(keyData[0][1]) && keyData[0][1] !== '') { - value = _moment(keyData[0][1]).toDate(); + if (isDefinedAndNotNull(keyValue) && keyValue !== '') { + if (keyValue instanceof Date) { + value = keyValue; + } else { + value = _moment(keyValue).toDate(); + } } else { value = null; } break; case 'time': - value = _moment().startOf('day').add(keyData[0][1], 'ms').toDate(); + if (keyValue instanceof Date) { + value = keyValue; + } else { + value = _moment().startOf('day').add(keyValue, 'ms').toDate(); + } break; case 'booleanCheckbox': case 'booleanSwitch': - value = (keyData[0][1] === 'true'); + if (isBoolean(keyValue)) { + value = keyValue; + } else { + value = (keyValue === 'true'); + } break; case 'select': - value = keyData[0][1].toString(); + value = keyValue.toString(); break; default: - value = keyData[0][1]; + value = keyValue; } key.value = value; } @@ -399,6 +462,18 @@ export class MultipleInputWidgetComponent extends PageComponent implements OnIni }); } + private getKeyValue(data: any, keySetting: MultipleInputWidgetDataKeySettings) { + if (isDefined(keySetting.getValueFunction)) { + try { + return keySetting.getValueFunction(data, this.ctx); + } catch (e) { + console.warn(`Call function getValue`, e); + return data; + } + } + return data; + } + private updateWidgetDisplaying() { this.changeAlignment = (this.ctx.$container && this.ctx.$container[0].offsetWidth < 620); } @@ -493,7 +568,8 @@ export class MultipleInputWidgetComponent extends PageComponent implements OnIni if (!this.settings.showActionButtons && !this.isSavingInProgress) { this.isSavingInProgress = true; const currentValue = this.multipleInputFormGroup.get(key.formId).value; - if (!key.settings.required || (key.settings.required && isDefinedAndNotNull(currentValue) && isNotEmptyStr(currentValue.toString()))) { + if (!key.settings.required || + (key.settings.required && isDefinedAndNotNull(currentValue) && isNotEmptyStr(currentValue.toString()))) { const dataToSave: MultipleInputWidgetSource = { datasource: source.datasource, keys: [key] @@ -523,8 +599,9 @@ export class MultipleInputWidgetComponent extends PageComponent implements OnIni const sharedAttributes: AttributeData[] = []; const telemetry: AttributeData[] = []; for (const key of toSave.keys) { - const currentValue = key.settings.dataKeyHidden ? key.value : this.multipleInputFormGroup.get(key.formId).value; + let currentValue = key.settings.dataKeyHidden ? key.value : this.multipleInputFormGroup.get(key.formId).value; if (!isEqual(currentValue, key.value) || this.settings.updateAllValues) { + currentValue = this.setKeyValue(currentValue, key, toSave); const attribute: AttributeData = { key: key.name, value: null @@ -615,6 +692,21 @@ export class MultipleInputWidgetComponent extends PageComponent implements OnIni } } + private setKeyValue(value: any, key: MultipleInputWidgetDataKey, source: MultipleInputWidgetSource) { + if (isDefined(key.settings.setValueFunction)) { + const currentDatasourceData = this.subscription.data + .find(dsData => dsData.datasource === source.datasource && dsData.dataKey.name === key.name); + const originValue = currentDatasourceData.data[0][1]; + try { + return key.settings.setValueFunction(value, originValue, this.ctx); + } catch (e) { + console.warn(`Call function setValue`, e); + return value; + } + } + return value; + } + public discardAll() { this.multipleInputFormGroup.reset(undefined, {emitEvent: false}); this.sources.forEach((source) => { From ddcee3d69d8a6e039ed9ded7fc4415115a521860 Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Tue, 21 Dec 2021 13:46:55 +0200 Subject: [PATCH 280/432] sql batch thread count have to be a prime number like 3 or 5 to gain perfect hash distribution --- application/src/main/resources/thingsboard.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index 3932ca28a9..c3ce2e3805 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -265,17 +265,17 @@ sql: batch_size: "${SQL_ATTRIBUTES_BATCH_SIZE:10000}" batch_max_delay: "${SQL_ATTRIBUTES_BATCH_MAX_DELAY_MS:100}" stats_print_interval_ms: "${SQL_ATTRIBUTES_BATCH_STATS_PRINT_MS:10000}" - batch_threads: "${SQL_ATTRIBUTES_BATCH_THREADS:4}" + batch_threads: "${SQL_ATTRIBUTES_BATCH_THREADS:3}" # batch thread count have to be a prime number like 3 or 5 to gain perfect hash distribution ts: batch_size: "${SQL_TS_BATCH_SIZE:10000}" batch_max_delay: "${SQL_TS_BATCH_MAX_DELAY_MS:100}" stats_print_interval_ms: "${SQL_TS_BATCH_STATS_PRINT_MS:10000}" - batch_threads: "${SQL_TS_BATCH_THREADS:4}" + batch_threads: "${SQL_TS_BATCH_THREADS:3}" # batch thread count have to be a prime number like 3 or 5 to gain perfect hash distribution ts_latest: batch_size: "${SQL_TS_LATEST_BATCH_SIZE:10000}" batch_max_delay: "${SQL_TS_LATEST_BATCH_MAX_DELAY_MS:100}" stats_print_interval_ms: "${SQL_TS_LATEST_BATCH_STATS_PRINT_MS:10000}" - batch_threads: "${SQL_TS_LATEST_BATCH_THREADS:4}" + batch_threads: "${SQL_TS_LATEST_BATCH_THREADS:3}" # batch thread count have to be a prime number like 3 or 5 to gain perfect hash distribution update_by_latest_ts: "${SQL_TS_UPDATE_BY_LATEST_TIMESTAMP:true}" # Specify whether to sort entities before batch update. Should be enabled for cluster mode to avoid deadlocks batch_sort: "${SQL_BATCH_SORT:false}" @@ -290,7 +290,7 @@ sql: timescale: # Specify Interval size for new data chunks storage. chunk_time_interval: "${SQL_TIMESCALE_CHUNK_TIME_INTERVAL:604800000}" - batch_threads: "${SQL_TIMESCALE_BATCH_THREADS:4}" + batch_threads: "${SQL_TIMESCALE_BATCH_THREADS:3}" # batch thread count have to be a prime number like 3 or 5 to gain perfect hash distribution ttl: ts: enabled: "${SQL_TTL_TS_ENABLED:true}" From 9c44530ab92d8490debf5cc856745b8539f2d656 Mon Sep 17 00:00:00 2001 From: dlandiak Date: Tue, 21 Dec 2021 15:19:30 +0200 Subject: [PATCH 281/432] added boolean param to the mqtt node to allow adding a suffix for client id param --- .../main/java/org/thingsboard/rule/engine/mqtt/TbMqttNode.java | 3 ++- .../thingsboard/rule/engine/mqtt/TbMqttNodeConfiguration.java | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNode.java index 4f4dc7ab60..ac5fa9e7ea 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNode.java @@ -104,7 +104,8 @@ public class TbMqttNode implements TbNode { protected MqttClient initClient(TbContext ctx) throws Exception { MqttClientConfig config = new MqttClientConfig(getSslContext()); if (!StringUtils.isEmpty(this.mqttNodeConfiguration.getClientId())) { - config.setClientId(this.mqttNodeConfiguration.getClientId()); + config.setClientId(this.mqttNodeConfiguration.isAppendClientIdSuffix() ? + this.mqttNodeConfiguration.getClientId() + "_" + ctx.getServiceId() : this.mqttNodeConfiguration.getClientId()); } config.setCleanSession(this.mqttNodeConfiguration.isCleanSession()); diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNodeConfiguration.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNodeConfiguration.java index 9ac797a98a..46c81f3ddd 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNodeConfiguration.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNodeConfiguration.java @@ -28,6 +28,7 @@ public class TbMqttNodeConfiguration implements NodeConfiguration Date: Tue, 21 Dec 2021 17:19:30 +0200 Subject: [PATCH 282/432] Improve map widgets: ability to return marker and tooltip offset from marker image function --- .../components/widget/lib/maps/leaflet-map.ts | 18 ++++---- .../components/widget/lib/maps/map-models.ts | 21 +++++++-- .../components/widget/lib/maps/map-widget2.ts | 2 +- .../components/widget/lib/maps/markers.ts | 46 +++++++++++-------- 4 files changed, 53 insertions(+), 34 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts index 1abd64093d..78f459990e 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import L, { FeatureGroup, Icon, LatLngBounds, LatLngTuple, Projection } from 'leaflet'; +import L, { FeatureGroup, LatLngBounds, LatLngTuple, Projection } from 'leaflet'; import tinycolor from 'tinycolor2'; import 'leaflet-providers'; import { MarkerClusterGroup, MarkerClusterGroupOptions } from 'leaflet.markercluster/dist/leaflet.markercluster'; @@ -24,7 +24,7 @@ import { defaultSettings, FormattedData, MapSettings, - MarkerSettings, + MarkerSettings, MarkerIconInfo, MarkerImageInfo, PolygonSettings, PolylineSettings, ReplaceInfo, @@ -64,7 +64,7 @@ export default abstract class LeafletMap { points: FeatureGroup; markersData: FormattedData[] = []; polygonsData: FormattedData[] = []; - defaultMarkerIconInfo: { size: number[], icon: Icon }; + defaultMarkerIconInfo: MarkerIconInfo; loadingDiv: JQuery; loading = false; replaceInfoLabelMarker: Array = []; @@ -536,16 +536,16 @@ export default abstract class LeafletMap { let m: Marker; rawMarkers.forEach(data => { if (data.rotationAngle || data.rotationAngle === 0) { - const currentImage = this.options.useMarkerImageFunction ? + const currentImage: MarkerImageInfo = this.options.useMarkerImageFunction ? safeExecute(this.options.markerImageFunction, [data, this.options.markerImages, markersData, data.dsIndex]) : this.options.currentImage; const style = currentImage ? 'background-image: url(' + currentImage.url + ');' : ''; - this.options.icon = L.divIcon({ + this.options.icon = { icon: L.divIcon({ html: `
` - }); + style="transform: translate(-10px, -10px) + rotate(${data.rotationAngle}deg); + ${style}">
` + }), size: [30, 30]}; } else { this.options.icon = null; } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-models.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-models.ts index 981e71d787..e65479f588 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-models.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-models.ts @@ -17,13 +17,15 @@ import { Datasource } from '@app/shared/models/widget.models'; import { EntityType } from '@shared/models/entity-type.models'; import tinycolor from 'tinycolor2'; +import { BaseIconOptions, Icon } from 'leaflet'; export const DEFAULT_MAP_PAGE_SIZE = 16384; export const DEFAULT_ZOOM_LEVEL = 8; export type GenericFunction = (data: FormattedData, dsData: FormattedData[], dsIndex: number) => string; -export type MarkerImageFunction = (data: FormattedData, dsData: FormattedData[], dsIndex: number) => string; +export type MarkerImageFunction = (data: FormattedData, dsData: FormattedData[], dsIndex: number) => MarkerImageInfo; export type PosFuncton = (origXPos, origYPos) => { x, y }; +export type MarkerIconReadyFunction = (icon: MarkerIconInfo) => void; export type MapSettings = { draggableMarker: boolean; @@ -51,7 +53,6 @@ export type MapSettings = { useDefaultCenterPosition?: boolean; gmDefaultMapType?: string; useLabelFunction: boolean; - icon?: any; zoomOnClick: boolean, maxZoom: number, showCoverageOnHover: boolean, @@ -73,10 +74,22 @@ export enum MapProviders { tencent = 'tencent-map' } +export type MarkerImageInfo = { + url: string; + size: number; + markerOffset?: [number, number]; + tooltipOffset?: [number, number]; +}; + +export type MarkerIconInfo = { + icon: Icon; + size: [number, number]; +}; + export type MarkerSettings = { tooltipPattern?: any; tooltipAction: { [name: string]: actionsHandler }; - icon?: any; + icon?: MarkerIconInfo; showLabel?: boolean; label: string; labelColor: string; @@ -91,7 +104,7 @@ export type MarkerSettings = { autocloseTooltip: boolean; showTooltipAction: string; useClusterMarkers: boolean; - currentImage?: string; + currentImage?: MarkerImageInfo; useMarkerImageFunction?: boolean; markerImages?: string[]; markerImageSize: number; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-widget2.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-widget2.ts index f755754eca..565887b160 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-widget2.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-widget2.ts @@ -258,7 +258,7 @@ export class MapWidgetController implements MapWidgetInterface { settings.mapProviderHere = hereProviders[0]; } } - const customOptions = { + const customOptions: Partial = { provider: this.provider, mapUrl: settings?.mapImageUrl, labelFunction: parseFunction(settings.labelFunction, functionParams), diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/markers.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/markers.ts index f2fae19ab0..85020b7f33 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/markers.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/markers.ts @@ -15,7 +15,7 @@ /// import L, { Icon, LeafletMouseEvent } from 'leaflet'; -import { FormattedData, MarkerSettings } from './map-models'; +import { FormattedData, MarkerIconInfo, MarkerIconReadyFunction, MarkerImageInfo, MarkerSettings } from './map-models'; import { bindPopupActions, createTooltip, @@ -55,11 +55,7 @@ export class Marker { isDefined(settings.tooltipOffsetY) ? settings.tooltipOffsetY : -1, ]; - this.createMarkerIcon((iconInfo) => { - this.leafletMarker.setIcon(iconInfo.icon); - this.labelOffset = [0, -iconInfo.size[1] * this.markerOffset[1] + 10]; - this.updateMarkerLabel(settings); - }); + this.updateMarkerIcon(settings); if (settings.showTooltip) { this.tooltip = createTooltip(this.leafletMarker, settings, data.$datasource); @@ -130,20 +126,22 @@ export class Marker { updateMarkerIcon(settings: MarkerSettings) { this.createMarkerIcon((iconInfo) => { this.leafletMarker.setIcon(iconInfo.icon); - this.labelOffset = [0, -iconInfo.size[1] * this.markerOffset[1] + 10]; + const anchor = iconInfo.icon.options.iconAnchor; + if (anchor && Array.isArray(anchor)) { + this.labelOffset = [iconInfo.size[0] / 2 - anchor[0], 10 - anchor[1]]; + } else { + this.labelOffset = [0, -iconInfo.size[1] * this.markerOffset[1] + 10]; + } this.updateMarkerLabel(settings); }); } - createMarkerIcon(onMarkerIconReady) { + private createMarkerIcon(onMarkerIconReady: MarkerIconReadyFunction) { if (this.settings.icon) { - onMarkerIconReady({ - size: [30, 30], - icon: this.settings.icon, - }); - return; + onMarkerIconReady(this.settings.icon); + return; } - const currentImage = this.settings.useMarkerImageFunction ? + const currentImage: MarkerImageInfo = this.settings.useMarkerImageFunction ? safeExecute(this.settings.markerImageFunction, [this.data, this.settings.markerImages, this.dataSources, this.data.dsIndex]) : this.settings.currentImage; let currentColor = this.settings.tinyColor; @@ -167,13 +165,21 @@ export class Marker { width = currentImage.size * aspect; height = currentImage.size; } + let iconAnchor = currentImage.markerOffset; + let popupAnchor = currentImage.tooltipOffset; + if (!iconAnchor) { + iconAnchor = [width * this.markerOffset[0], height * this.markerOffset[1]]; + } + if (!popupAnchor) { + popupAnchor = [width * this.tooltipOffset[0], height * this.tooltipOffset[1]]; + } const icon = L.icon({ iconUrl: currentImage.url, iconSize: [width, height], - iconAnchor: [width * this.markerOffset[0], height * this.markerOffset[1]], - popupAnchor: [width * this.tooltipOffset[0], height * this.tooltipOffset[1]] + iconAnchor, + popupAnchor }); - const iconInfo = { + const iconInfo: MarkerIconInfo = { size: [width, height], icon }; @@ -188,8 +194,8 @@ export class Marker { } } - createDefaultMarkerIcon(color: tinycolor.Instance, onMarkerIconReady) { - let icon: { size: number[], icon: Icon }; + createDefaultMarkerIcon(color: tinycolor.Instance, onMarkerIconReady: MarkerIconReadyFunction) { + let icon: MarkerIconInfo; if (!tinycolor.equals(color, this.settings.tinyColor)) { icon = this.createColoredMarkerIcon(color); } else { @@ -201,7 +207,7 @@ export class Marker { onMarkerIconReady(icon); } - createColoredMarkerIcon(color: tinycolor.Instance): { size: number[], icon: Icon } { + createColoredMarkerIcon(color: tinycolor.Instance): MarkerIconInfo { return { size: [21, 34], icon: L.icon({ From 551f67ec02de132df028a282c89e989b5baf1a70 Mon Sep 17 00:00:00 2001 From: van-vanich Date: Wed, 22 Dec 2021 11:14:04 +0200 Subject: [PATCH 283/432] add this feature for target attribute: use ${metadataKey} for value from metadata, $[messageKey] for value from the message body --- .../rule/engine/metadata/TbEntityGetAttrNode.java | 8 ++++++-- .../rule/engine/metadata/AbstractAttributeNodeTest.java | 7 ++++--- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbEntityGetAttrNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbEntityGetAttrNode.java index 747549cd77..13451a3b34 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbEntityGetAttrNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbEntityGetAttrNode.java @@ -68,8 +68,11 @@ public abstract class TbEntityGetAttrNode implements TbNode Map mappingsMap = new HashMap<>(); config.getAttrMapping().forEach((key, value) -> { - String processPattern = TbNodeUtils.processPattern(key, msg); - mappingsMap.put(processPattern, value); + log.info("key = {}, value = {}", key, value); + log.info(msg.toString()); + String processPatternKey = TbNodeUtils.processPattern(key, msg); + String processPatternValue = TbNodeUtils.processPattern(value, msg); + mappingsMap.put(processPatternKey, processPatternValue); }); List keys = List.copyOf(mappingsMap.keySet()); @@ -94,6 +97,7 @@ public abstract class TbEntityGetAttrNode implements TbNode private void putAttributesAndTell(TbContext ctx, TbMsg msg, List attributes, Map map) { attributes.forEach(r -> { String attrName = map.get(r.getKey()); + log.info("attrName = {}, value = {}", attrName, r.getValueAsString()); msg.getMetaData().putValue(attrName, r.getValueAsString()); }); ctx.tellSuccess(msg); diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/AbstractAttributeNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/AbstractAttributeNodeTest.java index 005b40b4e7..a0f2879851 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/AbstractAttributeNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/AbstractAttributeNodeTest.java @@ -72,7 +72,7 @@ public abstract class AbstractAttributeNodeTest { final RuleChainId ruleChainId = new RuleChainId(Uuids.timeBased()); final RuleNodeId ruleNodeId = new RuleNodeId(Uuids.timeBased()); final String keyAttrConf = "${word}"; - final String valueAttrConf = "result"; + final String valueAttrConf = "${result}"; @Mock TbContext ctx; @Mock @@ -95,6 +95,7 @@ public abstract class AbstractAttributeNodeTest { metaData = new HashMap<>(); metaData.putIfAbsent("word", "temperature"); + metaData.putIfAbsent("result", "answer"); this.node = node; this.node.init(null, nodeConfiguration); @@ -181,7 +182,7 @@ public abstract class AbstractAttributeNodeTest { node.onMsg(ctx, msg); verify(ctx).tellSuccess(msg); - assertEquals(msg.getMetaData().getValue("result"), "highest"); + assertEquals(msg.getMetaData().getValue("answer"), "highest"); } void entityAttributeFetched(EntityId entityId) { @@ -193,7 +194,7 @@ public abstract class AbstractAttributeNodeTest { node.onMsg(ctx, msg); verify(ctx).tellSuccess(msg); - assertEquals(msg.getMetaData().getValue("result"), "high"); + assertEquals(msg.getMetaData().getValue("answer"), "high"); } TbGetEntityAttrNodeConfiguration getTbNodeConfig() { From 167a40d4169548cdf2da853db170c359974fb837 Mon Sep 17 00:00:00 2001 From: van-vanich Date: Wed, 22 Dec 2021 11:30:18 +0200 Subject: [PATCH 284/432] remove unnecessary code --- .../thingsboard/rule/engine/metadata/TbEntityGetAttrNode.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbEntityGetAttrNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbEntityGetAttrNode.java index 13451a3b34..c2e19c6826 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbEntityGetAttrNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbEntityGetAttrNode.java @@ -68,8 +68,6 @@ public abstract class TbEntityGetAttrNode implements TbNode Map mappingsMap = new HashMap<>(); config.getAttrMapping().forEach((key, value) -> { - log.info("key = {}, value = {}", key, value); - log.info(msg.toString()); String processPatternKey = TbNodeUtils.processPattern(key, msg); String processPatternValue = TbNodeUtils.processPattern(value, msg); mappingsMap.put(processPatternKey, processPatternValue); @@ -97,7 +95,6 @@ public abstract class TbEntityGetAttrNode implements TbNode private void putAttributesAndTell(TbContext ctx, TbMsg msg, List attributes, Map map) { attributes.forEach(r -> { String attrName = map.get(r.getKey()); - log.info("attrName = {}, value = {}", attrName, r.getValueAsString()); msg.getMetaData().putValue(attrName, r.getValueAsString()); }); ctx.tellSuccess(msg); From 5cbc78fbf44e9b15520ec0e321709c74d396fd83 Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Wed, 22 Dec 2021 15:53:23 +0200 Subject: [PATCH 285/432] Added sort by ID for edge event to properly fetch events by page in case of repeated createdTime --- .../rpc/fetch/BasePageableEdgeEventFetcher.java | 16 ++-------------- .../server/dao/sql/edge/JpaBaseEdgeEventDao.java | 16 ++++++++++------ 2 files changed, 12 insertions(+), 20 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/BasePageableEdgeEventFetcher.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/BasePageableEdgeEventFetcher.java index eb8592dae5..a3dc409cdf 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/BasePageableEdgeEventFetcher.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/BasePageableEdgeEventFetcher.java @@ -15,25 +15,13 @@ */ package org.thingsboard.server.service.edge.rpc.fetch; -import com.fasterxml.jackson.databind.ObjectMapper; import lombok.extern.slf4j.Slf4j; -import org.thingsboard.server.common.data.BaseData; import org.thingsboard.server.common.data.edge.Edge; import org.thingsboard.server.common.data.edge.EdgeEvent; -import org.thingsboard.server.common.data.edge.EdgeEventActionType; -import org.thingsboard.server.common.data.edge.EdgeEventType; -import org.thingsboard.server.common.data.id.EntityId; -import org.thingsboard.server.common.data.id.EventId; -import org.thingsboard.server.common.data.id.HasId; -import org.thingsboard.server.common.data.id.HasUUID; -import org.thingsboard.server.common.data.id.IdBased; -import org.thingsboard.server.common.data.id.RuleChainId; import org.thingsboard.server.common.data.id.TenantId; -import org.thingsboard.server.common.data.id.UUIDBased; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; -import org.thingsboard.server.common.data.rule.RuleChain; -import org.thingsboard.server.service.edge.rpc.EdgeEventUtils; +import org.thingsboard.server.common.data.page.SortOrder; import java.util.ArrayList; import java.util.List; @@ -43,7 +31,7 @@ public abstract class BasePageableEdgeEventFetcher implements EdgeEventFetche @Override public PageLink getPageLink(int pageSize) { - return new PageLink(pageSize); + return new PageLink(pageSize, 0, null, new SortOrder("createdTime", SortOrder.Direction.ASC)); } @Override diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/edge/JpaBaseEdgeEventDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/edge/JpaBaseEdgeEventDao.java index ff5da30f31..8645efccf7 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/edge/JpaBaseEdgeEventDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/edge/JpaBaseEdgeEventDao.java @@ -16,29 +16,28 @@ package org.thingsboard.server.dao.sql.edge; import com.datastax.oss.driver.api.core.uuid.Uuids; -import com.google.common.util.concurrent.ListenableFuture; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.repository.CrudRepository; import org.springframework.stereotype.Component; import org.thingsboard.server.common.data.edge.EdgeEvent; -import org.thingsboard.server.common.data.edge.EdgeEventActionType; import org.thingsboard.server.common.data.id.EdgeEventId; import org.thingsboard.server.common.data.id.EdgeId; -import org.thingsboard.server.common.data.id.EventId; import org.thingsboard.server.common.data.page.PageData; +import org.thingsboard.server.common.data.page.SortOrder; import org.thingsboard.server.common.data.page.TimePageLink; import org.thingsboard.server.dao.DaoUtil; import org.thingsboard.server.dao.edge.EdgeEventDao; import org.thingsboard.server.dao.model.sql.EdgeEventEntity; -import org.thingsboard.server.dao.model.sql.EventEntity; import org.thingsboard.server.dao.sql.JpaAbstractSearchTextDao; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; import java.util.Objects; import java.util.Optional; import java.util.UUID; @@ -100,6 +99,11 @@ public class JpaBaseEdgeEventDao extends JpaAbstractSearchTextDao findEdgeEvents(UUID tenantId, EdgeId edgeId, TimePageLink pageLink, boolean withTsUpdate) { + List sortOrders = new ArrayList<>(); + sortOrders.add(new SortOrder("id", SortOrder.Direction.ASC)); + if (pageLink.getSortOrder() != null) { + sortOrders.add(pageLink.getSortOrder()); + } final Lock readWriteLock = readWriteLocks.computeIfAbsent(edgeId, id -> new ReentrantLock()); readWriteLock.lock(); try { @@ -112,7 +116,7 @@ public class JpaBaseEdgeEventDao extends JpaAbstractSearchTextDao Date: Wed, 22 Dec 2021 17:10:28 +0200 Subject: [PATCH 286/432] Moved toSort from DaoUtil to PageLink/TimePageLink classes --- common/data/pom.xml | 4 ++ .../server/common/data/page/PageLink.java | 34 ++++++++++++++ .../server/common/data/page/TimePageLink.java | 31 +++++++++++++ .../org/thingsboard/server/dao/DaoUtil.java | 46 ++----------------- .../dao/sql/edge/JpaBaseEdgeEventDao.java | 9 +--- 5 files changed, 74 insertions(+), 50 deletions(-) diff --git a/common/data/pom.xml b/common/data/pom.xml index 80be41e6a0..5a5838d7da 100644 --- a/common/data/pom.xml +++ b/common/data/pom.xml @@ -64,6 +64,10 @@ com.fasterxml.jackson.core jackson-databind + + org.springframework.boot + spring-boot-starter-data-jpa + org.springframework.boot spring-boot-starter-test diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/page/PageLink.java b/common/data/src/main/java/org/thingsboard/server/common/data/page/PageLink.java index a31f834068..acf0d2f71e 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/page/PageLink.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/page/PageLink.java @@ -18,9 +18,19 @@ package org.thingsboard.server.common.data.page; import com.fasterxml.jackson.annotation.JsonIgnore; import lombok.Data; +import org.springframework.data.domain.Sort; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + @Data public class PageLink { + protected static final String DEFAULT_SORT_PROPERTY = "id"; + private static final Sort DEFAULT_SORT = Sort.by(Sort.Direction.ASC, DEFAULT_SORT_PROPERTY); + private final String textSearch; private final int pageSize; private final int page; @@ -57,4 +67,28 @@ public class PageLink { return new PageLink(this.pageSize, this.page+1, this.textSearch, this.sortOrder); } + public Sort toSort(SortOrder sortOrder, Map columnMap) { + if (sortOrder == null) { + return DEFAULT_SORT; + } else { + String property = sortOrder.getProperty(); + if (columnMap.containsKey(property)) { + property = columnMap.get(property); + } + return Sort.by(Sort.Direction.fromString(sortOrder.getDirection().name()), property); + } + } + + public Sort toSort(List sortOrders, Map columnMap) { + return Sort.by(sortOrders.stream().map(s -> toSortOrder(s, columnMap)).collect(Collectors.toList())); + } + + private Sort.Order toSortOrder(SortOrder sortOrder, Map columnMap) { + String property = sortOrder.getProperty(); + if (columnMap.containsKey(property)) { + property = columnMap.get(property); + } + return new Sort.Order(Sort.Direction.fromString(sortOrder.getDirection().name()), property, Sort.NullHandling.NULLS_LAST); + } + } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/page/TimePageLink.java b/common/data/src/main/java/org/thingsboard/server/common/data/page/TimePageLink.java index be4878b50e..7be6f1ec8b 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/page/TimePageLink.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/page/TimePageLink.java @@ -19,6 +19,11 @@ import com.fasterxml.jackson.annotation.JsonIgnore; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.ToString; +import org.springframework.data.domain.Sort; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; @Data @ToString(callSuper = true) @@ -61,4 +66,30 @@ public class TimePageLink extends PageLink { return new TimePageLink(this.getPageSize(), this.getPage()+1, this.getTextSearch(), this.getSortOrder(), this.startTime, this.endTime); } + + @Override + public Sort toSort(SortOrder sortOrder, Map columnMap) { + if (sortOrder == null) { + return super.toSort(sortOrder, columnMap); + } else { + return toSort(new ArrayList<>(List.of(sortOrder)), columnMap); + } + } + + @Override + public Sort toSort(List sortOrders, Map columnMap) { + if (!isDefaultSortOrderAvailable(sortOrders)) { + sortOrders.add(new SortOrder(DEFAULT_SORT_PROPERTY, SortOrder.Direction.ASC)); + } + return super.toSort(sortOrders, columnMap); + } + + private boolean isDefaultSortOrderAvailable(List sortOrders) { + for (SortOrder sortOrder : sortOrders) { + if (DEFAULT_SORT_PROPERTY.equals(sortOrder.getProperty())) { + return true; + } + } + return false; + } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/DaoUtil.java b/dao/src/main/java/org/thingsboard/server/dao/DaoUtil.java index 19f613bd30..b6ab190573 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/DaoUtil.java +++ b/dao/src/main/java/org/thingsboard/server/dao/DaoUtil.java @@ -18,7 +18,7 @@ package org.thingsboard.server.dao; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; -import org.springframework.data.domain.Sort; + import org.thingsboard.server.common.data.id.UUIDBased; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; @@ -32,13 +32,9 @@ import java.util.List; import java.util.Map; import java.util.Optional; import java.util.UUID; -import java.util.stream.Collectors; public abstract class DaoUtil { - public static final String DEFAULT_SORT_PROPERTY = "id"; - public static final Sort DEFAULT_SORT = Sort.by(Sort.Direction.ASC, DEFAULT_SORT_PROPERTY); - private DaoUtil() { } @@ -56,7 +52,7 @@ public abstract class DaoUtil { } public static Pageable toPageable(PageLink pageLink, Map columnMap) { - return PageRequest.of(pageLink.getPage(), pageLink.getPageSize(), toSort(pageLink.getSortOrder(), columnMap)); + return PageRequest.of(pageLink.getPage(), pageLink.getPageSize(), pageLink.toSort(pageLink.getSortOrder(), columnMap)); } public static Pageable toPageable(PageLink pageLink, List sortOrders) { @@ -64,43 +60,7 @@ public abstract class DaoUtil { } public static Pageable toPageable(PageLink pageLink, Map columnMap, List sortOrders) { - return PageRequest.of(pageLink.getPage(), pageLink.getPageSize(), toSort(sortOrders, columnMap)); - } - - public static Sort toSort(SortOrder sortOrder) { - return toSort(sortOrder, Collections.emptyMap()); - } - - public static Sort toSort(SortOrder sortOrder, Map columnMap) { - if (sortOrder == null) { - return DEFAULT_SORT; - } else { - String property = sortOrder.getProperty(); - if (columnMap.containsKey(property)) { - property = columnMap.get(property); - } - return Sort.by(Sort.Direction.fromString(sortOrder.getDirection().name()), property); - } - } - - public static Sort toSort(List sortOrders) { - return toSort(sortOrders, Collections.emptyMap()); - } - - public static Sort toSort(List sortOrders, Map columnMap) { - return toSort(sortOrders, columnMap, Sort.NullHandling.NULLS_LAST); - } - - public static Sort toSort(List sortOrders, Map columnMap, Sort.NullHandling nullHandlingHint) { - return Sort.by(sortOrders.stream().map(s -> toSortOrder(s, columnMap, nullHandlingHint)).collect(Collectors.toList())); - } - - public static Sort.Order toSortOrder(SortOrder sortOrder, Map columnMap, Sort.NullHandling nullHandlingHint) { - String property = sortOrder.getProperty(); - if (columnMap.containsKey(property)) { - property = columnMap.get(property); - } - return new Sort.Order(Sort.Direction.fromString(sortOrder.getDirection().name()), property, nullHandlingHint); + return PageRequest.of(pageLink.getPage(), pageLink.getPageSize(), pageLink.toSort(sortOrders, columnMap)); } public static List convertDataList(Collection> toDataList) { diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/edge/JpaBaseEdgeEventDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/edge/JpaBaseEdgeEventDao.java index 8645efccf7..dfb00eafcc 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/edge/JpaBaseEdgeEventDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/edge/JpaBaseEdgeEventDao.java @@ -99,11 +99,6 @@ public class JpaBaseEdgeEventDao extends JpaAbstractSearchTextDao findEdgeEvents(UUID tenantId, EdgeId edgeId, TimePageLink pageLink, boolean withTsUpdate) { - List sortOrders = new ArrayList<>(); - sortOrders.add(new SortOrder("id", SortOrder.Direction.ASC)); - if (pageLink.getSortOrder() != null) { - sortOrders.add(pageLink.getSortOrder()); - } final Lock readWriteLock = readWriteLocks.computeIfAbsent(edgeId, id -> new ReentrantLock()); readWriteLock.lock(); try { @@ -116,7 +111,7 @@ public class JpaBaseEdgeEventDao extends JpaAbstractSearchTextDao Date: Wed, 22 Dec 2021 17:15:10 +0200 Subject: [PATCH 287/432] Add ability to set widget and dashboard level CSS. Introduce dashboard state component with ability to be embedded inside markdown widget. --- .../dashboard-page.component.ts | 36 ++- .../dashboard-settings-dialog.component.html | 13 ++ .../dashboard-settings-dialog.component.scss | 29 +++ .../dashboard-settings-dialog.component.ts | 3 +- .../dashboard-state.component.html | 25 +++ .../dashboard-state.component.ts | 70 ++++++ .../dashboard/dashboard.component.html | 3 +- .../home/components/home-components.module.ts | 9 +- .../src/app/modules/home/components/tokens.ts | 3 + .../widget/lib/markdown-widget.component.html | 3 +- .../widget/lib/markdown-widget.component.ts | 4 +- .../widget/widget-component.service.ts | 10 +- .../widget/widget-config.component.html | 4 + .../widget/widget-config.component.scss | 2 +- .../widget/widget-config.component.ts | 2 + .../widget/widget-container.component.html | 2 +- .../widget/widget-container.component.ts | 53 ++++- .../components/widget/widget.component.ts | 32 +-- .../home/models/widget-component.models.ts | 27 ++- .../app/shared/components/css.component.html | 41 ++++ .../app/shared/components/css.component.scss | 66 ++++++ .../app/shared/components/css.component.ts | 207 ++++++++++++++++++ .../shared/components/markdown.component.ts | 15 +- .../src/app/shared/models/dashboard.models.ts | 1 + ui-ngx/src/app/shared/models/widget.models.ts | 1 + ui-ngx/src/app/shared/shared.module.ts | 3 + .../assets/locale/locale.constant-en_US.json | 3 + 27 files changed, 618 insertions(+), 49 deletions(-) create mode 100644 ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-state.component.html create mode 100644 ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-state.component.ts create mode 100644 ui-ngx/src/app/shared/components/css.component.html create mode 100644 ui-ngx/src/app/shared/components/css.component.scss create mode 100644 ui-ngx/src/app/shared/components/css.component.ts diff --git a/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.ts b/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.ts index 37ef5e0429..e15f04d766 100644 --- a/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.ts +++ b/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.ts @@ -17,7 +17,7 @@ import { ChangeDetectionStrategy, ChangeDetectorRef, - Component, ElementRef, + Component, ElementRef, HostBinding, Inject, Injector, Input, @@ -48,7 +48,7 @@ import { } from '@app/shared/models/dashboard.models'; import { WINDOW } from '@core/services/window.service'; import { WindowMessage } from '@shared/models/window-message.model'; -import { deepClone, isDefined, isDefinedAndNotNull } from '@app/core/utils'; +import { deepClone, guid, hashCode, isDefined, isDefinedAndNotNull, isNotEmptyStr } from '@app/core/utils'; import { DashboardContext, DashboardPageLayout, @@ -132,6 +132,8 @@ import { DashboardImageDialogData, DashboardImageDialogResult } from '@home/components/dashboard-page/dashboard-image-dialog.component'; import { DomSanitizer, SafeUrl } from '@angular/platform-browser'; +import cssjs from '@core/css/css'; +import { DOCUMENT } from '@angular/common'; // @dynamic @Component({ @@ -147,6 +149,9 @@ export class DashboardPageComponent extends PageComponent implements IDashboardC authUser: AuthUser = this.authState.authUser; + @HostBinding('class') + dashboardPageClass: string; + @Input() embedded = false; @@ -302,6 +307,7 @@ export class DashboardPageComponent extends PageComponent implements IDashboardC constructor(protected store: Store, @Inject(WINDOW) private window: Window, + @Inject(DOCUMENT) private document: Document, private breakpointObserver: BreakpointObserver, private route: ActivatedRoute, private router: Router, @@ -419,6 +425,8 @@ export class DashboardPageComponent extends PageComponent implements IDashboardC this.dashboardConfiguration.entityAliases, this.dashboardConfiguration.filters); + this.updateDashboardCss(); + if (this.widgetEditMode) { const message: WindowMessage = { type: 'widgetEditModeInited' @@ -427,6 +435,27 @@ export class DashboardPageComponent extends PageComponent implements IDashboardC } } + private updateDashboardCss() { + this.cleanupDashboardCss(); + const cssString = this.dashboardConfiguration.settings.dashboardCss; + if (isNotEmptyStr(cssString)) { + const cssParser = new cssjs(); + cssParser.testMode = false; + this.dashboardPageClass = 'tb-dashboard-page-css-' + guid(); + cssParser.cssPreviewNamespace = this.dashboardPageClass; + cssParser.createStyleElement(this.dashboardPageClass, cssString); + } + } + + private cleanupDashboardCss() { + if (this.dashboardPageClass) { + const el = this.document.getElementById(this.dashboardPageClass); + if (el) { + el.parentNode.removeChild(el); + } + } + } + private reset() { this.dashboard = null; this.translatedDashboardTitle = null; @@ -466,6 +495,7 @@ export class DashboardPageComponent extends PageComponent implements IDashboardC } ngOnDestroy(): void { + this.cleanupDashboardCss(); if (this.isMobileApp && this.syncStateWithQueryParam) { this.mobileService.unregisterToggleLayoutFunction(); } @@ -729,6 +759,7 @@ export class DashboardPageComponent extends PageComponent implements IDashboardC if (data) { this.dashboard.configuration.settings = data.settings; this.dashboardLogoCache = undefined; + this.updateDashboardCss(); const newGridSettings = data.gridSettings; if (newGridSettings) { const layout = this.dashboard.configuration.states[layoutKeys.state].layouts[layoutKeys.layout]; @@ -893,6 +924,7 @@ export class DashboardPageComponent extends PageComponent implements IDashboardC this.dashboardLogoCache = undefined; this.dashboardConfiguration = this.dashboard.configuration; this.dashboardCtx.dashboardTimewindow = this.dashboardConfiguration.timewindow; + this.updateDashboardCss(); this.entityAliasesUpdated(); this.filtersUpdated(); this.updateLayouts(); diff --git a/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-settings-dialog.component.html b/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-settings-dialog.component.html index 14c2df301b..0c0a430fdb 100644 --- a/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-settings-dialog.component.html +++ b/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-settings-dialog.component.html @@ -87,6 +87,19 @@ {{ 'dashboard.display-update-dashboard-image' | translate }} + + + + dashboard.advanced-settings + + + + + +
diff --git a/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-settings-dialog.component.scss b/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-settings-dialog.component.scss index 5587d9c35a..47845eb9b0 100644 --- a/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-settings-dialog.component.scss +++ b/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-settings-dialog.component.scss @@ -30,4 +30,33 @@ .mat-slide-toggle-content { white-space: normal; } + .mat-expansion-panel { + &.tb-settings { + box-shadow: none; + .mat-content { + overflow: visible; + } + .mat-expansion-panel-header { + padding: 0; + &:hover { + background: none; + } + .mat-expansion-indicator { + padding: 2px; + } + } + .mat-expansion-panel-header-description { + align-items: center; + } + .mat-expansion-panel-body{ + padding: 0; + } + .tb-css-content-panel { + margin: 0 0 8px; + } + } + .mat-expansion-panel-content { + font: inherit; + } + } } diff --git a/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-settings-dialog.component.ts b/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-settings-dialog.component.ts index 5d17d33eaa..c2d01f3d9c 100644 --- a/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-settings-dialog.component.ts +++ b/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-settings-dialog.component.ts @@ -97,7 +97,8 @@ export class DashboardSettingsDialogComponent extends DialogComponent { diff --git a/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-state.component.html b/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-state.component.html new file mode 100644 index 0000000000..24c3eadb08 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-state.component.html @@ -0,0 +1,25 @@ + + + diff --git a/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-state.component.ts b/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-state.component.ts new file mode 100644 index 0000000000..00bd266c2a --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-state.component.ts @@ -0,0 +1,70 @@ +/// +/// Copyright © 2016-2021 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { Component, Input, OnInit } from '@angular/core'; +import { PageComponent } from '@shared/components/page.component'; +import { Store } from '@ngrx/store'; +import { AppState } from '@core/core.state'; +import { Dashboard } from '@shared/models/dashboard.models'; +import { StateObject, StateParams } from '@core/api/widget-api.models'; +import { updateEntityParams, WidgetContext } from '../../models/widget-component.models'; +import { deepClone, objToBase64 } from '@core/utils'; +import { IDashboardComponent } from '@home/models/dashboard-component.models'; +import { EntityId } from '@shared/models/id/entity-id'; + +@Component({ + selector: 'tb-dashboard-state', + templateUrl: './dashboard-state.component.html', + styleUrls: [] +}) +export class DashboardStateComponent extends PageComponent implements OnInit { + + @Input() + ctx: WidgetContext; + + @Input() + stateId: string; + + @Input() + entityParamName: string; + + @Input() + entityId: EntityId; + + currentState: string; + + dashboard: Dashboard; + + parentDashboard: IDashboardComponent; + + constructor(protected store: Store) { + super(store); + } + + ngOnInit(): void { + this.dashboard = deepClone(this.ctx.stateController.dashboardCtrl.dashboardCtx.getDashboard()); + const stateObject: StateObject = {}; + const params = deepClone(this.ctx.stateController.getStateParams()); + updateEntityParams(params, this.entityParamName, this.entityId); + stateObject.params = params; + if (this.stateId) { + stateObject.id = this.stateId; + } + this.currentState = objToBase64([stateObject]); + this.parentDashboard = this.ctx.parentDashboard ? + this.ctx.parentDashboard : this.ctx.dashboard; + } +} diff --git a/ui-ngx/src/app/modules/home/components/dashboard/dashboard.component.html b/ui-ngx/src/app/modules/home/components/dashboard/dashboard.component.html index c48030050d..dafb67df0b 100644 --- a/ui-ngx/src/app/modules/home/components/dashboard/dashboard.component.html +++ b/ui-ngx/src/app/modules/home/components/dashboard/dashboard.component.html @@ -63,8 +63,9 @@
- + > = new InjectionToken>('SHARED_HOME_COMPONENTS_MODULE_TOKEN'); +export const HOME_COMPONENTS_MODULE_TOKEN: InjectionToken> = + new InjectionToken>('HOME_COMPONENTS_MODULE_TOKEN'); + export const COMPLEX_FILTER_PREDICATE_DIALOG_COMPONENT_TOKEN: InjectionToken> = new InjectionToken>('COMPLEX_FILTER_PREDICATE_DIALOG_COMPONENT_TOKEN'); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/markdown-widget.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/markdown-widget.component.html index 46069c15f0..b808897845 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/markdown-widget.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/markdown-widget.component.html @@ -15,4 +15,5 @@ limitations under the License. --> - + diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/markdown-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/markdown-widget.component.ts index fd0197996e..60dea214bc 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/markdown-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/markdown-widget.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { ChangeDetectorRef, Component, HostBinding, Input, OnInit } from '@angular/core'; +import { ChangeDetectorRef, Component, HostBinding, Inject, Input, OnInit, Type } from '@angular/core'; import { PageComponent } from '@shared/components/page.component'; import { WidgetContext } from '@home/models/widget-component.models'; import { Store } from '@ngrx/store'; @@ -32,6 +32,7 @@ import { FormattedData } from '@home/components/widget/lib/maps/map-models'; import { hashCode, isNotEmptyStr } from '@core/utils'; import cssjs from '@core/css/css'; import { UtilsService } from '@core/services/utils.service'; +import { HOME_COMPONENTS_MODULE_TOKEN } from '@home/components/tokens'; interface MarkdownWidgetSettings { markdownTextPattern: string; @@ -62,6 +63,7 @@ export class MarkdownWidgetComponent extends PageComponent implements OnInit { constructor(protected store: Store, private utils: UtilsService, + @Inject(HOME_COMPONENTS_MODULE_TOKEN) public homeComponentsModule: Type, private cd: ChangeDetectorRef) { super(store); } diff --git a/ui-ngx/src/app/modules/home/components/widget/widget-component.service.ts b/ui-ngx/src/app/modules/home/components/widget/widget-component.service.ts index 90b3087ced..7dcac82833 100644 --- a/ui-ngx/src/app/modules/home/components/widget/widget-component.service.ts +++ b/ui-ngx/src/app/modules/home/components/widget/widget-component.service.ts @@ -45,6 +45,7 @@ import { MODULES_MAP } from '@shared/public-api'; import * as tinycolor_ from 'tinycolor2'; import moment from 'moment'; import { IModulesMap } from '@modules/common/modules-map.models'; +import { HOME_COMPONENTS_MODULE_TOKEN } from '@home/components/tokens'; const tinycolor = tinycolor_; @@ -66,6 +67,7 @@ export class WidgetComponentService { constructor(@Inject(WINDOW) private window: Window, @Optional() @Inject(MODULES_MAP) private modulesMap: IModulesMap, + @Inject(HOME_COMPONENTS_MODULE_TOKEN) private homeComponentsModule: Type, private dynamicComponentFactoryService: DynamicComponentFactoryService, private widgetService: WidgetService, private utils: UtilsService, @@ -177,8 +179,10 @@ export class WidgetComponentService { forkJoin(widgetModulesTasks).subscribe( () => { const loadDefaultWidgetInfoTasks = [ - this.loadWidgetResources(this.missingWidgetType, 'global-widget-missing-type', [SharedModule, WidgetComponentsModule]), - this.loadWidgetResources(this.errorWidgetType, 'global-widget-error-type', [SharedModule, WidgetComponentsModule]), + this.loadWidgetResources(this.missingWidgetType, 'global-widget-missing-type', + [SharedModule, WidgetComponentsModule, this.homeComponentsModule]), + this.loadWidgetResources(this.errorWidgetType, 'global-widget-error-type', + [SharedModule, WidgetComponentsModule, this.homeComponentsModule]), ]; forkJoin(loadDefaultWidgetInfoTasks).subscribe( () => { @@ -274,7 +278,7 @@ export class WidgetComponentService { } if (widgetControllerDescriptor) { const widgetNamespace = `widget-type-${(isSystem ? 'sys-' : '')}${bundleAlias}-${widgetInfo.alias}`; - this.loadWidgetResources(widgetInfo, widgetNamespace, [SharedModule, WidgetComponentsModule]).subscribe( + this.loadWidgetResources(widgetInfo, widgetNamespace, [SharedModule, WidgetComponentsModule, this.homeComponentsModule]).subscribe( () => { if (widgetControllerDescriptor.settingsSchema) { widgetInfo.typeSettingsSchema = widgetControllerDescriptor.settingsSchema; diff --git a/ui-ngx/src/app/modules/home/components/widget/widget-config.component.html b/ui-ngx/src/app/modules/home/components/widget/widget-config.component.html index 97542fd3cb..1073b32e42 100644 --- a/ui-ngx/src/app/modules/home/components/widget/widget-config.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/widget-config.component.html @@ -418,6 +418,10 @@ label="{{ 'widget-config.widget-style' | translate }}" formControlName="widgetStyle" > +
diff --git a/ui-ngx/src/app/modules/home/components/widget/widget-config.component.scss b/ui-ngx/src/app/modules/home/components/widget/widget-config.component.scss index c29afa5629..e6fd1a509e 100644 --- a/ui-ngx/src/app/modules/home/components/widget/widget-config.component.scss +++ b/ui-ngx/src/app/modules/home/components/widget/widget-config.component.scss @@ -133,7 +133,7 @@ .mat-expansion-panel-body{ padding: 0; } - .tb-json-object-panel { + .tb-json-object-panel, .tb-css-content-panel { margin: 0 0 8px; } .mat-checkbox-layout { diff --git a/ui-ngx/src/app/modules/home/components/widget/widget-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/widget-config.component.ts index 7d779a3a6c..29af888e37 100644 --- a/ui-ngx/src/app/modules/home/components/widget/widget-config.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/widget-config.component.ts @@ -206,6 +206,7 @@ export class WidgetConfigComponent extends PageComponent implements OnInit, Cont padding: [null, []], margin: [null, []], widgetStyle: [null, []], + widgetCss: [null, []], titleStyle: [null, []], units: [null, []], decimals: [null, [Validators.min(0), Validators.max(15), Validators.pattern(/^\d*$/)]], @@ -406,6 +407,7 @@ export class WidgetConfigComponent extends PageComponent implements OnInit, Cont padding: config.padding, margin: config.margin, widgetStyle: isDefined(config.widgetStyle) ? config.widgetStyle : {}, + widgetCss: isDefined(config.widgetCss) ? config.widgetCss : '', titleStyle: isDefined(config.titleStyle) ? config.titleStyle : { fontSize: '16px', fontWeight: 400 diff --git a/ui-ngx/src/app/modules/home/components/widget/widget-container.component.html b/ui-ngx/src/app/modules/home/components/widget/widget-container.component.html index 09f3199b06..3a2712f4f6 100644 --- a/ui-ngx/src/app/modules/home/components/widget/widget-container.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/widget-container.component.html @@ -15,7 +15,7 @@ limitations under the License. --> -
= new EventEmitter(); + private cssClass: string; + constructor(protected store: Store, - private cd: ChangeDetectorRef) { + private cd: ChangeDetectorRef, + private renderer: Renderer2, + @Inject(DOCUMENT) private document: Document) { super(store); } ngOnInit(): void { this.widget.widgetContext.containerChangeDetector = this.cd; + const cssString = this.widget.widget.config.widgetCss; + if (isNotEmptyStr(cssString)) { + const cssParser = new cssjs(); + cssParser.testMode = false; + this.cssClass = 'tb-widget-css-' + guid(); + this.renderer.addClass(this.gridsterItem.el, this.cssClass); + cssParser.cssPreviewNamespace = this.cssClass; + cssParser.createStyleElement(this.cssClass, cssString); + } + } + + ngOnDestroy(): void { + if (this.cssClass) { + const el = this.document.getElementById(this.cssClass); + if (el) { + el.parentNode.removeChild(el); + } + } } isHighlighted(widget: DashboardWidget) { @@ -105,6 +141,11 @@ export class WidgetContainerComponent extends PageComponent implements OnInit { } onFullscreenChanged(expanded: boolean) { + if (expanded) { + this.renderer.addClass(this.tbWidgetElement.nativeElement, this.cssClass); + } else { + this.renderer.removeClass(this.tbWidgetElement.nativeElement, this.cssClass); + } this.widgetFullscreenChanged.emit(expanded); } diff --git a/ui-ngx/src/app/modules/home/components/widget/widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/widget.component.ts index c1208d0241..e85d507e9b 100644 --- a/ui-ngx/src/app/modules/home/components/widget/widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/widget.component.ts @@ -65,7 +65,7 @@ import { validateEntityId } from '@core/utils'; import { - IDynamicWidgetComponent, ShowWidgetHeaderActionFunction, + IDynamicWidgetComponent, ShowWidgetHeaderActionFunction, updateEntityParams, WidgetContext, WidgetHeaderAction, WidgetInfo, @@ -1070,7 +1070,7 @@ export class WidgetComponent extends PageComponent implements OnInit, AfterViewI case WidgetActionType.updateDashboardState: let targetDashboardStateId = descriptor.targetDashboardStateId; const params = deepClone(this.widgetContext.stateController.getStateParams()); - this.updateEntityParams(params, targetEntityParamName, targetEntityId, entityName, entityLabel); + updateEntityParams(params, targetEntityParamName, targetEntityId, entityName, entityLabel); if (type === WidgetActionType.openDashboardState) { if (descriptor.openInPopover) { this.openDashboardStateInPopover($event, descriptor.targetDashboardStateId, params, @@ -1091,7 +1091,7 @@ export class WidgetComponent extends PageComponent implements OnInit, AfterViewI targetDashboardStateId = descriptor.targetDashboardStateId; const stateObject: StateObject = {}; stateObject.params = {}; - this.updateEntityParams(stateObject.params, targetEntityParamName, targetEntityId, entityName, entityLabel); + updateEntityParams(stateObject.params, targetEntityParamName, targetEntityId, entityName, entityLabel); if (targetDashboardStateId) { stateObject.id = targetDashboardStateId; } @@ -1360,7 +1360,7 @@ export class WidgetComponent extends PageComponent implements OnInit, AfterViewI this.widgetContentContainer, this.dashboardPageComponent, preferredPlacement, hideOnClickOutside, injector, { - embed: true, + embedded: true, syncStateWithQueryParam: false, hideToolbar: hideDashboardToolbar, currentState: objToBase64([stateObject]), @@ -1443,30 +1443,6 @@ export class WidgetComponent extends PageComponent implements OnInit, AfterViewI } } - private updateEntityParams(params: StateParams, targetEntityParamName?: string, targetEntityId?: EntityId, - entityName?: string, entityLabel?: string) { - if (targetEntityId) { - let targetEntityParams: StateParams; - if (targetEntityParamName && targetEntityParamName.length) { - targetEntityParams = params[targetEntityParamName]; - if (!targetEntityParams) { - targetEntityParams = {}; - params[targetEntityParamName] = targetEntityParams; - params.targetEntityParamName = targetEntityParamName; - } - } else { - targetEntityParams = params; - } - targetEntityParams.entityId = targetEntityId; - if (entityName) { - targetEntityParams.entityName = entityName; - } - if (entityLabel) { - targetEntityParams.entityLabel = entityLabel; - } - } - } - private loadCustomActionResources(actionNamespace: string, customCss: string, customResources: Array): Observable { if (isDefined(customCss) && customCss.length > 0) { this.cssParser.cssPreviewNamespace = actionNamespace; diff --git a/ui-ngx/src/app/modules/home/models/widget-component.models.ts b/ui-ngx/src/app/modules/home/models/widget-component.models.ts index 2a530c8b4e..402e414f02 100644 --- a/ui-ngx/src/app/modules/home/models/widget-component.models.ts +++ b/ui-ngx/src/app/modules/home/models/widget-component.models.ts @@ -37,7 +37,7 @@ import { IStateController, IWidgetSubscription, IWidgetUtils, - RpcApi, + RpcApi, StateParams, SubscriptionEntityInfo, TimewindowFunctions, WidgetActionsApi, @@ -81,6 +81,7 @@ import { Router } from '@angular/router'; import { catchError, map, mergeMap, switchMap } from 'rxjs/operators'; import { FormattedData } from '@home/components/widget/lib/maps/map-models'; import { TbPopoverComponent } from '@shared/components/popover.component'; +import { EntityId } from '@shared/models/id/entity-id'; export interface IWidgetAction { name: string; @@ -545,3 +546,27 @@ export function toWidgetType(widgetInfo: WidgetInfo, id: WidgetTypeId, tenantId: descriptor }; } + +export function updateEntityParams(params: StateParams, targetEntityParamName?: string, targetEntityId?: EntityId, + entityName?: string, entityLabel?: string) { + if (targetEntityId) { + let targetEntityParams: StateParams; + if (targetEntityParamName && targetEntityParamName.length) { + targetEntityParams = params[targetEntityParamName]; + if (!targetEntityParams) { + targetEntityParams = {}; + params[targetEntityParamName] = targetEntityParams; + params.targetEntityParamName = targetEntityParamName; + } + } else { + targetEntityParams = params; + } + targetEntityParams.entityId = targetEntityId; + if (entityName) { + targetEntityParams.entityName = entityName; + } + if (entityLabel) { + targetEntityParams.entityLabel = entityLabel; + } + } +} diff --git a/ui-ngx/src/app/shared/components/css.component.html b/ui-ngx/src/app/shared/components/css.component.html new file mode 100644 index 0000000000..33d19672c3 --- /dev/null +++ b/ui-ngx/src/app/shared/components/css.component.html @@ -0,0 +1,41 @@ + +
+
+ + + +
+
+ +
+
+
+
+
+
+
diff --git a/ui-ngx/src/app/shared/components/css.component.scss b/ui-ngx/src/app/shared/components/css.component.scss new file mode 100644 index 0000000000..dd045bbd2d --- /dev/null +++ b/ui-ngx/src/app/shared/components/css.component.scss @@ -0,0 +1,66 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +.tb-css { + position: relative; + + &.tb-disabled { + color: rgba(0, 0, 0, .38); + } + + &.fill-height { + height: 100%; + } + + .tb-css-content-panel { + height: calc(100% - 80px); + margin-left: 15px; + border: 1px solid #c0c0c0; + + #tb-css-input { + width: 100%; + min-width: 200px; + height: 100%; + + &:not(.fill-height) { + min-height: 200px; + } + } + } + + .tb-css-toolbar { + & > * { + &:not(:last-child) { + margin-right: 4px; + } + } + button.mat-button, button.mat-icon-button, button.mat-icon-button.tb-mat-32 { + background: rgba(220, 220, 220, .35); + align-items: center; + vertical-align: middle; + min-width: 32px; + min-height: 15px; + padding: 4px; + font-size: .8rem; + line-height: 15px; + &:not(.tb-help-popup-button) { + color: #7b7b7b; + } + } + .tb-help-popup-button-loading { + background: #f3f3f3; + } + } +} diff --git a/ui-ngx/src/app/shared/components/css.component.ts b/ui-ngx/src/app/shared/components/css.component.ts new file mode 100644 index 0000000000..c1367d04ee --- /dev/null +++ b/ui-ngx/src/app/shared/components/css.component.ts @@ -0,0 +1,207 @@ +/// +/// Copyright © 2016-2021 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { + Component, + ElementRef, + forwardRef, + Input, + OnDestroy, + OnInit, + ViewChild, + ViewEncapsulation +} from '@angular/core'; +import { ControlValueAccessor, FormControl, NG_VALIDATORS, NG_VALUE_ACCESSOR, Validator } from '@angular/forms'; +import { Ace } from 'ace-builds'; +import { getAce } from '@shared/models/ace/ace.models'; +import { coerceBooleanProperty } from '@angular/cdk/coercion'; +import { Store } from '@ngrx/store'; +import { AppState } from '@core/core.state'; +import { UtilsService } from '@core/services/utils.service'; +import { TranslateService } from '@ngx-translate/core'; +import { CancelAnimationFrame, RafService } from '@core/services/raf.service'; +import { ResizeObserver } from '@juggle/resize-observer'; +import { beautifyCss } from '@shared/models/beautify.models'; + +@Component({ + selector: 'tb-css', + templateUrl: './css.component.html', + styleUrls: ['./css.component.scss'], + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => CssComponent), + multi: true + }, + { + provide: NG_VALIDATORS, + useExisting: forwardRef(() => CssComponent), + multi: true, + } + ], + encapsulation: ViewEncapsulation.None +}) +export class CssComponent implements OnInit, OnDestroy, ControlValueAccessor, Validator { + + @ViewChild('cssEditor', {static: true}) + cssEditorElmRef: ElementRef; + + private cssEditor: Ace.Editor; + private editorsResizeCaf: CancelAnimationFrame; + private editorResize$: ResizeObserver; + private ignoreChange = false; + + @Input() label: string; + + @Input() disabled: boolean; + + @Input() fillHeight: boolean; + + private requiredValue: boolean; + get required(): boolean { + return this.requiredValue; + } + @Input() + set required(value: boolean) { + this.requiredValue = coerceBooleanProperty(value); + } + + fullscreen = false; + + modelValue: string; + + hasErrors = false; + + private propagateChange = null; + + constructor(public elementRef: ElementRef, + private utils: UtilsService, + private translate: TranslateService, + protected store: Store, + private raf: RafService) { + } + + ngOnInit(): void { + const editorElement = this.cssEditorElmRef.nativeElement; + let editorOptions: Partial = { + mode: 'ace/mode/css', + showGutter: true, + showPrintMargin: true, + readOnly: this.disabled + }; + + const advancedOptions = { + enableSnippets: true, + enableBasicAutocompletion: true, + enableLiveAutocompletion: true + }; + + editorOptions = {...editorOptions, ...advancedOptions}; + getAce().subscribe( + (ace) => { + this.cssEditor = ace.edit(editorElement, editorOptions); + this.cssEditor.session.setUseWrapMode(true); + this.cssEditor.setValue(this.modelValue ? this.modelValue : '', -1); + this.cssEditor.setReadOnly(this.disabled); + this.cssEditor.on('change', () => { + if (!this.ignoreChange) { + this.updateView(); + } + }); + // @ts-ignore + this.cssEditor.session.on('changeAnnotation', () => { + const annotations = this.cssEditor.session.getAnnotations(); + const hasErrors = annotations.filter(annotation => annotation.type === 'error').length > 0; + if (this.hasErrors !== hasErrors) { + this.hasErrors = hasErrors; + this.propagateChange(this.modelValue); + } + }); + this.editorResize$ = new ResizeObserver(() => { + this.onAceEditorResize(); + }); + this.editorResize$.observe(editorElement); + } + ); + } + + ngOnDestroy(): void { + if (this.editorResize$) { + this.editorResize$.disconnect(); + } + } + + private onAceEditorResize() { + if (this.editorsResizeCaf) { + this.editorsResizeCaf(); + this.editorsResizeCaf = null; + } + this.editorsResizeCaf = this.raf.raf(() => { + this.cssEditor.resize(); + this.cssEditor.renderer.updateFull(); + }); + } + + registerOnChange(fn: any): void { + this.propagateChange = fn; + } + + registerOnTouched(fn: any): void { + } + + setDisabledState(isDisabled: boolean): void { + this.disabled = isDisabled; + if (this.cssEditor) { + this.cssEditor.setReadOnly(this.disabled); + } + } + + public validate(c: FormControl) { + return (!this.hasErrors) ? null : { + css: { + valid: false, + }, + }; + } + + beautifyCss() { + beautifyCss(this.modelValue, {indent_size: 4}).subscribe( + (res) => { + if (this.modelValue !== res) { + this.cssEditor.setValue(res ? res : '', -1); + this.updateView(); + } + } + ); + } + + writeValue(value: string): void { + this.modelValue = value; + if (this.cssEditor) { + this.ignoreChange = true; + this.cssEditor.setValue(this.modelValue ? this.modelValue : '', -1); + this.ignoreChange = false; + } + } + + updateView() { + const editorValue = this.cssEditor.getValue(); + if (this.modelValue !== editorValue) { + this.modelValue = editorValue; + this.propagateChange(this.modelValue); + } + } +} diff --git a/ui-ngx/src/app/shared/components/markdown.component.ts b/ui-ngx/src/app/shared/components/markdown.component.ts index 1abfc5b9e6..29933cba21 100644 --- a/ui-ngx/src/app/shared/components/markdown.component.ts +++ b/ui-ngx/src/app/shared/components/markdown.component.ts @@ -47,6 +47,10 @@ export class TbMarkdownComponent implements OnChanges { @Input() data: string | undefined; + @Input() context: any; + + @Input() additionalCompileModules: Type[]; + @Input() markdownClass: string | undefined; @Input() style: { [klass: string]: any } = {}; @@ -94,6 +98,10 @@ export class TbMarkdownComponent implements OnChanges { this.markdownContainer.clear(); const parent = this; let readyObservable: Observable; + let compileModules = [this.sharedModule]; + if (this.additionalCompileModules) { + compileModules = compileModules.concat(this.additionalCompileModules); + } this.dynamicComponentFactoryService.createDynamicComponentFactory( class TbMarkdownInstance { ngOnDestroy(): void { @@ -101,7 +109,7 @@ export class TbMarkdownComponent implements OnChanges { } }, template, - [this.sharedModule], + compileModules, true ).subscribe((factory) => { this.tbMarkdownInstanceComponentFactory = factory; @@ -109,6 +117,11 @@ export class TbMarkdownComponent implements OnChanges { try { this.tbMarkdownInstanceComponentRef = this.markdownContainer.createComponent(this.tbMarkdownInstanceComponentFactory, 0, injector); + if (this.context) { + for (const propName of Object.keys(this.context)) { + this.tbMarkdownInstanceComponentRef.instance[propName] = this.context[propName]; + } + } this.tbMarkdownInstanceComponentRef.instance.style = this.style; this.handlePlugins(this.tbMarkdownInstanceComponentRef.location.nativeElement); this.markdownService.highlight(this.tbMarkdownInstanceComponentRef.location.nativeElement); diff --git a/ui-ngx/src/app/shared/models/dashboard.models.ts b/ui-ngx/src/app/shared/models/dashboard.models.ts index db20056fde..f00e0e3878 100644 --- a/ui-ngx/src/app/shared/models/dashboard.models.ts +++ b/ui-ngx/src/app/shared/models/dashboard.models.ts @@ -97,6 +97,7 @@ export interface DashboardSettings { toolbarAlwaysOpen?: boolean; hideToolbar?: boolean; titleColor?: string; + dashboardCss?: string; } export interface DashboardConfiguration { diff --git a/ui-ngx/src/app/shared/models/widget.models.ts b/ui-ngx/src/app/shared/models/widget.models.ts index 0b0353c7a9..8e8aed3e53 100644 --- a/ui-ngx/src/app/shared/models/widget.models.ts +++ b/ui-ngx/src/app/shared/models/widget.models.ts @@ -506,6 +506,7 @@ export interface WidgetConfig { padding?: string; margin?: string; widgetStyle?: {[klass: string]: any}; + widgetCss?: string; titleStyle?: {[klass: string]: any}; units?: string; decimals?: number; diff --git a/ui-ngx/src/app/shared/shared.module.ts b/ui-ngx/src/app/shared/shared.module.ts index 1f66aedf47..086768c854 100644 --- a/ui-ngx/src/app/shared/shared.module.ts +++ b/ui-ngx/src/app/shared/shared.module.ts @@ -156,6 +156,7 @@ import { TbPopoverService } from '@shared/components/popover.service'; import { HELP_MARKDOWN_COMPONENT_TOKEN, SHARED_MODULE_TOKEN } from '@shared/components/tokens'; import { TbMarkdownComponent } from '@shared/components/markdown.component'; import { ProtobufContentComponent } from '@shared/components/protobuf-content.component'; +import { CssComponent } from '@shared/components/css.component'; export function MarkedOptionsFactory(markedOptionsService: MarkedOptionsService) { return markedOptionsService; @@ -233,6 +234,7 @@ export function MarkedOptionsFactory(markedOptionsService: MarkedOptionsService) JsonObjectEditComponent, JsonContentComponent, JsFuncComponent, + CssComponent, FabTriggerDirective, FabActionsDirective, FabToolbarComponent, @@ -378,6 +380,7 @@ export function MarkedOptionsFactory(markedOptionsService: MarkedOptionsService) JsonObjectEditComponent, JsonContentComponent, JsFuncComponent, + CssComponent, FabTriggerDirective, FabActionsDirective, FabToolbarComponent, diff --git a/ui-ngx/src/assets/locale/locale.constant-en_US.json b/ui-ngx/src/assets/locale/locale.constant-en_US.json index 170cea807b..807f3781a9 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -811,6 +811,8 @@ "dashboard-logo-settings": "Dashboard logo settings", "display-dashboard-logo": "Display logo in dashboard fullscreen mode", "dashboard-logo-image": "Dashboard logo image", + "advanced-settings": "Advanced settings", + "dashboard-css": "Dashboard CSS", "import": "Import dashboard", "export": "Export dashboard", "export-failed-error": "Unable to export dashboard: {{error}}", @@ -3084,6 +3086,7 @@ "padding": "Padding", "margin": "Margin", "widget-style": "Widget style", + "widget-css": "Widget CSS", "title-style": "Title style", "mobile-mode-settings": "Mobile mode", "order": "Order", From 36103ef01c76848c7eedd93894f51bcab583058a Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Wed, 22 Dec 2021 17:38:12 +0200 Subject: [PATCH 288/432] Edge events must be sorted by ID as last sort --- .../thingsboard/server/dao/sql/edge/JpaBaseEdgeEventDao.java | 2 +- .../server/dao/service/BaseEdgeEventServiceTest.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/edge/JpaBaseEdgeEventDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/edge/JpaBaseEdgeEventDao.java index 8645efccf7..e5883c20ab 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/edge/JpaBaseEdgeEventDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/edge/JpaBaseEdgeEventDao.java @@ -100,10 +100,10 @@ public class JpaBaseEdgeEventDao extends JpaAbstractSearchTextDao findEdgeEvents(UUID tenantId, EdgeId edgeId, TimePageLink pageLink, boolean withTsUpdate) { List sortOrders = new ArrayList<>(); - sortOrders.add(new SortOrder("id", SortOrder.Direction.ASC)); if (pageLink.getSortOrder() != null) { sortOrders.add(pageLink.getSortOrder()); } + sortOrders.add(new SortOrder(DaoUtil.DEFAULT_SORT_PROPERTY, SortOrder.Direction.ASC)); final Lock readWriteLock = readWriteLocks.computeIfAbsent(edgeId, id -> new ReentrantLock()); readWriteLock.lock(); try { diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseEdgeEventServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseEdgeEventServiceTest.java index 7c86e38eec..51a4975dcd 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseEdgeEventServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseEdgeEventServiceTest.java @@ -106,7 +106,7 @@ public abstract class BaseEdgeEventServiceTest extends AbstractServiceTest { EdgeId edgeId = new EdgeId(Uuids.timeBased()); DeviceId deviceId = new DeviceId(Uuids.timeBased()); TenantId tenantId = new TenantId(Uuids.timeBased()); - TimePageLink pageLink = new TimePageLink(1); + TimePageLink pageLink = new TimePageLink(1, 0, null, new SortOrder("createdTime", SortOrder.Direction.ASC)); EdgeEvent edgeEventWithTsUpdate = generateEdgeEvent(tenantId, edgeId, deviceId, EdgeEventActionType.TIMESERIES_UPDATED); edgeEventService.save(edgeEventWithTsUpdate); From 34fcf746598e0c75404898bc2b181dcb34c11d40 Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Wed, 22 Dec 2021 17:42:59 +0200 Subject: [PATCH 289/432] Organize imports --- .../thingsboard/server/dao/sql/edge/JpaBaseEdgeEventDao.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/edge/JpaBaseEdgeEventDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/edge/JpaBaseEdgeEventDao.java index dfb00eafcc..8fe7c281aa 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/edge/JpaBaseEdgeEventDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/edge/JpaBaseEdgeEventDao.java @@ -25,7 +25,6 @@ import org.thingsboard.server.common.data.edge.EdgeEvent; import org.thingsboard.server.common.data.id.EdgeEventId; import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.page.PageData; -import org.thingsboard.server.common.data.page.SortOrder; import org.thingsboard.server.common.data.page.TimePageLink; import org.thingsboard.server.dao.DaoUtil; import org.thingsboard.server.dao.edge.EdgeEventDao; @@ -36,8 +35,6 @@ import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; -import java.util.ArrayList; -import java.util.List; import java.util.Objects; import java.util.Optional; import java.util.UUID; From aac4ec07ab2e85512ad49014fa2af16b71e0f0dd Mon Sep 17 00:00:00 2001 From: ArtemDzhereleiko Date: Wed, 22 Dec 2021 18:12:17 +0200 Subject: [PATCH 290/432] UI: Update and refactoring --- .../server/controller/RpcV2Controller.java | 2 +- ui-ngx/src/app/core/api/widget-api.models.ts | 5 +- .../src/app/core/api/widget-subscription.ts | 41 ------ ui-ngx/src/app/core/http/device.service.ts | 10 +- ui-ngx/src/app/modules/common/modules-map.ts | 2 + .../rpc/persistent-add-dialog.component.html | 2 +- .../rpc/persistent-add-dialog.component.scss | 5 +- .../rpc/persistent-add-dialog.component.ts | 32 ++--- .../persistent-details-dialog.component.html | 2 +- .../persistent-details-dialog.component.scss | 5 +- .../persistent-details-dialog.component.ts | 61 +++------ .../persistent-filter-panel.component.html | 2 +- .../persistent-filter-panel.component.scss | 1 + .../rpc/persistent-filter-panel.component.ts | 16 +-- .../lib/rpc/persistent-table.component.html | 2 +- .../lib/rpc/persistent-table.component.scss | 1 + .../lib/rpc/persistent-table.component.ts | 129 ++++++++++++++---- .../json-object-view.component.html | 2 +- .../components/json-object-view.component.ts | 2 +- ui-ngx/src/app/shared/models/rpc.models.ts | 1 - ui-ngx/src/app/shared/shared.module.ts | 2 +- .../assets/locale/locale.constant-uk_UA.json | 2 +- 22 files changed, 171 insertions(+), 156 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/RpcV2Controller.java b/application/src/main/java/org/thingsboard/server/controller/RpcV2Controller.java index 3f85841b3c..81e9a9e394 100644 --- a/application/src/main/java/org/thingsboard/server/controller/RpcV2Controller.java +++ b/application/src/main/java/org/thingsboard/server/controller/RpcV2Controller.java @@ -188,7 +188,7 @@ public class RpcV2Controller extends AbstractRpcController { @RequestParam(required = false) String sortOrder) throws ThingsboardException { checkParameter("DeviceId", strDeviceId); try { - if (rpcStatus.equals(RpcStatus.DELETED)) { + if (rpcStatus != null && rpcStatus.equals(RpcStatus.DELETED)) { throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "RpcStatus: DELETED"); } diff --git a/ui-ngx/src/app/core/api/widget-api.models.ts b/ui-ngx/src/app/core/api/widget-api.models.ts index c0bab56e4e..7559692561 100644 --- a/ui-ngx/src/app/core/api/widget-api.models.ts +++ b/ui-ngx/src/app/core/api/widget-api.models.ts @@ -55,8 +55,7 @@ import { TranslateService } from '@ngx-translate/core'; import { AlarmDataService } from '@core/api/alarm-data.service'; import { IDashboardController } from '@home/components/dashboard-page/dashboard-page.models'; import { PopoverPlacement } from '@shared/components/popover.models'; -import { PageLink } from '@shared/models/page/page-link'; -import { PersistentRpc, RpcStatus } from '@shared/models/rpc.models'; +import { PersistentRpc } from '@shared/models/rpc.models'; export interface TimewindowFunctions { onUpdateTimewindow: (startTimeMs: number, endTimeMs: number, interval?: number) => void; @@ -322,8 +321,6 @@ export interface IWidgetSubscription { persistentPollingInterval?: number, retries?: number, additionalInfo?: any, requestUUID?: string): Observable; clearRpcError(): void; - subscribeForPersistentRequests(pageLink: PageLink, keyFileter: RpcStatus): Observable; - subscribe(): void; subscribeAllForPaginatedData(pageLink: EntityDataPageLink, diff --git a/ui-ngx/src/app/core/api/widget-subscription.ts b/ui-ngx/src/app/core/api/widget-subscription.ts index 1634bb7b87..0f864335aa 100644 --- a/ui-ngx/src/app/core/api/widget-subscription.ts +++ b/ui-ngx/src/app/core/api/widget-subscription.ts @@ -70,7 +70,6 @@ import { import { distinct, filter, map, switchMap, takeUntil } from 'rxjs/operators'; import { AlarmDataListener } from '@core/api/alarm-data.service'; import { RpcStatus } from '@shared/models/rpc.models'; -import { PageLink } from '@shared/models/page/page-link'; const moment = moment_; @@ -781,46 +780,6 @@ export class WidgetSubscription implements IWidgetSubscription { } } - subscribeForPersistentRequests(pageLink: PageLink, keyFilter: RpcStatus): Observable { - if (!this.rpcEnabled) { - return throwError(new Error('Rpc disabled!')); - } else if (!this.targetDeviceId) { - return throwError(new Error('Target device is not set!')); - } - const rpcSubject: Subject = new Subject(); - - this.ctx.deviceService.getPersistedRpcRequests(this.targetDeviceId, pageLink, keyFilter).subscribe( - (responseBody) => { - rpcSubject.next(responseBody); - rpcSubject.complete(); - }, - (rejection: HttpErrorResponse) => { - const index = this.executingSubjects.indexOf(rpcSubject); - if (index >= 0) { - this.executingSubjects.splice( index, 1 ); - } - this.executingRpcRequest = this.executingSubjects.length > 0; - this.callbacks.rpcStateChanged(this); - if (!this.executingRpcRequest || rejection.status === 504) { - this.rpcRejection = rejection; - if (rejection.status === 504) { - this.rpcErrorText = 'Request Timeout.'; - } else { - this.rpcErrorText = 'Error : ' + rejection.status + ' - ' + rejection.statusText; - const error = this.extractRejectionErrorText(rejection); - if (error) { - this.rpcErrorText += '
'; - this.rpcErrorText += error; - } - } - this.callbacks.onRpcFailed(this); - } - rpcSubject.error(rejection); - } - ); - return rpcSubject.asObservable(); - } - private extractRejectionErrorText(rejection: HttpErrorResponse) { let error = null; if (rejection.error) { diff --git a/ui-ngx/src/app/core/http/device.service.ts b/ui-ngx/src/app/core/http/device.service.ts index 9b5119d317..88f0cacb46 100644 --- a/ui-ngx/src/app/core/http/device.service.ts +++ b/ui-ngx/src/app/core/http/device.service.ts @@ -148,10 +148,12 @@ export class DeviceService { } public getPersistedRpcRequests(deviceId: string, pageLink: PageLink, - keyFilter: RpcStatus, config?: RequestConfig): Observable> { - const rpcStatus = keyFilter ? '&rpcStatus=' + keyFilter : ''; - return this.http.get>(`/api/rpc/persistent/device/${deviceId}${pageLink.toQuery()}${rpcStatus}`, - defaultHttpOptionsFromConfig(config)); + rpcStatus?: RpcStatus, config?: RequestConfig): Observable> { + let url = `/api/rpc/persistent/device/${deviceId}${pageLink.toQuery()}`; + if (rpcStatus && rpcStatus.length) { + url += `&rpcStatus=${rpcStatus}`; + } + return this.http.get>(url, defaultHttpOptionsFromConfig(config)); } public findByQuery(query: DeviceSearchQuery, diff --git a/ui-ngx/src/app/modules/common/modules-map.ts b/ui-ngx/src/app/modules/common/modules-map.ts index 3cd4139ec4..147492ec29 100644 --- a/ui-ngx/src/app/modules/common/modules-map.ts +++ b/ui-ngx/src/app/modules/common/modules-map.ts @@ -139,6 +139,7 @@ import * as QueueTypeListComponent from '@shared/components/queue/queue-type-lis import * as RelationTypeAutocompleteComponent from '@shared/components/relation/relation-type-autocomplete.component'; import * as SocialSharePanelComponent from '@shared/components/socialshare-panel.component'; import * as JsonObjectEditComponent from '@shared/components/json-object-edit.component'; +import * as JsonObjectViewComponent from '@shared/components/json-object-view.component'; import * as JsonContentComponent from '@shared/components/json-content.component'; import * as JsFuncComponent from '@shared/components/js-func.component'; import * as FabToolbarComponent from '@shared/components/fab-toolbar.component'; @@ -420,6 +421,7 @@ class ModulesMap implements IModulesMap { '@shared/components/relation/relation-type-autocomplete.component': RelationTypeAutocompleteComponent, '@shared/components/socialshare-panel.component': SocialSharePanelComponent, '@shared/components/json-object-edit.component': JsonObjectEditComponent, + '@shared/components/json-object-view.component': JsonObjectViewComponent, '@shared/components/json-content.component': JsonContentComponent, '@shared/components/js-func.component': JsFuncComponent, '@shared/components/fab-toolbar.component': FabToolbarComponent, diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-add-dialog.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-add-dialog.component.html index 7e0ae3056f..1e74657946 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-add-dialog.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-add-dialog.component.html @@ -32,7 +32,7 @@
- {{ 'widgets.persistent-table.message-types.' + persistentFormGroup.get('oneWayElseTwoWay').value | translate }} + {{ rpcMessageTypeText }}
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-add-dialog.component.scss b/ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-add-dialog.component.scss index e450fa4a09..3c9d0b43a2 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-add-dialog.component.scss +++ b/ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-add-dialog.component.scss @@ -13,8 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -:host { - .add-dialog ::ng-deep { + +:host ::ng-deep { + .add-dialog { .params-json-editor, .additional-json-editor { diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-add-dialog.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-add-dialog.component.ts index c4e87c5e6b..8c4f47a904 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-add-dialog.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-add-dialog.component.ts @@ -22,6 +22,7 @@ import { Router } from '@angular/router'; import { MatDialogRef } from '@angular/material/dialog'; import { FormBuilder, FormGroup, Validators } from '@angular/forms'; import { RequestData } from '@shared/models/rpc.models'; +import { TranslateService } from '@ngx-translate/core'; @Component({ selector: 'tb-persistent-add-dialog', @@ -32,15 +33,15 @@ import { RequestData } from '@shared/models/rpc.models'; export class PersistentAddDialogComponent extends DialogComponent implements OnInit { public persistentFormGroup: FormGroup; + public rpcMessageTypeText: string; - private requestData: RequestData = { - persistentUpdated: false - }; + private requestData: RequestData = null; constructor(protected store: Store, protected router: Router, public dialogRef: MatDialogRef, - private fb: FormBuilder) { + private fb: FormBuilder, + private translate: TranslateService) { super(store, router, dialogRef); this.persistentFormGroup = this.fb.group( @@ -48,27 +49,24 @@ export class PersistentAddDialogComponent extends DialogComponent { + this.rpcMessageTypeText = this.translate.instant(`widgets.persistent-table.message-types.${this.persistentFormGroup.get('oneWayElseTwoWay').value}`); + } + ); } close(): void { diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-details-dialog.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-details-dialog.component.html index 3a9451db67..440b142db2 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-details-dialog.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-details-dialog.component.html @@ -48,7 +48,7 @@ widgets.persistent-table.status + [ngStyle]="{ fontWeight: 'bold', color: rpcStatusColorsMap.get(data.persistentRequest.status) }"> widgets.persistent-table.method diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-details-dialog.component.scss b/ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-details-dialog.component.scss index ec456d5d9e..2a6a06c2a8 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-details-dialog.component.scss +++ b/ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-details-dialog.component.scss @@ -13,8 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -:host { - .rpc-dialog ::ng-deep { +:host ::ng-deep { + .rpc-dialog { .mat-expansion-panel-body { padding-bottom: 0 !important; } @@ -23,6 +23,7 @@ margin: 0 0 16px 0; } } + .tb-audit-log-response-data { width: 100%; min-width: 400px; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-details-dialog.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-details-dialog.component.ts index 552175b905..8e7e755e86 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-details-dialog.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-details-dialog.component.ts @@ -24,13 +24,7 @@ import { TranslateService } from '@ngx-translate/core'; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; import { FormBuilder, FormGroup } from '@angular/forms'; import { DeviceService } from '@core/http/device.service'; -import { - PersistentRpc, - rpcStatusColors, - RpcStatus, - rpcStatusTranslation -} from '@shared/models/rpc.models'; -import { isDefinedAndNotNull } from '@core/utils'; +import { PersistentRpc, RpcStatus, rpcStatusColors, rpcStatusTranslation } from '@shared/models/rpc.models'; import { NULL_UUID } from '@shared/models/id/has-uuid'; import { DialogService } from '@core/services/dialog.service'; @@ -82,7 +76,7 @@ export class PersistentDetailsDialogComponent extends DialogComponent { if (res) { - if (res) { - this.deviceService.deletePersistedRpc(persistentRpc.id.id).subscribe(() => { - this.persistentUpdated = true; - this.close(); - }); - } + this.deviceService.deletePersistedRpc(persistentRpc.id.id).subscribe(() => { + this.persistentUpdated = true; + this.close(); + }); } }); } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-filter-panel.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-filter-panel.component.html index ffbcab5749..d5eca15a5f 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-filter-panel.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-filter-panel.component.html @@ -19,7 +19,7 @@ widgets.persistent-table.rpc-status-list + placeholder="{{ rpcSearchPlaceholder }}"> {{ 'widgets.persistent-table.rpc-search-status-all' | translate }} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-filter-panel.component.scss b/ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-filter-panel.component.scss index 63f832d78c..2ad57a3f7f 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-filter-panel.component.scss +++ b/ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-filter-panel.component.scss @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + :host { width: 100%; height: 100%; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-filter-panel.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-filter-panel.component.ts index d60c80ac43..c8a72ffc3b 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-filter-panel.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-filter-panel.component.ts @@ -18,6 +18,7 @@ import { Component, Inject, InjectionToken } from '@angular/core'; import { FormBuilder, FormGroup } from '@angular/forms'; import { OverlayRef } from '@angular/cdk/overlay'; import { RpcStatus, rpcStatusTranslation } from '@shared/models/rpc.models'; +import { TranslateService } from '@ngx-translate/core'; export const PERSISTENT_FILTER_PANEL_DATA = new InjectionToken('AlarmFilterPanelData'); @@ -35,26 +36,21 @@ export class PersistentFilterPanelComponent { public persistentFilterFormGroup: FormGroup; public result: PersistentFilterPanelData; public rpcSearchStatusTranslationMap = rpcStatusTranslation; + public rpcSearchPlaceholder: string; - public persistentSearchStatuses = [ - RpcStatus.QUEUED, - RpcStatus.SENT, - RpcStatus.DELIVERED, - RpcStatus.SUCCESSFUL, - RpcStatus.TIMEOUT, - RpcStatus.EXPIRED, - RpcStatus.FAILED - ]; + public persistentSearchStatuses = Object.keys(RpcStatus); constructor(@Inject(PERSISTENT_FILTER_PANEL_DATA) public data: PersistentFilterPanelData, public overlayRef: OverlayRef, - private fb: FormBuilder) { + private fb: FormBuilder, + private translate: TranslateService) { this.persistentFilterFormGroup = this.fb.group( { rpcStatus: this.data.rpcStatus } ); + this.rpcSearchPlaceholder = this.translate.instant('widgets.persistent-table.any-status'); } update() { diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-table.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-table.component.html index fd86fd92cc..e786efec7b 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-table.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-table.component.html @@ -15,7 +15,7 @@ limitations under the License. --> -
+
{ - const showHidePageSize = this.persistentWidgetContainerRef.nativeElement.offsetWidth < hidePageSizePixelValue; + const showHidePageSize = this.elementRef.nativeElement.offsetWidth < hidePageSizePixelValue; if (showHidePageSize !== this.hidePageSize) { this.hidePageSize = showHidePageSize; - this.ctx.detectChanges(); + this.cd.markForCheck(); } }); - this.widgetResize$.observe(this.persistentWidgetContainerRef.nativeElement); + this.widgetResize$.observe(this.elementRef.nativeElement); } } @@ -250,7 +257,7 @@ export class PersistentTableComponent extends PageComponent implements OnInit { this.displayedColumns.push('actions'); } - this.persistentDatasource = new PersistentDatasource(this.translate, this.subscription); + this.persistentDatasource = new PersistentDatasource(this.translate, this.subscription, this.ctx); const cssString = constructTableCssString(this.widgetConfig); const cssParser = new cssjs(); @@ -300,11 +307,9 @@ export class PersistentTableComponent extends PageComponent implements OnInit { this.translate.instant('action.yes') ).subscribe((res) => { if (res) { - if (res) { - this.deviceService.deletePersistedRpc(persistentRpc.id.id).subscribe(() => { - this.reloadPersistentRequests(); - }); - } + this.deviceService.deletePersistedRpc(persistentRpc.id.id).subscribe(() => { + this.reloadPersistentRequests(); + }); } }); } @@ -345,7 +350,7 @@ export class PersistentTableComponent extends PageComponent implements OnInit { panelClass: ['tb-dialog', 'tb-fullscreen-dialog'] }).afterClosed().subscribe( (requestData) => { - if (requestData.persistentUpdated) { + if (requestData) { this.sendRequests(requestData); } } @@ -440,11 +445,16 @@ class PersistentDatasource implements DataSource { private persistentSubject = new BehaviorSubject([]); private pageDataSubject = new BehaviorSubject>(emptyPageData()); + private rpcErrorText: string; + private executingSubjects: Array>; + private executingRpcRequest = false; + public dataLoading = true; public pageData$ = this.pageDataSubject.asObservable(); constructor(private translate: TranslateService, - private subscription: IWidgetSubscription) { + private subscription: IWidgetSubscription, + private ctx: WidgetContext) { } connect(collectionViewer: CollectionViewer): Observable> { @@ -462,11 +472,11 @@ class PersistentDatasource implements DataSource { this.pageDataSubject.next(pageData); } - loadPersistent(pageLink: PageLink, keyFilter: RpcStatus) { + loadPersistent(pageLink: PageLink, rpcStatusFilter: RpcStatus) { this.dataLoading = true; const result = new ReplaySubject>(); - this.fetchEntities(pageLink, keyFilter).pipe( + this.fetchEntities(pageLink, rpcStatusFilter).pipe( catchError(() => of(emptyPageData())), ).subscribe( (pageData) => { @@ -479,8 +489,81 @@ class PersistentDatasource implements DataSource { return result; } - fetchEntities(pageLink: PageLink, keyFilter: RpcStatus): Observable> { - return this.subscription.subscribeForPersistentRequests(pageLink, keyFilter); + fetchEntities(pageLink: PageLink, rpcStatusFilter: RpcStatus): Observable> { + if (!this.subscription.rpcEnabled) { + return throwError(new Error('Rpc disabled!')); + } else if (!this.subscription.targetDeviceId) { + return throwError(new Error('Target device is not set!')); + } + const rpcSubject: Subject = new Subject(); + + this.ctx.deviceService.getPersistedRpcRequests(this.subscription.targetDeviceId, pageLink, rpcStatusFilter).subscribe( + (responseBody) => { + rpcSubject.next(responseBody); + rpcSubject.complete(); + }, + (rejection: HttpErrorResponse) => { + this.rpcErrorText = null; + this.executingSubjects = []; + + const index = this.executingSubjects.indexOf(rpcSubject); + if (index >= 0) { + this.executingSubjects.splice(index, 1); + } + this.executingRpcRequest = this.executingSubjects.length > 0; + this.subscription.options.callbacks.rpcStateChanged(this.subscription); + if (!this.executingRpcRequest || rejection.status === 504) { + this.subscription.rpcRejection = rejection; + if (rejection.status === 504) { + this.subscription.rpcErrorText = 'Request Timeout.'; + } else { + this.subscription.rpcErrorText = 'Error : ' + rejection.status + ' - ' + rejection.statusText; + const error = this.extractRejectionErrorText(rejection); + if (error) { + this.subscription.rpcErrorText += '
'; + this.subscription.rpcErrorText += error.message || ''; + } + } + this.subscription.callbacks.onRpcFailed(this.subscription); + } + rpcSubject.error(rejection); + } + ); + return rpcSubject.asObservable(); + } + + extractRejectionErrorText(rejection: HttpErrorResponse) { + let error = null; + if (rejection.error) { + error = rejection.error; + try { + error = rejection.error ? JSON.parse(rejection.error) : null; + } catch (e) {} + } + if (error && !error.message) { + error = this.prepareMessageFromData(error); + } else if (error && error.message) { + error = error.message; + } + return error; + } + + prepareMessageFromData(data) { + if (typeof data === 'object' && data.constructor === ArrayBuffer) { + const msg = String.fromCharCode.apply(null, new Uint8Array(data)); + try { + const msgObj = JSON.parse(msg); + if (msgObj.message) { + return msgObj.message; + } else { + return msg; + } + } catch (e) { + return msg; + } + } else { + return data; + } } isEmpty(): Observable { diff --git a/ui-ngx/src/app/shared/components/json-object-view.component.html b/ui-ngx/src/app/shared/components/json-object-view.component.html index 379c557b44..b3fbcef2de 100644 --- a/ui-ngx/src/app/shared/components/json-object-view.component.html +++ b/ui-ngx/src/app/shared/components/json-object-view.component.html @@ -18,5 +18,5 @@
-
+
diff --git a/ui-ngx/src/app/shared/components/json-object-view.component.ts b/ui-ngx/src/app/shared/components/json-object-view.component.ts index 5ce00b0189..b85988c3d3 100644 --- a/ui-ngx/src/app/shared/components/json-object-view.component.ts +++ b/ui-ngx/src/app/shared/components/json-object-view.component.ts @@ -153,7 +153,7 @@ export class JsonObjectViewComponent implements OnInit { }, 2); } } catch (e) { - // + console.error(e); } if (this.jsonViewer) { this.jsonViewer.setValue(this.contentValue ? this.contentValue : '', -1); diff --git a/ui-ngx/src/app/shared/models/rpc.models.ts b/ui-ngx/src/app/shared/models/rpc.models.ts index 61a94a401e..4512b590a0 100644 --- a/ui-ngx/src/app/shared/models/rpc.models.ts +++ b/ui-ngx/src/app/shared/models/rpc.models.ts @@ -79,7 +79,6 @@ export interface PersistentRpcData extends PersistentRpc { } export interface RequestData { - persistentUpdated: boolean; method?: string; oneWayElseTwoWay?: boolean; persistentPollingInterval?: number; diff --git a/ui-ngx/src/app/shared/shared.module.ts b/ui-ngx/src/app/shared/shared.module.ts index 71a4d344bf..bb16964806 100644 --- a/ui-ngx/src/app/shared/shared.module.ts +++ b/ui-ngx/src/app/shared/shared.module.ts @@ -150,7 +150,7 @@ import { TogglePasswordComponent } from '@shared/components/button/toggle-passwo import { HelpPopupComponent } from '@shared/components/help-popup.component'; import { TbPopoverComponent, TbPopoverDirective } from '@shared/components/popover.component'; import { TbStringTemplateOutletDirective } from '@shared/components/directives/sring-template-outlet.directive'; -import { TbComponentOutletDirective} from '@shared/components/directives/component-outlet.directive'; +import { TbComponentOutletDirective } from '@shared/components/directives/component-outlet.directive'; import { HelpMarkdownComponent } from '@shared/components/help-markdown.component'; import { MarkedOptionsService } from '@shared/components/marked-options.service'; import { TbPopoverService } from '@shared/components/popover.service'; diff --git a/ui-ngx/src/assets/locale/locale.constant-uk_UA.json b/ui-ngx/src/assets/locale/locale.constant-uk_UA.json index 3942a5193c..943598baef 100644 --- a/ui-ngx/src/assets/locale/locale.constant-uk_UA.json +++ b/ui-ngx/src/assets/locale/locale.constant-uk_UA.json @@ -2395,7 +2395,7 @@ }, "rpc-search-status-all": "ВСІ", "message-types": { - "false": "Двусторонній", + "false": "Двосторонній", "true": "Односторонній" } } From c20f6e4021a29bc0f3f6a38ac19392cbbdf21258 Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Thu, 23 Dec 2021 11:20:22 +0200 Subject: [PATCH 291/432] UI: Add in map widgets new group setting - Editor setting --- ui-ngx/package.json | 2 +- .../components/widget/lib/maps/leaflet-map.ts | 52 +++++---- .../components/widget/lib/maps/map-models.ts | 19 +++- .../components/widget/lib/maps/map-widget2.ts | 3 + .../components/widget/lib/maps/markers.ts | 29 ++--- .../components/widget/lib/maps/polygon.ts | 7 +- .../components/widget/lib/maps/schemes.ts | 58 ++++++++++ ui-ngx/yarn.lock | 107 ++++++++---------- 8 files changed, 178 insertions(+), 99 deletions(-) diff --git a/ui-ngx/package.json b/ui-ngx/package.json index adec5e815a..1153524a26 100644 --- a/ui-ngx/package.json +++ b/ui-ngx/package.json @@ -28,7 +28,7 @@ "@date-io/date-fns": "^2.11.0", "@flowjs/flow.js": "^2.14.1", "@flowjs/ngx-flow": "~0.4.6", - "@geoman-io/leaflet-geoman-free": "^2.11.3", + "@geoman-io/leaflet-geoman-free": "^2.11.4", "@juggle/resize-observer": "^3.3.1", "@mat-datetimepicker/core": "~7.0.1", "@material-ui/core": "^4.12.3", diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts index 78f459990e..9d661ae8d2 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts @@ -24,7 +24,9 @@ import { defaultSettings, FormattedData, MapSettings, - MarkerSettings, MarkerIconInfo, MarkerImageInfo, + MarkerIconInfo, + MarkerImageInfo, + MarkerSettings, PolygonSettings, PolylineSettings, ReplaceInfo, @@ -182,7 +184,7 @@ export default abstract class LeafletMap { addEditControl() { // Customize edit marker - if (this.options.draggableMarker) { + if (this.options.draggableMarker && !this.options.hideDrawControlButton) { const actions = [{ text: L.PM.Utils.getTranslation('actions.cancel'), onClick: () => this.toggleDrawMode('tbMarker') @@ -197,7 +199,7 @@ export default abstract class LeafletMap { } // Customize edit polygon - if (this.editPolygons) { + if (this.editPolygons && !this.options.hideDrawControlButton) { const rectangleActions = [ { text: L.PM.Utils.getTranslation('actions.cancel'), @@ -231,18 +233,27 @@ export default abstract class LeafletMap { const translateService = this.ctx.$injector.get(TranslateService); this.map.pm.setLang('en', translateService.instant('widgets.maps'), 'en'); - this.map.pm.addControls({ - position: 'topleft', - drawMarker: false, - drawCircle: false, - drawCircleMarker: false, - drawRectangle: false, - drawPolyline: false, - drawPolygon: false, - editMode: this.editPolygons, - cutPolygon: this.editPolygons, - rotateMode: this.editPolygons - }); + if (!this.options.hideAllControlButton) { + this.map.pm.addControls({ + position: 'topleft', + drawControls: !this.options.hideDrawControlButton, + drawMarker: false, + drawCircle: false, + drawCircleMarker: false, + drawRectangle: false, + drawPolyline: false, + drawPolygon: false, + dragMode: !this.options.hideEditControlButton, + editMode: this.editPolygons && !this.options.hideEditControlButton, + cutPolygon: this.editPolygons && !this.options.hideEditControlButton, + removalMode: !this.options.hideRemoveControlButton, + rotateMode: this.editPolygons && !this.options.hideEditControlButton + }); + } + + if (this.options.initDragMode) { + this.map.pm.enableGlobalDragMode(); + } this.map.on('pm:create', (e) => { if (e.shape === 'tbMarker') { @@ -344,6 +355,7 @@ export default abstract class LeafletMap { } if (this.options.draggableMarker || this.editPolygons) { map.pm.setGlobalOptions({ snappable: false } as L.PM.GlobalOptions); + map.pm.applyGlobalOptions(); this.addEditControl(); } else { this.map.pm.disableDraw(); @@ -555,7 +567,7 @@ export default abstract class LeafletMap { updatedMarkers.push(m); } } else { - m = this.createMarker(data.entityName, data, markersData, this.options as MarkerSettings, updateBounds, callback); + m = this.createMarker(data.entityName, data, markersData, this.options, updateBounds, callback); if (m) { createdMarkers.push(m); } @@ -569,7 +581,7 @@ export default abstract class LeafletMap { } }); this.markersData = markersData; - if ((this.options as MarkerSettings).useClusterMarkers) { + if (this.options.useClusterMarkers) { if (createdMarkers.length) { this.markersCluster.addLayers(createdMarkers.map(marker => marker.leafletMarker)); } @@ -589,7 +601,7 @@ export default abstract class LeafletMap { this.saveLocation(data, this.convertToCustomFormat(e.target._latlng)).subscribe(); } - private createMarker(key: string, data: FormattedData, dataSources: FormattedData[], settings: MarkerSettings, + private createMarker(key: string, data: FormattedData, dataSources: FormattedData[], settings: UnitedMapSettings, updateBounds = true, callback?): Marker { const newMarker = new Marker(this, this.convertPosition(data), settings, data, dataSources, this.dragMarker); if (callback) { @@ -597,7 +609,7 @@ export default abstract class LeafletMap { callback(data, true); }); } - if (this.bounds && updateBounds && !(this.options as MarkerSettings).useClusterMarkers) { + if (this.bounds && updateBounds && !this.options.useClusterMarkers) { this.fitBounds(this.bounds.extend(newMarker.leafletMarker.getLatLng())); } this.markers.set(key, newMarker); @@ -786,7 +798,7 @@ export default abstract class LeafletMap { this.saveLocation(data, this.convertPolygonToCustomFormat(coordinates)).subscribe(() => {}); } - createPolygon(polyData: FormattedData, dataSources: FormattedData[], settings: PolygonSettings, updateBounds = true) { + createPolygon(polyData: FormattedData, dataSources: FormattedData[], settings: UnitedMapSettings, updateBounds = true) { const polygon = new Polygon(this.map, polyData, dataSources, settings, this.dragPolygonVertex); if (updateBounds) { const bounds = polygon.leafletPoly.getBounds(); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-models.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-models.ts index e65479f588..de94bdc156 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-models.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-models.ts @@ -192,6 +192,15 @@ export type PolylineSettings = { strokeWeightFunction: GenericFunction; }; +export interface EditorSettings { + snappable: boolean; + initDragMode: boolean; + hideAllControlButton: boolean; + hideDrawControlButton: boolean; + hideEditControlButton: boolean; + hideRemoveControlButton: boolean; +} + export interface HistorySelectSettings { buttonColor: string; } @@ -231,7 +240,7 @@ export interface TripAnimationSettings extends PolygonSettings { export type actionsHandler = ($event: Event, datasource: Datasource) => void; -export type UnitedMapSettings = MapSettings & PolygonSettings & MarkerSettings & PolylineSettings & TripAnimationSettings; +export type UnitedMapSettings = MapSettings & PolygonSettings & MarkerSettings & PolylineSettings & TripAnimationSettings & EditorSettings; export const defaultSettings: any = { xPosKeyName: 'xPos', @@ -271,7 +280,13 @@ export const defaultSettings: any = { draggableMarker: false, editablePolygon: false, fitMapBounds: true, - mapPageSize: DEFAULT_MAP_PAGE_SIZE + mapPageSize: DEFAULT_MAP_PAGE_SIZE, + snappable: false, + initDragMode: false, + hideAllControlButton: false, + hideDrawControlButton: false, + hideEditControlButton: false, + hideRemoveControlButton: false }; export const hereProviders = [ diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-widget2.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-widget2.ts index 565887b160..bc042e4fc0 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-widget2.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-widget2.ts @@ -18,6 +18,7 @@ import { defaultSettings, FormattedData, hereProviders, MapProviders, UnitedMapS import LeafletMap from './leaflet-map'; import { commonMapSettingsSchema, + editorSettingSchema, mapPolygonSchema, markerClusteringSettingsSchema, markerClusteringSettingsSchemaLeaflet, @@ -115,6 +116,8 @@ export class MapWidgetController implements MapWidgetInterface { `model.useClusterMarkers === true && model.provider !== "image-map"`)]); addToSchema(schema, clusteringSchema); addGroupInfo(schema, 'Markers Clustering Settings'); + addToSchema(schema, addCondition(editorSettingSchema, '(model.editablePolygon === true || model.draggableMarker === true)')); + addGroupInfo(schema, 'Editor settings'); } return schema; } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/markers.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/markers.ts index 85020b7f33..741cf22719 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/markers.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/markers.ts @@ -14,19 +14,17 @@ /// limitations under the License. /// -import L, { Icon, LeafletMouseEvent } from 'leaflet'; -import { FormattedData, MarkerIconInfo, MarkerIconReadyFunction, MarkerImageInfo, MarkerSettings } from './map-models'; +import L, { LeafletMouseEvent } from 'leaflet'; import { - bindPopupActions, - createTooltip, -} from './maps-utils'; -import { - aspectCache, - fillPattern, - parseWithTranslation, - processPattern, - safeExecute -} from './common-maps-utils'; + FormattedData, + MarkerIconInfo, + MarkerIconReadyFunction, + MarkerImageInfo, + MarkerSettings, + UnitedMapSettings +} from './map-models'; +import { bindPopupActions, createTooltip, } from './maps-utils'; +import { aspectCache, fillPattern, parseWithTranslation, processPattern, safeExecute } from './common-maps-utils'; import tinycolor from 'tinycolor2'; import { isDefined, isDefinedAndNotNull } from '@core/utils'; import LeafletMap from './leaflet-map'; @@ -40,10 +38,13 @@ export class Marker { data: FormattedData; dataSources: FormattedData[]; - constructor(private map: LeafletMap, private location: L.LatLng, public settings: MarkerSettings, + constructor(private map: LeafletMap, private location: L.LatLng, public settings: UnitedMapSettings, data?: FormattedData, dataSources?, onDragendListener?) { this.setDataSources(data, dataSources); - this.leafletMarker = L.marker(location, {pmIgnore: !settings.draggableMarker}); + this.leafletMarker = L.marker(location, { + pmIgnore: !settings.draggableMarker, + snapIgnore: !settings.snappable + }); this.markerOffset = [ isDefined(settings.markerOffsetX) ? settings.markerOffsetX : 0.5, diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/polygon.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/polygon.ts index 908952e7d2..de55d9b1b0 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/polygon.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/polygon.ts @@ -23,7 +23,7 @@ import { processPattern, safeExecute } from './common-maps-utils'; -import { FormattedData, MarkerSettings, PolygonSettings } from './map-models'; +import { FormattedData, PolygonSettings, UnitedMapSettings } from './map-models'; export class Polygon { @@ -32,7 +32,7 @@ export class Polygon { data: FormattedData; dataSources: FormattedData[]; - constructor(public map, data: FormattedData, dataSources: FormattedData[], private settings: PolygonSettings, + constructor(public map, data: FormattedData, dataSources: FormattedData[], private settings: UnitedMapSettings, private onDragendListener?) { this.dataSources = dataSources; this.data = data; @@ -47,7 +47,8 @@ export class Polygon { weight: settings.polygonStrokeWeight, fillOpacity: settings.polygonOpacity, opacity: settings.polygonStrokeOpacity, - pmIgnore: !settings.editablePolygon + pmIgnore: !settings.editablePolygon, + snapIgnore: !settings.snappable }).addTo(this.map); this.updateLabel(settings); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/schemes.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/schemes.ts index 2924ff688e..1c383b75e0 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/schemes.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/schemes.ts @@ -1311,3 +1311,61 @@ export const providerSets: { [key: string]: IProvider } = { name: 'image-map' } }; + +export const editorSettingSchema = + { + schema: { + title: 'Editor settings', + type: 'object', + properties: { + snappable: { + title: 'Enable snapping to other vertices for precision drawing', + type: 'boolean', + default: false + }, + initDragMode: { + title: 'Initialize map in draggable mode', + type: 'boolean', + default: false + }, + hideAllControlButton: { + title: 'Hide all button', + type: 'boolean', + default: false + }, + hideDrawControlButton: { + title: 'Hide draw buttons', + type: 'boolean', + default: false + }, + hideEditControlButton: { + title: 'Hide edit buttons', + type: 'boolean', + default: false + }, + hideRemoveControlButton: { + title: 'Hide remove button', + type: 'boolean', + default: false + }, + }, + required: [] + }, + form: [ + 'snappable', + 'initDragMode', + 'hideAllControlButton', + { + key: 'hideDrawControlButton', + condition: 'model.hideAllControlButton == false' + }, + { + key: 'hideEditControlButton', + condition: 'model.hideAllControlButton == false' + }, + { + key: 'hideRemoveControlButton', + condition: 'model.hideAllControlButton == false' + } + ] + }; diff --git a/ui-ngx/yarn.lock b/ui-ngx/yarn.lock index f1e5a9abc9..25ca2b4b64 100644 --- a/ui-ngx/yarn.lock +++ b/ui-ngx/yarn.lock @@ -1308,15 +1308,15 @@ resolved "https://registry.yarnpkg.com/@gar/promisify/-/promisify-1.1.2.tgz#30aa825f11d438671d585bd44e7fd564535fc210" integrity sha512-82cpyJyKRoQoRi+14ibCeGPu0CwypgtBAdBhq1WfvagpCZNKqwXbKwXllYSMG91DhmG4jt9gN8eP6lGOtozuaw== -"@geoman-io/leaflet-geoman-free@^2.11.3": - version "2.11.3" - resolved "https://registry.yarnpkg.com/@geoman-io/leaflet-geoman-free/-/leaflet-geoman-free-2.11.3.tgz#480164ab76c2b2a885003e0c111284f3c3160a36" - integrity sha512-LsiurEgKEHBcTnAVl8h7EfS5V/doCuxePzPE9SnfrhtJBN7IzP6UwkEo35Agwko+BnIuw/o2bE4F7irvKwQzjw== - dependencies: - "@turf/boolean-contains" "6.3.0" - "@turf/kinks" "6.3.0" - "@turf/line-intersect" "6.3.0" - "@turf/line-split" "6.3.0" +"@geoman-io/leaflet-geoman-free@^2.11.4": + version "2.11.4" + resolved "https://registry.yarnpkg.com/@geoman-io/leaflet-geoman-free/-/leaflet-geoman-free-2.11.4.tgz#4a43fa8d3d5d2bca751135b775c19c6cc0063699" + integrity sha512-uWfgaGDhrtoCMHdHi2oNVKb8WXFMQvyNnan1sS/+Yn5jMPuhijWFyAjy0G5kTCamXhGXg4vUvlEpiRSrBwewKg== + dependencies: + "@turf/boolean-contains" "^6.5.0" + "@turf/kinks" "^6.5.0" + "@turf/line-intersect" "^6.5.0" + "@turf/line-split" "^6.5.0" lodash "4.17.21" polygon-clipping "0.15.3" @@ -1601,7 +1601,7 @@ resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.2.tgz#423c77877d0569db20e1fc80885ac4118314010e" integrity sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA== -"@turf/bbox@*", "@turf/bbox@^6.3.0": +"@turf/bbox@*", "@turf/bbox@^6.5.0": version "6.5.0" resolved "https://registry.yarnpkg.com/@turf/bbox/-/bbox-6.5.0.tgz#bec30a744019eae420dac9ea46fb75caa44d8dc5" integrity sha512-RBbLaao5hXTYyyg577iuMtDB8ehxMlUqHEJiMs8jT1GHkFhr6sYre3lmLsPeYEi/ZKj5TP5tt7fkzNdJ4GIVyw== @@ -1617,18 +1617,18 @@ "@turf/helpers" "^6.5.0" "@turf/invariant" "^6.5.0" -"@turf/boolean-contains@6.3.0": - version "6.3.0" - resolved "https://registry.yarnpkg.com/@turf/boolean-contains/-/boolean-contains-6.3.0.tgz#fe4fc359e408c8c3c89e7fb159c9d31fde48779a" - integrity sha512-1MW7B5G5tIu1lnAv3pXyFzl75wfBYnbA2GhwHDb4okIXMhloy/r5uIqAZHo0fOXykKVJS/gIfA/MioKIftoTug== +"@turf/boolean-contains@^6.5.0": + version "6.5.0" + resolved "https://registry.yarnpkg.com/@turf/boolean-contains/-/boolean-contains-6.5.0.tgz#f802e7432fb53109242d5bf57393ef2f53849bbf" + integrity sha512-4m8cJpbw+YQcKVGi8y0cHhBUnYT+QRfx6wzM4GI1IdtYH3p4oh/DOBJKrepQyiDzFDaNIjxuWXBh0ai1zVwOQQ== dependencies: - "@turf/bbox" "^6.3.0" - "@turf/boolean-point-in-polygon" "^6.3.0" - "@turf/boolean-point-on-line" "^6.3.0" - "@turf/helpers" "^6.3.0" - "@turf/invariant" "^6.3.0" + "@turf/bbox" "^6.5.0" + "@turf/boolean-point-in-polygon" "^6.5.0" + "@turf/boolean-point-on-line" "^6.5.0" + "@turf/helpers" "^6.5.0" + "@turf/invariant" "^6.5.0" -"@turf/boolean-point-in-polygon@^6.3.0": +"@turf/boolean-point-in-polygon@^6.5.0": version "6.5.0" resolved "https://registry.yarnpkg.com/@turf/boolean-point-in-polygon/-/boolean-point-in-polygon-6.5.0.tgz#6d2e9c89de4cd2e4365004c1e51490b7795a63cf" integrity sha512-DtSuVFB26SI+hj0SjrvXowGTUCHlgevPAIsukssW6BG5MlNSBQAo70wpICBNJL6RjukXg8d2eXaAWuD/CqL00A== @@ -1636,7 +1636,7 @@ "@turf/helpers" "^6.5.0" "@turf/invariant" "^6.5.0" -"@turf/boolean-point-on-line@^6.3.0": +"@turf/boolean-point-on-line@^6.5.0": version "6.5.0" resolved "https://registry.yarnpkg.com/@turf/boolean-point-on-line/-/boolean-point-on-line-6.5.0.tgz#a8efa7bad88760676f395afb9980746bc5b376e9" integrity sha512-A1BbuQ0LceLHvq7F/P7w3QvfpmZqbmViIUPHdNLvZimFNLo4e6IQunmzbe+8aSStH9QRZm3VOflyvNeXvvpZEQ== @@ -1660,37 +1660,26 @@ "@turf/helpers" "^6.5.0" "@turf/invariant" "^6.5.0" -"@turf/helpers@6.x", "@turf/helpers@^6.3.0", "@turf/helpers@^6.5.0": +"@turf/helpers@6.x", "@turf/helpers@^6.5.0": version "6.5.0" resolved "https://registry.yarnpkg.com/@turf/helpers/-/helpers-6.5.0.tgz#f79af094bd6b8ce7ed2bd3e089a8493ee6cae82e" integrity sha512-VbI1dV5bLFzohYYdgqwikdMVpe7pJ9X3E+dlr425wa2/sMJqYDhTO++ec38/pcPvPE6oD9WEEeU3Xu3gza+VPw== -"@turf/invariant@^6.3.0", "@turf/invariant@^6.5.0": +"@turf/invariant@^6.5.0": version "6.5.0" resolved "https://registry.yarnpkg.com/@turf/invariant/-/invariant-6.5.0.tgz#970afc988023e39c7ccab2341bd06979ddc7463f" integrity sha512-Wv8PRNCtPD31UVbdJE/KVAWKe7l6US+lJItRR/HOEW3eh+U/JwRCSUl/KZ7bmjM/C+zLNoreM2TU6OoLACs4eg== dependencies: "@turf/helpers" "^6.5.0" -"@turf/kinks@6.3.0": - version "6.3.0" - resolved "https://registry.yarnpkg.com/@turf/kinks/-/kinks-6.3.0.tgz#a16b4ccc5a5aae139d43e36271e0a0494fdb4bf7" - integrity sha512-BLWvbl2/fa4SeJzVMbleT6Vo1cmzwmzRfxL2xxMei2jmf6JSvqDoMJFwIHGXrLZXvhOCb1b2C+MhBfhtc7kYkQ== - dependencies: - "@turf/helpers" "^6.3.0" - -"@turf/line-intersect@6.3.0": - version "6.3.0" - resolved "https://registry.yarnpkg.com/@turf/line-intersect/-/line-intersect-6.3.0.tgz#726a50edc66bb7b5e798b052b103fb0da4d1c4f4" - integrity sha512-3naxR7XpkPd2vst3Mw6DFry4C9m3o0/f2n/xu5UAyxb88Ie4m2k+1eqkhzMMx/0L+E6iThWpLx7DASM6q6o9ow== +"@turf/kinks@^6.5.0": + version "6.5.0" + resolved "https://registry.yarnpkg.com/@turf/kinks/-/kinks-6.5.0.tgz#80e7456367535365012f658cf1a988b39a2c920b" + integrity sha512-ViCngdPt1eEL7hYUHR2eHR662GvCgTc35ZJFaNR6kRtr6D8plLaDju0FILeFFWSc+o8e3fwxZEJKmFj9IzPiIQ== dependencies: - "@turf/helpers" "^6.3.0" - "@turf/invariant" "^6.3.0" - "@turf/line-segment" "^6.3.0" - "@turf/meta" "^6.3.0" - geojson-rbush "3.x" + "@turf/helpers" "^6.5.0" -"@turf/line-intersect@^6.3.0", "@turf/line-intersect@^6.5.0": +"@turf/line-intersect@^6.5.0": version "6.5.0" resolved "https://registry.yarnpkg.com/@turf/line-intersect/-/line-intersect-6.5.0.tgz#dea48348b30c093715d2195d2dd7524aee4cf020" integrity sha512-CS6R1tZvVQD390G9Ea4pmpM6mJGPWoL82jD46y0q1KSor9s6HupMIo1kY4Ny+AEYQl9jd21V3Scz20eldpbTVA== @@ -1701,7 +1690,7 @@ "@turf/meta" "^6.5.0" geojson-rbush "3.x" -"@turf/line-segment@^6.3.0", "@turf/line-segment@^6.5.0": +"@turf/line-segment@^6.5.0": version "6.5.0" resolved "https://registry.yarnpkg.com/@turf/line-segment/-/line-segment-6.5.0.tgz#ee73f3ffcb7c956203b64ed966d96af380a4dd65" integrity sha512-jI625Ho4jSuJESNq66Mmi290ZJ5pPZiQZruPVpmHkUw257Pew0alMmb6YrqYNnLUuiVVONxAAKXUVeeUGtycfw== @@ -1710,30 +1699,30 @@ "@turf/invariant" "^6.5.0" "@turf/meta" "^6.5.0" -"@turf/line-split@6.3.0": - version "6.3.0" - resolved "https://registry.yarnpkg.com/@turf/line-split/-/line-split-6.3.0.tgz#ee218f66cd65ce84eafc4956c24083663f6082ea" - integrity sha512-Q0nUJ0vczy11piyEz0FaKScFwSQtb1HJ2RPEMCw1coUJhTCB02KBWQLImhYqwsD3uLg+H/fxaJ1Gva6EPWoDNQ== - dependencies: - "@turf/bbox" "^6.3.0" - "@turf/helpers" "^6.3.0" - "@turf/invariant" "^6.3.0" - "@turf/line-intersect" "^6.3.0" - "@turf/line-segment" "^6.3.0" - "@turf/meta" "^6.3.0" - "@turf/nearest-point-on-line" "^6.3.0" - "@turf/square" "^6.3.0" - "@turf/truncate" "^6.3.0" +"@turf/line-split@^6.5.0": + version "6.5.0" + resolved "https://registry.yarnpkg.com/@turf/line-split/-/line-split-6.5.0.tgz#116d7fbf714457878225187f5820ef98db7b02c2" + integrity sha512-/rwUMVr9OI2ccJjw7/6eTN53URtGThNSD5I0GgxyFXMtxWiloRJ9MTff8jBbtPWrRka/Sh2GkwucVRAEakx9Sw== + dependencies: + "@turf/bbox" "^6.5.0" + "@turf/helpers" "^6.5.0" + "@turf/invariant" "^6.5.0" + "@turf/line-intersect" "^6.5.0" + "@turf/line-segment" "^6.5.0" + "@turf/meta" "^6.5.0" + "@turf/nearest-point-on-line" "^6.5.0" + "@turf/square" "^6.5.0" + "@turf/truncate" "^6.5.0" geojson-rbush "3.x" -"@turf/meta@6.x", "@turf/meta@^6.3.0", "@turf/meta@^6.5.0": +"@turf/meta@6.x", "@turf/meta@^6.5.0": version "6.5.0" resolved "https://registry.yarnpkg.com/@turf/meta/-/meta-6.5.0.tgz#b725c3653c9f432133eaa04d3421f7e51e0418ca" integrity sha512-RrArvtsV0vdsCBegoBtOalgdSOfkBrTJ07VkpiCnq/491W67hnMWmDu7e6Ztw0C3WldRYTXkg3SumfdzZxLBHA== dependencies: "@turf/helpers" "^6.5.0" -"@turf/nearest-point-on-line@^6.3.0": +"@turf/nearest-point-on-line@^6.5.0": version "6.5.0" resolved "https://registry.yarnpkg.com/@turf/nearest-point-on-line/-/nearest-point-on-line-6.5.0.tgz#8e1cd2cdc0b5acaf4c8d8b3b33bb008d3cb99e7b" integrity sha512-WthrvddddvmymnC+Vf7BrkHGbDOUu6Z3/6bFYUGv1kxw8tiZ6n83/VG6kHz4poHOfS0RaNflzXSkmCi64fLBlg== @@ -1746,7 +1735,7 @@ "@turf/line-intersect" "^6.5.0" "@turf/meta" "^6.5.0" -"@turf/square@^6.3.0": +"@turf/square@^6.5.0": version "6.5.0" resolved "https://registry.yarnpkg.com/@turf/square/-/square-6.5.0.tgz#ab43eef99d39c36157ab5b80416bbeba1f6b2122" integrity sha512-BM2UyWDmiuHCadVhHXKIx5CQQbNCpOxB6S/aCNOCLbhCeypKX5Q0Aosc5YcmCJgkwO5BERCC6Ee7NMbNB2vHmQ== @@ -1754,7 +1743,7 @@ "@turf/distance" "^6.5.0" "@turf/helpers" "^6.5.0" -"@turf/truncate@^6.3.0": +"@turf/truncate@^6.5.0": version "6.5.0" resolved "https://registry.yarnpkg.com/@turf/truncate/-/truncate-6.5.0.tgz#c3a16cad959f1be1c5156157d5555c64b19185d8" integrity sha512-pFxg71pLk+eJj134Z9yUoRhIi8vqnnKvCYwdT4x/DQl/19RVdq1tV3yqOT3gcTQNfniteylL5qV1uTBDV5sgrg== From 00167d5872a855cc31ceb02058cc18404e86021a Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Thu, 23 Dec 2021 11:44:17 +0200 Subject: [PATCH 292/432] UI: Refactoring attribute-datasource --- .../modules/home/models/datasource/attribute-datasource.ts | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/ui-ngx/src/app/modules/home/models/datasource/attribute-datasource.ts b/ui-ngx/src/app/modules/home/models/datasource/attribute-datasource.ts index 6e6c937a8e..9b5cbd1598 100644 --- a/ui-ngx/src/app/modules/home/models/datasource/attribute-datasource.ts +++ b/ui-ngx/src/app/modules/home/models/datasource/attribute-datasource.ts @@ -89,12 +89,7 @@ export class AttributeDatasource implements DataSource { pageLink: PageLink): Observable> { return this.getAllAttributes(entityId, attributesScope).pipe( map((data) => { - let filteredData = []; - for(let key in data) { - if(data[key]['value'] !== null) { - filteredData.push(data[key]); - } - } + const filteredData = data.filter(attrData => attrData.lastUpdateTs !== 0 && attrData.value !== null); return pageLink.filterData(filteredData); }) ); From d7f4bd5436c72b1701fd806d9661bbd1ce203371 Mon Sep 17 00:00:00 2001 From: ArtemDzhereleiko Date: Thu, 23 Dec 2021 14:16:22 +0200 Subject: [PATCH 293/432] UI: Show legend fieldset only in timeseries and latest widget --- .../home/components/widget/legend.component.ts | 12 +++++++----- .../components/widget/widget-config.component.html | 2 +- .../components/widget/widget-config.component.ts | 4 ++++ 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/legend.component.ts b/ui-ngx/src/app/modules/home/components/widget/legend.component.ts index 004fd5087b..3f66fc8aba 100644 --- a/ui-ngx/src/app/modules/home/components/widget/legend.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/legend.component.ts @@ -60,11 +60,13 @@ export class LegendComponent implements OnInit { } legendKeys(): LegendKey[] { - let keys = this.legendData.keys; - if (this.legendConfig.sortDataKeys) { - keys = this.legendData.keys.sort((key1, key2) => key1.dataKey.label.localeCompare(key2.dataKey.label)); - } - return keys.filter(legendKey => this.legendData.keys[legendKey.dataIndex].dataKey.inLegend); + try { + let keys = this.legendData.keys; + if (this.legendConfig.sortDataKeys) { + keys = this.legendData.keys.sort((key1, key2) => key1.dataKey.label.localeCompare(key2.dataKey.label)); + } + return keys.filter(legendKey => this.legendData.keys[legendKey.dataIndex].dataKey.inLegend); + } catch (e) {} } } diff --git a/ui-ngx/src/app/modules/home/components/widget/widget-config.component.html b/ui-ngx/src/app/modules/home/components/widget/widget-config.component.html index 97542fd3cb..6878a19d60 100644 --- a/ui-ngx/src/app/modules/home/components/widget/widget-config.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/widget-config.component.html @@ -421,7 +421,7 @@ -
+
widget-config.legend diff --git a/ui-ngx/src/app/modules/home/components/widget/widget-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/widget-config.component.ts index 7d779a3a6c..e64cc4de42 100644 --- a/ui-ngx/src/app/modules/home/components/widget/widget-config.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/widget-config.component.ts @@ -159,6 +159,8 @@ export class WidgetConfigComponent extends PageComponent implements OnInit, Cont modelValue: WidgetConfigComponentData; + showLegendFieldset = true; + private propagateChange = null; public dataSettings: FormGroup; @@ -322,6 +324,8 @@ export class WidgetConfigComponent extends PageComponent implements OnInit, Cont this.datasourceTypes.push(DatasourceType.entityCount); } } + this.showLegendFieldset = (this.widgetType === widgetType.timeseries || this.widgetType === widgetType.latest); + this.dataSettings = this.fb.group({}); this.targetDeviceSettings = this.fb.group({}); this.alarmSourceSettings = this.fb.group({}); From c3e65c50191af207466cea5527b8aa49b2839293 Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Thu, 23 Dec 2021 14:21:59 +0200 Subject: [PATCH 294/432] Fixed dependency - use data commons instead of boot jpa starter --- common/data/pom.xml | 4 ++-- .../org/thingsboard/server/common/data/page/PageLink.java | 1 - pom.xml | 6 ++++++ 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/common/data/pom.xml b/common/data/pom.xml index 5a5838d7da..2cdb30457f 100644 --- a/common/data/pom.xml +++ b/common/data/pom.xml @@ -65,8 +65,8 @@ jackson-databind - org.springframework.boot - spring-boot-starter-data-jpa + org.springframework.data + spring-data-commons org.springframework.boot diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/page/PageLink.java b/common/data/src/main/java/org/thingsboard/server/common/data/page/PageLink.java index acf0d2f71e..2dac4f0a7c 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/page/PageLink.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/page/PageLink.java @@ -20,7 +20,6 @@ import lombok.Data; import org.springframework.data.domain.Sort; -import java.util.Collections; import java.util.List; import java.util.Map; import java.util.stream.Collectors; diff --git a/pom.xml b/pom.xml index b7c873898f..4f2713e190 100755 --- a/pom.xml +++ b/pom.xml @@ -40,6 +40,7 @@ 2.3.2 2.3.2 2.3.12.RELEASE + 2.3.9.RELEASE 5.2.16.RELEASE 5.2.11.RELEASE 5.4.7 @@ -1130,6 +1131,11 @@ spring-boot-starter-data-jpa ${spring-boot.version} + + org.springframework.data + spring-data-commons + ${spring-data.version} + org.apache.kafka kafka-clients From ce3d929fecf2a6dd8e15834b8babbe9f184d315a Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Thu, 23 Dec 2021 15:50:47 +0200 Subject: [PATCH 295/432] Fix json form default values handling --- .../json-form/react/json-form-base-component.tsx | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/ui-ngx/src/app/shared/components/json-form/react/json-form-base-component.tsx b/ui-ngx/src/app/shared/components/json-form/react/json-form-base-component.tsx index 17885e7c50..f0f5456191 100644 --- a/ui-ngx/src/app/shared/components/json-form/react/json-form-base-component.tsx +++ b/ui-ngx/src/app/shared/components/json-form/react/json-form-base-component.tsx @@ -16,6 +16,7 @@ import * as React from 'react'; import JsonFormUtils from './json-form-utils'; import { JsonFormFieldProps, JsonFormFieldState } from '@shared/components/json-form/react/json-form.models'; +import { isDefinedAndNotNull } from '@core/utils'; export default ThingsboardBaseComponent => class

extends React.Component { @@ -96,13 +97,13 @@ export default ThingsboardBaseComponent => class

} } } else { - if (!value && typeof this.props.form.default !== 'undefined') { + if (!value && isDefinedAndNotNull(this.props.form.default)) { value = this.props.form.default; } - if (!value && this.props.form.schema && typeof this.props.form.schema.default !== 'undefined') { + if (!value && this.props.form.schema && isDefinedAndNotNull(this.props.form.schema.default)) { value = this.props.form.schema.default; } - if (!value && this.props.form.titleMap && typeof this.props.form.titleMap[0].value !== 'undefined') { + if (!value && this.props.form.titleMap && isDefinedAndNotNull(this.props.form.titleMap[0].value)) { value = this.props.form.titleMap[0].value; } } From 3ae20647aa6fd46b9beaec4c9d19f1157ec831bf Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Thu, 23 Dec 2021 19:01:43 +0200 Subject: [PATCH 296/432] Implement sync with parent state params for dashboard state component --- ui-ngx/src/app/core/api/widget-api.models.ts | 1 + .../dashboard-state.component.ts | 33 +++++++++++++++---- .../default-state-controller.component.ts | 2 +- .../entity-state-controller.component.ts | 2 +- .../states/state-controller.component.ts | 13 ++++++-- .../states/state-controller.models.ts | 1 + .../states/states-component.directive.ts | 6 +++- 7 files changed, 47 insertions(+), 11 deletions(-) diff --git a/ui-ngx/src/app/core/api/widget-api.models.ts b/ui-ngx/src/app/core/api/widget-api.models.ts index d053efb601..8d7ea6dbe7 100644 --- a/ui-ngx/src/app/core/api/widget-api.models.ts +++ b/ui-ngx/src/app/core/api/widget-api.models.ts @@ -150,6 +150,7 @@ export type StateControllerHolder = () => IStateController; export interface IStateController { dashboardCtrl: IDashboardController; getStateParams(): StateParams; + stateChanged(): Observable; getStateParamsByStateId(stateId: string): StateParams; openState(id: string, params?: StateParams, openRightLayout?: boolean): void; updateState(id?: string, params?: StateParams, openRightLayout?: boolean): void; diff --git a/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-state.component.ts b/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-state.component.ts index 00bd266c2a..5c02f26227 100644 --- a/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-state.component.ts +++ b/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-state.component.ts @@ -14,23 +14,24 @@ /// limitations under the License. /// -import { Component, Input, OnInit } from '@angular/core'; +import { Component, Input, OnDestroy, OnInit } from '@angular/core'; import { PageComponent } from '@shared/components/page.component'; import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; import { Dashboard } from '@shared/models/dashboard.models'; -import { StateObject, StateParams } from '@core/api/widget-api.models'; -import { updateEntityParams, WidgetContext } from '../../models/widget-component.models'; +import { StateObject } from '@core/api/widget-api.models'; +import { updateEntityParams, WidgetContext } from '@home/models/widget-component.models'; import { deepClone, objToBase64 } from '@core/utils'; import { IDashboardComponent } from '@home/models/dashboard-component.models'; import { EntityId } from '@shared/models/id/entity-id'; +import { Subscription } from 'rxjs'; @Component({ selector: 'tb-dashboard-state', templateUrl: './dashboard-state.component.html', styleUrls: [] }) -export class DashboardStateComponent extends PageComponent implements OnInit { +export class DashboardStateComponent extends PageComponent implements OnInit, OnDestroy { @Input() ctx: WidgetContext; @@ -38,6 +39,9 @@ export class DashboardStateComponent extends PageComponent implements OnInit { @Input() stateId: string; + @Input() + syncParentStateParams = false; + @Input() entityParamName: string; @@ -50,12 +54,31 @@ export class DashboardStateComponent extends PageComponent implements OnInit { parentDashboard: IDashboardComponent; + private stateSubscription: Subscription; + constructor(protected store: Store) { super(store); } ngOnInit(): void { this.dashboard = deepClone(this.ctx.stateController.dashboardCtrl.dashboardCtx.getDashboard()); + this.updateCurrentState(); + this.parentDashboard = this.ctx.parentDashboard ? + this.ctx.parentDashboard : this.ctx.dashboard; + if (this.syncParentStateParams) { + this.stateSubscription = this.ctx.stateController.stateChanged().subscribe(() => { + this.updateCurrentState(); + }); + } + } + + ngOnDestroy(): void { + if (this.stateSubscription) { + this.stateSubscription.unsubscribe(); + } + } + + private updateCurrentState(): void { const stateObject: StateObject = {}; const params = deepClone(this.ctx.stateController.getStateParams()); updateEntityParams(params, this.entityParamName, this.entityId); @@ -64,7 +87,5 @@ export class DashboardStateComponent extends PageComponent implements OnInit { stateObject.id = this.stateId; } this.currentState = objToBase64([stateObject]); - this.parentDashboard = this.ctx.parentDashboard ? - this.ctx.parentDashboard : this.ctx.dashboard; } } diff --git a/ui-ngx/src/app/modules/home/components/dashboard-page/states/default-state-controller.component.ts b/ui-ngx/src/app/modules/home/components/dashboard-page/states/default-state-controller.component.ts index 674386f108..67e24b628c 100644 --- a/ui-ngx/src/app/modules/home/components/dashboard-page/states/default-state-controller.component.ts +++ b/ui-ngx/src/app/modules/home/components/dashboard-page/states/default-state-controller.component.ts @@ -54,7 +54,7 @@ export class DefaultStateControllerComponent extends StateControllerComponent im super.ngOnDestroy(); } - protected init() { + public init() { if (this.preservedState) { this.stateObject = this.preservedState; setTimeout(() => { diff --git a/ui-ngx/src/app/modules/home/components/dashboard-page/states/entity-state-controller.component.ts b/ui-ngx/src/app/modules/home/components/dashboard-page/states/entity-state-controller.component.ts index f12dd033aa..c559459819 100644 --- a/ui-ngx/src/app/modules/home/components/dashboard-page/states/entity-state-controller.component.ts +++ b/ui-ngx/src/app/modules/home/components/dashboard-page/states/entity-state-controller.component.ts @@ -58,7 +58,7 @@ export class EntityStateControllerComponent extends StateControllerComponent imp super.ngOnDestroy(); } - protected init() { + public init() { if (this.preservedState) { this.stateObject = this.preservedState; this.selectedStateIndex = this.stateObject.length - 1; diff --git a/ui-ngx/src/app/modules/home/components/dashboard-page/states/state-controller.component.ts b/ui-ngx/src/app/modules/home/components/dashboard-page/states/state-controller.component.ts index 5acf57095f..fed15b9088 100644 --- a/ui-ngx/src/app/modules/home/components/dashboard-page/states/state-controller.component.ts +++ b/ui-ngx/src/app/modules/home/components/dashboard-page/states/state-controller.component.ts @@ -17,7 +17,7 @@ import { IStateControllerComponent, StateControllerState } from '@home/components/dashboard-page/states/state-controller.models'; import { IDashboardController } from '../dashboard-page.models'; import { DashboardState } from '@app/shared/models/dashboard.models'; -import { Subscription } from 'rxjs'; +import { Observable, Subject, Subscription } from 'rxjs'; import { NgZone, OnDestroy, OnInit, Directive } from '@angular/core'; import { ActivatedRoute, Params, Router } from '@angular/router'; import { StatesControllerService } from '@home/components/dashboard-page/states/states-controller.service'; @@ -27,6 +27,7 @@ import { StateObject, StateParams } from '@app/core/api/widget-api.models'; @Directive() export abstract class StateControllerComponent implements IStateControllerComponent, OnInit, OnDestroy { + private stateChangedSubject = new Subject(); stateObject: StateControllerState = []; dashboardCtrl: IDashboardController; preservedState: any; @@ -108,6 +109,7 @@ export abstract class StateControllerComponent implements IStateControllerCompon const newState = this.decodeStateParam(paramMap.get('state')); if (this.currentState !== newState) { this.currentState = newState; + this.stateChangedSubject.next(); if (this.inited) { this.onStateChanged(); } @@ -124,6 +126,7 @@ export abstract class StateControllerComponent implements IStateControllerCompon subscription.unsubscribe(); }); this.rxSubscriptions.length = 0; + this.stateChangedSubject.complete(); } protected updateStateParam(newState: string, replaceCurrentHistoryUrl = false) { @@ -142,6 +145,11 @@ export abstract class StateControllerComponent implements IStateControllerCompon }); }); } + this.stateChangedSubject.next(); + } + + public stateChanged(): Observable { + return this.stateChangedSubject.asObservable(); } public openRightLayout(): void { @@ -159,6 +167,7 @@ export abstract class StateControllerComponent implements IStateControllerCompon public reInit() { this.preservedState = null; this.currentState = this.decodeStateParam(this.route.snapshot.queryParamMap.get('state')); + this.stateChangedSubject.next(); this.init(); } @@ -166,7 +175,7 @@ export abstract class StateControllerComponent implements IStateControllerCompon return stateURI !== null ? decodeURIComponent(stateURI) : null; } - protected abstract init(); + public abstract init(); protected abstract onMobileChanged(); diff --git a/ui-ngx/src/app/modules/home/components/dashboard-page/states/state-controller.models.ts b/ui-ngx/src/app/modules/home/components/dashboard-page/states/state-controller.models.ts index 6a21ac564f..333a66b3d1 100644 --- a/ui-ngx/src/app/modules/home/components/dashboard-page/states/state-controller.models.ts +++ b/ui-ngx/src/app/modules/home/components/dashboard-page/states/state-controller.models.ts @@ -30,4 +30,5 @@ export interface IStateControllerComponent extends IStateController { dashboardId: string; preservedState: any; reInit(): void; + init(): void; } diff --git a/ui-ngx/src/app/modules/home/components/dashboard-page/states/states-component.directive.ts b/ui-ngx/src/app/modules/home/components/dashboard-page/states/states-component.directive.ts index b6911ed9d8..e9d65a6323 100644 --- a/ui-ngx/src/app/modules/home/components/dashboard-page/states/states-component.directive.ts +++ b/ui-ngx/src/app/modules/home/components/dashboard-page/states/states-component.directive.ts @@ -76,6 +76,7 @@ export class StatesComponentDirective implements OnInit, OnDestroy, OnChanges { ngOnChanges(changes: SimpleChanges): void { let reInitController = false; + let initController = false; for (const propName of Object.keys(changes)) { const change = changes[propName]; if (!change.firstChange && change.currentValue !== change.previousValue) { @@ -92,12 +93,15 @@ export class StatesComponentDirective implements OnInit, OnDestroy, OnChanges { this.stateControllerComponent.state = this.state; } else if (propName === 'currentState') { this.stateControllerComponent.currentState = this.currentState; + initController = true; } else if (propName === 'syncStateWithQueryParam') { this.stateControllerComponent.syncStateWithQueryParam = this.syncStateWithQueryParam; } } } - if (reInitController) { + if (initController) { + this.stateControllerComponent.init(); + } else if (reInitController) { this.stateControllerComponent.reInit(); } } From 40c2d71488def03da0fe0566b5cb7aab7d56ae31 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Thu, 23 Dec 2021 19:26:58 +0200 Subject: [PATCH 297/432] Improve parent state change handling by dashboard state component --- .../components/dashboard-page/dashboard-state.component.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-state.component.ts b/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-state.component.ts index 5c02f26227..cb9055b5d3 100644 --- a/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-state.component.ts +++ b/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-state.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, Input, OnDestroy, OnInit } from '@angular/core'; +import { ChangeDetectorRef, Component, Input, OnDestroy, OnInit } from '@angular/core'; import { PageComponent } from '@shared/components/page.component'; import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; @@ -56,7 +56,8 @@ export class DashboardStateComponent extends PageComponent implements OnInit, On private stateSubscription: Subscription; - constructor(protected store: Store) { + constructor(protected store: Store, + private cd: ChangeDetectorRef) { super(store); } @@ -68,6 +69,7 @@ export class DashboardStateComponent extends PageComponent implements OnInit, On if (this.syncParentStateParams) { this.stateSubscription = this.ctx.stateController.stateChanged().subscribe(() => { this.updateCurrentState(); + this.cd.markForCheck(); }); } } From 94d502e6eedde28c9360789c43cfda454efd2b4b Mon Sep 17 00:00:00 2001 From: ArtemDzhereleiko Date: Fri, 24 Dec 2021 11:13:28 +0200 Subject: [PATCH 298/432] UI: Refactoring --- .../modules/home/components/widget/widget-config.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/widget-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/widget-config.component.ts index e64cc4de42..6b485dd66b 100644 --- a/ui-ngx/src/app/modules/home/components/widget/widget-config.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/widget-config.component.ts @@ -324,7 +324,6 @@ export class WidgetConfigComponent extends PageComponent implements OnInit, Cont this.datasourceTypes.push(DatasourceType.entityCount); } } - this.showLegendFieldset = (this.widgetType === widgetType.timeseries || this.widgetType === widgetType.latest); this.dataSettings = this.fb.group({}); this.targetDeviceSettings = this.fb.group({}); @@ -389,6 +388,7 @@ export class WidgetConfigComponent extends PageComponent implements OnInit, Cont if (this.modelValue) { if (this.widgetType !== this.modelValue.widgetType) { this.widgetType = this.modelValue.widgetType; + this.showLegendFieldset = (this.widgetType === widgetType.timeseries || this.widgetType === widgetType.latest); this.buildForms(); } const config = this.modelValue.config; From cfead9941ed1a66e29b89adaf28cad40ca28b982 Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Fri, 24 Dec 2021 11:28:20 +0200 Subject: [PATCH 299/432] UI: Fixed code style --- ui-ngx/src/app/shared/components/json-object-view.component.ts | 1 - ui-ngx/src/assets/locale/locale.constant-en_US.json | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/ui-ngx/src/app/shared/components/json-object-view.component.ts b/ui-ngx/src/app/shared/components/json-object-view.component.ts index b85988c3d3..483d1a014a 100644 --- a/ui-ngx/src/app/shared/components/json-object-view.component.ts +++ b/ui-ngx/src/app/shared/components/json-object-view.component.ts @@ -127,7 +127,6 @@ export class JsonObjectViewComponent implements OnInit { newWidth = 8 * maxLineLength + 16; } if (this.heigthValue) { - // this.renderer.setStyle(editorElement, 'minHeight', newHeight.toString() + 'px'); this.renderer.setStyle(editorElement, 'height', newHeight.toString() + 'px'); } if (this.widthValue) { diff --git a/ui-ngx/src/assets/locale/locale.constant-en_US.json b/ui-ngx/src/assets/locale/locale.constant-en_US.json index bd33c10376..e4fa66b4e5 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -3279,7 +3279,7 @@ "EXPIRED": "EXPIRED", "FAILED": "FAILED" }, - "rpc-search-status-all": "ALL", + "rpc-search-status-all": "ALL", "message-types": { "false": "Two-way", "true": "One-way" From 95e3f3c05b76d25025aa46c9fa90012763d16d7c Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Fri, 24 Dec 2021 11:55:46 +0200 Subject: [PATCH 300/432] fixed double sending ota update after sleeping --- .../server/client/LwM2mClientContextImpl.java | 11 ++----- .../ota/DefaultLwM2MOtaUpdateService.java | 31 ++++++++++++++++--- .../server/ota/LwM2MOtaUpdateService.java | 2 ++ 3 files changed, 31 insertions(+), 13 deletions(-) diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java index dd9edd2909..f7e4a4a5cc 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java @@ -37,7 +37,6 @@ import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; import org.thingsboard.server.transport.lwm2m.secure.TbLwM2MSecurityInfo; import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportContext; -import org.thingsboard.server.transport.lwm2m.server.LwM2mVersionedModelProvider; import org.thingsboard.server.transport.lwm2m.server.ota.LwM2MOtaUpdateService; import org.thingsboard.server.transport.lwm2m.server.session.LwM2MSessionManager; import org.thingsboard.server.transport.lwm2m.server.store.TbLwM2MClientStore; @@ -71,7 +70,6 @@ public class LwM2mClientContextImpl implements LwM2mClientContext { private final TbLwM2MClientStore clientStore; private final LwM2MSessionManager sessionManager; private final TransportDeviceProfileCache deviceProfileCache; - private final LwM2mVersionedModelProvider modelProvider; @Autowired @Lazy @@ -229,10 +227,7 @@ public class LwM2mClientContextImpl implements LwM2mClientContext { throw new LwM2MClientStateException(client.getState(), "Client is in invalid state."); } client.setRegistration(registration); - onUplink(client); - if (compareAndSetSleepFlag(client, false)) { - sendMsgsAfterSleeping(client); - } else { + if (!awake(client)) { clientStore.put(client); } } finally { @@ -419,7 +414,7 @@ public class LwM2mClientContextImpl implements LwM2mClientContext { powerMode = PowerMode.DRX; } } - if (PowerMode.DRX.equals(powerMode)) { + if (PowerMode.DRX.equals(powerMode) || otaUpdateService.isOtaDownloading(client)) { return true; } client.lock(); @@ -503,7 +498,7 @@ public class LwM2mClientContextImpl implements LwM2mClientContext { sleepTask.cancel(false); } Future task = context.getScheduler().schedule(() -> { - if (uplinkTime == client.getLastUplinkTime()) { + if (uplinkTime == client.getLastUplinkTime() && !otaUpdateService.isOtaDownloading(client)) { asleep(client); } return null; diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/DefaultLwM2MOtaUpdateService.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/DefaultLwM2MOtaUpdateService.java index 5fda8f87a9..1ebd2e75f8 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/DefaultLwM2MOtaUpdateService.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/DefaultLwM2MOtaUpdateService.java @@ -182,9 +182,9 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl } var clientSettings = clientContext.getProfile(client.getProfileId()).getClientLwM2mSettings(); - onFirmwareStrategyUpdate(client, clientSettings); + initFwStrategy(client, clientSettings); onCurrentSoftwareStrategyUpdate(client, clientSettings); - + if (!attributesToFetch.isEmpty()) { var future = attributesService.getSharedAttributes(client, attributesToFetch); DonAsynchron.withCallback(future, attrs -> { @@ -193,7 +193,7 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl Optional newFwVersion = getAttributeValue(attrs, FIRMWARE_VERSION); Optional newFwTag = getAttributeValue(attrs, FIRMWARE_TAG); Optional newFwUrl = getAttributeValue(attrs, FIRMWARE_URL); - if (newFwTitle.isPresent() && newFwVersion.isPresent()) { + if (newFwTitle.isPresent() && newFwVersion.isPresent() && !isOtaDownloading(client) && !UPDATING.equals(fwInfo.status)) { onTargetFirmwareUpdate(client, newFwTitle.get(), newFwVersion.get(), newFwUrl, newFwTag); } } @@ -245,10 +245,14 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl @Override public void onFirmwareStrategyUpdate(LwM2mClient client, OtherConfiguration configuration) { log.debug("[{}] Current fw strategy: {}", client.getEndpoint(), configuration.getFwUpdateStrategy()); + startFirmwareUpdateIfNeeded(client, initFwStrategy(client, configuration)); + } + + private LwM2MClientFwOtaInfo initFwStrategy(LwM2mClient client, OtherConfiguration configuration) { LwM2MClientFwOtaInfo fwInfo = getOrInitFwInfo(client); fwInfo.setStrategy(LwM2MFirmwareUpdateStrategy.fromStrategyFwByCode(configuration.getFwUpdateStrategy())); fwInfo.setBaseUrl(configuration.getFwUpdateResource()); - startFirmwareUpdateIfNeeded(client, fwInfo); + return fwInfo; } @Override @@ -308,6 +312,7 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl if (FirmwareUpdateResult.INITIAL.equals(result) && OtaPackageUpdateStatus.UPDATING.equals(fwInfo.getStatus())) { status = Optional.of(UPDATED); fwInfo.setRetryAttempts(0); + fwInfo.setFailedPackageId(null); } status.ifPresent(otaStatus -> { @@ -388,6 +393,22 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl startSoftwareUpdateIfNeeded(client, fwInfo); } + @Override + public boolean isOtaDownloading(LwM2mClient client) { + String endpoint = client.getEndpoint(); + LwM2MClientFwOtaInfo fwInfo = fwStates.get(endpoint); + LwM2MClientSwOtaInfo swInfo = swStates.get(endpoint); + + if (fwInfo != null && (DOWNLOADING.equals(fwInfo.getStatus()))) { + return true; + } + if (swInfo != null && (DOWNLOADING.equals(swInfo.getStatus()))) { + return true; + } + + return false; + } + private void startFirmwareUpdateIfNeeded(LwM2mClient client, LwM2MClientFwOtaInfo fwInfo) { try { if (!fwInfo.isSupported() && fwInfo.isAssigned()) { @@ -401,7 +422,7 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl log.debug("[{}] Starting update to [{}{}] using binary", client.getEndpoint(), fwInfo.getTargetName(), fwInfo.getTargetVersion()); startUpdateUsingBinary(client, fwInfo); } - } else if (fwInfo.getResult() != null && fwInfo.getResult().getCode() > UPDATE_SUCCESSFULLY.getCode()) { + } else if (fwInfo.getResult() != null && fwInfo.getResult().getCode() > UPDATE_SUCCESSFULLY.getCode()) { log.trace("[{}] Previous update failed. [{}]", client.getEndpoint(), fwInfo); logService.log(client, "Previous update firmware failed. Result: " + fwInfo.getResult().name()); } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/LwM2MOtaUpdateService.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/LwM2MOtaUpdateService.java index b23924b906..4aa3776682 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/LwM2MOtaUpdateService.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/LwM2MOtaUpdateService.java @@ -55,4 +55,6 @@ public interface LwM2MOtaUpdateService { void onCurrentSoftwareStateUpdate(LwM2mClient lwM2MClient, Long value); void onCurrentSoftwareResultUpdate(LwM2mClient client, Long result); + + boolean isOtaDownloading(LwM2mClient client); } From a0af567bf01f77ac8f5e9fa0f5843782c1e4fec2 Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Fri, 24 Dec 2021 12:06:14 +0200 Subject: [PATCH 301/432] removing old tag if new tag is empty --- .../service/ota/DefaultOtaPackageStateService.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/ota/DefaultOtaPackageStateService.java b/application/src/main/java/org/thingsboard/server/service/ota/DefaultOtaPackageStateService.java index c239dd78b3..883745e643 100644 --- a/application/src/main/java/org/thingsboard/server/service/ota/DefaultOtaPackageStateService.java +++ b/application/src/main/java/org/thingsboard/server/service/ota/DefaultOtaPackageStateService.java @@ -17,11 +17,11 @@ package org.thingsboard.server.service.ota; import com.google.common.util.concurrent.FutureCallback; import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Required; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.thingsboard.rule.engine.api.RuleEngineTelemetryService; import org.thingsboard.rule.engine.api.msg.DeviceAttributesEventNotificationMsg; +import org.thingsboard.server.cluster.TbClusterService; import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.DeviceProfile; @@ -51,8 +51,6 @@ import org.thingsboard.server.queue.TbQueueProducer; import org.thingsboard.server.queue.common.TbProtoQueueMsg; import org.thingsboard.server.queue.provider.TbCoreQueueFactory; import org.thingsboard.server.queue.provider.TbRuleEngineQueueFactory; -import org.thingsboard.server.queue.util.TbCoreComponent; -import org.thingsboard.server.cluster.TbClusterService; import javax.annotation.Nullable; import java.util.ArrayList; @@ -302,14 +300,16 @@ public class DefaultOtaPackageStateService implements OtaPackageStateService { private void updateAttributes(Device device, OtaPackageInfo otaPackage, long ts, TenantId tenantId, DeviceId deviceId, OtaPackageType otaPackageType) { List attributes = new ArrayList<>(); + List attrToRemove = new ArrayList<>(); attributes.add(new BaseAttributeKvEntry(ts, new StringDataEntry(getAttributeKey(otaPackageType, TITLE), otaPackage.getTitle()))); attributes.add(new BaseAttributeKvEntry(ts, new StringDataEntry(getAttributeKey(otaPackageType, VERSION), otaPackage.getVersion()))); if (StringUtils.isNotEmpty(otaPackage.getTag())) { attributes.add(new BaseAttributeKvEntry(ts, new StringDataEntry(getAttributeKey(otaPackageType, TAG), otaPackage.getTag()))); + } else { + attrToRemove.add(getAttributeKey(otaPackageType, TAG)); } if (otaPackage.hasUrl()) { attributes.add(new BaseAttributeKvEntry(ts, new StringDataEntry(getAttributeKey(otaPackageType, URL), otaPackage.getUrl()))); - List attrToRemove = new ArrayList<>(); if (otaPackage.getDataSize() == null) { attrToRemove.add(getAttributeKey(otaPackageType, SIZE)); @@ -328,15 +328,15 @@ public class DefaultOtaPackageStateService implements OtaPackageStateService { } else { attributes.add(new BaseAttributeKvEntry(ts, new StringDataEntry(getAttributeKey(otaPackageType, CHECKSUM), otaPackage.getChecksum()))); } - - remove(device, otaPackageType, attrToRemove); } else { attributes.add(new BaseAttributeKvEntry(ts, new LongDataEntry(getAttributeKey(otaPackageType, SIZE), otaPackage.getDataSize()))); attributes.add(new BaseAttributeKvEntry(ts, new StringDataEntry(getAttributeKey(otaPackageType, CHECKSUM_ALGORITHM), otaPackage.getChecksumAlgorithm().name()))); attributes.add(new BaseAttributeKvEntry(ts, new StringDataEntry(getAttributeKey(otaPackageType, CHECKSUM), otaPackage.getChecksum()))); - remove(device, otaPackageType, Collections.singletonList(getAttributeKey(otaPackageType, URL))); + attrToRemove.add(getAttributeKey(otaPackageType, URL)); } + remove(device, otaPackageType, attrToRemove); + telemetryService.saveAndNotify(tenantId, deviceId, DataConstants.SHARED_SCOPE, attributes, new FutureCallback<>() { @Override public void onSuccess(@Nullable Void tmp) { From c94aa3a25a197dd0d746f44cb1d2297548786834 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Fri, 24 Dec 2021 15:53:18 +0200 Subject: [PATCH 302/432] Improve markdown widget. Fix parent state params sync in dashboard state component when dashboard edit mode changed. --- .../main/data/json/system/widget_bundles/cards.json | 4 ++-- ui-ngx/src/app/core/api/widget-api.models.ts | 2 +- .../dashboard-page/dashboard-page.component.ts | 1 + .../components/dashboard-page/dashboard-page.models.ts | 2 ++ .../dashboard-page/dashboard-state.component.ts | 2 +- .../states/state-controller.component.ts | 10 +++++----- .../states/states-component.directive.ts | 8 ++++++++ .../components/widget/lib/markdown-widget.component.ts | 8 ++++++++ 8 files changed, 28 insertions(+), 9 deletions(-) diff --git a/application/src/main/data/json/system/widget_bundles/cards.json b/application/src/main/data/json/system/widget_bundles/cards.json index 9b70d91a08..4b15c8b510 100644 --- a/application/src/main/data/json/system/widget_bundles/cards.json +++ b/application/src/main/data/json/system/widget_bundles/cards.json @@ -180,11 +180,11 @@ "resources": [], "templateHtml": "\n", "templateCss": "#container tb-markdown-widget {\n height: 100%;\n display: block;\n}\n\n#container tb-markdown-widget .tb-markdown-view {\n height: 100%;\n overflow: auto;\n}\n", - "controllerScript": "self.onInit = function() {\n}\n\nself.onDataUpdated = function() {\n self.ctx.$scope.markdownWidget.onDataUpdated();\n}\n\nself.actionSources = function() {\n return {\n 'elementClick': {\n name: 'widget-action.element-click',\n multiple: true\n }\n };\n}\n\nself.typeParameters = function() {\n return {\n dataKeysOptional: true,\n datasourcesOptional: true\n };\n}\n\nself.onDestroy = function() {\n}\n\n", + "controllerScript": "self.onInit = function() {\n}\n\nself.onDataUpdated = function() {\n self.ctx.$scope.markdownWidget.onDataUpdated();\n}\n\nself.actionSources = function() {\n return {\n 'elementClick': {\n name: 'widget-action.element-click',\n multiple: true\n }\n };\n}\n\nself.typeParameters = function() {\n return {\n dataKeysOptional: true,\n datasourcesOptional: true,\n hasDataPageLink: true\n };\n}\n\nself.onDestroy = function() {\n}\n\n", "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"Markdown/HTML card\",\n \"properties\": {\n \"markdownTextPattern\": {\n \"title\": \"Markdown/HTML pattern (markdown or HTML with variables, for ex. '${entityName} or ${keyName} - some text.')\",\n \"type\": \"string\",\n \"default\": \"# Markdown/HTML card \\n - **Current entity**: **${entityName}**. \\n - **Current value**: **${Random}**.\"\n },\n \"markdownCss\": {\n \"title\": \"Markdown/HTML CSS\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"useMarkdownTextFunction\": {\n \"title\": \"Use markdown/HTML value function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"markdownTextFunction\": {\n \"title\": \"Markdown/HTML value function: f(data)\",\n \"type\": \"string\",\n \"default\": \"return '# Some title\\\\n - Entity name: ' + data[0]['entityName'];\"\n }\n },\n \"required\": []\n },\n \"form\": [\n \"useMarkdownTextFunction\",\n {\n \"key\": \"markdownTextPattern\",\n \"type\": \"markdown\",\n \"condition\": \"model.useMarkdownTextFunction !== true\"\n },\n {\n \"key\": \"markdownTextFunction\",\n \"type\": \"javascript\",\n \"helpId\": \"widget/lib/markdown/markdown_text_fn\",\n \"condition\": \"model.useMarkdownTextFunction === true\"\n },\n {\n \"key\": \"markdownCss\",\n \"type\": \"css\"\n }\n ]\n}\n", "dataKeySettingsSchema": "{}\n", "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Random\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.15479322438769105,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -1000) {\\n\\tvalue = -1000;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":false,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"markdownTextPattern\":\"### Markdown/HTML card\\n - **Current entity**: ${entityName}.\\n - **Current value**: ${Random}.\",\"markdownTextFunction\":\"return '# Some title\\\\n - Entity name: ' + data[0]['entityName'];\",\"useMarkdownTextFunction\":false},\"title\":\"Markdown/HTML Card\",\"showTitleIcon\":false,\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"24px\",\"titleTooltip\":\"\",\"dropShadow\":true,\"enableFullscreen\":true,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"showLegend\":false}" } } ] -} \ No newline at end of file +} diff --git a/ui-ngx/src/app/core/api/widget-api.models.ts b/ui-ngx/src/app/core/api/widget-api.models.ts index 8d7ea6dbe7..ad02f0d7be 100644 --- a/ui-ngx/src/app/core/api/widget-api.models.ts +++ b/ui-ngx/src/app/core/api/widget-api.models.ts @@ -150,7 +150,7 @@ export type StateControllerHolder = () => IStateController; export interface IStateController { dashboardCtrl: IDashboardController; getStateParams(): StateParams; - stateChanged(): Observable; + stateChanged(): Observable; getStateParamsByStateId(stateId: string): StateParams; openState(id: string, params?: StateParams, openRightLayout?: boolean): void; updateState(id?: string, params?: StateParams, openRightLayout?: boolean): void; diff --git a/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.ts b/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.ts index e15f04d766..4b11f29de0 100644 --- a/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.ts +++ b/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.ts @@ -233,6 +233,7 @@ export class DashboardPageComponent extends PageComponent implements IDashboardC dashboardTimewindow: null, state: null, stateController: null, + stateChanged: null, aliasController: null, runChangeDetection: this.runChangeDetection.bind(this) }; diff --git a/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.models.ts b/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.models.ts index c4f7a2965a..ddef622f99 100644 --- a/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.models.ts +++ b/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.models.ts @@ -20,6 +20,7 @@ import { Timewindow } from '@shared/models/time/time.models'; import { IAliasController, IStateController } from '@core/api/widget-api.models'; import { ILayoutController } from './layout/layout.models'; import { DashboardContextMenuItem, WidgetContextMenuItem } from '@home/models/dashboard-component.models'; +import { Observable } from 'rxjs'; export declare type DashboardPageScope = 'tenant' | 'customer'; @@ -30,6 +31,7 @@ export interface DashboardContext { dashboardTimewindow: Timewindow; aliasController: IAliasController; stateController: IStateController; + stateChanged: Observable; runChangeDetection: () => void; } diff --git a/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-state.component.ts b/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-state.component.ts index cb9055b5d3..fb22d9f3c2 100644 --- a/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-state.component.ts +++ b/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-state.component.ts @@ -67,7 +67,7 @@ export class DashboardStateComponent extends PageComponent implements OnInit, On this.parentDashboard = this.ctx.parentDashboard ? this.ctx.parentDashboard : this.ctx.dashboard; if (this.syncParentStateParams) { - this.stateSubscription = this.ctx.stateController.stateChanged().subscribe(() => { + this.stateSubscription = this.ctx.stateController.dashboardCtrl.dashboardCtx.stateChanged.subscribe(() => { this.updateCurrentState(); this.cd.markForCheck(); }); diff --git a/ui-ngx/src/app/modules/home/components/dashboard-page/states/state-controller.component.ts b/ui-ngx/src/app/modules/home/components/dashboard-page/states/state-controller.component.ts index fed15b9088..ef66915a9e 100644 --- a/ui-ngx/src/app/modules/home/components/dashboard-page/states/state-controller.component.ts +++ b/ui-ngx/src/app/modules/home/components/dashboard-page/states/state-controller.component.ts @@ -27,7 +27,7 @@ import { StateObject, StateParams } from '@app/core/api/widget-api.models'; @Directive() export abstract class StateControllerComponent implements IStateControllerComponent, OnInit, OnDestroy { - private stateChangedSubject = new Subject(); + private stateChangedSubject = new Subject(); stateObject: StateControllerState = []; dashboardCtrl: IDashboardController; preservedState: any; @@ -109,7 +109,7 @@ export abstract class StateControllerComponent implements IStateControllerCompon const newState = this.decodeStateParam(paramMap.get('state')); if (this.currentState !== newState) { this.currentState = newState; - this.stateChangedSubject.next(); + this.stateChangedSubject.next(this.currentState); if (this.inited) { this.onStateChanged(); } @@ -145,10 +145,10 @@ export abstract class StateControllerComponent implements IStateControllerCompon }); }); } - this.stateChangedSubject.next(); + this.stateChangedSubject.next(this.currentState); } - public stateChanged(): Observable { + public stateChanged(): Observable { return this.stateChangedSubject.asObservable(); } @@ -167,7 +167,7 @@ export abstract class StateControllerComponent implements IStateControllerCompon public reInit() { this.preservedState = null; this.currentState = this.decodeStateParam(this.route.snapshot.queryParamMap.get('state')); - this.stateChangedSubject.next(); + this.stateChangedSubject.next(this.currentState); this.init(); } diff --git a/ui-ngx/src/app/modules/home/components/dashboard-page/states/states-component.directive.ts b/ui-ngx/src/app/modules/home/components/dashboard-page/states/states-component.directive.ts index e9d65a6323..5ddfa7ea71 100644 --- a/ui-ngx/src/app/modules/home/components/dashboard-page/states/states-component.directive.ts +++ b/ui-ngx/src/app/modules/home/components/dashboard-page/states/states-component.directive.ts @@ -28,6 +28,7 @@ import { DashboardState } from '@shared/models/dashboard.models'; import { IDashboardController } from '@home/components/dashboard-page/dashboard-page.models'; import { StatesControllerService } from '@home/components/dashboard-page/states/states-controller.service'; import { IStateControllerComponent } from '@home/components/dashboard-page/states/state-controller.models'; +import { Subject } from 'rxjs'; @Directive({ // tslint:disable-next-line:directive-selector @@ -62,6 +63,8 @@ export class StatesComponentDirective implements OnInit, OnDestroy, OnChanges { stateControllerComponentRef: ComponentRef; stateControllerComponent: IStateControllerComponent; + private stateChangedSubject = new Subject(); + constructor(private viewContainerRef: ViewContainerRef, private statesControllerService: StatesControllerService) { } @@ -72,6 +75,7 @@ export class StatesComponentDirective implements OnInit, OnDestroy, OnChanges { ngOnDestroy(): void { this.destroy(); + this.stateChangedSubject.complete(); } ngOnChanges(changes: SimpleChanges): void { @@ -123,6 +127,10 @@ export class StatesComponentDirective implements OnInit, OnDestroy, OnChanges { this.stateControllerComponentRef = this.viewContainerRef.createComponent(stateControllerFactory); this.stateControllerComponent = this.stateControllerComponentRef.instance; this.dashboardCtrl.dashboardCtx.stateController = this.stateControllerComponent; + this.dashboardCtrl.dashboardCtx.stateChanged = this.stateChangedSubject.asObservable(); + this.stateControllerComponent.stateChanged().subscribe((state) => { + this.stateChangedSubject.next(state); + }); this.stateControllerComponent.preservedState = preservedState; this.stateControllerComponent.dashboardCtrl = this.dashboardCtrl; this.stateControllerComponent.stateControllerInstanceId = stateControllerInstanceId; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/markdown-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/markdown-widget.component.ts index 60dea214bc..1b23584a0d 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/markdown-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/markdown-widget.component.ts @@ -33,6 +33,7 @@ import { hashCode, isNotEmptyStr } from '@core/utils'; import cssjs from '@core/css/css'; import { UtilsService } from '@core/services/utils.service'; import { HOME_COMPONENTS_MODULE_TOKEN } from '@home/components/tokens'; +import { EntityDataPageLink } from '@shared/models/query/query.models'; interface MarkdownWidgetSettings { markdownTextPattern: string; @@ -81,6 +82,13 @@ export class MarkdownWidgetComponent extends PageComponent implements OnInit { cssParser.cssPreviewNamespace = this.markdownClass; cssParser.createStyleElement(this.markdownClass, cssString); } + const pageLink: EntityDataPageLink = { + page: 0, + pageSize: 16384, + textSearch: null, + dynamic: true + }; + this.ctx.defaultSubscription.subscribeAllForPaginatedData(pageLink, null); } public onDataUpdated() { From 19d8aca4a1672f059a3ee00364cd74312b49a568 Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Fri, 24 Dec 2021 15:53:24 +0200 Subject: [PATCH 303/432] if write request can not be parsed to "multiple" we parse that to single --- .../DefaultLwM2MAttributesService.java | 20 +++++++------- .../DefaultLwM2mDownlinkMsgHandler.java | 15 ++++------- .../rpc/DefaultLwM2MRpcRequestHandler.java | 17 +++++------- .../lwm2m/utils/LwM2MTransportUtil.java | 27 +++---------------- 4 files changed, 25 insertions(+), 54 deletions(-) diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/attributes/DefaultLwM2MAttributesService.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/attributes/DefaultLwM2MAttributesService.java index 38fc288aee..d054354035 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/attributes/DefaultLwM2MAttributesService.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/attributes/DefaultLwM2MAttributesService.java @@ -33,7 +33,6 @@ import org.thingsboard.server.gen.transport.TransportProtos.GetAttributeResponse import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportServerHelper; -import org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil; import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientContext; import org.thingsboard.server.transport.lwm2m.server.downlink.LwM2mDownlinkMsgHandler; @@ -42,6 +41,7 @@ import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MWriteRespon import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService; import org.thingsboard.server.transport.lwm2m.server.ota.LwM2MOtaUpdateService; import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler; +import org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil; import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl; import java.util.ArrayList; @@ -191,7 +191,7 @@ public class DefaultLwM2MAttributesService implements LwM2MAttributesService { @Override public void onAttributesUpdate(LwM2mClient lwM2MClient, List tsKvProtos, boolean logFailedUpdateOfNonChangedValue) { log.trace("[{}] onAttributesUpdate [{}]", lwM2MClient.getEndpoint(), tsKvProtos); - Map attributesUpdate = new ConcurrentHashMap<>(); + Map attributesUpdate = new ConcurrentHashMap<>(); tsKvProtos.forEach(tsKvProto -> { try { String pathIdVer = clientContext.getObjectIdByKeyNameFromProfile(lwM2MClient, tsKvProto.getKv().getKey()); @@ -207,8 +207,8 @@ public class DefaultLwM2MAttributesService implements LwM2MAttributesService { attributesUpdate.put(pathIdVer, tsKvProto); } } - } catch (IllegalArgumentException e){ - log.error("Failed update resource ["+lwM2MClient.getEndpoint()+"] onAttributesUpdate:", e); + } catch (IllegalArgumentException e) { + log.error("Failed update resource [" + lwM2MClient.getEndpoint() + "] onAttributesUpdate:", e); String logMsg = String.format("%s: Failed update resource onAttributesUpdate %s.", LOG_LWM2M_ERROR, e.getMessage()); logService.log(lwM2MClient, logMsg); @@ -226,8 +226,8 @@ public class DefaultLwM2MAttributesService implements LwM2MAttributesService { try { pushUpdateMultiToClientIfNeeded(lwM2MClient, resourceModel, (JsonElement) newValProto, (Map) oldResourceValue, pathIdVer, logFailedUpdateOfNonChangedValue); - } catch (Exception e){ - log.error("Failed update resource ["+lwM2MClient.getEndpoint()+"] onAttributesUpdate:", e); + } catch (Exception e) { + log.error("Failed update resource [" + lwM2MClient.getEndpoint() + "] onAttributesUpdate:", e); String logMsg = String.format("%s: Failed update resource onAttributesUpdate %s.", LOG_LWM2M_ERROR, e.getMessage()); logService.log(lwM2MClient, logMsg); @@ -243,7 +243,7 @@ public class DefaultLwM2MAttributesService implements LwM2MAttributesService { LOG_LWM2M_ERROR, versionedId, "null"); logService.log(lwM2MClient, logMsg); log.error("Failed update resource [{}] [{}]", versionedId, "null"); - } else if ((oldValue == null) || !valueEquals(newValue, oldValue)) { + } else if ((oldValue == null) || !valueEquals(newValue, oldValue)) { TbLwM2MWriteReplaceRequest request = TbLwM2MWriteReplaceRequest.builder().versionedId(versionedId).value(newValue).timeout(clientContext.getRequestTimeout(lwM2MClient)).build(); downlinkHandler.sendWriteReplaceRequest(lwM2MClient, request, new TbLwM2MWriteResponseCallback(uplinkHandler, logService, lwM2MClient, versionedId)); } else if (logFailedUpdateOfNonChangedValue) { @@ -256,10 +256,10 @@ public class DefaultLwM2MAttributesService implements LwM2MAttributesService { private void pushUpdateMultiToClientIfNeeded(LwM2mClient client, ResourceModel resourceModel, JsonElement newValProto, Map valueOld, String versionedId, - boolean logFailedUpdateOfNonChangedValue) throws Exception { - Map newValues = convertMultiResourceValuesFromJson(newValProto, resourceModel.type, versionedId); + boolean logFailedUpdateOfNonChangedValue) { + Map newValues = convertMultiResourceValuesFromJson(newValProto, resourceModel.type, versionedId); if (newValues.size() > 0 && valueOld != null && valueOld.size() > 0) { - valueOld.values().stream().forEach((v) -> { + valueOld.values().forEach((v) -> { if (newValues.containsKey(v.getId())) { if (valueEquals(newValues.get(v.getId()), v.getValue())) { newValues.remove(v.getId()); diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2mDownlinkMsgHandler.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2mDownlinkMsgHandler.java index 1e478ffd55..170112c924 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2mDownlinkMsgHandler.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2mDownlinkMsgHandler.java @@ -300,14 +300,13 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im String msgError = ""; if (resourceModelWrite.multiple) { try { - Map value = convertMultiResourceValuesFromRpcBody(request.getValue(), resourceModelWrite.type, request.getObjectId()); + Map value = convertMultiResourceValuesFromRpcBody(request.getValue(), resourceModelWrite.type, request.getObjectId()); downlink = new WriteRequest(contentFormat, resultIds.getObjectId(), resultIds.getObjectInstanceId(), resultIds.getResourceId(), value, resourceModelWrite.type); } catch (Exception e) { - msgError = "Resource id=" + resultIds.toString() + ", value = " + request.getValue() + - ", class = " + request.getValue().getClass().getSimpleName() + ". Format value is bad. Value for this Multi-Instance Resource must be in Json format!"; } - } else { + } + if (downlink == null) { try { downlink = this.getWriteRequestSingleResource(resourceModelWrite.type, contentFormat, resultIds.getObjectId(), resultIds.getObjectInstanceId(), resultIds.getResourceId(), request.getValue()); @@ -319,15 +318,11 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im if (downlink != null) { sendSimpleRequest(client, downlink, request.getTimeout(), callback); } else { - if (msgError.isEmpty()) { - msgError = "WriteRequest is null."; - } callback.onValidationError(toString(request), msgError); } } catch (Exception e) { callback.onError(toString(request), e); } - } else { callback.onValidationError(toString(request), "Resource " + request.getVersionedId() + " is not configured in the device profile!"); } @@ -378,7 +373,7 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im if (resourceModelWrite != null) { if (resourceModelWrite.multiple) { try { - Map value = convertMultiResourceValuesFromRpcBody(request.getValue(), resourceModelWrite.type, request.getObjectId()); + Map value = convertMultiResourceValuesFromRpcBody(request.getValue(), resourceModelWrite.type, request.getObjectId()); downlink = new WriteRequest(WriteRequest.Mode.UPDATE, contentFormat, resultIds.getObjectId(), resultIds.getObjectInstanceId(), resultIds.getResourceId(), value, resourceModelWrite.type); @@ -608,7 +603,7 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im LwM2mPath pathIds = new LwM2mPath(fromVersionedIdToObjectId(versionedId)); if (pathIds.isResource() || pathIds.isResourceInstance()) { ResourceModel resourceModel = client.getResourceModel(versionedId, modelProvider); - if (resourceModel!= null && (pathIds.isResourceInstance() || (pathIds.isResource() && !resourceModel.multiple))) { + if (resourceModel != null && (pathIds.isResourceInstance() || (pathIds.isResource() && !resourceModel.multiple))) { if (OBJLNK.equals(resourceModel.type)) { return ContentFormat.LINK; } else if (OPAQUE.equals(resourceModel.type)) { diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/DefaultLwM2MRpcRequestHandler.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/DefaultLwM2MRpcRequestHandler.java index c602b6729d..5f0ba9a150 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/DefaultLwM2MRpcRequestHandler.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/DefaultLwM2MRpcRequestHandler.java @@ -278,11 +278,9 @@ public class DefaultLwM2MRpcRequestHandler implements LwM2MRpcRequestHandler { ResourceModel resourceModel = client.getResourceModel(versionedId, modelProvider); if (resourceModel != null && resourceModel.multiple) { try { - Map value = convertMultiResourceValuesFromRpcBody(requestBody.getValue(), resourceModel.type, versionedId); + Map value = convertMultiResourceValuesFromRpcBody(requestBody.getValue(), resourceModel.type, versionedId); requestBody.setValue(value); } catch (Exception e) { - throw new IllegalArgumentException("Resource id=" + versionedId + ", class = " + - requestBody.getValue().getClass().getSimpleName() + ", value = " + requestBody.getValue() + " is bad. Value of Multi-Instance Resource must be in Json format!"); } } } @@ -304,7 +302,7 @@ public class DefaultLwM2MRpcRequestHandler implements LwM2MRpcRequestHandler { */ private void sendWriteCompositeRequest(LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, ContentFormat contentFormatComposite) { RpcWriteCompositeRequest rpcWriteCompositeRequest = JacksonUtil.fromString(requestMsg.getParams(), RpcWriteCompositeRequest.class); - Map validNodes = validateNodes(client, rpcWriteCompositeRequest.getNodes()); + Map validNodes = validateNodes(client, rpcWriteCompositeRequest.getNodes()); if (validNodes.size() > 0) { rpcWriteCompositeRequest.setNodes(validNodes); var mainCallback = new TbLwM2MWriteResponseCompositeCallback(uplinkHandler, logService, client, null); @@ -315,22 +313,21 @@ public class DefaultLwM2MRpcRequestHandler implements LwM2MRpcRequestHandler { } } - private Map validateNodes(LwM2mClient client, Map nodes) { - Map newNodes = new LinkedHashMap(); + private Map validateNodes(LwM2mClient client, Map nodes) { + Map newNodes = new LinkedHashMap<>(); nodes.forEach((key, value) -> { String versionedId; try { - // validate key.toString() - LwM2mPath path = new LwM2mPath(fromVersionedIdToObjectId(key.toString())); + LwM2mPath path = new LwM2mPath(fromVersionedIdToObjectId(key)); if (path.isResource() || path.isResourceInstance()) { - versionedId = key.toString(); + versionedId = key; } else { throw new IllegalArgumentException(String.format("nodes: %s is not validate value. " + "The WriteComposite operation is only used for SingleResources or/and ResourceInstance.", nodes.toString())); } } catch (Exception e) { - versionedId = clientContext.getObjectIdByKeyNameFromProfile(client, key.toString()); + versionedId = clientContext.getObjectIdByKeyNameFromProfile(client, key); } // validate value. Must be only primitive, not JsonObject or JsonArray try { diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2MTransportUtil.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2MTransportUtil.java index ad4189dc90..37b93a6b8e 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2MTransportUtil.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2MTransportUtil.java @@ -351,14 +351,14 @@ public class LwM2MTransportUtil { } } - public static Map convertMultiResourceValuesFromRpcBody(Object value, ResourceModel.Type type, String versionedId) throws Exception { + public static Map convertMultiResourceValuesFromRpcBody(Object value, ResourceModel.Type type, String versionedId) throws Exception { String valueJsonStr = JsonUtils.writeValueAsString(value); JsonElement element = JsonUtils.parse(valueJsonStr); return convertMultiResourceValuesFromJson(element, type, versionedId); } - public static Map convertMultiResourceValuesFromJson(JsonElement newValProto, ResourceModel.Type type, String versionedId) throws Exception{ - Map newValues = equalsMultiResourceValuesResourceType(type); + public static Map convertMultiResourceValuesFromJson(JsonElement newValProto, ResourceModel.Type type, String versionedId) { + Map newValues = new HashMap<>(); newValProto.getAsJsonObject().entrySet().forEach((obj) -> { newValues.put(Integer.valueOf(obj.getKey()), LwM2mValueConverterImpl.getInstance().convertValue(obj.getValue().getAsString(), STRING, type, new LwM2mPath(fromVersionedIdToObjectId(versionedId)))); @@ -366,27 +366,6 @@ public class LwM2MTransportUtil { return newValues; } - public static Map equalsMultiResourceValuesResourceType(ResourceModel.Type type) { - switch (type) { - case FLOAT: - return new HashMap(); - case INTEGER: - return new HashMap(); - case STRING: - return new HashMap(); - case BOOLEAN: - return new HashMap(); - case OPAQUE: - return new HashMap(); - case TIME: - return new HashMap(); - case OBJLNK: - return new HashMap(); - default: - return null; - } - } - public static Object convertWriteAttributes(String type, Object value, DefaultLwM2mUplinkMsgHandler serviceImpl, String target) { switch (type) { /** Integer [0:255]; */ From 8a421e3aa0cf399573940437f98116f0b9ebd271 Mon Sep 17 00:00:00 2001 From: ArtemDzhereleiko Date: Fri, 24 Dec 2021 16:05:24 +0200 Subject: [PATCH 304/432] UI: Fixed constant boolean filters creating form --- .../filter/boolean-filter-predicate.component.ts | 7 +++++-- .../home/components/filter/key-filter-dialog.component.ts | 6 +++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/filter/boolean-filter-predicate.component.ts b/ui-ngx/src/app/modules/home/components/filter/boolean-filter-predicate.component.ts index d5299a52ea..e0a4868898 100644 --- a/ui-ngx/src/app/modules/home/components/filter/boolean-filter-predicate.component.ts +++ b/ui-ngx/src/app/modules/home/components/filter/boolean-filter-predicate.component.ts @@ -109,8 +109,11 @@ export class BooleanFilterPredicateComponent implements ControlValueAccessor, Va } private updateModel() { - const predicate: BooleanFilterPredicate = this.booleanFilterPredicateFormGroup.getRawValue(); - predicate.type = FilterPredicateType.BOOLEAN; + let predicate: BooleanFilterPredicate = null; + if (this.booleanFilterPredicateFormGroup.valid) { + predicate = this.booleanFilterPredicateFormGroup.getRawValue(); + predicate.type = FilterPredicateType.BOOLEAN; + } this.propagateChange(predicate); } diff --git a/ui-ngx/src/app/modules/home/components/filter/key-filter-dialog.component.ts b/ui-ngx/src/app/modules/home/components/filter/key-filter-dialog.component.ts index 6c9c85330a..41520eede7 100644 --- a/ui-ngx/src/app/modules/home/components/filter/key-filter-dialog.component.ts +++ b/ui-ngx/src/app/modules/home/components/filter/key-filter-dialog.component.ts @@ -134,6 +134,10 @@ export class KeyFilterDialogComponent extends } ); } + if (valueType === EntityKeyValueType.BOOLEAN) { + this.keyFilterFormGroup.get('value').clearValidators(); + this.keyFilterFormGroup.get('value').updateValueAndValidity(); + } }); this.keyFilterFormGroup.get('key.type').valueChanges.pipe( @@ -148,7 +152,7 @@ export class KeyFilterDialogComponent extends this.showAutocomplete = false; } if (this.data.telemetryKeysOnly) { - if (type === EntityKeyType.CONSTANT) { + if (type === EntityKeyType.CONSTANT && (this.keyFilterFormGroup.get('valueType').value !== EntityKeyValueType.BOOLEAN)) { this.keyFilterFormGroup.get('value').setValidators(Validators.required); this.keyFilterFormGroup.get('value').updateValueAndValidity(); } else { From 9d0867e272f34ae821a2bcafaf6d5a4767bf79d9 Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Fri, 24 Dec 2021 16:44:03 +0200 Subject: [PATCH 305/432] Fixed queue start ts display on UI - use value instead of last update ts. Fixed ++ for queuestartts --- .../thingsboard/server/service/edge/rpc/EdgeGrpcSession.java | 5 +++-- .../thingsboard/server/dao/sql/edge/EdgeEventRepository.java | 4 ++-- .../home/components/edge/edge-downlink-table-config.ts | 4 +--- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcSession.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcSession.java index 46b36ca99f..1d546e693d 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcSession.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcSession.java @@ -501,8 +501,9 @@ public final class EdgeGrpcSession implements Closeable { private ListenableFuture> updateQueueStartTs(Long newStartTs) { log.trace("[{}] updating QueueStartTs [{}][{}]", this.sessionId, edge.getId(), newStartTs); - newStartTs = ++newStartTs; // increments ts by 1 - next edge event search starts from current offset + 1 - List attributes = Collections.singletonList(new BaseAttributeKvEntry(new LongDataEntry(QUEUE_START_TS_ATTR_KEY, newStartTs), System.currentTimeMillis())); + List attributes = Collections.singletonList( + new BaseAttributeKvEntry( + new LongDataEntry(QUEUE_START_TS_ATTR_KEY, newStartTs), System.currentTimeMillis())); return ctx.getAttributesService().save(edge.getTenantId(), edge.getId(), DataConstants.SERVER_SCOPE, attributes); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/edge/EdgeEventRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/edge/EdgeEventRepository.java index 48aaffb96e..79517fcc8b 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/edge/EdgeEventRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/edge/EdgeEventRepository.java @@ -30,7 +30,7 @@ public interface EdgeEventRepository extends PagingAndSortingRepository= :startTime) " + + "AND (:startTime IS NULL OR e.createdTime > :startTime) " + "AND (:endTime IS NULL OR e.createdTime <= :endTime) " + "AND LOWER(e.edgeEventType) LIKE LOWER(CONCAT('%', :textSearch, '%'))" ) @@ -44,7 +44,7 @@ public interface EdgeEventRepository extends PagingAndSortingRepository= :startTime) " + + "AND (:startTime IS NULL OR e.createdTime > :startTime) " + "AND (:endTime IS NULL OR e.createdTime <= :endTime) " + "AND e.edgeEventAction <> 'TIMESERIES_UPDATED' " + "AND LOWER(e.edgeEventType) LIKE LOWER(CONCAT('%', :textSearch, '%'))" diff --git a/ui-ngx/src/app/modules/home/components/edge/edge-downlink-table-config.ts b/ui-ngx/src/app/modules/home/components/edge/edge-downlink-table-config.ts index 38c3317ff0..360cfacbdd 100644 --- a/ui-ngx/src/app/modules/home/components/edge/edge-downlink-table-config.ts +++ b/ui-ngx/src/app/modules/home/components/edge/edge-downlink-table-config.ts @@ -98,9 +98,7 @@ export class EdgeDownlinkTableConfig extends EntityTableConfig Date: Fri, 24 Dec 2021 17:03:51 +0200 Subject: [PATCH 306/432] UI: Added a condition for ckeck boolean key type only for constant type --- .../home/components/filter/key-filter-dialog.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui-ngx/src/app/modules/home/components/filter/key-filter-dialog.component.ts b/ui-ngx/src/app/modules/home/components/filter/key-filter-dialog.component.ts index 41520eede7..c96bc66419 100644 --- a/ui-ngx/src/app/modules/home/components/filter/key-filter-dialog.component.ts +++ b/ui-ngx/src/app/modules/home/components/filter/key-filter-dialog.component.ts @@ -134,7 +134,7 @@ export class KeyFilterDialogComponent extends } ); } - if (valueType === EntityKeyValueType.BOOLEAN) { + if (valueType === EntityKeyValueType.BOOLEAN && this.isConstantKeyType) { this.keyFilterFormGroup.get('value').clearValidators(); this.keyFilterFormGroup.get('value').updateValueAndValidity(); } From 5590ecb87e4757a14d65a6089f79bc3c11efe0f8 Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Fri, 24 Dec 2021 17:40:49 +0200 Subject: [PATCH 307/432] Fixed base edge event fetcher page link --- .../service/edge/rpc/fetch/BasePageableEdgeEventFetcher.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/BasePageableEdgeEventFetcher.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/BasePageableEdgeEventFetcher.java index a3dc409cdf..b3b614458f 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/BasePageableEdgeEventFetcher.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/BasePageableEdgeEventFetcher.java @@ -31,7 +31,7 @@ public abstract class BasePageableEdgeEventFetcher implements EdgeEventFetche @Override public PageLink getPageLink(int pageSize) { - return new PageLink(pageSize, 0, null, new SortOrder("createdTime", SortOrder.Direction.ASC)); + return new PageLink(pageSize); } @Override From 036bde062c0a9d4a20021cec32592bf3adc2257b Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Fri, 24 Dec 2021 19:22:05 +0200 Subject: [PATCH 308/432] removed unnecessary test --- .../rpc/sql/RpcLwm2mIntegrationWriteTest.java | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationWriteTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationWriteTest.java index e039efa8eb..1a92831a36 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationWriteTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationWriteTest.java @@ -108,24 +108,6 @@ public class RpcLwm2mIntegrationWriteTest extends AbstractRpcLwM2MIntegrationTes assertTrue(actualValues.contains(expected)); } - /** - * id - * WriteReplace {"id":"/19/0/0","value":"0081"}.. - */ - @Test - public void testWriteReplaceValueMultipleResourceAsSingleResource_Result_BAD_REQUEST_Value_Multi_Instance_Resource_must_be_in_Json_format() throws Exception { - String objectInstanceIdVer_19 = (String) expectedObjectIdVerInstances.stream().filter(path -> ((String) path).contains("/" + BINARY_APP_DATA_CONTAINER)).findFirst().get(); - String expectedPath = objectInstanceIdVer_19 + "/" + resourceId_0; - String expectedValue = "0081"; - String actualResult = sendRPCWriteStringById("WriteReplace", expectedPath, expectedValue); - ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); - assertEquals(ResponseCode.BAD_REQUEST.getName(), rpcActualResult.get("result").asText()); - String actualValues = rpcActualResult.get("error").asText(); - String expected = "Value of Multi-Instance Resource must be in Json format!"; - assertTrue(actualValues.contains(expected)); - } - - /** * bad: singleResource, operation="R" - only read * WriteReplace {"id":"/3/0/9","value":90} From edcde714c7fbb1255c9e628317e30cf598b57744 Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Tue, 28 Dec 2021 12:01:26 +0200 Subject: [PATCH 309/432] UI: Added entity details page --- ui-ngx/src/app/core/utils.ts | 14 ++ .../entity/entity-details-page.component.html | 57 ++++++ .../entity/entity-details-page.component.scss | 119 +++++++++++++ .../entity/entity-details-page.component.ts | 154 ++++++++++++++++ .../entity/entity-details-panel.component.ts | 16 +- .../components/entity/entity.component.ts | 2 + .../home/components/home-components.module.ts | 3 + ...device-profile-autocomplete.component.html | 7 + ...device-profile-autocomplete.component.scss | 21 +++ .../device-profile-autocomplete.component.ts | 9 +- ...ofile-provision-configuration.component.ts | 2 +- .../profile/device-profile.component.html | 8 + ...tenant-profile-autocomplete.component.html | 7 + ...tenant-profile-autocomplete.component.scss | 21 +++ .../tenant-profile-autocomplete.component.ts | 16 +- .../profile/tenant-profile.component.html | 6 + .../relation/relation-table.component.html | 8 +- .../relation/relation-table.component.scss | 3 + .../models/datasource/relation-datasource.ts | 5 +- .../home/pages/admin/admin-routing.module.ts | 38 +++- .../resources-library-table-config.resolve.ts | 13 +- .../resource/resources-library.component.html | 6 + .../resource/resources-library.component.ts | 5 +- .../home/pages/asset/asset-routing.module.ts | 42 ++++- .../home/pages/asset/asset.component.html | 6 + .../asset/assets-table-config.resolver.ts | 10 ++ .../pages/customer/customer-routing.module.ts | 167 +++++++++++++++--- .../pages/customer/customer.component.html | 6 + .../customers-table-config.resolver.ts | 10 ++ .../device-profile-routing.module.ts | 20 +++ .../device-profiles-table-config.resolver.ts | 13 +- .../pages/device/device-routing.module.ts | 42 ++++- .../home/pages/device/device.component.html | 7 + .../home/pages/device/device.component.ts | 1 + .../device/devices-table-config.resolver.ts | 10 ++ .../home/pages/edge/edge-routing.module.ts | 131 ++++++++++++-- .../home/pages/edge/edge.component.html | 6 + .../pages/edge/edges-table-config.resolver.ts | 10 ++ .../entity-view/entity-view-routing.module.ts | 42 ++++- .../entity-view/entity-view.component.html | 6 + .../entity-views-table-config.resolver.ts | 10 ++ .../ota-update/ota-update-routing.module.ts | 39 +++- .../ota-update-table-config.resolve.ts | 13 +- .../ota-update/ota-update.component.html | 9 +- .../tenant-profile-routing.module.ts | 20 +++ .../tenant-profiles-table-config.resolver.ts | 15 +- .../pages/tenant/tenant-routing.module.ts | 55 +++++- .../home/pages/tenant/tenant.component.html | 7 + .../tenant/tenants-table-config.resolver.ts | 10 ++ .../home/pages/user/user-routing.module.ts | 43 ++++- .../home/pages/user/user.component.html | 6 + .../pages/user/users-table-config.resolver.ts | 27 ++- .../shared/components/breadcrumb.component.ts | 8 +- .../ota-package-autocomplete.component.html | 7 + .../ota-package-autocomplete.component.scss | 21 +++ .../ota-package-autocomplete.component.ts | 10 +- ui-ngx/src/app/shared/models/constants.ts | 15 ++ .../src/app/shared/models/relation.models.ts | 1 + ui-ngx/src/app/shared/shared.module.ts | 1 + .../assets/locale/locale.constant-en_US.json | 3 +- 60 files changed, 1271 insertions(+), 118 deletions(-) create mode 100644 ui-ngx/src/app/modules/home/components/entity/entity-details-page.component.html create mode 100644 ui-ngx/src/app/modules/home/components/entity/entity-details-page.component.scss create mode 100644 ui-ngx/src/app/modules/home/components/entity/entity-details-page.component.ts create mode 100644 ui-ngx/src/app/modules/home/components/profile/device-profile-autocomplete.component.scss create mode 100644 ui-ngx/src/app/modules/home/components/profile/tenant-profile-autocomplete.component.scss create mode 100644 ui-ngx/src/app/shared/components/ota-package/ota-package-autocomplete.component.scss diff --git a/ui-ngx/src/app/core/utils.ts b/ui-ngx/src/app/core/utils.ts index b986583171..c09488a593 100644 --- a/ui-ngx/src/app/core/utils.ts +++ b/ui-ngx/src/app/core/utils.ts @@ -20,6 +20,10 @@ import { finalize, share } from 'rxjs/operators'; import { Datasource } from '@app/shared/models/widget.models'; import { EntityId } from '@shared/models/id/entity-id'; import { NULL_UUID } from '@shared/models/id/has-uuid'; +import { BreadCrumbLabelFunction } from '@shared/components/breadcrumb'; +import { EntityDetailsPageComponent } from '@home/components/entity/entity-details-page.component'; +import { baseDetailsPageByEntityType } from '@shared/models/constants'; +import { EntityType } from '@shared/models/entity-type.models'; const varsRegex = /\${([^}]*)}/g; @@ -460,3 +464,13 @@ export function randomAlphanumeric(length: number): string { } return result; } + +export const entityDetailsPageBreadcrumbLabelFunction: BreadCrumbLabelFunction + = ((route, translate, component) => { + return component.entity?.name || component.headerSubtitle; +}); + + +export function getEntityDetailsPageURL(id: string, entityType: EntityType): string { + return `${baseDetailsPageByEntityType.get(entityType)}/${id}`; +} diff --git a/ui-ngx/src/app/modules/home/components/entity/entity-details-page.component.html b/ui-ngx/src/app/modules/home/components/entity/entity-details-page.component.html new file mode 100644 index 0000000000..e025534f2b --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/entity/entity-details-page.component.html @@ -0,0 +1,57 @@ + + + +

+
+
{{ headerTitle }}
+
{{ headerSubtitle }}
+
+
+ +
+ + +
+
+ + + + + + + + + + + diff --git a/ui-ngx/src/app/modules/home/components/entity/entity-details-page.component.scss b/ui-ngx/src/app/modules/home/components/entity/entity-details-page.component.scss new file mode 100644 index 0000000000..a74e9e46c1 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/entity/entity-details-page.component.scss @@ -0,0 +1,119 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +@import "../../../../../scss/constants"; + +:host { + width: 100%; + height: 100%; + display: flex; + flex-direction: column; + overflow: hidden; + + .settings-card { + margin: 8px; + padding: 0; + width: 100%; + height: 100%; + display: flex; + flex-direction: column; + + .details-toolbar { + height: 84px; + min-height: 84px; + border-radius: 4px 4px 0 0; + background: #fff; + border-bottom: 1px solid rgba(0, 0, 0, 0.12); + + .mat-toolbar-tools { + padding: 0 8px; + } + + .tb-details-title-header { + min-width: 0; + width: auto; + } + + .tb-details-title { + font-size: 1rem; + font-weight: 500; + + @media #{$mat-gt-sm} { + font-size: 1.2rem; + } + } + + .tb-details-subtitle { + font-size: 0.9rem; + opacity: .8; + } + + .tb-ellipsis { + width: 100%; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + } + + @media #{$mat-md} { + width: 80%; + } + + @media #{$mat-gt-md} { + width: 60%; + } + + .tb-header-button { + .tb-btn-header { + position: relative !important; + display: inline-block !important; + animation: tbMoveFromTopFade .3s ease both; + + &.tb-hide { + animation: tbMoveToTopFade .3s ease both; + } + } + } + } +} + +:host ::ng-deep { + .tb-help { + .mat-icon-button.mat-primary { + color: rgba(0, 0, 0, 0.52); + } + } + + .mat-card-content { + position: relative; + overflow: hidden; + + > .mat-tab-group { + > .mat-tab-body-wrapper { + position: absolute; + top: 49px; + left: 0; + right: 0; + bottom: 0; + } + > .mat-tab-header { + .mat-tab-label { + min-width: 40px; + } + } + } + } +} diff --git a/ui-ngx/src/app/modules/home/components/entity/entity-details-page.component.ts b/ui-ngx/src/app/modules/home/components/entity/entity-details-page.component.ts new file mode 100644 index 0000000000..27ed899c79 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/entity/entity-details-page.component.ts @@ -0,0 +1,154 @@ +/// +/// Copyright © 2016-2021 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { + ChangeDetectionStrategy, + ChangeDetectorRef, + Component, + ComponentFactoryResolver, + HostBinding, + Injector, + OnDestroy, + OnInit +} from '@angular/core'; +import { Store } from '@ngrx/store'; +import { AppState } from '@core/core.state'; +import { EntityTableConfig } from '@home/models/entity/entities-table-config.models'; +import { BaseData, HasId } from '@shared/models/base-data'; +import { ActivatedRoute, Router } from '@angular/router'; +import { FormGroup } from '@angular/forms'; +import { AssetId } from '@shared/models/id/asset-id'; +import { TranslateService } from '@ngx-translate/core'; +import { deepClone, mergeDeep } from '@core/utils'; +import { BroadcastService } from '@core/services/broadcast.service'; +import { EntityDetailsPanelComponent } from '@home/components/entity/entity-details-panel.component'; + +@Component({ + selector: 'tb-entity-details-page', + templateUrl: './entity-details-page.component.html', + styleUrls: ['./entity-details-page.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class EntityDetailsPageComponent extends EntityDetailsPanelComponent implements OnInit, OnDestroy { + + headerTitle: string; + headerSubtitle: string; + + isReadOnly = false; + + set entitiesTableConfig(entitiesTableConfig: EntityTableConfig>) { + if (this.entitiesTableConfigValue !== entitiesTableConfig) { + this.entitiesTableConfigValue = entitiesTableConfig; + if (this.entitiesTableConfigValue) { + this.isEdit = false; + this.entity = null; + } + } + } + + get entitiesTableConfig(): EntityTableConfig> { + return this.entitiesTableConfigValue; + } + + @HostBinding('class') 'tb-absolute-fill'; + + constructor(private route: ActivatedRoute, + private router: Router, + protected injector: Injector, + protected cd: ChangeDetectorRef, + protected componentFactoryResolver: ComponentFactoryResolver, + private broadcast: BroadcastService, + private translate: TranslateService, + protected store: Store) { + super(store, injector, cd, componentFactoryResolver); + this.entitiesTableConfig = this.route.snapshot.data.entitiesTableConfig; + } + + ngOnInit() { + this.headerSubtitle = ''; + this.route.paramMap.subscribe( paramMap => { + this.entityId = new AssetId(paramMap.get('entityId')); + }); + this.headerSubtitle = this.translate.instant(this.entitiesTableConfig.entityTranslations.details); + super.init(); + this.entityComponent.isDetailsPage = true; + } + + ngOnDestroy() { + super.ngOnDestroy(); + } + + reload(): void { + this.isEdit = false; + this.entitiesTableConfig.loadEntity(this.currentEntityId).subscribe( + (entity) => { + this.entity = entity; + this.broadcast.broadcast('updateBreadcrumb'); + this.isReadOnly = this.entitiesTableConfig.detailsReadonly(entity); + this.headerTitle = this.entitiesTableConfig.entityTitle(entity); + this.entityComponent.entity = entity; + this.entityComponent.isEdit = false; + if (this.entityTabsComponent) { + this.entityTabsComponent.entity = entity; + } + } + ); + } + + onToggleDetailsEditMode() { + if (this.isEdit) { + this.entityComponent.entity = this.entity; + if (this.entityTabsComponent) { + this.entityTabsComponent.entity = this.entity; + } + this.isEdit = !this.isEdit; + } else { + this.isEdit = !this.isEdit; + this.editingEntity = deepClone(this.entity); + this.entityComponent.entity = this.editingEntity; + if (this.entityTabsComponent) { + this.entityTabsComponent.entity = this.editingEntity; + } + if (this.entitiesTableConfig.hideDetailsTabsOnEdit) { + this.selectedTab = 0; + } + } + } + + onApplyDetails() { + if (this.detailsForm && this.detailsForm.valid) { + const editingEntity = {...this.editingEntity, ...this.detailsForm.getRawValue()}; + if (this.detailsForm.hasOwnProperty('additionalInfo')) { + editingEntity.additionalInfo = + mergeDeep((this.editingEntity as any).additionalInfo, this.detailsForm.getRawValue()?.additionalInfo); + } + this.entitiesTableConfig.saveEntity(editingEntity, this.editingEntity).subscribe( + (entity) => { + this.entity = entity; + this.entityComponent.entity = entity; + if (this.entityTabsComponent) { + this.entityTabsComponent.entity = entity; + } + this.isEdit = false; + } + ); + } + } + + confirmForm(): FormGroup { + return this.detailsForm; + } +} diff --git a/ui-ngx/src/app/modules/home/components/entity/entity-details-panel.component.ts b/ui-ngx/src/app/modules/home/components/entity/entity-details-panel.component.ts index d6378620f9..c5e7968935 100644 --- a/ui-ngx/src/app/modules/home/components/entity/entity-details-panel.component.ts +++ b/ui-ngx/src/app/modules/home/components/entity/entity-details-panel.component.ts @@ -88,15 +88,15 @@ export class EntityDetailsPanelComponent extends PageComponent implements AfterV entity: BaseData; editingEntity: BaseData; - private currentEntityId: HasId; - private subscriptions: Subscription[] = []; - private viewInited = false; - private pendingTabs: MatTab[]; + protected currentEntityId: HasId; + protected subscriptions: Subscription[] = []; + protected viewInited = false; + protected pendingTabs: MatTab[]; constructor(protected store: Store, - private injector: Injector, - private cd: ChangeDetectorRef, - private componentFactoryResolver: ComponentFactoryResolver) { + protected injector: Injector, + protected cd: ChangeDetectorRef, + protected componentFactoryResolver: ComponentFactoryResolver) { super(store); } @@ -139,7 +139,7 @@ export class EntityDetailsPanelComponent extends PageComponent implements AfterV return this.isEditValue; } - private init() { + protected init() { this.translations = this.entitiesTableConfig.entityTranslations; this.resources = this.entitiesTableConfig.entityResources; this.buildEntityComponent(); diff --git a/ui-ngx/src/app/modules/home/components/entity/entity.component.ts b/ui-ngx/src/app/modules/home/components/entity/entity.component.ts index 8d868eff98..5da90b49ff 100644 --- a/ui-ngx/src/app/modules/home/components/entity/entity.component.ts +++ b/ui-ngx/src/app/modules/home/components/entity/entity.component.ts @@ -38,6 +38,8 @@ export abstract class EntityComponent, isEditValue: boolean; + isDetailsPage = false; + @Input() set entitiesTableConfig(entitiesTableConfig: C) { this.setEntitiesTableConfig(entitiesTableConfig); diff --git a/ui-ngx/src/app/modules/home/components/home-components.module.ts b/ui-ngx/src/app/modules/home/components/home-components.module.ts index 73361eddce..0960d98620 100644 --- a/ui-ngx/src/app/modules/home/components/home-components.module.ts +++ b/ui-ngx/src/app/modules/home/components/home-components.module.ts @@ -147,6 +147,7 @@ import { HOME_COMPONENTS_MODULE_TOKEN } from '@home/components/tokens'; import { DashboardStateComponent } from '@home/components/dashboard-page/dashboard-state.component'; +import { EntityDetailsPageComponent } from '@home/components/entity/entity-details-page.component'; @NgModule({ declarations: @@ -155,6 +156,7 @@ import { DashboardStateComponent } from '@home/components/dashboard-page/dashboa AddEntityDialogComponent, DetailsPanelComponent, EntityDetailsPanelComponent, + EntityDetailsPageComponent, AuditLogTableComponent, AuditLogDetailsDialogComponent, EventContentDialogComponent, @@ -282,6 +284,7 @@ import { DashboardStateComponent } from '@home/components/dashboard-page/dashboa AddEntityDialogComponent, DetailsPanelComponent, EntityDetailsPanelComponent, + EntityDetailsPageComponent, AuditLogTableComponent, EventTableComponent, EdgeDownlinkTableHeaderComponent, diff --git a/ui-ngx/src/app/modules/home/components/profile/device-profile-autocomplete.component.html b/ui-ngx/src/app/modules/home/components/profile/device-profile-autocomplete.component.html index 20f271d660..2b73fc32c4 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device-profile-autocomplete.component.html +++ b/ui-ngx/src/app/modules/home/components/profile/device-profile-autocomplete.component.html @@ -38,6 +38,13 @@ (click)="editDeviceProfile($event)"> edit + DeviceProfileAutocompleteComponent), @@ -79,6 +80,9 @@ export class DeviceProfileAutocompleteComponent implements ControlValueAccessor, @Input() addNewProfile = true; + @Input() + showDetailsPageLink = false; + @Input() transportType: DeviceTransportType = null; @@ -110,6 +114,7 @@ export class DeviceProfileAutocompleteComponent implements ControlValueAccessor, filteredDeviceProfiles: Observable>; searchText = ''; + deviceProfileURL: string; private dirty = false; @@ -240,6 +245,7 @@ export class DeviceProfileAutocompleteComponent implements ControlValueAccessor, this.deviceProfileService.getDeviceProfileInfo(value.id).subscribe( (profile) => { this.modelValue = new DeviceProfileId(profile.id.id); + this.deviceProfileURL = getEntityDetailsPageURL(this.modelValue.id, this.modelValue.entityType); this.selectDeviceProfileFormGroup.get('deviceProfile').patchValue(profile, {emitEvent: false}); this.deviceProfileChanged.emit(profile); } @@ -278,6 +284,7 @@ export class DeviceProfileAutocompleteComponent implements ControlValueAccessor, const idValue = deviceProfile && deviceProfile.id ? new DeviceProfileId(deviceProfile.id.id) : null; if (!entityIdEquals(this.modelValue, idValue)) { this.modelValue = idValue; + this.deviceProfileURL = getEntityDetailsPageURL(this.modelValue.id, this.modelValue.entityType); this.propagateChange(this.modelValue); this.deviceProfileChanged.emit(deviceProfile); } diff --git a/ui-ngx/src/app/modules/home/components/profile/device-profile-provision-configuration.component.ts b/ui-ngx/src/app/modules/home/components/profile/device-profile-provision-configuration.component.ts index 28559dc4f7..3693c82f8f 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device-profile-provision-configuration.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device-profile-provision-configuration.component.ts @@ -130,7 +130,7 @@ export class DeviceProfileProvisionConfigurationComponent implements ControlValu setDisabledState(isDisabled: boolean){ this.disabled = isDisabled; if (this.disabled){ - this.provisionConfigurationFormGroup.disable(); + this.provisionConfigurationFormGroup.disable({emitEvent: false}); } else { if (this.provisionConfigurationFormGroup.get('type').value !== DeviceProvisionType.DISABLED) { this.provisionConfigurationFormGroup.enable({emitEvent: false}); diff --git a/ui-ngx/src/app/modules/home/components/profile/device-profile.component.html b/ui-ngx/src/app/modules/home/components/profile/device-profile.component.html index 917ad25dd2..df00bdf8fa 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device-profile.component.html +++ b/ui-ngx/src/app/modules/home/components/profile/device-profile.component.html @@ -16,6 +16,12 @@ -->
+ + TenantProfileAutocompleteComponent), @@ -66,6 +67,9 @@ export class TenantProfileAutocompleteComponent implements ControlValueAccessor, @Input() disabled: boolean; + @Input() + showDetailsPageLink = false; + @Output() tenantProfileUpdated = new EventEmitter(); @@ -74,6 +78,7 @@ export class TenantProfileAutocompleteComponent implements ControlValueAccessor, filteredTenantProfiles: Observable>; searchText = ''; + tenantProfileURL: string; private dirty = false; @@ -123,6 +128,7 @@ export class TenantProfileAutocompleteComponent implements ControlValueAccessor, (profile) => { if (profile) { this.modelValue = new TenantProfileId(profile.id.id); + this.tenantProfileURL = getEntityDetailsPageURL(this.modelValue.id, this.modelValue.entityType); this.selectTenantProfileFormGroup.get('tenantProfile').patchValue(profile, {emitEvent: false}); this.propagateChange(this.modelValue); } @@ -133,6 +139,11 @@ export class TenantProfileAutocompleteComponent implements ControlValueAccessor, setDisabledState(isDisabled: boolean): void { this.disabled = isDisabled; + if (this.disabled) { + this.selectTenantProfileFormGroup.disable(); + } else { + this.selectTenantProfileFormGroup.enable(); + } } writeValue(value: TenantProfileId | null): void { @@ -141,6 +152,7 @@ export class TenantProfileAutocompleteComponent implements ControlValueAccessor, this.tenantProfileService.getTenantProfileInfo(value.id).subscribe( (profile) => { this.modelValue = new TenantProfileId(profile.id.id); + this.tenantProfileURL = getEntityDetailsPageURL(this.modelValue.id, this.modelValue.entityType); this.selectTenantProfileFormGroup.get('tenantProfile').patchValue(profile, {emitEvent: false}); } ); diff --git a/ui-ngx/src/app/modules/home/components/profile/tenant-profile.component.html b/ui-ngx/src/app/modules/home/components/profile/tenant-profile.component.html index e5a3a54293..f98d0b6a80 100644 --- a/ui-ngx/src/app/modules/home/components/profile/tenant-profile.component.html +++ b/ui-ngx/src/app/modules/home/components/profile/tenant-profile.component.html @@ -16,6 +16,12 @@ -->
+ + diff --git a/ui-ngx/src/app/shared/components/ota-package/ota-package-autocomplete.component.scss b/ui-ngx/src/app/shared/components/ota-package/ota-package-autocomplete.component.scss new file mode 100644 index 0000000000..38af76b016 --- /dev/null +++ b/ui-ngx/src/app/shared/components/ota-package/ota-package-autocomplete.component.scss @@ -0,0 +1,21 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +:host{ + .mat-icon-button a { + border-bottom: none; + color: inherit; + } +} diff --git a/ui-ngx/src/app/shared/components/ota-package/ota-package-autocomplete.component.ts b/ui-ngx/src/app/shared/components/ota-package/ota-package-autocomplete.component.ts index 6609d4ceb7..4d22d1f298 100644 --- a/ui-ngx/src/app/shared/components/ota-package/ota-package-autocomplete.component.ts +++ b/ui-ngx/src/app/shared/components/ota-package/ota-package-autocomplete.component.ts @@ -31,12 +31,13 @@ import { OtaPackageInfo, OtaUpdateTranslation, OtaUpdateType } from '@shared/mod import { OtaPackageService } from '@core/http/ota-package.service'; import { PageLink } from '@shared/models/page/page-link'; import { Direction } from '@shared/models/page/sort-order'; -import { emptyPageData } from "@shared/models/page/page-data"; +import { emptyPageData } from '@shared/models/page/page-data'; +import { getEntityDetailsPageURL } from '@core/utils'; @Component({ selector: 'tb-ota-package-autocomplete', templateUrl: './ota-package-autocomplete.component.html', - styleUrls: [], + styleUrls: ['./ota-package-autocomplete.component.scss'], providers: [{ provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => OtaPackageAutocompleteComponent), @@ -64,6 +65,9 @@ export class OtaPackageAutocompleteComponent implements ControlValueAccessor, On @Input() useFullEntityId = false; + @Input() + showDetailsPageLink = false; + private requiredValue: boolean; get required(): boolean { @@ -83,6 +87,7 @@ export class OtaPackageAutocompleteComponent implements ControlValueAccessor, On filteredPackages: Observable>; searchText = ''; + packageURL: string; private dirty = false; @@ -166,6 +171,7 @@ export class OtaPackageAutocompleteComponent implements ControlValueAccessor, On if (packageId !== '') { this.entityService.getEntity(EntityType.OTA_PACKAGE, packageId, {ignoreLoading: true, ignoreErrors: true}).subscribe( (entity) => { + this.packageURL = getEntityDetailsPageURL(entity.id.id, EntityType.OTA_PACKAGE); this.modelValue = this.useFullEntityId ? entity.id : entity.id.id; this.otaPackageFormGroup.get('packageId').patchValue(entity, {emitEvent: false}); }, diff --git a/ui-ngx/src/app/shared/models/constants.ts b/ui-ngx/src/app/shared/models/constants.ts index 9bf120f8b7..fa73e0d40e 100644 --- a/ui-ngx/src/app/shared/models/constants.ts +++ b/ui-ngx/src/app/shared/models/constants.ts @@ -16,6 +16,7 @@ import { InjectionToken } from '@angular/core'; import { IModulesMap } from '@modules/common/modules-map.models'; +import { AliasEntityType, EntityType } from '@shared/models/entity-type.models'; export const Constants = { serverErrorCode: { @@ -137,6 +138,20 @@ export const HelpLinks = { } }; +export const baseDetailsPageByEntityType = new Map([ + [EntityType.TENANT, '/tenants'], + [EntityType.TENANT_PROFILE, '/tenantProfiles'], + [EntityType.CUSTOMER, '/customers'], + [EntityType.USER, '/users'], + [EntityType.ASSET, '/assets'], + [EntityType.DEVICE, '/devices'], + [EntityType.DEVICE_PROFILE, '/deviceProfiles'], + [EntityType.EDGE, '/edgeInstances'], + [EntityType.ENTITY_VIEW, '/entityViews'], + [EntityType.TB_RESOURCE, '/settings/resources-library'], + [EntityType.OTA_PACKAGE, '/otaUpdates'] +]); + export interface ValueTypeData { name: string; icon: string; diff --git a/ui-ngx/src/app/shared/models/relation.models.ts b/ui-ngx/src/app/shared/models/relation.models.ts index c9037a5dab..b1601753d8 100644 --- a/ui-ngx/src/app/shared/models/relation.models.ts +++ b/ui-ngx/src/app/shared/models/relation.models.ts @@ -89,4 +89,5 @@ export interface EntityRelationInfo extends EntityRelation { toEntityTypeName?: string; toName: string; fromEntityTypeName?: string; + entityURL?: string; } diff --git a/ui-ngx/src/app/shared/shared.module.ts b/ui-ngx/src/app/shared/shared.module.ts index 086768c854..50975b9f11 100644 --- a/ui-ngx/src/app/shared/shared.module.ts +++ b/ui-ngx/src/app/shared/shared.module.ts @@ -455,6 +455,7 @@ export function MarkedOptionsFactory(markedOptionsService: MarkedOptionsService) KeyboardShortcutPipe, FileSizePipe, SelectableColumnsPipe, + RouterModule, TranslateModule, JsonObjectEditDialogComponent, HistorySelectorComponent, diff --git a/ui-ngx/src/assets/locale/locale.constant-en_US.json b/ui-ngx/src/assets/locale/locale.constant-en_US.json index 807f3781a9..4d3a51d087 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -622,7 +622,8 @@ "enter-search": "Enter search", "created-time": "Created time", "loading": "Loading...", - "proceed": "Proceed" + "proceed": "Proceed", + "open-details-page": "Open details page" }, "content-type": { "json": "Json", From 4060d10ed739286c09e28099ecc26627fc9c00d3 Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Tue, 28 Dec 2021 14:07:21 +0200 Subject: [PATCH 310/432] fixed double sending sw updates after sleeping --- .../lwm2m/server/ota/DefaultLwM2MOtaUpdateService.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/DefaultLwM2MOtaUpdateService.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/DefaultLwM2MOtaUpdateService.java index 1ebd2e75f8..e52cdc9956 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/DefaultLwM2MOtaUpdateService.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/DefaultLwM2MOtaUpdateService.java @@ -183,7 +183,7 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl var clientSettings = clientContext.getProfile(client.getProfileId()).getClientLwM2mSettings(); initFwStrategy(client, clientSettings); - onCurrentSoftwareStrategyUpdate(client, clientSettings); + initSwStrategy(client, clientSettings); if (!attributesToFetch.isEmpty()) { var future = attributesService.getSharedAttributes(client, attributesToFetch); @@ -258,10 +258,14 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl @Override public void onCurrentSoftwareStrategyUpdate(LwM2mClient client, OtherConfiguration configuration) { log.debug("[{}] Current sw strategy: {}", client.getEndpoint(), configuration.getSwUpdateStrategy()); + startSoftwareUpdateIfNeeded(client, initSwStrategy(client, configuration)); + } + + private LwM2MClientSwOtaInfo initSwStrategy(LwM2mClient client, OtherConfiguration configuration) { LwM2MClientSwOtaInfo swInfo = getOrInitSwInfo(client); swInfo.setStrategy(LwM2MSoftwareUpdateStrategy.fromStrategySwByCode(configuration.getSwUpdateStrategy())); swInfo.setBaseUrl(configuration.getSwUpdateResource()); - startSoftwareUpdateIfNeeded(client, swInfo); + return swInfo; } @Override From 38b37a6eef5a03a386e439f8185d89c9cba4bb88 Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Tue, 28 Dec 2021 16:22:18 +0200 Subject: [PATCH 311/432] Removed incorrect statistics calculation for regularQueryInvocationCnt/regularQueryInvocationTime --- .../server/service/subscription/TbAbstractDataSubCtx.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/subscription/TbAbstractDataSubCtx.java b/application/src/main/java/org/thingsboard/server/service/subscription/TbAbstractDataSubCtx.java index 1d5f8eb603..d7fac40ad5 100644 --- a/application/src/main/java/org/thingsboard/server/service/subscription/TbAbstractDataSubCtx.java +++ b/application/src/main/java/org/thingsboard/server/service/subscription/TbAbstractDataSubCtx.java @@ -74,11 +74,7 @@ public abstract class TbAbstractDataSubCtx newData = findEntityData(); - long end = System.currentTimeMillis(); - stats.getRegularQueryInvocationCnt().incrementAndGet(); - stats.getRegularQueryTimeSpent().addAndGet(end - start); Map oldDataMap; if (data != null && !data.getData().isEmpty()) { oldDataMap = data.getData().stream().collect(Collectors.toMap(EntityData::getEntityId, Function.identity(), (a, b) -> a)); From b58b3a303b4861f71635faa626eaa9d81021bec2 Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Tue, 28 Dec 2021 18:37:37 +0200 Subject: [PATCH 312/432] UI: Added support delete entity in details page --- .../entity/entity-details-page.component.ts | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/ui-ngx/src/app/modules/home/components/entity/entity-details-page.component.ts b/ui-ngx/src/app/modules/home/components/entity/entity-details-page.component.ts index 27ed899c79..c2878680e5 100644 --- a/ui-ngx/src/app/modules/home/components/entity/entity-details-page.component.ts +++ b/ui-ngx/src/app/modules/home/components/entity/entity-details-page.component.ts @@ -35,6 +35,7 @@ import { TranslateService } from '@ngx-translate/core'; import { deepClone, mergeDeep } from '@core/utils'; import { BroadcastService } from '@core/services/broadcast.service'; import { EntityDetailsPanelComponent } from '@home/components/entity/entity-details-panel.component'; +import { DialogService } from '@core/services/dialog.service'; @Component({ selector: 'tb-entity-details-page', @@ -72,6 +73,7 @@ export class EntityDetailsPageComponent extends EntityDetailsPanelComponent impl protected componentFactoryResolver: ComponentFactoryResolver, private broadcast: BroadcastService, private translate: TranslateService, + private dialogService: DialogService, protected store: Store) { super(store, injector, cd, componentFactoryResolver); this.entitiesTableConfig = this.route.snapshot.data.entitiesTableConfig; @@ -85,6 +87,11 @@ export class EntityDetailsPageComponent extends EntityDetailsPanelComponent impl this.headerSubtitle = this.translate.instant(this.entitiesTableConfig.entityTranslations.details); super.init(); this.entityComponent.isDetailsPage = true; + this.subscriptions.push(this.entityAction.subscribe((action) => { + if (action.action === 'delete') { + this.deleteEntity(action.event, action.entity); + } + })); } ngOnDestroy() { @@ -151,4 +158,25 @@ export class EntityDetailsPageComponent extends EntityDetailsPanelComponent impl confirmForm(): FormGroup { return this.detailsForm; } + + private deleteEntity($event: Event, entity: BaseData) { + if ($event) { + $event.stopPropagation(); + } + this.dialogService.confirm( + this.entitiesTableConfig.deleteEntityTitle(entity), + this.entitiesTableConfig.deleteEntityContent(entity), + this.translate.instant('action.no'), + this.translate.instant('action.yes'), + true + ).subscribe((result) => { + if (result) { + this.entitiesTableConfig.deleteEntity(entity.id).subscribe( + () => { + this.router.navigate(['../'], {relativeTo: this.route}); + } + ); + } + }); + } } From 35e8a53f8cef7d13c2e603faf67016ec348984df Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Tue, 28 Dec 2021 19:46:32 +0200 Subject: [PATCH 313/432] mqtt: log.info replaced with log.debug for connect/disconnect event. It reduces log, CPU and disk overhead when few thousand devices in place. As alternative to debug mqtt - logback.xml adjusted --- application/src/main/resources/logback.xml | 3 +++ .../server/transport/mqtt/MqttTransportHandler.java | 8 ++++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/application/src/main/resources/logback.xml b/application/src/main/resources/logback.xml index caf78e1537..18c023bb80 100644 --- a/application/src/main/resources/logback.xml +++ b/application/src/main/resources/logback.xml @@ -40,6 +40,9 @@ + + + diff --git a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportHandler.java b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportHandler.java index 693b47d42f..bf474cc266 100644 --- a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportHandler.java +++ b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportHandler.java @@ -753,7 +753,7 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement } void processConnect(ChannelHandlerContext ctx, MqttConnectMessage msg) { - log.info("[{}] Processing connect msg for client: {}!", sessionId, msg.payload().clientIdentifier()); + log.debug("[{}] Processing connect msg for client: {}!", sessionId, msg.payload().clientIdentifier()); String userName = msg.payload().userName(); String clientId = msg.payload().clientIdentifier(); if (DataConstants.PROVISION.equals(userName) || DataConstants.PROVISION.equals(clientId)) { @@ -771,7 +771,7 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement private void processAuthTokenConnect(ChannelHandlerContext ctx, MqttConnectMessage connectMessage) { String userName = connectMessage.payload().userName(); - log.info("[{}] Processing connect msg for client with user name: {}!", sessionId, userName); + log.debug("[{}] Processing connect msg for client with user name: {}!", sessionId, userName); TransportProtos.ValidateBasicMqttCredRequestMsg.Builder request = TransportProtos.ValidateBasicMqttCredRequestMsg.newBuilder() .setClientId(connectMessage.payload().clientIdentifier()); if (userName != null) { @@ -917,7 +917,7 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement public void doDisconnect() { if (deviceSessionCtx.isConnected()) { - log.info("[{}] Client disconnected!", sessionId); + log.debug("[{}] Client disconnected!", sessionId); transportService.process(deviceSessionCtx.getSessionInfo(), DefaultTransportService.getSessionEventMsg(SessionEvent.CLOSED), null); transportService.deregisterSession(deviceSessionCtx.getSessionInfo()); if (gatewaySessionHandler != null) { @@ -944,7 +944,7 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement checkGatewaySession(sessionMetaData); ctx.writeAndFlush(createMqttConnAckMsg(CONNECTION_ACCEPTED, connectMessage)); deviceSessionCtx.setConnected(true); - log.info("[{}] Client connected!", sessionId); + log.debug("[{}] Client connected!", sessionId); transportService.getCallbackExecutor().execute(() -> processMsgQueue(ctx)); //this callback will execute in Producer worker thread and hard or blocking work have to be submitted to the separate thread. } From 5d7b8f7c4ec5b24c7713bd8b69f8310bcc3a26d6 Mon Sep 17 00:00:00 2001 From: Viacheslav Klimov Date: Wed, 29 Dec 2021 10:30:51 +0200 Subject: [PATCH 314/432] Fix invalid serialization of '=' to \u003d in JsonMqttAdaptor --- .../server/transport/mqtt/adaptors/JsonMqttAdaptor.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/JsonMqttAdaptor.java b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/JsonMqttAdaptor.java index dc2b74a8ea..cfe123c8e8 100644 --- a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/JsonMqttAdaptor.java +++ b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/JsonMqttAdaptor.java @@ -15,7 +15,6 @@ */ package org.thingsboard.server.transport.mqtt.adaptors; -import com.google.gson.Gson; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParser; @@ -56,8 +55,6 @@ public class JsonMqttAdaptor implements MqttTransportAdaptor { protected static final Charset UTF8 = StandardCharsets.UTF_8; - private static final Gson GSON = new Gson(); - @Override public TransportProtos.PostTelemetryMsg convertToPostTelemetry(MqttDeviceAwareSessionContext ctx, MqttPublishMessage inbound) throws AdaptorException { String payload = validatePayload(ctx.getSessionId(), inbound.payload(), false); @@ -246,7 +243,7 @@ public class JsonMqttAdaptor implements MqttTransportAdaptor { new MqttFixedHeader(MqttMessageType.PUBLISH, false, ctx.getQoSForTopic(topic), false, 0); MqttPublishVariableHeader header = new MqttPublishVariableHeader(topic, ctx.nextMsgId()); ByteBuf payload = ALLOCATOR.buffer(); - payload.writeBytes(GSON.toJson(json).getBytes(UTF8)); + payload.writeBytes(json.toString().getBytes(UTF8)); return new MqttPublishMessage(mqttFixedHeader, header, payload); } From 7570ab5703cb21479d4b8f973a835b7c1cc7f98a Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Wed, 29 Dec 2021 10:56:06 +0200 Subject: [PATCH 315/432] Added functionality to handle pong responses on web sockets --- .../controller/plugin/TbWebSocketHandler.java | 57 ++++++++++++------- .../DefaultTelemetryWebSocketService.java | 5 +- 2 files changed, 40 insertions(+), 22 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/plugin/TbWebSocketHandler.java b/application/src/main/java/org/thingsboard/server/controller/plugin/TbWebSocketHandler.java index 0e59030fe2..167d1146bb 100644 --- a/application/src/main/java/org/thingsboard/server/controller/plugin/TbWebSocketHandler.java +++ b/application/src/main/java/org/thingsboard/server/controller/plugin/TbWebSocketHandler.java @@ -23,6 +23,7 @@ import org.springframework.security.core.Authentication; import org.springframework.stereotype.Service; import org.springframework.util.StringUtils; import org.springframework.web.socket.CloseStatus; +import org.springframework.web.socket.PongMessage; import org.springframework.web.socket.TextMessage; import org.springframework.web.socket.WebSocketSession; import org.springframework.web.socket.adapter.NativeWebSocketSession; @@ -111,6 +112,22 @@ public class TbWebSocketHandler extends TextWebSocketHandler implements Telemetr } } + @Override + protected void handlePongMessage(WebSocketSession session, PongMessage message) throws Exception { + try { + SessionMetaData sessionMd = internalSessionMap.get(session.getId()); + if (sessionMd != null) { + log.trace("[{}][{}] Processing pong response {}", sessionMd.sessionRef.getSecurityCtx().getTenantId(), session.getId(), message.getPayload()); + sessionMd.processPongMessage(System.currentTimeMillis()); + } else { + log.trace("[{}] Failed to find session", session.getId()); + session.close(CloseStatus.SERVER_ERROR.withReason("Session not found!")); + } + } catch (IOException e) { + log.warn("IO error", e); + } + } + @Override public void afterConnectionEstablished(WebSocketSession session) throws Exception { super.afterConnectionEstablished(session); @@ -213,19 +230,29 @@ public class TbWebSocketHandler extends TextWebSocketHandler implements Telemetr synchronized void sendPing(long currentTime) { try { if (currentTime - lastActivityTime >= pingTimeout) { + log.warn("[{}] Closing session due to ping timeout", session.getId()); + closeSession(CloseStatus.SESSION_NOT_RELIABLE); + } else { this.asyncRemote.sendPing(PING_MSG); - lastActivityTime = currentTime; } } catch (Exception e) { log.trace("[{}] Failed to send ping msg", session.getId(), e); - try { - close(this.sessionRef, CloseStatus.SESSION_NOT_RELIABLE); - } catch (IOException ioe) { - log.trace("[{}] Session transport error", session.getId(), ioe); - } + closeSession(CloseStatus.SESSION_NOT_RELIABLE); } } + private void closeSession(CloseStatus reason) { + try { + close(this.sessionRef, reason); + } catch (IOException ioe) { + log.trace("[{}] Session transport error", session.getId(), ioe); + } + } + + synchronized void processPongMessage(long currentTime) { + lastActivityTime = currentTime; + } + synchronized void sendMsg(String msg) { if (isSending) { try { @@ -236,11 +263,7 @@ public class TbWebSocketHandler extends TextWebSocketHandler implements Telemetr } else { log.info("[{}][{}] Session closed due to queue error", sessionRef.getSecurityCtx().getTenantId(), session.getId()); } - try { - close(sessionRef, CloseStatus.POLICY_VIOLATION.withReason("Max pending updates limit reached!")); - } catch (IOException ioe) { - log.trace("[{}] Session transport error", session.getId(), ioe); - } + closeSession(CloseStatus.POLICY_VIOLATION.withReason("Max pending updates limit reached!")); } } else { isSending = true; @@ -253,11 +276,7 @@ public class TbWebSocketHandler extends TextWebSocketHandler implements Telemetr this.asyncRemote.sendText(msg, this); } catch (Exception e) { log.trace("[{}] Failed to send msg", session.getId(), e); - try { - close(this.sessionRef, CloseStatus.SESSION_NOT_RELIABLE); - } catch (IOException ioe) { - log.trace("[{}] Session transport error", session.getId(), ioe); - } + closeSession(CloseStatus.SESSION_NOT_RELIABLE); } } @@ -265,11 +284,7 @@ public class TbWebSocketHandler extends TextWebSocketHandler implements Telemetr public void onResult(SendResult result) { if (!result.isOK()) { log.trace("[{}] Failed to send msg", session.getId(), result.getException()); - try { - close(this.sessionRef, CloseStatus.SESSION_NOT_RELIABLE); - } catch (IOException ioe) { - log.trace("[{}] Session transport error", session.getId(), ioe); - } + closeSession(CloseStatus.SESSION_NOT_RELIABLE); } else { lastActivityTime = System.currentTimeMillis(); String msg = msgQueue.poll(); diff --git a/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetryWebSocketService.java b/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetryWebSocketService.java index 73eed820ab..482c577091 100644 --- a/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetryWebSocketService.java +++ b/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetryWebSocketService.java @@ -146,6 +146,9 @@ public class DefaultTelemetryWebSocketService implements TelemetryWebSocketServi @Value("${server.ws.limits.max_subscriptions_per_public_user:0}") private int maxSubscriptionsPerPublicUser; + @Value("${server.ws.ping_timeout:30000}") + private long pingTimeout; + private ConcurrentMap> tenantSubscriptionsMap = new ConcurrentHashMap<>(); private ConcurrentMap> customerSubscriptionsMap = new ConcurrentHashMap<>(); private ConcurrentMap> regularUserSubscriptionsMap = new ConcurrentHashMap<>(); @@ -162,7 +165,7 @@ public class DefaultTelemetryWebSocketService implements TelemetryWebSocketServi executor = ThingsBoardExecutors.newWorkStealingPool(50, getClass()); pingExecutor = Executors.newSingleThreadScheduledExecutor(ThingsBoardThreadFactory.forName("telemetry-web-socket-ping")); - pingExecutor.scheduleWithFixedDelay(this::sendPing, 10000, 10000, TimeUnit.MILLISECONDS); + pingExecutor.scheduleWithFixedDelay(this::sendPing, pingTimeout/3, pingTimeout/3, TimeUnit.MILLISECONDS); } @PreDestroy From d7f9b1d430fbb9009346da5458c522a862cd1b5e Mon Sep 17 00:00:00 2001 From: ArtemDzhereleiko Date: Wed, 29 Dec 2021 12:59:39 +0200 Subject: [PATCH 316/432] UI: Disable column sort if enable post processing func --- .../widget/lib/entities-table-widget.component.html | 2 +- .../components/widget/lib/entities-table-widget.component.ts | 4 ++++ .../home/components/widget/lib/table-widget.models.ts | 1 + .../widget/lib/timeseries-table-widget.component.html | 2 +- .../widget/lib/timeseries-table-widget.component.ts | 5 ++++- 5 files changed, 11 insertions(+), 3 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.html index 74ccd53ec2..bfb775306b 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.html @@ -41,7 +41,7 @@
- {{ column.title }} + {{ column.title }} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.ts index bd52f2ab9b..a2e4f7b922 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.ts @@ -324,6 +324,7 @@ export class EntitiesTableWidgetComponent extends PageComponent implements OnIni label: 'entityName', def: 'entityName', title: entityNameColumnTitle, + sortable: true, entityKey: { key: 'name', type: EntityKeyType.ENTITY_FIELD @@ -347,6 +348,7 @@ export class EntitiesTableWidgetComponent extends PageComponent implements OnIni label: 'entityLabel', def: 'entityLabel', title: entityLabelColumnTitle, + sortable: true, entityKey: { key: 'label', type: EntityKeyType.ENTITY_FIELD @@ -370,6 +372,7 @@ export class EntitiesTableWidgetComponent extends PageComponent implements OnIni label: 'entityType', def: 'entityType', title: this.translate.instant('entity.entity-type'), + sortable: true, entityKey: { key: 'entityType', type: EntityKeyType.ENTITY_FIELD @@ -403,6 +406,7 @@ export class EntitiesTableWidgetComponent extends PageComponent implements OnIni dataKey.label = this.utils.customTranslation(dataKey.label, dataKey.label); dataKey.title = dataKey.label; dataKey.def = 'def' + this.columns.length; + dataKey.sortable = !dataKey.usePostProcessing; const keySettings: TableWidgetDataKeySettings = dataKey.settings; if (dataKey.type === DataKeyType.entityField && !isDefined(keySettings.columnWidth) || keySettings.columnWidth === '0px') { diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/table-widget.models.ts b/ui-ngx/src/app/modules/home/components/widget/lib/table-widget.models.ts index f90c287111..1d798a88ca 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/table-widget.models.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/table-widget.models.ts @@ -73,6 +73,7 @@ export interface EntityData { export interface EntityColumn extends DataKey { def: string; title: string; + sortable: boolean; entityKey?: EntityKey; } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.html index 8c3b9084b0..d209a649b6 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.html @@ -52,7 +52,7 @@ - {{ h.dataKey.label }} + {{ h.dataKey.label }} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.ts index de8cec8dc7..198e36c919 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.ts @@ -88,6 +88,7 @@ interface TimeseriesRow { interface TimeseriesHeader { index: number; dataKey: DataKey; + sortable: boolean; } interface TimeseriesTableSource { @@ -308,10 +309,12 @@ export class TimeseriesTableWidgetComponent extends PageComponent implements OnI for (let a = 0; a < datasource.dataKeys.length; a++ ) { const dataKey = datasource.dataKeys[a]; const keySettings: TableWidgetDataKeySettings = dataKey.settings; + const sortable = !dataKey.usePostProcessing; const index = a + 1; source.header.push({ index, - dataKey + dataKey, + sortable }); source.displayedColumns.push(index + ''); source.rowDataTemplate[dataKey.label] = null; From 791b0594fd6f6fab1e39b6e35319ece26e16b8ff Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Wed, 29 Dec 2021 13:32:00 +0200 Subject: [PATCH 317/432] Fixed dynamic query count statistics. Updated default ping timeout to 30 seconds --- .../server/controller/plugin/TbWebSocketHandler.java | 8 ++++++-- .../DefaultTbEntityDataSubscriptionService.java | 3 ++- .../server/service/subscription/TbAbstractDataSubCtx.java | 5 +++++ .../server/service/subscription/TbAbstractSubCtx.java | 2 ++ .../server/service/subscription/TbAlarmDataSubCtx.java | 2 ++ .../server/service/subscription/TbEntityCountSubCtx.java | 4 ++++ .../telemetry/DefaultTelemetryWebSocketService.java | 5 +++-- application/src/main/resources/thingsboard.yml | 3 ++- .../server/common/data/query/AbstractDataQuery.java | 2 +- .../server/common/data/query/EntityCountQuery.java | 2 ++ .../server/common/data/query/EntityDataQuery.java | 2 +- 11 files changed, 30 insertions(+), 8 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/plugin/TbWebSocketHandler.java b/application/src/main/java/org/thingsboard/server/controller/plugin/TbWebSocketHandler.java index 167d1146bb..9fdda2215d 100644 --- a/application/src/main/java/org/thingsboard/server/controller/plugin/TbWebSocketHandler.java +++ b/application/src/main/java/org/thingsboard/server/controller/plugin/TbWebSocketHandler.java @@ -37,6 +37,7 @@ import org.thingsboard.server.config.WebSocketConfiguration; import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.service.security.model.SecurityUser; import org.thingsboard.server.service.security.model.UserPrincipal; +import org.thingsboard.server.service.telemetry.DefaultTelemetryWebSocketService; import org.thingsboard.server.service.telemetry.SessionEvent; import org.thingsboard.server.service.telemetry.TelemetryWebSocketMsgEndpoint; import org.thingsboard.server.service.telemetry.TelemetryWebSocketService; @@ -57,6 +58,8 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.LinkedBlockingQueue; +import static org.thingsboard.server.service.telemetry.DefaultTelemetryWebSocketService.NUMBER_OF_PING_ATTEMPTS; + @Service @TbCoreComponent @Slf4j @@ -229,10 +232,11 @@ public class TbWebSocketHandler extends TextWebSocketHandler implements Telemetr synchronized void sendPing(long currentTime) { try { - if (currentTime - lastActivityTime >= pingTimeout) { + long timeSinceLastActivity = currentTime - lastActivityTime; + if (timeSinceLastActivity >= pingTimeout) { log.warn("[{}] Closing session due to ping timeout", session.getId()); closeSession(CloseStatus.SESSION_NOT_RELIABLE); - } else { + } else if (timeSinceLastActivity >= pingTimeout / NUMBER_OF_PING_ATTEMPTS) { this.asyncRemote.sendPing(PING_MSG); } } catch (Exception e) { diff --git a/application/src/main/java/org/thingsboard/server/service/subscription/DefaultTbEntityDataSubscriptionService.java b/application/src/main/java/org/thingsboard/server/service/subscription/DefaultTbEntityDataSubscriptionService.java index 4ee8708805..c0f882bfe8 100644 --- a/application/src/main/java/org/thingsboard/server/service/subscription/DefaultTbEntityDataSubscriptionService.java +++ b/application/src/main/java/org/thingsboard/server/service/subscription/DefaultTbEntityDataSubscriptionService.java @@ -289,6 +289,7 @@ public class DefaultTbEntityDataSubscriptionService implements TbEntityDataSubsc long start = System.currentTimeMillis(); finalCtx.update(); long end = System.currentTimeMillis(); + log.trace("[{}][{}] Executing query: {}", finalCtx.getSessionId(), finalCtx.getCmdId(), finalCtx.getQuery()); stats.getDynamicQueryInvocationCnt().incrementAndGet(); stats.getDynamicQueryTimeSpent().addAndGet(end - start); } catch (Exception e) { @@ -304,7 +305,7 @@ public class DefaultTbEntityDataSubscriptionService implements TbEntityDataSubsc long regularQueryInvocationTimeValue = stats.getRegularQueryTimeSpent().getAndSet(0); int dynamicQueryInvocationCntValue = stats.getDynamicQueryInvocationCnt().getAndSet(0); long dynamicQueryInvocationTimeValue = stats.getDynamicQueryTimeSpent().getAndSet(0); - long dynamicQueryCnt = subscriptionsBySessionId.values().stream().map(Map::values).count(); + long dynamicQueryCnt = subscriptionsBySessionId.values().stream().mapToLong(m -> m.values().stream().filter(TbAbstractSubCtx::isDynamic).count()).sum(); if (regularQueryInvocationCntValue > 0 || dynamicQueryInvocationCntValue > 0 || dynamicQueryCnt > 0 || alarmQueryInvocationCntValue > 0) { log.info("Stats: regularQueryInvocationCnt = [{}], regularQueryInvocationTime = [{}], " + "dynamicQueryCnt = [{}] dynamicQueryInvocationCnt = [{}], dynamicQueryInvocationTime = [{}], " + diff --git a/application/src/main/java/org/thingsboard/server/service/subscription/TbAbstractDataSubCtx.java b/application/src/main/java/org/thingsboard/server/service/subscription/TbAbstractDataSubCtx.java index d7fac40ad5..136c625615 100644 --- a/application/src/main/java/org/thingsboard/server/service/subscription/TbAbstractDataSubCtx.java +++ b/application/src/main/java/org/thingsboard/server/service/subscription/TbAbstractDataSubCtx.java @@ -72,6 +72,11 @@ public abstract class TbAbstractDataSubCtx newData = findEntityData(); diff --git a/application/src/main/java/org/thingsboard/server/service/subscription/TbAbstractSubCtx.java b/application/src/main/java/org/thingsboard/server/service/subscription/TbAbstractSubCtx.java index f9b75ba217..05f0612717 100644 --- a/application/src/main/java/org/thingsboard/server/service/subscription/TbAbstractSubCtx.java +++ b/application/src/main/java/org/thingsboard/server/service/subscription/TbAbstractSubCtx.java @@ -174,6 +174,8 @@ public abstract class TbAbstractSubCtx { } } + public abstract boolean isDynamic(); + public abstract void fetchData(); protected abstract void update(); diff --git a/application/src/main/java/org/thingsboard/server/service/subscription/TbAlarmDataSubCtx.java b/application/src/main/java/org/thingsboard/server/service/subscription/TbAlarmDataSubCtx.java index 1ea6495517..99f7ac561b 100644 --- a/application/src/main/java/org/thingsboard/server/service/subscription/TbAlarmDataSubCtx.java +++ b/application/src/main/java/org/thingsboard/server/service/subscription/TbAlarmDataSubCtx.java @@ -17,6 +17,7 @@ package org.thingsboard.server.service.subscription; import lombok.Getter; import lombok.Setter; +import lombok.ToString; import lombok.extern.slf4j.Slf4j; import org.thingsboard.server.common.data.alarm.Alarm; import org.thingsboard.server.common.data.alarm.AlarmSearchStatus; @@ -56,6 +57,7 @@ import java.util.function.Function; import java.util.stream.Collectors; @Slf4j +@ToString(callSuper = true) public class TbAlarmDataSubCtx extends TbAbstractDataSubCtx { private final AlarmService alarmService; diff --git a/application/src/main/java/org/thingsboard/server/service/subscription/TbEntityCountSubCtx.java b/application/src/main/java/org/thingsboard/server/service/subscription/TbEntityCountSubCtx.java index e97892a37d..a9324d3ecf 100644 --- a/application/src/main/java/org/thingsboard/server/service/subscription/TbEntityCountSubCtx.java +++ b/application/src/main/java/org/thingsboard/server/service/subscription/TbEntityCountSubCtx.java @@ -52,4 +52,8 @@ public class TbEntityCountSubCtx extends TbAbstractSubCtx { } } + @Override + public boolean isDynamic() { + return true; + } } diff --git a/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetryWebSocketService.java b/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetryWebSocketService.java index 482c577091..dfc2185807 100644 --- a/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetryWebSocketService.java +++ b/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetryWebSocketService.java @@ -103,6 +103,8 @@ import java.util.stream.Collectors; @Slf4j public class DefaultTelemetryWebSocketService implements TelemetryWebSocketService { + public static final int NUMBER_OF_PING_ATTEMPTS = 3; + private static final int DEFAULT_LIMIT = 100; private static final Aggregation DEFAULT_AGGREGATION = Aggregation.NONE; private static final int UNKNOWN_SUBSCRIPTION_ID = 0; @@ -136,7 +138,6 @@ public class DefaultTelemetryWebSocketService implements TelemetryWebSocketServi @Autowired private TbServiceInfoProvider serviceInfoProvider; - @Value("${server.ws.limits.max_subscriptions_per_tenant:0}") private int maxSubscriptionsPerTenant; @Value("${server.ws.limits.max_subscriptions_per_customer:0}") @@ -165,7 +166,7 @@ public class DefaultTelemetryWebSocketService implements TelemetryWebSocketServi executor = ThingsBoardExecutors.newWorkStealingPool(50, getClass()); pingExecutor = Executors.newSingleThreadScheduledExecutor(ThingsBoardThreadFactory.forName("telemetry-web-socket-ping")); - pingExecutor.scheduleWithFixedDelay(this::sendPing, pingTimeout/3, pingTimeout/3, TimeUnit.MILLISECONDS); + pingExecutor.scheduleWithFixedDelay(this::sendPing, pingTimeout / NUMBER_OF_PING_ATTEMPTS, pingTimeout / NUMBER_OF_PING_ATTEMPTS, TimeUnit.MILLISECONDS); } @PreDestroy diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index c3ce2e3805..124462cd5e 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -54,7 +54,8 @@ server: log_controller_error_stack_trace: "${HTTP_LOG_CONTROLLER_ERROR_STACK_TRACE:false}" ws: send_timeout: "${TB_SERVER_WS_SEND_TIMEOUT:5000}" - ping_timeout: "${TB_SERVER_WS_PING_TIMEOUT:15000}" + # recommended timeout >= 30 seconds. Platform will attempt to send 'ping' request 3 times within the timeout + ping_timeout: "${TB_SERVER_WS_PING_TIMEOUT:30000}" limits: # Limit the amount of sessions and subscriptions available on each server. Put values to zero to disable particular limitation max_sessions_per_tenant: "${TB_SERVER_WS_TENANT_RATE_LIMITS_MAX_SESSIONS_PER_TENANT:0}" diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/query/AbstractDataQuery.java b/common/data/src/main/java/org/thingsboard/server/common/data/query/AbstractDataQuery.java index 0e807f8c37..adf16effb9 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/query/AbstractDataQuery.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/query/AbstractDataQuery.java @@ -20,7 +20,7 @@ import lombok.ToString; import java.util.List; -@ToString +@ToString(callSuper = true) public abstract class AbstractDataQuery extends EntityCountQuery { @Getter diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/query/EntityCountQuery.java b/common/data/src/main/java/org/thingsboard/server/common/data/query/EntityCountQuery.java index a66a6c0954..13434b358a 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/query/EntityCountQuery.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/query/EntityCountQuery.java @@ -17,11 +17,13 @@ package org.thingsboard.server.common.data.query; import io.swagger.annotations.ApiModel; import lombok.Getter; +import lombok.ToString; import java.util.Collections; import java.util.List; @ApiModel +@ToString public class EntityCountQuery { @Getter diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/query/EntityDataQuery.java b/common/data/src/main/java/org/thingsboard/server/common/data/query/EntityDataQuery.java index aca8437fe8..07b90a9327 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/query/EntityDataQuery.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/query/EntityDataQuery.java @@ -21,7 +21,7 @@ import lombok.ToString; import java.util.List; -@ToString +@ToString(callSuper = true) public class EntityDataQuery extends AbstractDataQuery { public EntityDataQuery() { From a4c9f8e78ed4e7b17f9addd0e78f2db0fa265670 Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Wed, 29 Dec 2021 16:01:06 +0200 Subject: [PATCH 318/432] lwm2m refactoring --- .../update/DefaultCacheCleanupService.java | 4 +- .../lwm2m/AbstractLwM2MIntegrationTest.java | 65 ++++++++++--------- .../TbLwM2mBootstrapTransportComponent.java | 2 +- .../queue/util/TbLwM2mTransportComponent.java | 2 +- .../LwM2mDefaultBootstrapSessionManager.java | 4 +- ...LwM2MBootstrapConfigStoreTaskProvider.java | 30 +++++---- .../store/LwM2MBootstrapSecurityStore.java | 3 +- .../LwM2MInMemoryBootstrapConfigStore.java | 1 - .../lwm2m/server/client/LwM2mClient.java | 6 +- .../lwm2m/server/client/ResourceValue.java | 3 +- .../server/downlink/TbLwM2MReadCallback.java | 20 +++--- .../rpc/DefaultLwM2MRpcRequestHandler.java | 1 - .../uplink/DefaultLwM2mUplinkMsgHandler.java | 30 +++++---- .../lwm2m/utils/LwM2MTransportUtil.java | 2 +- .../config/ssl/AbstractSslCredentials.java | 2 - .../common/transport/util/JsonUtils.java | 5 -- 16 files changed, 92 insertions(+), 88 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/install/update/DefaultCacheCleanupService.java b/application/src/main/java/org/thingsboard/server/service/install/update/DefaultCacheCleanupService.java index 1ed42bccd1..9dcb4f05bc 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/update/DefaultCacheCleanupService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/update/DefaultCacheCleanupService.java @@ -59,7 +59,9 @@ public class DefaultCacheCleanupService implements CacheCleanupService { break; case "3.3.2": log.info("Clear cache to upgrade from version 3.3.2 to 3.3.3 ..."); - clearAllCaches(); + clearCacheByName("devices"); + clearCacheByName("deviceProfiles"); + clearCacheByName("tenantProfiles"); break; default: //Do nothing, since cache cleanup is optional. diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/AbstractLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/AbstractLwM2MIntegrationTest.java index cb276b3fdc..5d4c32641d 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/AbstractLwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/AbstractLwM2MIntegrationTest.java @@ -35,8 +35,8 @@ import org.thingsboard.server.common.data.TbResource; import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MBootstrapClientCredentials; import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MClientCredential; import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MDeviceCredentials; -import org.thingsboard.server.common.data.device.credentials.lwm2m.NoSecClientCredential; import org.thingsboard.server.common.data.device.credentials.lwm2m.NoSecBootstrapClientCredential; +import org.thingsboard.server.common.data.device.credentials.lwm2m.NoSecClientCredential; import org.thingsboard.server.common.data.device.profile.DefaultDeviceProfileConfiguration; import org.thingsboard.server.common.data.device.profile.DeviceProfileData; import org.thingsboard.server.common.data.device.profile.DisabledDeviceProfileProvisionConfiguration; @@ -57,6 +57,7 @@ import org.thingsboard.server.service.telemetry.cmd.v2.EntityDataCmd; import org.thingsboard.server.service.telemetry.cmd.v2.EntityDataUpdate; import org.thingsboard.server.service.telemetry.cmd.v2.LatestValueCmd; import org.thingsboard.server.transport.lwm2m.client.LwM2MTestClient; + import java.util.Base64; import java.util.Collections; import java.util.List; @@ -141,7 +142,7 @@ public abstract class AbstractLwM2MIntegrationTest extends AbstractWebsocketTest this.defaultBootstrapCredentials.setLwm2mServer(serverCredentials); } - public void init () throws Exception{ + public void init () throws Exception{ executor = Executors.newScheduledThreadPool(10, ThingsBoardThreadFactory.forName("test-lwm2m-scheduled")); loginTenantAdmin(); @@ -167,46 +168,46 @@ public abstract class AbstractLwM2MIntegrationTest extends AbstractWebsocketTest @After public void after() { - executor.shutdownNow(); wsClient.close(); clientDestroy(); + executor.shutdownNow(); } public void basicTestConnectionObserveTelemetry(Security security, LwM2MClientCredential credentials, NetworkConfig coapConfig, String endpoint) throws Exception { - createDeviceProfile(transportConfiguration); - Device device = createDevice(credentials); + createDeviceProfile(transportConfiguration); + Device device = createDevice(credentials); - SingleEntityFilter sef = new SingleEntityFilter(); - sef.setSingleEntity(device.getId()); - LatestValueCmd latestCmd = new LatestValueCmd(); - latestCmd.setKeys(Collections.singletonList(new EntityKey(EntityKeyType.TIME_SERIES, "batteryLevel"))); - EntityDataQuery edq = new EntityDataQuery(sef, new EntityDataPageLink(1, 0, null, null), - Collections.emptyList(), Collections.emptyList(), Collections.emptyList()); + SingleEntityFilter sef = new SingleEntityFilter(); + sef.setSingleEntity(device.getId()); + LatestValueCmd latestCmd = new LatestValueCmd(); + latestCmd.setKeys(Collections.singletonList(new EntityKey(EntityKeyType.TIME_SERIES, "batteryLevel"))); + EntityDataQuery edq = new EntityDataQuery(sef, new EntityDataPageLink(1, 0, null, null), + Collections.emptyList(), Collections.emptyList(), Collections.emptyList()); - EntityDataCmd cmd = new EntityDataCmd(1, edq, null, latestCmd, null); - TelemetryPluginCmdsWrapper wrapper = new TelemetryPluginCmdsWrapper(); - wrapper.setEntityDataCmds(Collections.singletonList(cmd)); + EntityDataCmd cmd = new EntityDataCmd(1, edq, null, latestCmd, null); + TelemetryPluginCmdsWrapper wrapper = new TelemetryPluginCmdsWrapper(); + wrapper.setEntityDataCmds(Collections.singletonList(cmd)); - wsClient.send(mapper.writeValueAsString(wrapper)); - wsClient.waitForReply(); + wsClient.send(mapper.writeValueAsString(wrapper)); + wsClient.waitForReply(); - wsClient.registerWaitForUpdate(); - this.endpoint = endpoint; - createNewClient (security, coapConfig, false); - String msg = wsClient.waitForUpdate(); + wsClient.registerWaitForUpdate(); + this.endpoint = endpoint; + createNewClient(security, coapConfig, false); + String msg = wsClient.waitForUpdate(); - EntityDataUpdate update = mapper.readValue(msg, EntityDataUpdate.class); - Assert.assertEquals(1, update.getCmdId()); - List eData = update.getUpdate(); - Assert.assertNotNull(eData); - Assert.assertEquals(1, eData.size()); - Assert.assertEquals(device.getId(), eData.get(0).getEntityId()); - Assert.assertNotNull(eData.get(0).getLatest().get(EntityKeyType.TIME_SERIES)); - var tsValue = eData.get(0).getLatest().get(EntityKeyType.TIME_SERIES).get("batteryLevel"); - Assert.assertEquals(42, Long.parseLong(tsValue.getValue())); + EntityDataUpdate update = mapper.readValue(msg, EntityDataUpdate.class); + Assert.assertEquals(1, update.getCmdId()); + List eData = update.getUpdate(); + Assert.assertNotNull(eData); + Assert.assertEquals(1, eData.size()); + Assert.assertEquals(device.getId(), eData.get(0).getEntityId()); + Assert.assertNotNull(eData.get(0).getLatest().get(EntityKeyType.TIME_SERIES)); + var tsValue = eData.get(0).getLatest().get(EntityKeyType.TIME_SERIES).get("batteryLevel"); + Assert.assertEquals(42, Long.parseLong(tsValue.getValue())); } protected void createDeviceProfile(String transportConfiguration) throws Exception { @@ -256,15 +257,15 @@ public abstract class AbstractLwM2MIntegrationTest extends AbstractWebsocketTest return clientCredentials; } - public void setResources (String[] resources) { + public void setResources(String[] resources) { this.resources = resources; } - public void setEndpoint (String endpoint) { + public void setEndpoint(String endpoint) { this.endpoint = endpoint; } - public void createNewClient (Security security, NetworkConfig coapConfig, boolean isRpc) throws Exception { + public void createNewClient(Security security, NetworkConfig coapConfig, boolean isRpc) throws Exception { clientDestroy(); client = new LwM2MTestClient(this.executor, this.endpoint); int clientPort = SocketUtils.findAvailableTcpPort(); diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/util/TbLwM2mBootstrapTransportComponent.java b/common/queue/src/main/java/org/thingsboard/server/queue/util/TbLwM2mBootstrapTransportComponent.java index 938aaf3c78..d9de9269d0 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/util/TbLwM2mBootstrapTransportComponent.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/util/TbLwM2mBootstrapTransportComponent.java @@ -21,6 +21,6 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @Retention(RetentionPolicy.RUNTIME) -@ConditionalOnExpression("('${service.type:null}'=='tb-transport' || '${service.type:}'=='monolith') && '${transport.lwm2m.enabled:false}'=='true' && '${transport.lwm2m.bootstrap.enabled:false}'=='true'") +@ConditionalOnExpression("('${service.type:null}'=='tb-transport' || ('${service.type:null}'=='monolith' && '${transport.api_enabled:true}'=='true' && '${transport.lwm2m.enabled}'=='true')) && '${transport.lwm2m.bootstrap.enabled:false}'=='true'") public @interface TbLwM2mBootstrapTransportComponent { } diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/util/TbLwM2mTransportComponent.java b/common/queue/src/main/java/org/thingsboard/server/queue/util/TbLwM2mTransportComponent.java index fd1f729bec..344031a4bb 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/util/TbLwM2mTransportComponent.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/util/TbLwM2mTransportComponent.java @@ -21,6 +21,6 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @Retention(RetentionPolicy.RUNTIME) -@ConditionalOnExpression("('${service.type:null}'=='tb-transport' || '${service.type:}'=='monolith') && '${transport.lwm2m.enabled:false}'=='true'") +@ConditionalOnExpression("'${service.type:null}'=='tb-transport' || ('${service.type:null}'=='monolith' && '${transport.api_enabled:true}'=='true' && '${transport.lwm2m.enabled}'=='true')") public @interface TbLwM2mTransportComponent { } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2mDefaultBootstrapSessionManager.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2mDefaultBootstrapSessionManager.java index 5c2494ed6a..4d3f0a55f0 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2mDefaultBootstrapSessionManager.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2mDefaultBootstrapSessionManager.java @@ -107,7 +107,9 @@ public class LwM2mDefaultBootstrapSessionManager extends DefaultBootstrapSession @Override public boolean hasConfigFor(BootstrapSession session) { BootstrapTaskProvider.Tasks firstTasks = tasksProvider.getTasks(session, null); - if (firstTasks == null) return false; + if (firstTasks == null) { + return false; + } initTasks(session, firstTasks); return true; } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MBootstrapConfigStoreTaskProvider.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MBootstrapConfigStoreTaskProvider.java index 5c4e442875..a3b213239e 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MBootstrapConfigStoreTaskProvider.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MBootstrapConfigStoreTaskProvider.java @@ -19,7 +19,11 @@ import lombok.extern.slf4j.Slf4j; import org.eclipse.leshan.core.Link; import org.eclipse.leshan.core.node.LwM2mObject; import org.eclipse.leshan.core.node.LwM2mPath; -import org.eclipse.leshan.core.request.*; +import org.eclipse.leshan.core.request.BootstrapDeleteRequest; +import org.eclipse.leshan.core.request.BootstrapDiscoverRequest; +import org.eclipse.leshan.core.request.BootstrapDownlinkRequest; +import org.eclipse.leshan.core.request.BootstrapReadRequest; +import org.eclipse.leshan.core.request.ContentFormat; import org.eclipse.leshan.core.response.BootstrapDiscoverResponse; import org.eclipse.leshan.core.response.BootstrapReadResponse; import org.eclipse.leshan.core.response.LwM2mResponse; @@ -29,10 +33,15 @@ import org.eclipse.leshan.server.bootstrap.BootstrapSession; import org.eclipse.leshan.server.bootstrap.BootstrapTaskProvider; import org.eclipse.leshan.server.bootstrap.BootstrapUtil; -import java.net.InetSocketAddress; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; import java.util.stream.Collectors; -import java.util.stream.Stream; import static org.eclipse.leshan.server.bootstrap.BootstrapUtil.toWriteRequest; @@ -57,7 +66,6 @@ public class LwM2MBootstrapConfigStoreTaskProvider implements BootstrapTaskProvi @Override public Tasks getTasks(BootstrapSession session, List previousResponse) { - BootstrapConfig config = store.get(session.getEndpoint(), session.getIdentity(), session); if (config == null) { return null; @@ -72,7 +80,6 @@ public class LwM2MBootstrapConfigStoreTaskProvider implements BootstrapTaskProvi Tasks tasks = new Tasks(); if (this.supportedObjects == null) { initSupportedObjectsDefault(); - } // add supportedObjects tasks.supportedObjects = this.supportedObjects; @@ -114,7 +121,6 @@ public class LwM2MBootstrapConfigStoreTaskProvider implements BootstrapTaskProvi // create requests from config tasks.requestsToSend = BootstrapUtil.toRequests(config, config.contentFormat != null ? config.contentFormat : session.getContentFormat()); - } return tasks; } @@ -133,18 +139,18 @@ public class LwM2MBootstrapConfigStoreTaskProvider implements BootstrapTaskProvi LwM2mPath path = new LwM2mPath(link.getUrl()); if (path.isObjectInstance()) { if (link.getAttributes().containsKey("ssid")) { - int serverId = Integer.valueOf(link.getAttributes().get("ssid")); + int serverId = Integer.parseInt(link.getAttributes().get("ssid")); if (!this.securityInstances.containsKey(serverId)) { this.securityInstances.put(serverId, path.getObjectInstanceId()); } else { - log.error(String.format("Invalid lwm2mSecurityInstance by [{}]", path.getObjectInstanceId())); + log.error("Invalid lwm2mSecurityInstance by [{}]", path.getObjectInstanceId()); } this.securityInstances.put(Integer.valueOf(link.getAttributes().get("ssid")), path.getObjectInstanceId()); } else { if (!this.securityInstances.containsKey(0)) { this.securityInstances.put(0, path.getObjectInstanceId()); } else { - log.error(String.format("Invalid bootstrapSecurityInstance by [{}]", path.getObjectInstanceId())); + log.error("Invalid bootstrapSecurityInstance by [{}]", path.getObjectInstanceId()); } } } @@ -183,7 +189,7 @@ public class LwM2MBootstrapConfigStoreTaskProvider implements BootstrapTaskProvi Link[] links = response.getObjectLinks(); Arrays.stream(links).forEach(link -> { LwM2mPath path = new LwM2mPath(link.getUrl()); - if (path != null && !path.isRoot() && path.getObjectId() < 3) { + if (!path.isRoot() && path.getObjectId() < 3) { if (path.isObject()) { String ver = link.getAttributes().get("ver") != null ? link.getAttributes().get("ver") : "1.0"; this.supportedObjects.put(path.getObjectId(), ver); @@ -256,7 +262,7 @@ public class LwM2MBootstrapConfigStoreTaskProvider implements BootstrapTaskProvi requestsWrite.add(toWriteRequest(acl.getKey(), acl.getValue(), contentFormat)); } // handle delete - if (isBsServer & isLwServer) { + if (isBsServer && isLwServer) { requests.add(new BootstrapDeleteRequest("/0")); requests.add(new BootstrapDeleteRequest("/1")); } else { diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MBootstrapSecurityStore.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MBootstrapSecurityStore.java index 1c40ae943b..da09d77987 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MBootstrapSecurityStore.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MBootstrapSecurityStore.java @@ -68,7 +68,6 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore { @Override public Iterator getAllByEndpoint(String endPoint) { - // TODO TbLwM2MSecurityInfo store = lwM2MCredentialsSecurityInfoValidator.getEndpointSecurityInfoByCredentialsId(endPoint, BOOTSTRAP); if (store.getBootstrapCredentialConfig() != null) { /* add value to store from BootstrapJson */ @@ -79,7 +78,7 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore { try { boolean bootstrapServerUpdateEnable = ((Lwm2mDeviceProfileTransportConfiguration)store.getDeviceProfile().getProfileData().getTransportConfiguration()).isBootstrapServerUpdateEnable(); if (!bootstrapServerUpdateEnable) { - Optional> securities = bsConfigNew.security.entrySet().stream().filter(sec -> ((BootstrapConfig.ServerSecurity)sec.getValue()).bootstrapServer==true).findAny(); + Optional> securities = bsConfigNew.security.entrySet().stream().filter(sec -> sec.getValue().bootstrapServer).findAny(); if (securities.isPresent()) { bsConfigNew.security.entrySet().remove(securities.get()); int serverSortId = securities.get().getValue().serverId; diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MInMemoryBootstrapConfigStore.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MInMemoryBootstrapConfigStore.java index 54120d5c1e..8d6a62e89d 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MInMemoryBootstrapConfigStore.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MInMemoryBootstrapConfigStore.java @@ -75,7 +75,6 @@ public class LwM2MInMemoryBootstrapConfigStore extends InMemoryBootstrapConfigSt } public void addToStore(String endpoint, BootstrapConfig config) throws InvalidConfigurationException { - configChecker.verify(config); // Check PSK identity uniqueness for bootstrap server: PskByServer pskToAdd = getBootstrapPskIdentity(config); diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java index 917c7d1410..e1565d5be2 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java @@ -330,7 +330,7 @@ public class LwM2mClient implements Serializable { Collection resources = ConcurrentHashMap.newKeySet(); Map resourceModels = modelProvider.getObjectModel(registration) .getObjectModel(pathIds.getObjectId()).resources; - if (params != null && params instanceof Map && ((Map) params).size() > 0) { + if (params instanceof Map && ((Map) params).size() > 0) { Map paramsMap = (Map) params; resourceModels.forEach((resourceId, resourceModel) -> { if (paramsMap.containsKey(String.valueOf(resourceId))) { @@ -338,8 +338,8 @@ public class LwM2mClient implements Serializable { LwM2mResource resource; if (resourceModel.multiple) { try { - Map values = convertMultiResourceValuesFromRpcBody(value, resourceModel.type, pathRezIdVer); - resource = LwM2mMultipleResource.newResource(resourceId, (Map) values, resourceModel.type); + Map values = convertMultiResourceValuesFromRpcBody(value, resourceModel.type, pathRezIdVer); + resource = LwM2mMultipleResource.newResource(resourceId, values, resourceModel.type); } catch (Exception e) { throw new IllegalArgumentException("Resource id=" + resourceId + ", class = " + value.getClass().getSimpleName() + ", value = " + value + " is bad. Value of Multi-Instance Resource must be in Json format!"); diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/ResourceValue.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/ResourceValue.java index 700c589202..3a9ef3236b 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/ResourceValue.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/ResourceValue.java @@ -46,14 +46,13 @@ public class ResourceValue implements Serializable { public void updateLwM2mResource(LwM2mResource lwM2mResource, Mode mode) { if (lwM2mResource instanceof LwM2mSingleResource) { this.lwM2mResource = new TbLwM2MSingleResource(lwM2mResource.getId(), lwM2mResource.getValue(), lwM2mResource.getType()); - } else if (lwM2mResource instanceof LwM2mMultipleResource) { if (lwM2mResource.getInstances().values().size() > 0) { Set instancesSet = lwM2mResource.getInstances().values().stream().map(ResourceValue::toTbLwM2MResourceInstance).collect(Collectors.toSet()); if (Mode.REPLACE.equals(mode) && this.lwM2mResource != null) { Map oldInstances = this.lwM2mResource.getInstances(); oldInstances.values().forEach(v -> { - if (instancesSet.stream().filter(vIns -> v.getId() == vIns.getId()).collect(Collectors.toList()).size() == 0){ + if (instancesSet.stream().noneMatch(vIns -> v.getId() == vIns.getId())){ instancesSet.add(toTbLwM2MResourceInstance(v)); } }); diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MReadCallback.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MReadCallback.java index 0ae17ea449..033e9c12bf 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MReadCallback.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MReadCallback.java @@ -16,6 +16,7 @@ package org.thingsboard.server.transport.lwm2m.server.downlink; import lombok.extern.slf4j.Slf4j; +import org.eclipse.leshan.core.model.ResourceModel; import org.eclipse.leshan.core.node.LwM2mSingleResource; import org.eclipse.leshan.core.request.ReadRequest; import org.eclipse.leshan.core.response.ReadResponse; @@ -33,26 +34,25 @@ public class TbLwM2MReadCallback extends TbLwM2MUplinkTargetedCallback 0) { - int len = ((byte[])((LwM2mSingleResource) response.getContent()).getValue()).length; + LwM2mSingleResource singleResource = (LwM2mSingleResource) response.getContent(); + if (ResourceModel.Type.OPAQUE.equals(singleResource.getType())) { + byte[] valueInBytes = (byte[]) singleResource.getValue(); + int len = valueInBytes.length; + if (len > 0) { String valueReplace = len + "Bytes"; - String valueStr = Hex.encodeHexString((byte[]) (((LwM2mSingleResource) response.getContent()).getValue())); + String valueStr = Hex.encodeHexString(valueInBytes); return response.toString().replace(valueReplace, valueStr); } } - return response.toString(); - } - else { - return response.toString(); } + return response.toString(); } } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/DefaultLwM2MRpcRequestHandler.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/DefaultLwM2MRpcRequestHandler.java index 5f0ba9a150..9aae838cdb 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/DefaultLwM2MRpcRequestHandler.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/DefaultLwM2MRpcRequestHandler.java @@ -86,7 +86,6 @@ public class DefaultLwM2MRpcRequestHandler implements LwM2MRpcRequestHandler { private final TransportService transportService; private final LwM2mClientContext clientContext; - private final LwM2MTransportServerConfig config; private final LwM2mUplinkMsgHandler uplinkHandler; private final LwM2mDownlinkMsgHandler downlinkHandler; private final LwM2MTelemetryLogService logService; diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/DefaultLwM2mUplinkMsgHandler.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/DefaultLwM2mUplinkMsgHandler.java index bda4cbf733..db1390768e 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/DefaultLwM2mUplinkMsgHandler.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/DefaultLwM2mUplinkMsgHandler.java @@ -25,6 +25,7 @@ import org.eclipse.leshan.core.ResponseCode; import org.eclipse.leshan.core.model.ObjectModel; import org.eclipse.leshan.core.model.ResourceModel; import org.eclipse.leshan.core.node.LwM2mMultipleResource; +import org.eclipse.leshan.core.node.LwM2mNode; import org.eclipse.leshan.core.node.LwM2mObject; import org.eclipse.leshan.core.node.LwM2mObjectInstance; import org.eclipse.leshan.core.node.LwM2mPath; @@ -329,19 +330,21 @@ public class DefaultLwM2mUplinkMsgHandler extends LwM2MExecutorAwareService impl */ @Override public void onUpdateValueAfterReadResponse(Registration registration, String path, ReadResponse response) { - if (response.getContent() != null) { + LwM2mNode content = response.getContent(); + if (content != null) { LwM2mClient lwM2MClient = clientContext.getClientByEndpoint(registration.getEndpoint()); ObjectModel objectModelVersion = lwM2MClient.getObjectModel(path, modelProvider); if (objectModelVersion != null) { - if (response.getContent() instanceof LwM2mObject) { - LwM2mObject lwM2mObject = (LwM2mObject) response.getContent(); - this.updateObjectResourceValue(lwM2MClient, lwM2mObject, path, response.getCode().getCode()); - } else if (response.getContent() instanceof LwM2mObjectInstance) { - LwM2mObjectInstance lwM2mObjectInstance = (LwM2mObjectInstance) response.getContent(); - this.updateObjectInstanceResourceValue(lwM2MClient, lwM2mObjectInstance, path, response.getCode().getCode()); - } else if (response.getContent() instanceof LwM2mResource) { - LwM2mResource lwM2mResource = (LwM2mResource) response.getContent(); - this.updateResourcesValue(lwM2MClient, lwM2mResource, path, Mode.UPDATE, response.getCode().getCode()); + int responseCode = response.getCode().getCode(); + if (content instanceof LwM2mObject) { + LwM2mObject lwM2mObject = (LwM2mObject) content; + this.updateObjectResourceValue(lwM2MClient, lwM2mObject, path, responseCode); + } else if (content instanceof LwM2mObjectInstance) { + LwM2mObjectInstance lwM2mObjectInstance = (LwM2mObjectInstance) content; + this.updateObjectInstanceResourceValue(lwM2MClient, lwM2mObjectInstance, path, responseCode); + } else if (content instanceof LwM2mResource) { + LwM2mResource lwM2mResource = (LwM2mResource) content; + this.updateResourcesValue(lwM2MClient, lwM2mResource, path, Mode.UPDATE, responseCode); } } if (clientContext.awake(lwM2MClient)) { @@ -359,12 +362,13 @@ public class DefaultLwM2mUplinkMsgHandler extends LwM2MExecutorAwareService impl LwM2mClient lwM2MClient = clientContext.getClientByEndpoint(registration.getEndpoint()); response.getContent().forEach((k, v) -> { if (v != null) { + int responseCode = response.getCode().getCode(); if (v instanceof LwM2mObject) { - this.updateObjectResourceValue(lwM2MClient, (LwM2mObject) v, k.toString(), response.getCode().getCode()); + this.updateObjectResourceValue(lwM2MClient, (LwM2mObject) v, k.toString(), responseCode); } else if (v instanceof LwM2mObjectInstance) { - this.updateObjectInstanceResourceValue(lwM2MClient, (LwM2mObjectInstance) v, k.toString(), response.getCode().getCode()); + this.updateObjectInstanceResourceValue(lwM2MClient, (LwM2mObjectInstance) v, k.toString(), responseCode); } else if (v instanceof LwM2mResource) { - this.updateResourcesValue(lwM2MClient, (LwM2mResource) v, k.toString(), Mode.UPDATE, response.getCode().getCode()); + this.updateResourcesValue(lwM2MClient, (LwM2mResource) v, k.toString(), Mode.UPDATE, responseCode); } } }); diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2MTransportUtil.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2MTransportUtil.java index 37b93a6b8e..1a05ce7b65 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2MTransportUtil.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2MTransportUtil.java @@ -352,7 +352,7 @@ public class LwM2MTransportUtil { } public static Map convertMultiResourceValuesFromRpcBody(Object value, ResourceModel.Type type, String versionedId) throws Exception { - String valueJsonStr = JsonUtils.writeValueAsString(value); + String valueJsonStr = JacksonUtil.toString(value); JsonElement element = JsonUtils.parse(valueJsonStr); return convertMultiResourceValuesFromJson(element, type, versionedId); } diff --git a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/config/ssl/AbstractSslCredentials.java b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/config/ssl/AbstractSslCredentials.java index 8043396e8d..01b7242805 100644 --- a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/config/ssl/AbstractSslCredentials.java +++ b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/config/ssl/AbstractSslCredentials.java @@ -115,7 +115,6 @@ public abstract class AbstractSslCredentials implements SslCredentials { return this.trusts; } - @Override public TrustManagerFactory createTrustManagerFactory() throws NoSuchAlgorithmException, KeyStoreException { TrustManagerFactory tmFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); @@ -130,7 +129,6 @@ public abstract class AbstractSslCredentials implements SslCredentials { return kmf; } - @Override public String getValueFromSubjectNameByKey(String subjectName, String key) { String[] dns = subjectName.split(","); diff --git a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/util/JsonUtils.java b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/util/JsonUtils.java index 76320da164..63383b5e33 100644 --- a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/util/JsonUtils.java +++ b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/util/JsonUtils.java @@ -15,7 +15,6 @@ */ package org.thingsboard.server.common.transport.util; -import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.google.gson.JsonElement; import com.google.gson.JsonObject; @@ -57,8 +56,4 @@ public class JsonUtils { return jsonParser.parse(params); } - public static String writeValueAsString(Object value) throws JsonProcessingException { - return json.writeValueAsString(value); - - } } From e69871d8869af3513a746119d14e884939d57bb5 Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Wed, 29 Dec 2021 17:50:56 +0200 Subject: [PATCH 319/432] UI: Added constants in baseDetailsPageByEntityType --- ui-ngx/src/app/shared/models/constants.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ui-ngx/src/app/shared/models/constants.ts b/ui-ngx/src/app/shared/models/constants.ts index fa73e0d40e..251f310f9b 100644 --- a/ui-ngx/src/app/shared/models/constants.ts +++ b/ui-ngx/src/app/shared/models/constants.ts @@ -143,9 +143,11 @@ export const baseDetailsPageByEntityType = new Map([ [EntityType.TENANT_PROFILE, '/tenantProfiles'], [EntityType.CUSTOMER, '/customers'], [EntityType.USER, '/users'], + [EntityType.DASHBOARD, '/dashboards'], [EntityType.ASSET, '/assets'], [EntityType.DEVICE, '/devices'], [EntityType.DEVICE_PROFILE, '/deviceProfiles'], + [EntityType.RULE_CHAIN, '/ruleChains'], [EntityType.EDGE, '/edgeInstances'], [EntityType.ENTITY_VIEW, '/entityViews'], [EntityType.TB_RESOURCE, '/settings/resources-library'], From 233f58cc46c9adfe15509d3b02af2911e7a89fa8 Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Tue, 28 Dec 2021 20:17:19 +0200 Subject: [PATCH 320/432] netty version upgrade from 4.1.71.Final to 4.1.72.Final --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 4f2713e190..a3199c69dc 100755 --- a/pom.xml +++ b/pom.xml @@ -79,7 +79,7 @@ 1.42.1 1.18.18 1.2.4 - 4.1.71.Final + 4.1.72.Final 2.0.46.Final 1.7.0 4.8.0 From 79bc08e02282de30dce7505bfa78347e9525d568 Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Tue, 28 Dec 2021 20:08:56 +0200 Subject: [PATCH 321/432] upgrade logback version to pass vulnerability check --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index a3199c69dc..d8ae55bf2e 100755 --- a/pom.xml +++ b/pom.xml @@ -49,7 +49,7 @@ 0.7.0 1.7.32 2.17.0 - 1.2.6 + 1.2.10 0.10 4.10.0 4.0.5 From 9921451b4026efae0c4141d785a3b17d4f4dc684 Mon Sep 17 00:00:00 2001 From: Jagveer Loky Date: Thu, 30 Dec 2021 10:14:49 +0000 Subject: [PATCH 322/432] Update Log4j 2.17.0 to 2.17.1 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index c06960c6ca..abe4b27f08 100755 --- a/pom.xml +++ b/pom.xml @@ -48,7 +48,7 @@ 3.3.0 0.7.0 1.7.32 - 2.17.0 + 2.17.1 1.2.10 0.10 4.10.0 From c655b58977990fc57bfe570509c1a7faf2e88e8d Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Thu, 30 Dec 2021 12:31:21 +0200 Subject: [PATCH 323/432] lwm2m delete security files jks and in yml security enable = false --- .../src/main/resources/thingsboard.yml | 10 +- .../credentials/shell/lwM2M_credentials.sh | 359 ----------------- .../credentials/shell/lwM2M_keygen.properties | 57 --- .../lwm2m/src/main/resources/lwm2mserver.jks | Bin 3849 -> 0 bytes pom.xml | 34 -- .../credentials/shell/lwM2M_credentials.sh | 360 ------------------ .../credentials/shell/lwM2M_keygen.properties | 57 --- transport/lwm2m/src/main/data/lwm2mserver.jks | Bin 4017 -> 0 bytes .../src/main/resources/tb-lwm2m-transport.yml | 10 +- 9 files changed, 10 insertions(+), 877 deletions(-) delete mode 100644 common/transport/lwm2m/src/main/resources/credentials/shell/lwM2M_credentials.sh delete mode 100644 common/transport/lwm2m/src/main/resources/credentials/shell/lwM2M_keygen.properties delete mode 100644 common/transport/lwm2m/src/main/resources/lwm2mserver.jks delete mode 100755 transport/lwm2m/src/main/data/credentials/shell/lwM2M_credentials.sh delete mode 100644 transport/lwm2m/src/main/data/credentials/shell/lwM2M_keygen.properties delete mode 100644 transport/lwm2m/src/main/data/lwm2mserver.jks diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index a502afb297..6865aebf9a 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -733,7 +733,7 @@ transport: # Server X509 Certificates support credentials: # Whether to enable LWM2M server X509 Certificate/RPK support - enabled: "${LWM2M_SERVER_CREDENTIALS_ENABLED:true}" + enabled: "${LWM2M_SERVER_CREDENTIALS_ENABLED:false}" # Server credentials type (PEM - pem certificate file; KEYSTORE - java keystore) type: "${LWM2M_SERVER_CREDENTIALS_TYPE:PEM}" # PEM server credentials @@ -769,7 +769,7 @@ transport: # Bootstrap server X509 Certificates support credentials: # Whether to enable LWM2M bootstrap server X509 Certificate/RPK support - enabled: "${LWM2M_BS_CREDENTIALS_ENABLED:true}" + enabled: "${LWM2M_BS_CREDENTIALS_ENABLED:false}" # Server credentials type (PEM - pem certificate file; KEYSTORE - java keystore) type: "${LWM2M_BS_CREDENTIALS_TYPE:PEM}" # PEM server credentials @@ -796,19 +796,19 @@ transport: # X509 trust certificates trust-credentials: # Whether to load X509 trust certificates - enabled: "${LWM2M_TRUST_CREDENTIALS_ENABLED:true}" + enabled: "${LWM2M_TRUST_CREDENTIALS_ENABLED:false}" # Trust certificates store type (PEM - pem certificates file; KEYSTORE - java keystore) type: "${LWM2M_TRUST_CREDENTIALS_TYPE:PEM}" # PEM certificates pem: # Path to the certificates file (holds trust certificates) - cert_file: "${LWM2M_TRUST_PEM_CERT:lwm2mserver.pem}" + cert_file: "${LWM2M_TRUST_PEM_CERT:lwm2mtruststorechain.pem}" # Keystore with trust certificates keystore: # Type of the key store type: "${LWM2M_TRUST_KEY_STORE_TYPE:JKS}" # Path to the key store that holds the X509 certificates - store_file: "${LWM2M_TRUST_KEY_STORE:lwm2mserver.jks}" + store_file: "${LWM2M_TRUST_KEY_STORE:lwm2mtruststorechain.jks}" # Password used to access the key store store_password: "${LWM2M_TRUST_KEY_STORE_PASSWORD:server_ks_password}" recommended_ciphers: "${LWM2M_RECOMMENDED_CIPHERS:false}" diff --git a/common/transport/lwm2m/src/main/resources/credentials/shell/lwM2M_credentials.sh b/common/transport/lwm2m/src/main/resources/credentials/shell/lwM2M_credentials.sh deleted file mode 100644 index f68ca30005..0000000000 --- a/common/transport/lwm2m/src/main/resources/credentials/shell/lwM2M_credentials.sh +++ /dev/null @@ -1,359 +0,0 @@ -#!/bin/sh -# -# Copyright © 2016-2021 The Thingsboard Authors -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -#/home/nick/Igor_project/Thingsboard_Perfrmance_test/performance-tests/src/main/resources/credentials/shell/lwM2M_credentials.sh -p LwX509 -s 0 -f 2000 -a client_alias_ -e client_self_signed_ -b bootstrap -d server -j serverKeyStore.jks -k clientKeyStore.jks -c client_ks_password -w server_ks_password - -#p) CLIENT_CN=$CLIENT_PREFIX00000000 -#s) client_start=0 -#f) client_finish=1 -#a) CLIENT_ALIAS=CLIENT_ALIAS_PREFIX_00000000 -#e) CLIENT_SELF_ALIAS=CLIENT_SELF_ALIAS_PREFIX_00000000 -#b) BOOTSTRAP_ALIAS=bootstrap -#d) SERVER_ALIAS=server -#j) SERVER_STORE=serverKeyStore.jks -#k) CLIENT_STORE=clientKeyStore.jks -#c) CLIENT_STORE_PWD=client_ks_password -#w) SERVER_STORE_PWD=server_ks_password -#l) ROOT_KEY_ALIAS=root_key_alias - -while getopts p:s:f:a:e:b:d:j:k:c:w:l: flag; do - case "${flag}" in - p) client_pref=${OPTARG} ;; - s) client_start=${OPTARG} ;; - f) client_finish=${OPTARG} ;; - a) client_alias_pref=${OPTARG} ;; - e) client_self_alias_pref=${OPTARG} ;; - b) bootstrap_alias=${OPTARG} ;; - d) server_alias=${OPTARG} ;; - j) key_store_server_file=${OPTARG} ;; - k) key_store_client_file=${OPTARG} ;; - c) client_key_store_pwd=${OPTARG} ;; - w) server_key_store_pwd=${OPTARG} ;; - w) root_key_alias=${OPTARG} ;; - esac -done - -# cd to dir of script -script_dir=$(dirname $0) -echo "script_dir: $script_dir" -cd $script_dir -# source the properties: -. ./lwM2M_keygen.properties - -if [ -n "$client_pref" ]; then - CLIENT_PREFIX=$client_pref -fi - -if [ -z "$client_start" ]; then - client_start=0 -fi - -if [ -z "$client_finish" ]; then - client_finish=1 -fi - -if [ -n "$client_alias_pref" ]; then - CLIENT_ALIAS_PREFIX=$client_alias_pref -fi - -if [ -n "$client_self_alias_pref" ]; then - CLIENT_SELF_ALIAS_PREFIX=$client_self_alias_pref -fi - -if [ -n "$bootstrap_alias" ]; then - BOOTSTRAP_ALIAS=$bootstrap_alias -fi - -if [ -n "$server_alias" ]; then - SERVER_ALIAS=$server_alias -fi - -if [ -n "$key_store_server_file" ]; then - SERVER_STORE=$key_store_server_file -fi - -if [ -n "$key_store_client_file" ]; then - CLIENT_STORE=$key_store_client_file -fi - -if [ -n "$client_key_store_pwd" ]; then - CLIENT_STORE_PWD=$client_key_store_pwd -fi - -if [ -n "$server_key_store_pwd" ]; then - SERVER_STORE_PWD=$server_key_store_pwd -fi - -if [ -n "$root_key_alias" ]; then - ROOT_KEY_ALIAS=$root_key_alias -fi - -CLIENT_NUMBER=$client_start - -echo "==Start==" -echo "CLIENT_PREFIX: $CLIENT_PREFIX" -echo "client_start: $client_start" -echo "client_finish: $client_finish" -echo "CLIENT_ALIAS_PREFIX: $CLIENT_ALIAS_PREFIX" -echo "CLIENT_SELF_ALIAS_PREFIX: $CLIENT_SELF_ALIAS_PREFIX" -echo "BOOTSTRAP_ALIAS: $BOOTSTRAP_ALIAS" -echo "SERVER_ALIAS: $SERVER_ALIAS" -echo "SERVER_STORE: $SERVER_STORE" -echo "CLIENT_STORE: $CLIENT_STORE" -echo "CLIENT_STORE_PWD: $CLIENT_STORE_PWD" -echo "SERVER_STORE_PWD: $SERVER_STORE_PWD" -echo "CLIENT_NUMBER: $CLIENT_NUMBER" -echo "ROOT_KEY_ALIAS: $ROOT_KEY_ALIAS" - -end_point() { - echo "$CLIENT_PREFIX$(printf "%08d" $CLIENT_NUMBER)" -} - -client_alias_point() { - echo "$CLIENT_ALIAS_PREFIX$(printf "%08d" $CLIENT_NUMBER)" -} - -client_self_alias_point() { - echo "$CLIENT_SELF_ALIAS_PREFIX$(printf "%08d" $CLIENT_NUMBER)" -} - -# Generation of the keystore. -echo "${H0}====START========${RESET}" -echo "${H1}Server Keystore : ${RESET}" -echo "${H1}==================${RESET}" -echo "${H2}Creating the trusted root CA key and certificate...${RESET}" -# -keysize -# 1024 (when using -genkeypair) -keytool \ - -genkeypair \ - -alias $ROOT_KEY_ALIAS \ - -keyalg EC \ - -dname "CN=$ROOT_CN, OU=$ORGANIZATIONAL_UNIT, O=$ORGANIZATION, L=$CITY, ST=$STATE_OR_PROVINCE, C=$TWO_LETTER_COUNTRY_CODE" \ - -validity $VALIDITY \ - -storetype $STORETYPE \ - -keypass $SERVER_STORE_PWD \ - -keystore $SERVER_STORE \ - -storepass $SERVER_STORE_PWD - -echo -echo "${H2}Creating server key and self-signed certificate ...${RESET}" -keytool \ - -genkeypair \ - -alias $SERVER_ALIAS \ - -keyalg EC \ - -dname "CN=$SERVER_SELF_CN, OU=$ORGANIZATIONAL_UNIT, O=$ORGANIZATION, L=$CITY, ST=$STATE_OR_PROVINCE, C=$TWO_LETTER_COUNTRY_CODE" \ - -validity $VALIDITY \ - -storetype $STORETYPE \ - -keypass $SERVER_STORE_PWD \ - -keystore $SERVER_STORE \ - -storepass $SERVER_STORE_PWD -keytool \ - -exportcert \ - -alias $SERVER_ALIAS \ - -keystore $SERVER_STORE \ - -storepass $SERVER_STORE_PWD | - keytool \ - -importcert \ - -alias $SERVER_SELF_ALIAS \ - -keystore $SERVER_STORE \ - -storepass $SERVER_STORE_PWD \ - -noprompt - -echo -echo "${H2}Creating server certificate signed by root CA...${RESET}" -keytool \ - -certreq \ - -alias $SERVER_ALIAS \ - -dname "CN=$SERVER_CN, OU=$ORGANIZATIONAL_UNIT, O=$ORGANIZATION, L=$CITY, ST=$STATE_OR_PROVINCE, C=$TWO_LETTER_COUNTRY_CODE" \ - -keystore $SERVER_STORE \ - -storepass $SERVER_STORE_PWD | - keytool \ - -gencert \ - -alias $ROOT_KEY_ALIAS \ - -keystore $SERVER_STORE \ - -storepass $SERVER_STORE_PWD \ - -storetype $STORETYPE \ - -validity $VALIDITY | - keytool \ - -importcert \ - -alias $SERVER_ALIAS \ - -keystore $SERVER_STORE \ - -storepass $SERVER_STORE_PWD - -echo -echo "${H2}Creating bootstrap key and self-signed certificate ...${RESET}" -keytool \ - -genkeypair \ - -alias $BOOTSTRAP_ALIAS \ - -keyalg EC \ - -dname "CN=$BOOTSTRAP_SELF_CN, OU=$ORGANIZATIONAL_UNIT, O=$ORGANIZATION, L=$CITY, ST=$STATE_OR_PROVINCE, C=$TWO_LETTER_COUNTRY_CODE" \ - -validity $VALIDITY \ - -storetype $STORETYPE \ - -keypass $SERVER_STORE_PWD \ - -keystore $SERVER_STORE \ - -storepass $SERVER_STORE_PWD -keytool \ - -exportcert \ - -alias $BOOTSTRAP_ALIAS \ - -keystore $SERVER_STORE \ - -storepass $SERVER_STORE_PWD | - keytool \ - -importcert \ - -alias $BOOTSTRAP_SELF_ALIAS \ - -keystore $SERVER_STORE \ - -storepass $SERVER_STORE_PWD \ - -noprompt - -echo -echo "${H2}Creating bootstrap certificate signed by root CA...${RESET}" -keytool \ - -certreq \ - -alias $BOOTSTRAP_ALIAS \ - -dname "CN=$BOOTSTRAP_CN, OU=$ORGANIZATIONAL_UNIT, O=$ORGANIZATION, L=$CITY, ST=$STATE_OR_PROVINCE, C=$TWO_LETTER_COUNTRY_CODE" \ - -keystore $SERVER_STORE \ - -storepass $SERVER_STORE_PWD | - keytool \ - -gencert \ - -alias $ROOT_KEY_ALIAS \ - -keystore $SERVER_STORE \ - -storepass $SERVER_STORE_PWD \ - -storetype $STORETYPE \ - -validity $VALIDITY | - keytool \ - -importcert \ - -alias $BOOTSTRAP_ALIAS \ - -keystore $SERVER_STORE \ - -storepass $SERVER_STORE_PWD - -if [ "$client_start" -lt "$client_finish" ]; then - echo - echo "${H2}Import root certificate just to be able to import need by root CA with expected CN to $CLIENT_STORE${RESET}" - keytool \ - -exportcert \ - -alias $ROOT_KEY_ALIAS \ - -keystore $SERVER_STORE \ - -storepass $SERVER_STORE_PWD | - keytool \ - -importcert \ - -alias $ROOT_KEY_ALIAS \ - -keystore $CLIENT_STORE \ - -storepass $CLIENT_STORE_PWD \ - -noprompt -fi - -cert_end_point() { - echo - echo "${H1}Client Keystore : ${RESET}" - echo "${H1}==================${RESET}" - echo "${H2}Creating client key and self-signed certificate with expected CN CLIENT_ALIAS: $CLIENT_ALIAS${RESET}" - keytool \ - -genkeypair \ - -alias $CLIENT_ALIAS \ - -keyalg EC \ - -dname "CN=$CLIENT_SELF_CN, OU=$ORGANIZATIONAL_UNIT, O=$ORGANIZATION, L=$CITY, ST=$STATE_OR_PROVINCE, C=$TWO_LETTER_COUNTRY_CODE" \ - -validity $VALIDITY \ - -storetype $STORETYPE \ - -keypass $CLIENT_STORE_PWD \ - -keystore $CLIENT_STORE \ - -storepass $CLIENT_STORE_PWD - keytool \ - -exportcert \ - -alias $CLIENT_ALIAS \ - -keystore $CLIENT_STORE \ - -storepass $CLIENT_STORE_PWD | - keytool \ - -importcert \ - -alias $CLIENT_SELF_ALIAS \ - -keystore $CLIENT_STORE \ - -storepass $CLIENT_STORE_PWD \ - -noprompt -# -# echo -# echo "${H2}Import root certificate just to be able to import ned by root CA with expected CN...${RESET}" -# keytool \ -# -exportcert \ -# -alias $ROOT_KEY_ALIAS \ -# -keystore $SERVER_STORE \ -# -storepass $SERVER_STORE_PWD | -# keytool \ -# -importcert \ -# -alias $ROOT_KEY_ALIAS \ -# -keystore $CLIENT_STORE \ -# -storepass $CLIENT_STORE_PWD \ -# -noprompt -# - - echo - echo "${H2}Creating client certificate signed by root CA with expected CN CLIENT_ALIAS: $CLIENT_ALIAS CLIENT_CN: $CLIENT_CN${RESET}" - keytool \ - -certreq \ - -alias $CLIENT_ALIAS \ - -dname "CN=$CLIENT_CN, OU=$ORGANIZATIONAL_UNIT, O=$ORGANIZATION, L=$CITY, ST=$STATE_OR_PROVINCE, C=$TWO_LETTER_COUNTRY_CODE" \ - -keystore $CLIENT_STORE \ - -storepass $CLIENT_STORE_PWD | - keytool \ - -gencert \ - -alias $ROOT_KEY_ALIAS \ - -keystore $SERVER_STORE \ - -storepass $SERVER_STORE_PWD \ - -storetype $STORETYPE \ - -validity $VALIDITY | - keytool \ - -importcert \ - -alias $CLIENT_ALIAS \ - -keystore $CLIENT_STORE \ - -storepass $CLIENT_STORE_PWD \ - -noprompt -} - -if [ "$client_start" -lt "$client_finish" ]; then - echo - echo "==Start Client==" - while [ "$CLIENT_NUMBER" -lt "$client_finish" ]; do - echo "number $CLIENT_NUMBER" - echo "finish $client_finish" - CLIENT_CN=$(end_point) - CLIENT_ALIAS=$(client_alias_point) - CLIENT_SELF_ALIAS=$(client_self_alias_point) - echo "CLIENT_CN $CLIENT_CN" - echo "CLIENT_ALIAS $CLIENT_ALIAS" - echo "CLIENT_SELF_ALIAS $CLIENT_SELF_ALIAS" - cert_end_point - CLIENT_NUMBER=$(($CLIENT_NUMBER + 1)) - echo - done -fi - -echo -echo "${H0}!!! Warning ${H2}Migrate ${H1}${SERVER_STORE} ${H2}to ${H1}PKCS12 ${H2}which is an industry standard format..${RESET}" -keytool \ - -importkeystore \ - -srckeystore $SERVER_STORE \ - -destkeystore $SERVER_STORE \ - -deststoretype pkcs12 \ - -srcstorepass $SERVER_STORE_PWD - -if [ "$client_start" -lt "$client_finish" ]; then - echo - echo "${H0}!!! Warning ${H2}Migrate ${H1}${CLIENT_STORE} ${H2}to ${H1}PKCS12 ${H2}which is an industry standard format..${RESET}" - keytool \ - -importkeystore \ - -srckeystore $CLIENT_STORE \ - -destkeystore $CLIENT_STORE \ - -deststoretype pkcs12 \ - -srcstorepass $CLIENT_STORE_PWD -fi diff --git a/common/transport/lwm2m/src/main/resources/credentials/shell/lwM2M_keygen.properties b/common/transport/lwm2m/src/main/resources/credentials/shell/lwM2M_keygen.properties deleted file mode 100644 index 7b3cd9c09a..0000000000 --- a/common/transport/lwm2m/src/main/resources/credentials/shell/lwM2M_keygen.properties +++ /dev/null @@ -1,57 +0,0 @@ -# -# Copyright © 2016-2017 The Thingsboard Authors -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# Keystore common parameters -ROOT_KEY_ALIAS=rootCA -DOMAIN_SUFFIX="$(hostname)" -ROOT_CN="$DOMAIN_SUFFIX $ROOT_KEY_ALIAS" -ORGANIZATIONAL_UNIT=Thingsboard -ORGANIZATION=Thingsboard -CITY=SF -STATE_OR_PROVINCE=CA -TWO_LETTER_COUNTRY_CODE=US -VALIDITY=36500 #days -STORETYPE="JKS" - -#Server -SERVER_STORE=serverKeyStore1.jks -SERVER_STORE_PWD=server_ks_password1 -SERVER_ALIAS=server1 -SERVER_CN="$DOMAIN_SUFFIX server LwM2M signed by root CA" -SERVER_SELF_ALIAS=server_self_signed -SERVER_SELF_CN="$DOMAIN_SUFFIX server LwM2M self-signed" -BOOTSTRAP_ALIAS=bootstrap1 -BOOTSTRAP_CN="$DOMAIN_SUFFIX bootstrap server LwM2M signed by root CA" -BOOTSTRAP_SELF_ALIAS=bootstrap_self_signed -BOOTSTRAP_SELF_CN="$DOMAIN_SUFFIX bootstrap server LwM2M self-signed" - -# Client -CLIENT_STORE=clientKeyStore1.jks -CLIENT_STORE_PWD=client_ks_password1 -CLIENT_ALIAS_PREFIX=client_alias_1 -CLIENT_PREFIX=LwX509___ -CLIENT_SELF_ALIAS_PREFIX=client_self_signed_1 -CLIENT_SELF_CN="$DOMAIN_SUFFIX client LwM2M self-signed" - -# Color output stuff -red=`tput setaf 1` -green=`tput setaf 2` -blue=`tput setaf 4` -bold=`tput bold` -H0=${red}${bold} -H1=${green}${bold} -H2=${blue} -RESET=`tput sgr0` diff --git a/common/transport/lwm2m/src/main/resources/lwm2mserver.jks b/common/transport/lwm2m/src/main/resources/lwm2mserver.jks deleted file mode 100644 index 5fab824aa1b19928fe711701cd27857472a9e739..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3849 zcma))cQ738*2k5#+A3Kq(YqjRcL_F1L>K%-FB_t+8ZBy+V6l1$qW9jSCDF?Y!3rTn zi{2%y-eQ&O-nn(={o|c8bI#27d(QLB`OJZ#>BvZkNnvQ(b|B>)j0)z2hM1f<7fo9Y zK+{%S%Ox;0$@BlQNYnvn5|wLN0fr`K1ycWW3PeRrk{g7B1@*v$fK>kyub*ZGK<*M} z={8PCcFVlAro7urVR?jwWRj2)b!h^EQgg>cnZ9_dBi7mrZl=C^`YJ^4Mwty}WZR0C zPQ-gm(fzX0-@T*x|zp44h)t@B? zY_f0D4EtZp_rA=3XLiAL`ZT!(KOmt+Y}|5c=e|dC*|5v*ja6N;P!Fd-Q7Q`#tIifw z(8tq0NuqRgD873qAUK+6Kh@$e%9I-Z1jhRBy(uAZS`HAA8xe}=6_MxPGmQH`CL zotg#=i4W;>Ob9Ot&9k&?^5MQpmW7E%3N-Utl0R8PkN5qGa#;OUfqhDFrT-=XfkQaJ zL>5HO*WrGR$^9CWIg!hMxBOp_9z7I+p+O4&CP@y=MT11IB{&H&(RI1=ABXsVt_t|~ zt6F7ER@7MOM!a^#FN=&4yAoJB+5Uko5KX-c!%Mvx8ue-o@|Y8>V=p&sOo11EWwN|r zj`X=_(lIw_*u>$y#?99EnlxHCuJ1sFLi1tvjUxeaUwu%Hl}w(?Dc^mU%SF|OSmTo$&6>m_Hq&%@zRJN|j9z8-8ugmY(5pMw@S`gcpZV=*L=9&ZUr;wmRYs&KNw`qCPGcvsC`=$Kz5GHI9WLoGw?Rut|#MUOiLQvr2Z(+2bYV11c z?0JoX3+wRi$WadS8;I!G-}+8!AOZGAbWTc7{bpo(e5Lu_>f?`7kwSeU8sn+o#A3sI z5-twp+FSDY{;;v0?ZD%O^1KPYTCyu89Yv+yHH>+IcG}B2(XMjCRET{#$TkpGm<8|PpkIa zD*_wKhsF8tT6RD&?TTM^|3oRL-r;Ept2LYEz2|9%Tz1f4HR%KyGbjuHvZYaamfdiV z3D7b;@!%7x>zUhWsL36>6fcQgztN^p{rFiZHSf5vuwEFv@N# zQsFQ1@GoT*tO=Y3d$HMnZ1dTWiu9>9sNgUCCT&|E$FbG<44A4nWxQ?#lDM+Yie>d#EuLBauH zgj`MgEeG3#g+(rB58z~09U}TZ^@KjTMJ{Z5Wf_|>cN!_>G8hKEME;U9#mWW+5p=7g zT!-Zd6RC@Vq;ky+gUOxNM`U>7txb`IXl0DKl*O3QI|dVX`cI=nH&ov~UMVN9OobR58$-80m8T zWl`BdzdWZD$+^mJt|o>kD>LW8?e5PxA#}$1{=UT-RZ!1Ct+5!m{)91j7okSnTprCT zK=bKzJXyyvx=#(b>FIHyj()0>;ANv&;! z_)RJh?TOP-HIA&P@SxIw=16K0(3L11dtqYXr?gq)J2$hP)`4E`FOK~bhZpr(x#2>y zgk-q=JjTO$WVI+I_LIF-V!g&ACh?~3F!J2>6kYRBf64(AH2+VivIo&k^Wi0cL8~8~ zmaDIDy-~ECGu@X(6e|)G(X(mx3v_F-^rO^YOuK4>54u$@azF6?Fos9Lx!z%Wf#N~> zoD=JI-ziyZoi_Uo?Sy_Md0l<|u%;DtG3;62{-I8vGksE5Y94yFNwLrjPN_h8e*581bHb7nwR+aY6P{HsoGZ5L=5H5JXoh`OiQjUo#Sc+9f95VHpu2m zm6|V?j@f`ZNng6BSyMq7k_j)je*_PO$gO9%>vW}ltSSPOY1ufO21C!&gp@rF%?e+h z*h)E9E@x$p#Dt=i)?Um^5?U!3AQGUeoYl7M(g-|0I^EQ(RllS){vVv)h$7II3}< zj>%Xa|CyE;(o*qC9(NgOj4ep@vHmyar-`uk>i1as`YKSHtw+qjP@`<>qf@X zfTW)6A~531(u>h(bzlX}hZCf}Znqcdl8lgAN;yxlq$!m9&ku@FVUYUfk!~Bjqz9Q7 zto$}nueJm{J%+3&+i5>TyyND`jM#sjR4|qyeL^~Vl`mA_Zy&K;MLXE}OF;ZeFg|-= zX4x}dOuK+Txf9nIVc)YN`=;yh{H@_SM{y!rPMt1xig;>~Dv-n?U%{(yPB(K>H!#ez z(7FIN1#uU{+U!-hxM1n$`~AZ86Cu;%-pzgThH?{Phyr^dHQyz;K}wFKPN9-4pD>4? z-rk?Qb5xiQ7g)w71ej~P#U;BeFikx&RlWYLTauoB%CTaJes~Q_tLU5n+p9v*e4A1E zz8OOHyym7|?nI;Hm*BIGiXqXmO_|~vx&Hi30X*fhvaD?RnFJM=Qta0q-x7vy!}qSlED(*#K$qn3=IqHN>esF#h$G|Z4A|GJ5aLqx9cXDwzfOk%8Tcquhv#>mBpUu z;r6Q07B#4S9v;mZ!nT9)3R{t0>2@Q%@V54d@-ur5$lNlyG-EH|%aSeOe9c(D6T>OU zXNylOO|Qd@%pJcUL6FOH(>$xw#NK8*#4(|;Wq~M zBa!vg_V^_ehS&qEo=%pXEyZvtT5n;dtmU`@pHXx1xHUnMwho64x17)eu7Ia<8o1FS zG4;M6<%J7g^a@NZQCw?rhWx3fa?Dl2qy7fmp2b;WI)h%%ot>y1MPYKP%u^vvrNteFCnDCe=`Sj#KteNow|(Q8d;a)JZhpYqoePcLA7QTAM`SCA~<_BDhA#= zMtKeSANuU+M){zwq9(y=5#Q9!z;SDYuQd#SOYQk9lPQAvn0IEpVUtsPgD&~X!($WB zM+Tl9rQCa)Xa3!Dg+{7duIhE(?=R-A9t^I0&QeFVdwLwQ_$2Jri4s59;$3~TP;|am zn!9z;+C22g(CJHg2+CK5n03Cns4;wzsrPV;+2#qUgnRPjOV@kO%|9o(RqHFx3u6U0 zos!a*#sD7?R9dIa8X%cMHn(@6sU{WE48Pb3*5id4tQ2FO7X9Iq{Iz#fI~&b#_6n(! zg{#6bH|=tob*20lMhkP86* b(C|b)G3l|ClS0(tPLrtJO%hUKOzz(RVYoVD diff --git a/pom.xml b/pom.xml index c06960c6ca..9dd8c043b2 100755 --- a/pom.xml +++ b/pom.xml @@ -403,39 +403,9 @@ false - - ../common/transport/lwm2m/src/main/resources - - **/*.xml - **/*.jks - - false - - - - - - copy-lwm2m-resources - ${pkg.process-resources.phase} - - copy-resources - - - ../transport/lwm2m/src/main/data - - - ../common/transport/lwm2m/src/main/resources - - **/*.xml - **/*.jks - - false - - - copy-docker-config ${pkg.process-resources.phase} @@ -829,10 +799,6 @@ **/*.proto.js docker/haproxy/** docker/tb-node/** - src/main/resources/models/*.xml - src/main/resources/credentials/*.jks - src/main/resources/credentials/shell/*.jks - src/main/resources/credentials/shell/*.jks.old ui/** src/.browserslistrc **/yarn.lock diff --git a/transport/lwm2m/src/main/data/credentials/shell/lwM2M_credentials.sh b/transport/lwm2m/src/main/data/credentials/shell/lwM2M_credentials.sh deleted file mode 100755 index d623bfad42..0000000000 --- a/transport/lwm2m/src/main/data/credentials/shell/lwM2M_credentials.sh +++ /dev/null @@ -1,360 +0,0 @@ -#!/bin/sh -# -# Copyright © 2016-2021 The Thingsboard Authors -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -#/home/nick/Igor_project/Thingsboard_Perfrmance_test/performance-tests/src/main/resources/credentials/shell/lwM2M_credentials.sh -p LwX509 -s 0 -f 2000 -a client_alias_ -e client_self_signed_ -b bootstrap -d server -j serverKeyStore.jks -k clientKeyStore.jks -c client_ks_password -w server_ks_password - -#p) CLIENT_CN=$CLIENT_PREFIX00000000 -#s) client_start=0 -#f) client_finish=1 -#a) CLIENT_ALIAS=CLIENT_ALIAS_PREFIX_00000000 -#e) CLIENT_SELF_ALIAS=CLIENT_SELF_ALIAS_PREFIX_00000000 -#b) BOOTSTRAP_ALIAS=bootstrap -#d) SERVER_ALIAS=server -#j) SERVER_STORE=serverKeyStore.jks -#k) CLIENT_STORE=clientKeyStore.jks -#c) CLIENT_STORE_PWD=client_ks_password -#w) SERVER_STORE_PWD=server_ks_password -#l) ROOT_KEY_ALIAS=root_key_alias - -while getopts p:s:f:a:e:b:d:j:k:c:w:l: flag; do - case "${flag}" in - p) client_pref=${OPTARG} ;; - s) client_start=${OPTARG} ;; - f) client_finish=${OPTARG} ;; - a) client_alias_pref=${OPTARG} ;; - e) client_self_alias_pref=${OPTARG} ;; - b) bootstrap_alias=${OPTARG} ;; - d) server_alias=${OPTARG} ;; - j) key_store_server_file=${OPTARG} ;; - k) key_store_client_file=${OPTARG} ;; - c) client_key_store_pwd=${OPTARG} ;; - w) server_key_store_pwd=${OPTARG} ;; - w) root_key_alias=${OPTARG} ;; - esac -done - -# cd to dir of script -script_dir=$(dirname $0) -echo "script_dir: $script_dir" -cd $script_dir -# source the properties: -. ./lwM2M_keygen.properties - -if [ -n "$client_pref" ]; then - CLIENT_PREFIX=$client_pref -fi - -if [ -z "$client_start" ]; then - client_start=0 -fi - -if [ -z "$client_finish" ]; then - client_finish=1 -fi - -if [ -n "$client_alias_pref" ]; then - CLIENT_ALIAS_PREFIX=$client_alias_pref -fi - -if [ -n "$client_self_alias_pref" ]; then - CLIENT_SELF_ALIAS_PREFIX=$client_self_alias_pref -fi - -if [ -n "$bootstrap_alias" ]; then - BOOTSTRAP_ALIAS=$bootstrap_alias -fi - -if [ -n "$server_alias" ]; then - SERVER_ALIAS=$server_alias -fi - -if [ -n "$key_store_server_file" ]; then - SERVER_STORE=$key_store_server_file -fi - -if [ -n "$key_store_client_file" ]; then - CLIENT_STORE=$key_store_client_file -fi - -if [ -n "$client_key_store_pwd" ]; then - CLIENT_STORE_PWD=$client_key_store_pwd -fi - -if [ -n "$server_key_store_pwd" ]; then - SERVER_STORE_PWD=$server_key_store_pwd -fi - -if [ -n "$root_key_alias" ]; then - ROOT_KEY_ALIAS=$root_key_alias -fi - -CLIENT_NUMBER=$client_start - -echo "==Start==" -echo "CLIENT_PREFIX: $CLIENT_PREFIX" -echo "client_start: $client_start" -echo "client_finish: $client_finish" -echo "CLIENT_ALIAS_PREFIX: $CLIENT_ALIAS_PREFIX" -echo "CLIENT_SELF_ALIAS_PREFIX: $CLIENT_SELF_ALIAS_PREFIX" -echo "BOOTSTRAP_ALIAS: $BOOTSTRAP_ALIAS" -echo "SERVER_ALIAS: $SERVER_ALIAS" -echo "SERVER_STORE: $SERVER_STORE" -echo "CLIENT_STORE: $CLIENT_STORE" -echo "CLIENT_STORE_PWD: $CLIENT_STORE_PWD" -echo "SERVER_STORE_PWD: $SERVER_STORE_PWD" -echo "CLIENT_NUMBER: $CLIENT_NUMBER" -echo "ROOT_KEY_ALIAS: $ROOT_KEY_ALIAS" - -end_point() { - echo "$CLIENT_PREFIX$(printf "%08d" $CLIENT_NUMBER)" -} - -client_alias_point() { - echo "$CLIENT_ALIAS_PREFIX$(printf "%08d" $CLIENT_NUMBER)" -} - -client_self_alias_point() { - echo "$CLIENT_SELF_ALIAS_PREFIX$(printf "%08d" $CLIENT_NUMBER)" -} - -# Generation of the keystore. -echo "${H0}====START========${RESET}" -echo "${H1}Server Keystore : ${RESET}" -echo "${H1}==================${RESET}" -echo "${H2}Creating the trusted root CA key and certificate...${RESET}" -# -keysize -# 1024 (when using -genkeypair) -keytool \ - -genkeypair \ - -alias $ROOT_KEY_ALIAS \ - -keyalg EC \ - -dname "CN=$ROOT_CN, OU=$ORGANIZATIONAL_UNIT, O=$ORGANIZATION, L=$CITY, ST=$STATE_OR_PROVINCE, C=$TWO_LETTER_COUNTRY_CODE" \ - -validity $VALIDITY \ - -storetype $STORETYPE \ - -keypass $SERVER_STORE_PWD \ - -keystore $SERVER_STORE \ - -storepass $SERVER_STORE_PWD - -echo -echo "${H2}Creating server key and self-signed certificate ...${RESET}" -keytool \ - -genkeypair \ - -alias $SERVER_ALIAS \ - -keyalg EC \ - -dname "CN=$SERVER_SELF_CN, OU=$ORGANIZATIONAL_UNIT, O=$ORGANIZATION, L=$CITY, ST=$STATE_OR_PROVINCE, C=$TWO_LETTER_COUNTRY_CODE" \ - -validity $VALIDITY \ - -storetype $STORETYPE \ - -keypass $SERVER_STORE_PWD \ - -keystore $SERVER_STORE \ - -storepass $SERVER_STORE_PWD -keytool \ - -exportcert \ - -alias $SERVER_ALIAS \ - -keystore $SERVER_STORE \ - -storepass $SERVER_STORE_PWD | - keytool \ - -importcert \ - -alias $SERVER_SELF_ALIAS \ - -keystore $SERVER_STORE \ - -storepass $SERVER_STORE_PWD \ - -noprompt - -echo -echo "${H2}Creating server certificate signed by root CA...${RESET}" -keytool \ - -certreq \ - -alias $SERVER_ALIAS \ - -dname "CN=$SERVER_CN, OU=$ORGANIZATIONAL_UNIT, O=$ORGANIZATION, L=$CITY, ST=$STATE_OR_PROVINCE, C=$TWO_LETTER_COUNTRY_CODE" \ - -keystore $SERVER_STORE \ - -storepass $SERVER_STORE_PWD | - keytool \ - -gencert \ - -alias $ROOT_KEY_ALIAS \ - -keystore $SERVER_STORE \ - -storepass $SERVER_STORE_PWD \ - -storetype $STORETYPE \ - -validity $VALIDITY | - keytool \ - -importcert \ - -alias $SERVER_ALIAS \ - -keystore $SERVER_STORE \ - -storepass $SERVER_STORE_PWD - -echo -echo "${H2}Creating bootstrap key and self-signed certificate ...${RESET}" -keytool \ - -genkeypair \ - -alias $BOOTSTRAP_ALIAS \ - -keyalg EC \ - -dname "CN=$BOOTSTRAP_SELF_CN, OU=$ORGANIZATIONAL_UNIT, O=$ORGANIZATION, L=$CITY, ST=$STATE_OR_PROVINCE, C=$TWO_LETTER_COUNTRY_CODE" \ - -validity $VALIDITY \ - -storetype $STORETYPE \ - -keypass $SERVER_STORE_PWD \ - -keystore $SERVER_STORE \ - -storepass $SERVER_STORE_PWD -keytool \ - -exportcert \ - -alias $BOOTSTRAP_ALIAS \ - -keystore $SERVER_STORE \ - -storepass $SERVER_STORE_PWD | - keytool \ - -importcert \ - -alias $BOOTSTRAP_SELF_ALIAS \ - -keystore $SERVER_STORE \ - -storepass $SERVER_STORE_PWD \ - -noprompt - -echo -echo "${H2}Creating bootstrap certificate signed by root CA...${RESET}" -keytool \ - -certreq \ - -alias $BOOTSTRAP_ALIAS \ - -dname "CN=$BOOTSTRAP_CN, OU=$ORGANIZATIONAL_UNIT, O=$ORGANIZATION, L=$CITY, ST=$STATE_OR_PROVINCE, C=$TWO_LETTER_COUNTRY_CODE" \ - -keystore $SERVER_STORE \ - -storepass $SERVER_STORE_PWD | - keytool \ - -gencert \ - -alias $ROOT_KEY_ALIAS \ - -keystore $SERVER_STORE \ - -storepass $SERVER_STORE_PWD \ - -storetype $STORETYPE \ - -validity $VALIDITY | - keytool \ - -importcert \ - -alias $BOOTSTRAP_ALIAS \ - -keystore $SERVER_STORE \ - -storepass $SERVER_STORE_PWD - -if [ "$client_start" -lt "$client_finish" ]; then - echo - echo "${H2}Import root certificate just to be able to import need by root CA with expected CN to $CLIENT_STORE${RESET}" - keytool \ - -exportcert \ - -alias $ROOT_KEY_ALIAS \ - -keystore $SERVER_STORE \ - -storepass $SERVER_STORE_PWD | - keytool \ - -importcert \ - -alias $ROOT_KEY_ALIAS \ - -keystore $CLIENT_STORE \ - -storepass $CLIENT_STORE_PWD \ - -noprompt -fi - -cert_end_point() { - echo - echo "${H1}Client Keystore : ${RESET}" - echo "${H1}==================${RESET}" - echo "${H2}Creating client key and self-signed certificate with expected CN CLIENT_ALIAS: $CLIENT_ALIAS${RESET}" - keytool \ - -genkeypair \ - -alias $CLIENT_ALIAS \ - -keyalg EC \ - -dname "CN=$CLIENT_SELF_CN, OU=$ORGANIZATIONAL_UNIT, O=$ORGANIZATION, L=$CITY, ST=$STATE_OR_PROVINCE, C=$TWO_LETTER_COUNTRY_CODE" \ - -validity $VALIDITY \ - -storetype $STORETYPE \ - -keypass $CLIENT_STORE_PWD \ - -keystore $CLIENT_STORE \ - -storepass $CLIENT_STORE_PWD - keytool \ - -exportcert \ - -alias $CLIENT_ALIAS \ - -keystore $CLIENT_STORE \ - -storepass $CLIENT_STORE_PWD | - keytool \ - -importcert \ - -alias $CLIENT_SELF_ALIAS \ - -keystore $CLIENT_STORE \ - -storepass $CLIENT_STORE_PWD \ - -noprompt -# -# echo -# echo "${H2}Import root certificate just to be able to import ned by root CA with expected CN...${RESET}" -# keytool \ -# -exportcert \ -# -alias $ROOT_KEY_ALIAS \ -# -keystore $SERVER_STORE \ -# -storepass $SERVER_STORE_PWD | -# keytool \ -# -importcert \ -# -alias $ROOT_KEY_ALIAS \ -# -keystore $CLIENT_STORE \ -# -storepass $CLIENT_STORE_PWD \ -# -noprompt -# - - echo - echo "${H2}Creating client certificate signed by root CA with expected CN CLIENT_ALIAS: $CLIENT_ALIAS CLIENT_CN: $CLIENT_CN${RESET}" - keytool \ - -certreq \ - -alias $CLIENT_ALIAS \ - -dname "CN=$CLIENT_CN, OU=$ORGANIZATIONAL_UNIT, O=$ORGANIZATION, L=$CITY, ST=$STATE_OR_PROVINCE, C=$TWO_LETTER_COUNTRY_CODE" \ - -keystore $CLIENT_STORE \ - -storepass $CLIENT_STORE_PWD | - keytool \ - -gencert \ - -alias $ROOT_KEY_ALIAS \ - -keystore $SERVER_STORE \ - -storepass $SERVER_STORE_PWD \ - -storetype $STORETYPE \ - -validity $VALIDITY | - keytool \ - -importcert \ - -alias $CLIENT_ALIAS \ - -keystore $CLIENT_STORE \ - -storepass $CLIENT_STORE_PWD \ - -noprompt -} - -if [ "$client_start" -lt "$client_finish" ]; then - - echo - echo "==Start Client==" - while [ "$CLIENT_NUMBER" -lt "$client_finish" ]; do - echo "number $CLIENT_NUMBER" - echo "finish $client_finish" - CLIENT_CN=$(end_point) - CLIENT_ALIAS=$(client_alias_point) - CLIENT_SELF_ALIAS=$(client_self_alias_point) - echo "CLIENT_CN $CLIENT_CN" - echo "CLIENT_ALIAS $CLIENT_ALIAS" - echo "CLIENT_SELF_ALIAS $CLIENT_SELF_ALIAS" - cert_end_point - CLIENT_NUMBER=$(($CLIENT_NUMBER + 1)) - echo - done -fi - -echo -echo "${H0}!!! Warning ${H2}Migrate ${H1}${SERVER_STORE} ${H2}to ${H1}PKCS12 ${H2}which is an industry standard format..${RESET}" -keytool \ - -importkeystore \ - -srckeystore $SERVER_STORE \ - -destkeystore $SERVER_STORE \ - -deststoretype pkcs12 \ - -srcstorepass $SERVER_STORE_PWD - -if [ "$client_start" -lt "$client_finish" ]; then - echo - echo "${H0}!!! Warning ${H2}Migrate ${H1}${CLIENT_STORE} ${H2}to ${H1}PKCS12 ${H2}which is an industry standard format..${RESET}" - keytool \ - -importkeystore \ - -srckeystore $CLIENT_STORE \ - -destkeystore $CLIENT_STORE \ - -deststoretype pkcs12 \ - -srcstorepass $CLIENT_STORE_PWD -fi diff --git a/transport/lwm2m/src/main/data/credentials/shell/lwM2M_keygen.properties b/transport/lwm2m/src/main/data/credentials/shell/lwM2M_keygen.properties deleted file mode 100644 index 7b3cd9c09a..0000000000 --- a/transport/lwm2m/src/main/data/credentials/shell/lwM2M_keygen.properties +++ /dev/null @@ -1,57 +0,0 @@ -# -# Copyright © 2016-2017 The Thingsboard Authors -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# Keystore common parameters -ROOT_KEY_ALIAS=rootCA -DOMAIN_SUFFIX="$(hostname)" -ROOT_CN="$DOMAIN_SUFFIX $ROOT_KEY_ALIAS" -ORGANIZATIONAL_UNIT=Thingsboard -ORGANIZATION=Thingsboard -CITY=SF -STATE_OR_PROVINCE=CA -TWO_LETTER_COUNTRY_CODE=US -VALIDITY=36500 #days -STORETYPE="JKS" - -#Server -SERVER_STORE=serverKeyStore1.jks -SERVER_STORE_PWD=server_ks_password1 -SERVER_ALIAS=server1 -SERVER_CN="$DOMAIN_SUFFIX server LwM2M signed by root CA" -SERVER_SELF_ALIAS=server_self_signed -SERVER_SELF_CN="$DOMAIN_SUFFIX server LwM2M self-signed" -BOOTSTRAP_ALIAS=bootstrap1 -BOOTSTRAP_CN="$DOMAIN_SUFFIX bootstrap server LwM2M signed by root CA" -BOOTSTRAP_SELF_ALIAS=bootstrap_self_signed -BOOTSTRAP_SELF_CN="$DOMAIN_SUFFIX bootstrap server LwM2M self-signed" - -# Client -CLIENT_STORE=clientKeyStore1.jks -CLIENT_STORE_PWD=client_ks_password1 -CLIENT_ALIAS_PREFIX=client_alias_1 -CLIENT_PREFIX=LwX509___ -CLIENT_SELF_ALIAS_PREFIX=client_self_signed_1 -CLIENT_SELF_CN="$DOMAIN_SUFFIX client LwM2M self-signed" - -# Color output stuff -red=`tput setaf 1` -green=`tput setaf 2` -blue=`tput setaf 4` -bold=`tput bold` -H0=${red}${bold} -H1=${green}${bold} -H2=${blue} -RESET=`tput sgr0` diff --git a/transport/lwm2m/src/main/data/lwm2mserver.jks b/transport/lwm2m/src/main/data/lwm2mserver.jks deleted file mode 100644 index 301f4e2c3ab90931eb166859e71b2c443fa35660..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4017 zcma)*cQ738_Qu!hy+@5+mMFVci!OQ(Ru@88A)>4{pTw>8WLbx+&DOH1S~;8^DpsgG!GdY z>bxuFM@5tx2x4L$wo`v?YwdnIkQ6X<3iSJ|Xw;7&h--}qD$ zQ~2h9rQ~C23WDC>R1dZ5-ZZitUSa*UVY?J?FQn)=DZ1bwV4jy&98YXFo`uT>Io>i1 z3)bUUT$kWc>@XsSD>Mpld78KRDiWj)AzEObfB&1B4Z^@j2M7Xq0uX@Ezn@^i|CsC$ zHZm5N_d`zsh$2+^svruGo63q;cm)4nczUunqrQImX*6B#lqu8qaZx2&NBUoQnpzT{ z-sg^6Qsr2=Uz8f6Hy7&}cb#9X=F3nr{zyQ;%^h3LNgpuLrc7`l{Zsya!l`kr4J6TA zJ-$L;vibOtt;~DgpO5CW52{#RcH;YqQ;Q68a46L^wU``h_$SWQ+3La@*c+mv`CK6$ zr#!DI)B(uX_C+$_X|G*X-PnQ=x5lT6yW!n#(8+V>*kP$YbbGW2M zY`JSn1!lPnC%rz0KXj$tiHaZ-rCQ6K3a2KSu>qUi-?4lMG-H^q^2+gIc@h~ZEj;5H`o}^6#-c!3Pld4t8f=Q+ml`~WoEwEH!t8EYG zH{SLO_bm9+D)v&KvU3mdwW}#E-6dOnDz zf}M_Ghpm(G@WUsZ=d@VYiE(uzQH8-;7{^&@bMAL~!tp*h$B=_lam1IWlZOjB))1g5 zCituA$^0$PT%y8q@9g1s>O3Xa9WmC{zWO7Lpi?4uWpTwTlGV$)rrIa72(oQPr~Zl? z88;ON{d!^<1C3a6h?_2k>^xeVZAc$r0hW8kgtVWYYK3*;V}DnGLC37Pj;LnMxh~Bs z8OwuKh^{xsN{`KLI_+Z2M9jqo546(N68BPbHr&-c;jmElOLuXJH);8UfDTiXx-k>S zgX5MPGR(+UVIiXs9K*9A;l27EdV%rnrvNAEg=I!qSzB!sEq$cA=pDp)YKHEU4d%_H z=kaTCRfbfYJH|80Iv*d?$ zvPqfyhU~s{{G>`jY2qn>To&%TP_FLv5kkn*I*UUM>yaf5k^2E{(aRbdzGm%Bpo*y>=F%-bmOhqj{1& zniV=XQj}IPk4@Ksn}3D;^&$g+7i@UOLeS^-{B@)n=lL9_=R5?bxlTu7>(s8(ZfRqh z7B1>cn)Y5{4^)BciAl{&u&zGOM~6!$N1yzayJ0F%__4fiDOT2FafWI9@*prZ6vSuU z&1i{Dky3n`T7F+oVLgncYcj|pY;3frI_uBc&qpzy~wK$+`g^>knAZ7Sq-L1mb9%|^7NLsI59H!oU<9fMka z7bf{wl_4z1@}ggjb>zMHgSr$9T_~clx3BB|Tfy}rH_!+Nt=rH7UV+;?>Sd?I%{R&E z%2pFClVKJz1N0fLstR5<*9tndby?cyZOn`Ye3ZYP%=tdIhF;E)N%ND7A=?FMx@KTz z;7@>(AvEL%Aw7?um8kn?mYZLflKl06Mtxs#3V+1OodlxFU68(g>auTu^Dy^Gnh?^N zKZAaDushoHe0MZXNld_Q3>^d`F7@pNkOWkBgSxu2^LCy0w`F697PK4_sOs4Y{3IX+?=-|<<<%E}x41@6qpZ^fnM*EQlQ4|dU| zlI|#ywY>%oe`k%Pl+Dh9AX5UxO+*UJ+Ju6y}u9P;qnzkm_i z*?R!4Z-*I*9S{H5Sl_7)%-vU;H#|+OX50(+<>z8u1U);E-F?TMv;Fy1g5v?xSd&gJ z5s{Sb(bBq;(sJklwrDWv_f) zu^7y1;C?zLwU#7bP=w3jnU9-@Q%mGI=%5UJ&RK!xJoNbSKH0H4XxCd})9??#JR#k2 zRXem*o7YDBHZDpDedj!xK>G|F&7Z10n{0D=L0UAVg6z%z8D%*&3Vth-p{mz+O`mon z`3M~cmFFu8kS6kNY30n7*OdevPn><+8|}4rnv1oAI8c&`HsGeki#S9~Qs@ctgIZYHU|~TA%?^At1ut1<21KzVq_yK%z+G-4U)x7Vz**?xn!`grLZ@Ut;8{c|WrT zY(9Twipqj%f2*V%^Kg2UTX%hNT3rS9cp*Vw-J$v11LSPp%fryPQaJT+?AxF$JTmkp zpN#RHE~pKYdy7FGW7JzmRTQS>WOW|$SY?T(0Vzcs;_sm)zk`Kbi<4O|LudGZK+Hc_ z6`0KF7qiGh2gve12#=sDsdC-;#0c!;)z2@NYwIG<;Y;`X?P&9g-l07qQ|E`kM<+9x z+nEjC(iZM65xY8c{VjHQ$3!vwAsTbUEaJw^)>8cQPy1Tba437A1Z>ZmEZh9>2+=#H zblrrGPzvZ~t#DCG+kcbJyZ*sm2_f$})7HxDF>{P_t}Wo2C=}TJU<0Iyu>D{@Z3fh6 zJ68Hjx5uJ-7?xs?Uuz%`(vRWr+m#NkBnFxm;N*6C;x4J0RUD;?n!QKAp=RI@k|r;! z=H5wg77q!VX1FK0CFZPM2(ZOIeDdRxj-y4>7JMAL7`9mMwKo}LV4)*JNTWjI&yRSa#`%`u&SNfBJ5<6ztqPz)H9ryOd6_Bv5bm@?SBnk zj_r0RJt*yS8cp9_drSa*@G-6}7@u83*VxA@x3H7#W=3s{i%f!d?|=()Wgp+X97#<^LzVF z8Jv3@vE_LA2yg8EtGI)q+-uhEg`U)bE`268udc>ru@#^s0jP>0WH5r3tDPg5fQ?4= z_Dp2=}z<1T1{g*SkZhM_Ynq*M_;FdNyJF`X1DfVniDgqzIZE^X^ zW|xLuc{_r3cb)QhxPd>X-p+VOkwhQ!d7H(U-=*&~@FiRn)j`Wp-e6_Njng|1l7Cmf zQq}esujWhJVy3!b?B_4C^euiYaywH+tBj!)?Qdl7SQv=y>_EcmJ&)($gmS8lwXvXXnBU0hY!f3rs1Kk4VL{xhN7-_^U7 ziS=#Fk-*Ot5>0#Nqv6LeL(!#83lJzV08ae$*bX*!|nv*>3 z=G#*9O-@G#2C6nOBj4hH?Dl`%$iZoh{#Y&xfFPhqW+k3M_IXrI3oaocSKRFWZ48&e z1ZF?e)aW?oSD;nBE!0&ndh(`SvnE%}cIE6eY5haknFsHI#}>Lxl)-+j|0j(x6%#ww zX;i+8$yhsDE`OK%EdfNNRnveab@tsFax#quNg1mg3X%xO39-H~+^4HR7KLeL_AeE- zo=s7%WHm)ZDM`qx^CTN?nR-~^OX`|YGRYzgDr^I-;!v#+=p~&P@wwZ@C(_9zF6DX)N{0 zJU_iwMEeAHvLLppJJ%uXjZ|$+SoBkh|EV^;wrbfB$tCi6M0YGNb5~Mm@r3t(a~*?AFgmX=Ec24(s2jDV+%@RaAPyFy~}iN@3#Yk zSQAn2Eye4=@)8LbHp9>Ho9|ONV;KkDs|r4u(wn&c{1N<4;}DgmuLy*^G>)Zmsy{G5 z_E>DP#=Z;B*jyfhFwOQ))L@To{KT21_+jA^tN|7TQ&W)NU?2r@lLN@uB*ok-_9H)F sw$v0r^7aQ>K?WP?WNbchVoVQMhCamwb{7rH3S-Ph2>d`&lEkvV0juF-*#H0l diff --git a/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml b/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml index 631968ad35..d7513bdf1f 100644 --- a/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml +++ b/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml @@ -114,7 +114,7 @@ transport: # Server X509 Certificates support credentials: # Whether to enable LWM2M server X509 Certificate/RPK support - enabled: "${LWM2M_SERVER_CREDENTIALS_ENABLED:true}" + enabled: "${LWM2M_SERVER_CREDENTIALS_ENABLED:false}" # Server credentials type (PEM - pem certificate file; KEYSTORE - java keystore) type: "${LWM2M_SERVER_CREDENTIALS_TYPE:PEM}" # PEM server credentials @@ -150,7 +150,7 @@ transport: # Bootstrap server X509 Certificates support credentials: # Whether to enable LWM2M bootstrap server X509 Certificate/RPK support - enabled: "${LWM2M_BS_CREDENTIALS_ENABLED:true}" + enabled: "${LWM2M_BS_CREDENTIALS_ENABLED:false}" # Server credentials type (PEM - pem certificate file; KEYSTORE - java keystore) type: "${LWM2M_BS_CREDENTIALS_TYPE:PEM}" # PEM server credentials @@ -177,19 +177,19 @@ transport: # X509 trust certificates trust-credentials: # Whether to load X509 trust certificates - enabled: "${LWM2M_TRUST_CREDENTIALS_ENABLED:true}" + enabled: "${LWM2M_TRUST_CREDENTIALS_ENABLED:false}" # Trust certificates store type (PEM - pem certificates file; KEYSTORE - java keystore) type: "${LWM2M_TRUST_CREDENTIALS_TYPE:PEM}" # PEM certificates pem: # Path to the certificates file (holds trust certificates) - cert_file: "${LWM2M_TRUST_PEM_CERT:lwm2mserver.pem}" + cert_file: "${LWM2M_TRUST_PEM_CERT:lwm2mtruststorechain.pem}" # Keystore with trust certificates keystore: # Type of the key store type: "${LWM2M_TRUST_KEY_STORE_TYPE:JKS}" # Path to the key store that holds the X509 certificates - store_file: "${LWM2M_TRUST_KEY_STORE:lwm2mserver.jks}" + store_file: "${LWM2M_TRUST_KEY_STORE:lwm2mtruststorechain.jks}" # Password used to access the key store store_password: "${LWM2M_TRUST_KEY_STORE_PASSWORD:server_ks_password}" recommended_ciphers: "${LWM2M_RECOMMENDED_CIPHERS:false}" From ff56e0e6220e349515f929159503f49e3695ef9f Mon Sep 17 00:00:00 2001 From: van-vanich Date: Thu, 30 Dec 2021 17:48:51 +0200 Subject: [PATCH 324/432] realize solve problems for issue for with saving last ts --- .../rule/engine/telemetry/TbMsgTimeseriesNode.java | 4 ++-- .../engine/telemetry/TbMsgTimeseriesNodeConfiguration.java | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbMsgTimeseriesNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbMsgTimeseriesNode.java index 1d52b7cdfa..711b7c1558 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbMsgTimeseriesNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbMsgTimeseriesNode.java @@ -49,7 +49,7 @@ import java.util.concurrent.TimeUnit; "Timestamp in milliseconds will be taken from metadata.ts, otherwise 'now' timestamp will be applied. " + "Allows stopping updating values for incoming keys in the latest ts_kv table if 'skipLatestPersistence' is set to true.", uiResources = {"static/rulenode/rulenode-core-config.js"}, - configDirective = "tbActionNodeTimeseriesConfig", + configDirective = "tbActionNodeTimeseriesConfig!", icon = "file_upload" ) public class TbMsgTimeseriesNode implements TbNode { @@ -77,7 +77,7 @@ public class TbMsgTimeseriesNode implements TbNode { ctx.tellFailure(msg, new IllegalArgumentException("Unsupported msg type: " + msg.getType())); return; } - long ts = getTs(msg); + long ts = config.isSaveWithMsgTs() ? msg.getTs() : getTs(msg); String src = msg.getData(); Map> tsKvMap = JsonConverter.convertToTelemetry(new JsonParser().parse(src), ts); if (tsKvMap.isEmpty()) { diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbMsgTimeseriesNodeConfiguration.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbMsgTimeseriesNodeConfiguration.java index bb661df905..89abac99fe 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbMsgTimeseriesNodeConfiguration.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbMsgTimeseriesNodeConfiguration.java @@ -23,12 +23,14 @@ public class TbMsgTimeseriesNodeConfiguration implements NodeConfiguration Date: Fri, 31 Dec 2021 13:20:40 +0200 Subject: [PATCH 325/432] UI: Fixed help link for OTA updates --- ui-ngx/src/app/shared/models/constants.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui-ngx/src/app/shared/models/constants.ts b/ui-ngx/src/app/shared/models/constants.ts index 9bf120f8b7..9b1b110a84 100644 --- a/ui-ngx/src/app/shared/models/constants.ts +++ b/ui-ngx/src/app/shared/models/constants.ts @@ -124,7 +124,7 @@ export const HelpLinks = { rulechains: helpBaseUrl + '/docs/user-guide/ui/rule-chains', resources: helpBaseUrl + '/docs/user-guide/ui/resources', dashboards: helpBaseUrl + '/docs/user-guide/ui/dashboards', - otaUpdates: helpBaseUrl + '/docs/user-guide/ui/ota-updates', + otaUpdates: helpBaseUrl + '/docs/user-guide/ota-updates', widgetsBundles: helpBaseUrl + '/docs/user-guide/ui/widget-library#bundles', widgetsConfig: helpBaseUrl + '/docs/user-guide/ui/dashboards#widget-configuration', widgetsConfigTimeseries: helpBaseUrl + '/docs/user-guide/ui/dashboards#timeseries', From 8ec7fd5de8ce0777f15ab9d4ad461e868aaeb50e Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Mon, 3 Jan 2022 15:38:40 +0200 Subject: [PATCH 326/432] Removed unused relation dao code --- .../dao/sql/relation/JpaRelationDao.java | 25 ------------------- 1 file changed, 25 deletions(-) diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/relation/JpaRelationDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/relation/JpaRelationDao.java index fbedef6c4e..a7a1ca6a27 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/relation/JpaRelationDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/relation/JpaRelationDao.java @@ -203,29 +203,4 @@ public class JpaRelationDao extends JpaAbstractDaoListeningExecutorService imple public List findRuleNodeToRuleChainRelations(RuleChainType ruleChainType, int limit) { return DaoUtil.convertDataList(relationRepository.findRuleNodeToRuleChainRelations(ruleChainType, PageRequest.of(0, limit))); } - - private Specification getEntityFieldsSpec(EntityId from, String relationType, RelationTypeGroup typeGroup, EntityType childType) { - return (root, criteriaQuery, criteriaBuilder) -> { - List predicates = new ArrayList<>(); - if (from != null) { - Predicate fromIdPredicate = criteriaBuilder.equal(root.get("fromId"), from.getId()); - predicates.add(fromIdPredicate); - Predicate fromEntityTypePredicate = criteriaBuilder.equal(root.get("fromType"), from.getEntityType().name()); - predicates.add(fromEntityTypePredicate); - } - if (relationType != null) { - Predicate relationTypePredicate = criteriaBuilder.equal(root.get("relationType"), relationType); - predicates.add(relationTypePredicate); - } - if (typeGroup != null) { - Predicate typeGroupPredicate = criteriaBuilder.equal(root.get("relationTypeGroup"), typeGroup.name()); - predicates.add(typeGroupPredicate); - } - if (childType != null) { - Predicate childTypePredicate = criteriaBuilder.equal(root.get("toType"), childType.name()); - predicates.add(childTypePredicate); - } - return criteriaBuilder.and(predicates.toArray(new Predicate[0])); - }; - } } From b9e6c2b75e28b6259405a2180dbfc18b4efbe49d Mon Sep 17 00:00:00 2001 From: Swoq Date: Fri, 29 Oct 2021 15:28:07 +0300 Subject: [PATCH 327/432] Event clearing --- .../server/controller/EventController.java | 33 +++++++++++++++++ .../server/dao/event/EventService.java | 1 + .../server/dao/event/BaseEventService.java | 37 ++++++++++++++----- 3 files changed, 61 insertions(+), 10 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/EventController.java b/application/src/main/java/org/thingsboard/server/controller/EventController.java index d1e9ad8efc..8547126643 100644 --- a/application/src/main/java/org/thingsboard/server/controller/EventController.java +++ b/application/src/main/java/org/thingsboard/server/controller/EventController.java @@ -18,6 +18,7 @@ package org.thingsboard.server.controller; import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiParam; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.PathVariable; @@ -26,6 +27,7 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestController; import org.thingsboard.server.common.data.Event; import org.thingsboard.server.common.data.event.EventFilter; @@ -238,4 +240,35 @@ public class EventController extends BaseController { } } + @ApiOperation(value = "Clear Events (clearEvents)", notes = "Clears events for specified entity.") + @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") + @RequestMapping(value = "/events/{entityType}/{entityId}/{eventType}/clear", method = RequestMethod.DELETE) + @ResponseStatus(HttpStatus.OK) + public void clearEvents( + @ApiParam(value = ENTITY_TYPE_PARAM_DESCRIPTION, required = true) + @PathVariable(ENTITY_TYPE) String strEntityType, + @ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION, required = true) + @PathVariable(ENTITY_ID) String strEntityId, + @ApiParam(value = TENANT_ID_PARAM_DESCRIPTION, required = true) + @RequestParam("tenantId") String strTenantId, + @ApiParam(value = "A string value representing event type", example = "STATS", required = true) + @PathVariable("eventType") String eventType, + @ApiParam(value = EVENT_START_TIME_DESCRIPTION) + @RequestParam(required = false) Long startTime, + @ApiParam(value = EVENT_END_TIME_DESCRIPTION) + @RequestParam(required = false) Long endTime) throws ThingsboardException { + checkParameter("EntityId", strEntityId); + checkParameter("EntityType", strEntityType); + try { + TenantId tenantId = new TenantId(toUUID(strTenantId)); + + EntityId entityId = EntityIdFactory.getByTypeAndId(strEntityType, strEntityId); + checkEntityId(entityId, Operation.DELETE); + + eventService.removeEventsByTypeInPeriod(tenantId, entityId, eventType, startTime, endTime); + } catch (Exception e) { + throw handleException(e); + } + } + } diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/event/EventService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/event/EventService.java index db1c77697e..973b5ad3cc 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/event/EventService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/event/EventService.java @@ -48,4 +48,5 @@ public interface EventService { void cleanupEvents(long ttl, long debugTtl); + void removeEventsByTypeInPeriod(TenantId tenantId, EntityId entityId, String eventType, Long startTime, Long endTime); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/event/BaseEventService.java b/dao/src/main/java/org/thingsboard/server/dao/event/BaseEventService.java index 2785df90df..a8888a230c 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/event/BaseEventService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/event/BaseEventService.java @@ -25,14 +25,18 @@ import org.springframework.stereotype.Service; import org.thingsboard.server.common.data.Event; import org.thingsboard.server.common.data.event.EventFilter; import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.id.IdBased; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.TimePageLink; import org.thingsboard.server.dao.exception.DataValidationException; import org.thingsboard.server.dao.service.DataValidator; +import java.sql.Time; import java.util.List; import java.util.Optional; +import java.util.UUID; +import java.util.stream.Collectors; @Service @Slf4j @@ -118,17 +122,8 @@ public class BaseEventService implements EventService { @Override public void removeEvents(TenantId tenantId, EntityId entityId) { - PageData eventPageData; TimePageLink eventPageLink = new TimePageLink(1000); - do { - eventPageData = findEvents(tenantId, entityId, eventPageLink); - for (Event event : eventPageData.getData()) { - eventDao.removeById(tenantId, event.getUuidId()); - } - if (eventPageData.hasNext()) { - eventPageLink = eventPageLink.nextPageLink(); - } - } while (eventPageData.hasNext()); + removeEventsByTypeAndPageLink(tenantId, entityId, null, eventPageLink); } @Override @@ -136,6 +131,28 @@ public class BaseEventService implements EventService { eventDao.cleanupEvents(ttl, debugTtl); } + @Override + public void removeEventsByTypeInPeriod(TenantId tenantId, EntityId entityId, String eventType, Long startTime, Long endTime) { + TimePageLink eventPageLink = + new TimePageLink(1000, 0, null, null, startTime, endTime); + removeEventsByTypeAndPageLink(tenantId, entityId, eventType, eventPageLink); + } + + private void removeEventsByTypeAndPageLink(TenantId tenantId, EntityId entityId, String eventType, TimePageLink eventPageLink) { + PageData eventPageData; + do { + if (eventType == null) + eventPageData = findEvents(tenantId, entityId, eventPageLink); + else + eventPageData = findEvents(tenantId, entityId, eventType, eventPageLink); + List eventsIds = eventPageData.getData().stream().map(IdBased::getUuidId).collect(Collectors.toList()); + eventDao.removeAllByIds(eventsIds); + if (eventPageData.hasNext()) { + eventPageLink = eventPageLink.nextPageLink(); + } + } while (eventPageData.hasNext()); + } + private DataValidator eventValidator = new DataValidator() { @Override From 144da0367aa76b703e29f9cf038d83c7ea160235 Mon Sep 17 00:00:00 2001 From: Viacheslav Klimov Date: Fri, 29 Oct 2021 16:52:19 +0300 Subject: [PATCH 328/432] Refactor events clearing --- .../server/controller/EventController.java | 2 +- .../server/dao/event/EventService.java | 3 +- .../server/dao/event/BaseEventService.java | 45 +++++++++---------- 3 files changed, 24 insertions(+), 26 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/EventController.java b/application/src/main/java/org/thingsboard/server/controller/EventController.java index 8547126643..ea8dda9673 100644 --- a/application/src/main/java/org/thingsboard/server/controller/EventController.java +++ b/application/src/main/java/org/thingsboard/server/controller/EventController.java @@ -265,7 +265,7 @@ public class EventController extends BaseController { EntityId entityId = EntityIdFactory.getByTypeAndId(strEntityType, strEntityId); checkEntityId(entityId, Operation.DELETE); - eventService.removeEventsByTypeInPeriod(tenantId, entityId, eventType, startTime, endTime); + eventService.removeEvents(tenantId, entityId, eventType, startTime, endTime); } catch (Exception e) { throw handleException(e); } diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/event/EventService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/event/EventService.java index 973b5ad3cc..3591627c51 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/event/EventService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/event/EventService.java @@ -46,7 +46,8 @@ public interface EventService { void removeEvents(TenantId tenantId, EntityId entityId); + void removeEvents(TenantId tenantId, EntityId entityId, String eventType, Long startTime, Long endTime); + void cleanupEvents(long ttl, long debugTtl); - void removeEventsByTypeInPeriod(TenantId tenantId, EntityId entityId, String eventType, Long startTime, Long endTime); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/event/BaseEventService.java b/dao/src/main/java/org/thingsboard/server/dao/event/BaseEventService.java index a8888a230c..5e0cba7f5e 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/event/BaseEventService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/event/BaseEventService.java @@ -32,7 +32,6 @@ import org.thingsboard.server.common.data.page.TimePageLink; import org.thingsboard.server.dao.exception.DataValidationException; import org.thingsboard.server.dao.service.DataValidator; -import java.sql.Time; import java.util.List; import java.util.Optional; import java.util.UUID; @@ -122,35 +121,33 @@ public class BaseEventService implements EventService { @Override public void removeEvents(TenantId tenantId, EntityId entityId) { - TimePageLink eventPageLink = new TimePageLink(1000); - removeEventsByTypeAndPageLink(tenantId, entityId, null, eventPageLink); + removeEvents(tenantId, entityId, null, null, null); } @Override - public void cleanupEvents(long ttl, long debugTtl) { - eventDao.cleanupEvents(ttl, debugTtl); - } + public void removeEvents(TenantId tenantId, EntityId entityId, String eventType, Long startTime, Long endTime) { + TimePageLink eventsPageLink = new TimePageLink(1000, 0, null, null, startTime, endTime); + PageData eventsPageData; + do { + if (eventType == null) { + eventsPageData = findEvents(tenantId, entityId, eventsPageLink); + } else { + eventsPageData = findEvents(tenantId, entityId, eventType, eventsPageLink); + } - @Override - public void removeEventsByTypeInPeriod(TenantId tenantId, EntityId entityId, String eventType, Long startTime, Long endTime) { - TimePageLink eventPageLink = - new TimePageLink(1000, 0, null, null, startTime, endTime); - removeEventsByTypeAndPageLink(tenantId, entityId, eventType, eventPageLink); - } + eventDao.removeAllByIds(eventsPageData.getData().stream() + .map(IdBased::getUuidId) + .collect(Collectors.toList())); - private void removeEventsByTypeAndPageLink(TenantId tenantId, EntityId entityId, String eventType, TimePageLink eventPageLink) { - PageData eventPageData; - do { - if (eventType == null) - eventPageData = findEvents(tenantId, entityId, eventPageLink); - else - eventPageData = findEvents(tenantId, entityId, eventType, eventPageLink); - List eventsIds = eventPageData.getData().stream().map(IdBased::getUuidId).collect(Collectors.toList()); - eventDao.removeAllByIds(eventsIds); - if (eventPageData.hasNext()) { - eventPageLink = eventPageLink.nextPageLink(); + if (eventsPageData.hasNext()) { + eventsPageLink = eventsPageLink.nextPageLink(); } - } while (eventPageData.hasNext()); + } while (eventsPageData.hasNext()); + } + + @Override + public void cleanupEvents(long ttl, long debugTtl) { + eventDao.cleanupEvents(ttl, debugTtl); } private DataValidator eventValidator = From c3d86624ed1663241b5647d45bef3b3b352da899 Mon Sep 17 00:00:00 2001 From: Kalutka Zhenya Date: Fri, 5 Nov 2021 17:29:46 +0200 Subject: [PATCH 329/432] Added 'clean' button for rule-node events --- .../components/entity/entities-table.component.html | 2 +- .../home/components/event/event-table-config.ts | 12 +++++++++++- .../home/components/event/event-table.component.ts | 7 +++++-- .../models/entity/entities-table-config.models.ts | 2 +- ui-ngx/src/assets/locale/locale.constant-en_US.json | 1 + 5 files changed, 19 insertions(+), 5 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/entity/entities-table.component.html b/ui-ngx/src/app/modules/home/components/entity/entities-table.component.html index c4f470bbd2..3242bb5a53 100644 --- a/ui-ngx/src/app/modules/home/components/entity/entities-table.component.html +++ b/ui-ngx/src/app/modules/home/components/entity/entities-table.component.html @@ -84,7 +84,7 @@ [fxShow]="actionDescriptor.isEnabled()" *ngFor="let actionDescriptor of headerActionDescriptors" matTooltip="{{ actionDescriptor.name }}" matTooltipPosition="above" - (click)="actionDescriptor.onAction($event)"> + (click)="actionDescriptor.onAction($event, entitiesTableConfig)"> {{actionDescriptor.icon}} diff --git a/ui-ngx/src/app/modules/home/components/event/event-table-config.ts b/ui-ngx/src/app/modules/home/components/event/event-table-config.ts index 9bf6912c9f..2d5cfbb428 100644 --- a/ui-ngx/src/app/modules/home/components/event/event-table-config.ts +++ b/ui-ngx/src/app/modules/home/components/event/event-table-config.ts @@ -48,6 +48,7 @@ import { EventFilterPanelData, FilterEntityColumn } from '@home/components/event/event-filter-panel.component'; +import { HttpClient } from '@angular/common/http'; export class EventTableConfig extends EntityTableConfig { @@ -82,7 +83,8 @@ export class EventTableConfig extends EntityTableConfig { private debugEventTypes: Array = null, private overlay: Overlay, private viewContainerRef: ViewContainerRef, - private cd: ChangeDetectorRef) { + private cd: ChangeDetectorRef, + private http: HttpClient) { super(); this.loadDataOnInit = false; this.tableTitle = ''; @@ -135,6 +137,14 @@ export class EventTableConfig extends EntityTableConfig { onAction: ($event) => { this.editEventFilter($event); } + }, + { + name: this.translate.instant('event.clean-events'), + icon: 'delete', + isEnabled: () => true, + onAction: ($event, entity) => { + this.http.delete(`/events/${entity.entityId.entityType}/${entity.entityId.id}/${entity.eventTypeValue}/clear`).subscribe(); + } }); } diff --git a/ui-ngx/src/app/modules/home/components/event/event-table.component.ts b/ui-ngx/src/app/modules/home/components/event/event-table.component.ts index 00aeb4f50c..e875036562 100644 --- a/ui-ngx/src/app/modules/home/components/event/event-table.component.ts +++ b/ui-ngx/src/app/modules/home/components/event/event-table.component.ts @@ -25,6 +25,7 @@ import { EventService } from '@core/http/event.service'; import { DialogService } from '@core/services/dialog.service'; import { DebugEventType, EventType } from '@shared/models/event.models'; import { Overlay } from '@angular/cdk/overlay'; +import { HttpClient } from '@angular/common/http'; @Component({ selector: 'tb-event-table', @@ -84,7 +85,8 @@ export class EventTableComponent implements OnInit { private dialog: MatDialog, private overlay: Overlay, private viewContainerRef: ViewContainerRef, - private cd: ChangeDetectorRef) { + private cd: ChangeDetectorRef, + private http: HttpClient) { } ngOnInit() { @@ -102,7 +104,8 @@ export class EventTableComponent implements OnInit { this.debugEventTypes, this.overlay, this.viewContainerRef, - this.cd + this.cd, + this.http ); } diff --git a/ui-ngx/src/app/modules/home/models/entity/entities-table-config.models.ts b/ui-ngx/src/app/modules/home/models/entity/entities-table-config.models.ts index 2f3d58e61f..c86ae6fef8 100644 --- a/ui-ngx/src/app/modules/home/models/entity/entities-table-config.models.ts +++ b/ui-ngx/src/app/modules/home/models/entity/entities-table-config.models.ts @@ -75,7 +75,7 @@ export interface HeaderActionDescriptor { icon: string; isMdiIcon?: boolean; isEnabled: () => boolean; - onAction: ($event: MouseEvent) => void; + onAction: ($event: MouseEvent, entity?) => void; } export type EntityTableColumnType = 'content' | 'action'; diff --git a/ui-ngx/src/assets/locale/locale.constant-en_US.json b/ui-ngx/src/assets/locale/locale.constant-en_US.json index 5d3adba457..f4a868a5c9 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -1853,6 +1853,7 @@ "event": { "event-type": "Event type", "events-filter": "Events Filter", + "clean-events": "Clean Events", "type-error": "Error", "type-lc-event": "Lifecycle event", "type-stats": "Statistics", From 4d86a61580b7b3c253bdb45a1058e35392d6430c Mon Sep 17 00:00:00 2001 From: Viacheslav Klimov Date: Mon, 8 Nov 2021 12:39:44 +0200 Subject: [PATCH 330/432] Update event clearing API --- .../thingsboard/server/controller/EventController.java | 9 +++++---- ui-ngx/src/app/core/http/event.service.ts | 9 ++++++++- .../modules/home/components/event/event-table-config.ts | 6 ++---- .../home/components/event/event-table.component.ts | 3 +-- ui-ngx/src/assets/locale/locale.constant-en_US.json | 2 +- 5 files changed, 17 insertions(+), 12 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/EventController.java b/application/src/main/java/org/thingsboard/server/controller/EventController.java index ea8dda9673..28c922afda 100644 --- a/application/src/main/java/org/thingsboard/server/controller/EventController.java +++ b/application/src/main/java/org/thingsboard/server/controller/EventController.java @@ -242,7 +242,7 @@ public class EventController extends BaseController { @ApiOperation(value = "Clear Events (clearEvents)", notes = "Clears events for specified entity.") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") - @RequestMapping(value = "/events/{entityType}/{entityId}/{eventType}/clear", method = RequestMethod.DELETE) + @RequestMapping(value = "/events/{entityType}/{entityId}/{eventType}/clear", method = RequestMethod.POST) @ResponseStatus(HttpStatus.OK) public void clearEvents( @ApiParam(value = ENTITY_TYPE_PARAM_DESCRIPTION, required = true) @@ -250,13 +250,14 @@ public class EventController extends BaseController { @ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION, required = true) @PathVariable(ENTITY_ID) String strEntityId, @ApiParam(value = TENANT_ID_PARAM_DESCRIPTION, required = true) - @RequestParam("tenantId") String strTenantId, - @ApiParam(value = "A string value representing event type", example = "STATS", required = true) @PathVariable("eventType") String eventType, @ApiParam(value = EVENT_START_TIME_DESCRIPTION) + @RequestParam("tenantId") String strTenantId, + @ApiParam(value = "A string value representing event type", example = "STATS", required = true) @RequestParam(required = false) Long startTime, @ApiParam(value = EVENT_END_TIME_DESCRIPTION) - @RequestParam(required = false) Long endTime) throws ThingsboardException { + @RequestParam(required = false) Long endTime, + @RequestBody EventFilter eventFilter) throws ThingsboardException { checkParameter("EntityId", strEntityId); checkParameter("EntityType", strEntityType); try { diff --git a/ui-ngx/src/app/core/http/event.service.ts b/ui-ngx/src/app/core/http/event.service.ts index fd740d73a7..e54f760b00 100644 --- a/ui-ngx/src/app/core/http/event.service.ts +++ b/ui-ngx/src/app/core/http/event.service.ts @@ -44,5 +44,12 @@ export class EventService { return this.http.post>(`/api/events/${entityId.entityType}/${entityId.id}` + `${pageLink.toQuery()}&tenantId=${tenantId}`, {...filters, eventType}, defaultHttpOptionsFromConfig(config)); } - + + public clearEvents(entityId: EntityId, eventType: EventType | DebugEventType, filters: FilterEventBody, tenantId: string, + startTime?: number, endTime?: number, config?: RequestConfig) { + return this.http.post(`/api/events/${entityId.entityType}/${entityId.id}/${eventType}/clear&tenantId=${tenantId}` + + (startTime ? `&startTime=${startTime}` : ``) + (endTime ? `&endTime=${endTime}` : ``), {...filters, eventType}, + defaultHttpOptionsFromConfig(config)); + } + } diff --git a/ui-ngx/src/app/modules/home/components/event/event-table-config.ts b/ui-ngx/src/app/modules/home/components/event/event-table-config.ts index 2d5cfbb428..07d8bfb82f 100644 --- a/ui-ngx/src/app/modules/home/components/event/event-table-config.ts +++ b/ui-ngx/src/app/modules/home/components/event/event-table-config.ts @@ -48,7 +48,6 @@ import { EventFilterPanelData, FilterEntityColumn } from '@home/components/event/event-filter-panel.component'; -import { HttpClient } from '@angular/common/http'; export class EventTableConfig extends EntityTableConfig { @@ -83,8 +82,7 @@ export class EventTableConfig extends EntityTableConfig { private debugEventTypes: Array = null, private overlay: Overlay, private viewContainerRef: ViewContainerRef, - private cd: ChangeDetectorRef, - private http: HttpClient) { + private cd: ChangeDetectorRef) { super(); this.loadDataOnInit = false; this.tableTitle = ''; @@ -143,7 +141,7 @@ export class EventTableConfig extends EntityTableConfig { icon: 'delete', isEnabled: () => true, onAction: ($event, entity) => { - this.http.delete(`/events/${entity.entityId.entityType}/${entity.entityId.id}/${entity.eventTypeValue}/clear`).subscribe(); + this.eventService.clearEvents(entity.entityId, entity.eventType, entity.filterParams, entity.tenantId, , ).subscribe(); } }); } diff --git a/ui-ngx/src/app/modules/home/components/event/event-table.component.ts b/ui-ngx/src/app/modules/home/components/event/event-table.component.ts index e875036562..85bd4cf81a 100644 --- a/ui-ngx/src/app/modules/home/components/event/event-table.component.ts +++ b/ui-ngx/src/app/modules/home/components/event/event-table.component.ts @@ -104,8 +104,7 @@ export class EventTableComponent implements OnInit { this.debugEventTypes, this.overlay, this.viewContainerRef, - this.cd, - this.http + this.cd ); } diff --git a/ui-ngx/src/assets/locale/locale.constant-en_US.json b/ui-ngx/src/assets/locale/locale.constant-en_US.json index f4a868a5c9..fee65c086f 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -1853,7 +1853,7 @@ "event": { "event-type": "Event type", "events-filter": "Events Filter", - "clean-events": "Clean Events", + "clean-events": "Clear Events", "type-error": "Error", "type-lc-event": "Lifecycle event", "type-stats": "Statistics", From e718e31f639320bd4ca32e1df48a56739d6d3ff8 Mon Sep 17 00:00:00 2001 From: Kalutka Zhenya Date: Mon, 8 Nov 2021 13:24:55 +0200 Subject: [PATCH 331/432] Update clear Events request --- ui-ngx/src/app/core/http/event.service.ts | 5 ++--- .../home/components/entity/entities-table.component.html | 2 +- .../app/modules/home/components/event/event-table-config.ts | 4 ++-- .../home/models/entity/entities-table-config.models.ts | 2 +- 4 files changed, 6 insertions(+), 7 deletions(-) diff --git a/ui-ngx/src/app/core/http/event.service.ts b/ui-ngx/src/app/core/http/event.service.ts index e54f760b00..5a3ec9e51f 100644 --- a/ui-ngx/src/app/core/http/event.service.ts +++ b/ui-ngx/src/app/core/http/event.service.ts @@ -46,10 +46,9 @@ export class EventService { } public clearEvents(entityId: EntityId, eventType: EventType | DebugEventType, filters: FilterEventBody, tenantId: string, - startTime?: number, endTime?: number, config?: RequestConfig) { + pageLink: TimePageLink, config?: RequestConfig) { return this.http.post(`/api/events/${entityId.entityType}/${entityId.id}/${eventType}/clear&tenantId=${tenantId}` + - (startTime ? `&startTime=${startTime}` : ``) + (endTime ? `&endTime=${endTime}` : ``), {...filters, eventType}, + `${pageLink.toQuery()}`, {...filters, eventType}, defaultHttpOptionsFromConfig(config)); } - } diff --git a/ui-ngx/src/app/modules/home/components/entity/entities-table.component.html b/ui-ngx/src/app/modules/home/components/entity/entities-table.component.html index 3242bb5a53..b103c29df5 100644 --- a/ui-ngx/src/app/modules/home/components/entity/entities-table.component.html +++ b/ui-ngx/src/app/modules/home/components/entity/entities-table.component.html @@ -84,7 +84,7 @@ [fxShow]="actionDescriptor.isEnabled()" *ngFor="let actionDescriptor of headerActionDescriptors" matTooltip="{{ actionDescriptor.name }}" matTooltipPosition="above" - (click)="actionDescriptor.onAction($event, entitiesTableConfig)"> + (click)="actionDescriptor.onAction($event, entitiesTableConfig, pageLink)"> {{actionDescriptor.icon}} diff --git a/ui-ngx/src/app/modules/home/components/event/event-table-config.ts b/ui-ngx/src/app/modules/home/components/event/event-table-config.ts index 07d8bfb82f..8a5201dc3f 100644 --- a/ui-ngx/src/app/modules/home/components/event/event-table-config.ts +++ b/ui-ngx/src/app/modules/home/components/event/event-table-config.ts @@ -140,8 +140,8 @@ export class EventTableConfig extends EntityTableConfig { name: this.translate.instant('event.clean-events'), icon: 'delete', isEnabled: () => true, - onAction: ($event, entity) => { - this.eventService.clearEvents(entity.entityId, entity.eventType, entity.filterParams, entity.tenantId, , ).subscribe(); + onAction: ($event, entity, pageLink: TimePageLink) => { + this.eventService.clearEvents(entity.entityId, entity.eventType, entity.filterParams, entity.tenantId, pageLink).subscribe(); } }); } diff --git a/ui-ngx/src/app/modules/home/models/entity/entities-table-config.models.ts b/ui-ngx/src/app/modules/home/models/entity/entities-table-config.models.ts index c86ae6fef8..7a352e8f17 100644 --- a/ui-ngx/src/app/modules/home/models/entity/entities-table-config.models.ts +++ b/ui-ngx/src/app/modules/home/models/entity/entities-table-config.models.ts @@ -75,7 +75,7 @@ export interface HeaderActionDescriptor { icon: string; isMdiIcon?: boolean; isEnabled: () => boolean; - onAction: ($event: MouseEvent, entity?) => void; + onAction: ($event: MouseEvent, entity?, pageLink?) => void; } export type EntityTableColumnType = 'content' | 'action'; From 13a74c784ee50344eac515b169ac18d2493850d9 Mon Sep 17 00:00:00 2001 From: Viacheslav Klimov Date: Mon, 8 Nov 2021 14:19:44 +0200 Subject: [PATCH 332/432] Events clearing by filter --- .../server/controller/EventController.java | 6 +-- .../server/dao/event/EventService.java | 2 +- .../server/dao/event/BaseEventService.java | 7 ++- ui-ngx/src/app/core/http/event.service.ts | 5 ++- .../components/event/event-table-config.ts | 43 +++++++++++-------- 5 files changed, 33 insertions(+), 30 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/EventController.java b/application/src/main/java/org/thingsboard/server/controller/EventController.java index 28c922afda..5759ffcac4 100644 --- a/application/src/main/java/org/thingsboard/server/controller/EventController.java +++ b/application/src/main/java/org/thingsboard/server/controller/EventController.java @@ -242,15 +242,13 @@ public class EventController extends BaseController { @ApiOperation(value = "Clear Events (clearEvents)", notes = "Clears events for specified entity.") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") - @RequestMapping(value = "/events/{entityType}/{entityId}/{eventType}/clear", method = RequestMethod.POST) + @RequestMapping(value = "/events/{entityType}/{entityId}/clear", method = RequestMethod.POST) @ResponseStatus(HttpStatus.OK) public void clearEvents( @ApiParam(value = ENTITY_TYPE_PARAM_DESCRIPTION, required = true) @PathVariable(ENTITY_TYPE) String strEntityType, @ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION, required = true) @PathVariable(ENTITY_ID) String strEntityId, - @ApiParam(value = TENANT_ID_PARAM_DESCRIPTION, required = true) - @PathVariable("eventType") String eventType, @ApiParam(value = EVENT_START_TIME_DESCRIPTION) @RequestParam("tenantId") String strTenantId, @ApiParam(value = "A string value representing event type", example = "STATS", required = true) @@ -266,7 +264,7 @@ public class EventController extends BaseController { EntityId entityId = EntityIdFactory.getByTypeAndId(strEntityType, strEntityId); checkEntityId(entityId, Operation.DELETE); - eventService.removeEvents(tenantId, entityId, eventType, startTime, endTime); + eventService.removeEvents(tenantId, entityId, eventFilter, startTime, endTime); } catch (Exception e) { throw handleException(e); } diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/event/EventService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/event/EventService.java index 3591627c51..f43d17915e 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/event/EventService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/event/EventService.java @@ -46,7 +46,7 @@ public interface EventService { void removeEvents(TenantId tenantId, EntityId entityId); - void removeEvents(TenantId tenantId, EntityId entityId, String eventType, Long startTime, Long endTime); + void removeEvents(TenantId tenantId, EntityId entityId, EventFilter eventFilter, Long startTime, Long endTime); void cleanupEvents(long ttl, long debugTtl); diff --git a/dao/src/main/java/org/thingsboard/server/dao/event/BaseEventService.java b/dao/src/main/java/org/thingsboard/server/dao/event/BaseEventService.java index 5e0cba7f5e..0c9cede327 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/event/BaseEventService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/event/BaseEventService.java @@ -34,7 +34,6 @@ import org.thingsboard.server.dao.service.DataValidator; import java.util.List; import java.util.Optional; -import java.util.UUID; import java.util.stream.Collectors; @Service @@ -125,14 +124,14 @@ public class BaseEventService implements EventService { } @Override - public void removeEvents(TenantId tenantId, EntityId entityId, String eventType, Long startTime, Long endTime) { + public void removeEvents(TenantId tenantId, EntityId entityId, EventFilter eventFilter, Long startTime, Long endTime) { TimePageLink eventsPageLink = new TimePageLink(1000, 0, null, null, startTime, endTime); PageData eventsPageData; do { - if (eventType == null) { + if (eventFilter == null) { eventsPageData = findEvents(tenantId, entityId, eventsPageLink); } else { - eventsPageData = findEvents(tenantId, entityId, eventType, eventsPageLink); + eventsPageData = findEventsByFilter(tenantId, entityId, eventFilter, eventsPageLink); } eventDao.removeAllByIds(eventsPageData.getData().stream() diff --git a/ui-ngx/src/app/core/http/event.service.ts b/ui-ngx/src/app/core/http/event.service.ts index 5a3ec9e51f..df3466bc3e 100644 --- a/ui-ngx/src/app/core/http/event.service.ts +++ b/ui-ngx/src/app/core/http/event.service.ts @@ -47,8 +47,9 @@ export class EventService { public clearEvents(entityId: EntityId, eventType: EventType | DebugEventType, filters: FilterEventBody, tenantId: string, pageLink: TimePageLink, config?: RequestConfig) { - return this.http.post(`/api/events/${entityId.entityType}/${entityId.id}/${eventType}/clear&tenantId=${tenantId}` + - `${pageLink.toQuery()}`, {...filters, eventType}, + return this.http.post(`/api/events/${entityId.entityType}/${entityId.id}/clear?tenantId=${tenantId}` + + (pageLink.startTime ? `&startTime=${pageLink.startTime}` : ``) + + (pageLink.endTime ? `&endTime=${pageLink.endTime}` : ``), {...filters, eventType}, defaultHttpOptionsFromConfig(config)); } } diff --git a/ui-ngx/src/app/modules/home/components/event/event-table-config.ts b/ui-ngx/src/app/modules/home/components/event/event-table-config.ts index 8a5201dc3f..9cd905492c 100644 --- a/ui-ngx/src/app/modules/home/components/event/event-table-config.ts +++ b/ui-ngx/src/app/modules/home/components/event/event-table-config.ts @@ -20,28 +20,28 @@ import { EntityTableColumn, EntityTableConfig } from '@home/models/entity/entities-table-config.models'; -import { DebugEventType, Event, EventType, FilterEventBody } from '@shared/models/event.models'; -import { TimePageLink } from '@shared/models/page/page-link'; -import { TranslateService } from '@ngx-translate/core'; -import { DatePipe } from '@angular/common'; -import { MatDialog } from '@angular/material/dialog'; -import { EntityId } from '@shared/models/id/entity-id'; -import { EventService } from '@app/core/http/event.service'; -import { EventTableHeaderComponent } from '@home/components/event/event-table-header.component'; -import { EntityTypeResource } from '@shared/models/entity-type.models'; -import { Observable } from 'rxjs'; -import { PageData } from '@shared/models/page/page-data'; -import { Direction } from '@shared/models/page/sort-order'; -import { DialogService } from '@core/services/dialog.service'; -import { ContentType } from '@shared/models/constants'; +import {DebugEventType, Event, EventType, FilterEventBody} from '@shared/models/event.models'; +import {TimePageLink} from '@shared/models/page/page-link'; +import {TranslateService} from '@ngx-translate/core'; +import {DatePipe} from '@angular/common'; +import {MatDialog} from '@angular/material/dialog'; +import {EntityId} from '@shared/models/id/entity-id'; +import {EventService} from '@app/core/http/event.service'; +import {EventTableHeaderComponent} from '@home/components/event/event-table-header.component'; +import {EntityTypeResource} from '@shared/models/entity-type.models'; +import {Observable} from 'rxjs'; +import {PageData} from '@shared/models/page/page-data'; +import {Direction} from '@shared/models/page/sort-order'; +import {DialogService} from '@core/services/dialog.service'; +import {ContentType} from '@shared/models/constants'; import { EventContentDialogComponent, EventContentDialogData } from '@home/components/event/event-content-dialog.component'; -import { isEqual, sortObjectKeys } from '@core/utils'; -import { ConnectedPosition, Overlay, OverlayConfig, OverlayRef } from '@angular/cdk/overlay'; -import { ChangeDetectorRef, Injector, StaticProvider, ViewContainerRef } from '@angular/core'; -import { ComponentPortal } from '@angular/cdk/portal'; +import {isEqual, sortObjectKeys} from '@core/utils'; +import {ConnectedPosition, Overlay, OverlayConfig, OverlayRef} from '@angular/cdk/overlay'; +import {ChangeDetectorRef, Injector, StaticProvider, ViewContainerRef} from '@angular/core'; +import {ComponentPortal} from '@angular/cdk/portal'; import { EVENT_FILTER_PANEL_DATA, EventFilterPanelComponent, @@ -141,7 +141,12 @@ export class EventTableConfig extends EntityTableConfig { icon: 'delete', isEnabled: () => true, onAction: ($event, entity, pageLink: TimePageLink) => { - this.eventService.clearEvents(entity.entityId, entity.eventType, entity.filterParams, entity.tenantId, pageLink).subscribe(); + this.eventService.clearEvents(entity.entityId, entity.eventType, entity.filterParams, entity.tenantId, pageLink).subscribe( + () => { + this.table.paginator.pageIndex = 0; + this.table.updateData(); + } + ); } }); } From 6e2c1e3419c21890a6bed123e5b1653f268f9b10 Mon Sep 17 00:00:00 2001 From: Kalutka Zhenya Date: Mon, 8 Nov 2021 19:21:26 +0200 Subject: [PATCH 333/432] Events clearing UI refactoring --- .../entity/entities-table.component.html | 2 +- .../components/event/event-table-config.ts | 40 +++++++++---------- .../components/event/event-table.component.ts | 4 +- .../entity/entities-table-config.models.ts | 5 ++- 4 files changed, 25 insertions(+), 26 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/entity/entities-table.component.html b/ui-ngx/src/app/modules/home/components/entity/entities-table.component.html index b103c29df5..c4f470bbd2 100644 --- a/ui-ngx/src/app/modules/home/components/entity/entities-table.component.html +++ b/ui-ngx/src/app/modules/home/components/entity/entities-table.component.html @@ -84,7 +84,7 @@ [fxShow]="actionDescriptor.isEnabled()" *ngFor="let actionDescriptor of headerActionDescriptors" matTooltip="{{ actionDescriptor.name }}" matTooltipPosition="above" - (click)="actionDescriptor.onAction($event, entitiesTableConfig, pageLink)"> + (click)="actionDescriptor.onAction($event)"> {{actionDescriptor.icon}} diff --git a/ui-ngx/src/app/modules/home/components/event/event-table-config.ts b/ui-ngx/src/app/modules/home/components/event/event-table-config.ts index 9cd905492c..d407cf262b 100644 --- a/ui-ngx/src/app/modules/home/components/event/event-table-config.ts +++ b/ui-ngx/src/app/modules/home/components/event/event-table-config.ts @@ -20,28 +20,28 @@ import { EntityTableColumn, EntityTableConfig } from '@home/models/entity/entities-table-config.models'; -import {DebugEventType, Event, EventType, FilterEventBody} from '@shared/models/event.models'; -import {TimePageLink} from '@shared/models/page/page-link'; -import {TranslateService} from '@ngx-translate/core'; -import {DatePipe} from '@angular/common'; -import {MatDialog} from '@angular/material/dialog'; -import {EntityId} from '@shared/models/id/entity-id'; -import {EventService} from '@app/core/http/event.service'; -import {EventTableHeaderComponent} from '@home/components/event/event-table-header.component'; -import {EntityTypeResource} from '@shared/models/entity-type.models'; -import {Observable} from 'rxjs'; -import {PageData} from '@shared/models/page/page-data'; -import {Direction} from '@shared/models/page/sort-order'; -import {DialogService} from '@core/services/dialog.service'; -import {ContentType} from '@shared/models/constants'; +import { DebugEventType, Event, EventType, FilterEventBody } from '@shared/models/event.models'; +import { TimePageLink } from '@shared/models/page/page-link'; +import { TranslateService } from '@ngx-translate/core'; +import { DatePipe } from '@angular/common'; +import { MatDialog } from '@angular/material/dialog'; +import { EntityId } from '@shared/models/id/entity-id'; +import { EventService } from '@app/core/http/event.service'; +import { EventTableHeaderComponent } from '@home/components/event/event-table-header.component'; +import { EntityTypeResource } from '@shared/models/entity-type.models'; +import { Observable } from 'rxjs'; +import { PageData } from '@shared/models/page/page-data'; +import { Direction } from '@shared/models/page/sort-order'; +import { DialogService } from '@core/services/dialog.service'; +import { ContentType } from '@shared/models/constants'; import { EventContentDialogComponent, EventContentDialogData } from '@home/components/event/event-content-dialog.component'; -import {isEqual, sortObjectKeys} from '@core/utils'; -import {ConnectedPosition, Overlay, OverlayConfig, OverlayRef} from '@angular/cdk/overlay'; -import {ChangeDetectorRef, Injector, StaticProvider, ViewContainerRef} from '@angular/core'; -import {ComponentPortal} from '@angular/cdk/portal'; +import { isEqual, sortObjectKeys } from '@core/utils'; +import { ConnectedPosition, Overlay, OverlayConfig, OverlayRef } from '@angular/cdk/overlay'; +import { ChangeDetectorRef, Injector, StaticProvider, ViewContainerRef } from '@angular/core'; +import { ComponentPortal } from '@angular/cdk/portal'; import { EVENT_FILTER_PANEL_DATA, EventFilterPanelComponent, @@ -140,8 +140,8 @@ export class EventTableConfig extends EntityTableConfig { name: this.translate.instant('event.clean-events'), icon: 'delete', isEnabled: () => true, - onAction: ($event, entity, pageLink: TimePageLink) => { - this.eventService.clearEvents(entity.entityId, entity.eventType, entity.filterParams, entity.tenantId, pageLink).subscribe( + onAction: ($event) => { + this.eventService.clearEvents(this.entityId, this.eventType, this.filterParams, this.tenantId, this.table.pageLink as TimePageLink).subscribe( () => { this.table.paginator.pageIndex = 0; this.table.updateData(); diff --git a/ui-ngx/src/app/modules/home/components/event/event-table.component.ts b/ui-ngx/src/app/modules/home/components/event/event-table.component.ts index 85bd4cf81a..00aeb4f50c 100644 --- a/ui-ngx/src/app/modules/home/components/event/event-table.component.ts +++ b/ui-ngx/src/app/modules/home/components/event/event-table.component.ts @@ -25,7 +25,6 @@ import { EventService } from '@core/http/event.service'; import { DialogService } from '@core/services/dialog.service'; import { DebugEventType, EventType } from '@shared/models/event.models'; import { Overlay } from '@angular/cdk/overlay'; -import { HttpClient } from '@angular/common/http'; @Component({ selector: 'tb-event-table', @@ -85,8 +84,7 @@ export class EventTableComponent implements OnInit { private dialog: MatDialog, private overlay: Overlay, private viewContainerRef: ViewContainerRef, - private cd: ChangeDetectorRef, - private http: HttpClient) { + private cd: ChangeDetectorRef) { } ngOnInit() { diff --git a/ui-ngx/src/app/modules/home/models/entity/entities-table-config.models.ts b/ui-ngx/src/app/modules/home/models/entity/entities-table-config.models.ts index 7a352e8f17..93e68e40b7 100644 --- a/ui-ngx/src/app/modules/home/models/entity/entities-table-config.models.ts +++ b/ui-ngx/src/app/modules/home/models/entity/entities-table-config.models.ts @@ -25,7 +25,8 @@ import { EntityComponent } from '@home/components/entity/entity.component'; import { Type } from '@angular/core'; import { EntityAction } from './entity-component.models'; import { HasUUID } from '@shared/models/id/has-uuid'; -import { PageLink } from '@shared/models/page/page-link'; +import { PageLink, TimePageLink } from '@shared/models/page/page-link'; +import { EntitiesTableComponent } from '@home/components/entity/entities-table.component'; import { EntityTableHeaderComponent } from '@home/components/entity/entity-table-header.component'; import { ActivatedRoute } from '@angular/router'; import { EntityTabsComponent } from '../../components/entity/entity-tabs.component'; @@ -75,7 +76,7 @@ export interface HeaderActionDescriptor { icon: string; isMdiIcon?: boolean; isEnabled: () => boolean; - onAction: ($event: MouseEvent, entity?, pageLink?) => void; + onAction: ($event: MouseEvent) => void; } export type EntityTableColumnType = 'content' | 'action'; From bbab11d5aa2d01a4d11a5d92bdefc3047ea5466f Mon Sep 17 00:00:00 2001 From: ArtemDzhereleiko Date: Tue, 4 Jan 2022 13:03:26 +0200 Subject: [PATCH 334/432] UI: Fixed cancel event on color picker --- .../shared/components/dialog/color-picker-dialog.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui-ngx/src/app/shared/components/dialog/color-picker-dialog.component.ts b/ui-ngx/src/app/shared/components/dialog/color-picker-dialog.component.ts index 499f857df8..2374749cbc 100644 --- a/ui-ngx/src/app/shared/components/dialog/color-picker-dialog.component.ts +++ b/ui-ngx/src/app/shared/components/dialog/color-picker-dialog.component.ts @@ -67,7 +67,7 @@ export class ColorPickerDialogComponent extends DialogComponent Date: Tue, 4 Jan 2022 13:17:50 +0200 Subject: [PATCH 335/432] Refactor events clearing api --- .../server/controller/EventController.java | 30 ++++++++----------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/EventController.java b/application/src/main/java/org/thingsboard/server/controller/EventController.java index 5759ffcac4..ea77fce94c 100644 --- a/application/src/main/java/org/thingsboard/server/controller/EventController.java +++ b/application/src/main/java/org/thingsboard/server/controller/EventController.java @@ -240,31 +240,27 @@ public class EventController extends BaseController { } } - @ApiOperation(value = "Clear Events (clearEvents)", notes = "Clears events for specified entity.") + @ApiOperation(value = "Clear Events (clearEvents)", notes = "Clears events by filter for specified entity.") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/events/{entityType}/{entityId}/clear", method = RequestMethod.POST) @ResponseStatus(HttpStatus.OK) - public void clearEvents( - @ApiParam(value = ENTITY_TYPE_PARAM_DESCRIPTION, required = true) - @PathVariable(ENTITY_TYPE) String strEntityType, - @ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION, required = true) - @PathVariable(ENTITY_ID) String strEntityId, - @ApiParam(value = EVENT_START_TIME_DESCRIPTION) - @RequestParam("tenantId") String strTenantId, - @ApiParam(value = "A string value representing event type", example = "STATS", required = true) - @RequestParam(required = false) Long startTime, - @ApiParam(value = EVENT_END_TIME_DESCRIPTION) - @RequestParam(required = false) Long endTime, - @RequestBody EventFilter eventFilter) throws ThingsboardException { + public void clearEvents(@ApiParam(value = ENTITY_TYPE_PARAM_DESCRIPTION, required = true) + @PathVariable(ENTITY_TYPE) String strEntityType, + @ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION, required = true) + @PathVariable(ENTITY_ID) String strEntityId, + @ApiParam(value = EVENT_START_TIME_DESCRIPTION) + @RequestParam(required = false) Long startTime, + @ApiParam(value = EVENT_END_TIME_DESCRIPTION) + @RequestParam(required = false) Long endTime, + @ApiParam(value = EVENT_FILTER_DEFINITION) + @RequestBody EventFilter eventFilter) throws ThingsboardException { checkParameter("EntityId", strEntityId); checkParameter("EntityType", strEntityType); try { - TenantId tenantId = new TenantId(toUUID(strTenantId)); - EntityId entityId = EntityIdFactory.getByTypeAndId(strEntityType, strEntityId); - checkEntityId(entityId, Operation.DELETE); + checkEntityId(entityId, Operation.WRITE); - eventService.removeEvents(tenantId, entityId, eventFilter, startTime, endTime); + eventService.removeEvents(getTenantId(), entityId, eventFilter, startTime, endTime); } catch (Exception e) { throw handleException(e); } From bb3c730e58c774ecf12e3ba39482fe91b2dba008 Mon Sep 17 00:00:00 2001 From: van-vanich Date: Wed, 5 Jan 2022 13:58:58 +0200 Subject: [PATCH 336/432] add test for sequential timeseries persistence and improve code for TbMsgTimeseriesNode rule node and config --- .../server/service/ServiceSqlTestSuite.java | 1 + .../SequentialTimeseriesPersistenceTest.java | 194 ++++++++++++++++++ .../engine/telemetry/TbMsgTimeseriesNode.java | 6 +- .../TbMsgTimeseriesNodeConfiguration.java | 4 +- 4 files changed, 202 insertions(+), 3 deletions(-) create mode 100644 application/src/test/java/org/thingsboard/server/service/sql/SequentialTimeseriesPersistenceTest.java diff --git a/application/src/test/java/org/thingsboard/server/service/ServiceSqlTestSuite.java b/application/src/test/java/org/thingsboard/server/service/ServiceSqlTestSuite.java index 508272085c..d3ad80f614 100644 --- a/application/src/test/java/org/thingsboard/server/service/ServiceSqlTestSuite.java +++ b/application/src/test/java/org/thingsboard/server/service/ServiceSqlTestSuite.java @@ -23,6 +23,7 @@ import org.thingsboard.server.queue.memory.InMemoryStorage; @RunWith(ClasspathSuite.class) @ClasspathSuite.ClassnameFilters({ "org.thingsboard.server.service.resource.sql.*Test", + "org.thingsboard.server.service.sql.*Test" }) public class ServiceSqlTestSuite { diff --git a/application/src/test/java/org/thingsboard/server/service/sql/SequentialTimeseriesPersistenceTest.java b/application/src/test/java/org/thingsboard/server/service/sql/SequentialTimeseriesPersistenceTest.java new file mode 100644 index 0000000000..9e6b6f0bc1 --- /dev/null +++ b/application/src/test/java/org/thingsboard/server/service/sql/SequentialTimeseriesPersistenceTest.java @@ -0,0 +1,194 @@ +package org.thingsboard.server.service.sql; + +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import lombok.extern.slf4j.Slf4j; +import org.jetbrains.annotations.NotNull; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.thingsboard.rule.engine.telemetry.TbMsgTimeseriesNode; +import org.thingsboard.rule.engine.telemetry.TbMsgTimeseriesNodeConfiguration; +import org.thingsboard.server.common.data.Device; +import org.thingsboard.server.common.data.Tenant; +import org.thingsboard.server.common.data.User; +import org.thingsboard.server.common.data.asset.Asset; +import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.kv.BasicTsKvEntry; +import org.thingsboard.server.common.data.kv.JsonDataEntry; +import org.thingsboard.server.common.data.kv.LongDataEntry; +import org.thingsboard.server.common.data.kv.TsKvEntry; +import org.thingsboard.server.common.data.security.Authority; +import org.thingsboard.server.common.msg.TbMsg; +import org.thingsboard.server.common.msg.TbMsgDataType; +import org.thingsboard.server.common.msg.TbMsgMetaData; +import org.thingsboard.server.common.msg.session.SessionMsgType; +import org.thingsboard.server.controller.AbstractControllerTest; +import org.thingsboard.server.dao.service.DaoSqlTest; +import org.thingsboard.server.dao.timeseries.TimeseriesService; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@DaoSqlTest +@Slf4j +public class SequentialTimeseriesPersistenceTest extends AbstractControllerTest { + + static final int TIMEOUT = 30; + + final String TOTALIZER = "Totalizer"; + final int TTL = 99999; + final String GENERIC_CUMULATIVE_OBJ = "genericCumulativeObj"; + final List ts = List.of(10L, 20L, 30L, 40L, 60L, 70L, 50L, 80L); + final List msgValue = List.of(1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L); + + @Autowired + TimeseriesService timeseriesService; + + TbMsgTimeseriesNodeConfiguration configuration; + Tenant savedTenant; + User tenantAdmin; + + @Before + public void beforeTest() throws Exception { + configuration = new TbMsgTimeseriesNodeConfiguration(); + configuration.setIgnoreMetadataTs(true); + + loginSysAdmin(); + + Tenant tenant = new Tenant(); + tenant.setTitle("My tenant"); + savedTenant = doPost("/api/tenant", tenant, Tenant.class); + Assert.assertNotNull(savedTenant); + + tenantAdmin = new User(); + tenantAdmin.setAuthority(Authority.TENANT_ADMIN); + tenantAdmin.setTenantId(savedTenant.getId()); + tenantAdmin.setEmail("tenant2@thingsboard.org"); + tenantAdmin.setFirstName("Joe"); + tenantAdmin.setLastName("Downs"); + + tenantAdmin = createUserAndLogin(tenantAdmin, "testPassword1"); + } + + @After + public void afterTest() throws Exception { + loginSysAdmin(); + doDelete("/api/tenant/" + savedTenant.getId().getId().toString()).andExpect(status().isOk()); + } + + @Test + public void testSequentialTimeseriesPersistence() throws Exception { + Asset asset = saveAsset("Asset"); + + Device deviceA = saveDevice("Device A"); + Device deviceB = saveDevice("Device B"); + Device deviceC = saveDevice("Device C"); + Device deviceD = saveDevice("Device D"); + List devices = List.of(deviceA, deviceB, deviceC, deviceD); + + for (int i = 0; i < 2; i++) { + int idx = i * (devices.size()); + saveLatestTsForAssetAndDevice(devices, asset, idx); + checkDiffBetweenLatestTsForDevicesAndAsset(devices, asset); + } + } + + Device saveDevice(String name) throws Exception { + Device device = new Device(); + device.setName(name); + device.setType("default"); + Device savedDevice = doPost("/api/device", device, Device.class); + Assert.assertNotNull(savedDevice); + return savedDevice; + } + + Asset saveAsset(String name) throws Exception { + Asset asset = new Asset(); + asset.setName(name); + asset.setType("default"); + Asset savedAsset = doPost("/api/asset", asset, Asset.class); + Assert.assertNotNull(savedAsset); + return savedAsset; + } + + private void saveLatestTsForAssetAndDevice(List devices, Asset asset, int idx) throws ExecutionException, InterruptedException, TimeoutException { + for (Device device : devices) { + TbMsg tbMsg = TbMsg.newMsg(SessionMsgType.POST_TELEMETRY_REQUEST.name(), + device.getId(), + getTbMsgMetadata(device.getName(), ts.get(idx)), + TbMsgDataType.JSON, + getTbMsgData(msgValue.get(idx))); + saveDeviceTsEntry(device.getId(), tbMsg, msgValue.get(idx)); + saveAssetTsEntry(asset, device.getName(), msgValue.get(idx), TbMsgTimeseriesNode.computeTs(tbMsg, configuration.isIgnoreMetadataTs())); + idx++; + } + } + + void checkDiffBetweenLatestTsForDevicesAndAsset(List devices, Asset asset) throws ExecutionException, InterruptedException, TimeoutException { + TsKvEntry assetTsKvEntry = getTsKvLatest(asset.getId(), GENERIC_CUMULATIVE_OBJ); + Assert.assertTrue(assetTsKvEntry.getJsonValue().isPresent()); + JsonObject assetJsonObject = new JsonParser().parse(assetTsKvEntry.getJsonValue().get()).getAsJsonObject(); + for (Device device : devices) { + Long assetValue = assetJsonObject.get(device.getName()).getAsLong(); + TsKvEntry deviceLatest = getTsKvLatest(device.getId(), TOTALIZER); + Assert.assertTrue(deviceLatest.getLongValue().isPresent()); + Long deviceValue = deviceLatest.getLongValue().get(); + Assert.assertEquals(assetValue, deviceValue); + } + } + + String getTbMsgData(long value) { + return "{\"Totalizer\": " + value + "}"; + } + + TbMsgMetaData getTbMsgMetadata(String name, long ts) { + Map metadata = new HashMap<>(); + metadata.put("deviceName", name); + metadata.put("ts", String.valueOf(ts)); + return new TbMsgMetaData(metadata); + } + + void saveDeviceTsEntry(EntityId entityId, TbMsg tbMsg, long value) throws ExecutionException, InterruptedException, TimeoutException { + TsKvEntry tsKvEntry = new BasicTsKvEntry(TbMsgTimeseriesNode.computeTs(tbMsg, configuration.isIgnoreMetadataTs()), new LongDataEntry(TOTALIZER, value)); + saveTimeseries(entityId, tsKvEntry); + } + + void saveAssetTsEntry(Asset asset, String key, long value, long ts) throws ExecutionException, InterruptedException, TimeoutException { + Optional tsKvEntryOpt = getTsKvLatest(asset.getId(), GENERIC_CUMULATIVE_OBJ).getJsonValue(); + TsKvEntry saveTsKvEntry = new BasicTsKvEntry(ts, new JsonDataEntry(GENERIC_CUMULATIVE_OBJ, getJsonObject(key, value, tsKvEntryOpt).toString())); + saveTimeseries(asset.getId(), saveTsKvEntry); + } + + @NotNull + private JsonObject getJsonObject(String key, long value, Optional tsKvEntryOpt) { + JsonObject jsonObject = new JsonObject(); + if (tsKvEntryOpt.isPresent()) { + jsonObject = new JsonParser().parse(tsKvEntryOpt.get()).getAsJsonObject(); + } + jsonObject.addProperty(key, value); + return jsonObject; + } + + private void saveTimeseries(EntityId entityId, TsKvEntry saveTsKvEntry) throws InterruptedException, ExecutionException, TimeoutException { + timeseriesService.save(savedTenant.getId(), entityId, List.of(saveTsKvEntry), TTL).get(TIMEOUT, TimeUnit.SECONDS); + } + + TsKvEntry getTsKvLatest(EntityId entityId, String key) throws InterruptedException, ExecutionException, TimeoutException { + List tsKvEntries = timeseriesService.findLatest( + savedTenant.getTenantId(), + entityId, + List.of(key)).get(TIMEOUT, TimeUnit.SECONDS); + Assert.assertEquals(1, tsKvEntries.size()); + return tsKvEntries.get(0); + } +} diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbMsgTimeseriesNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbMsgTimeseriesNode.java index 711b7c1558..47cf0f1bf2 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbMsgTimeseriesNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbMsgTimeseriesNode.java @@ -77,7 +77,7 @@ public class TbMsgTimeseriesNode implements TbNode { ctx.tellFailure(msg, new IllegalArgumentException("Unsupported msg type: " + msg.getType())); return; } - long ts = config.isSaveWithMsgTs() ? msg.getTs() : getTs(msg); + long ts = computeTs(msg, config.isIgnoreMetadataTs()); String src = msg.getData(); Map> tsKvMap = JsonConverter.convertToTelemetry(new JsonParser().parse(src), ts); if (tsKvMap.isEmpty()) { @@ -102,6 +102,10 @@ public class TbMsgTimeseriesNode implements TbNode { } } + public static long computeTs(TbMsg msg, boolean saveWithMsgTs) { + return saveWithMsgTs ? System.currentTimeMillis() : getTs(msg); + } + public static long getTs(TbMsg msg) { long ts = -1; String tsStr = msg.getMetaData().getValue("ts"); diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbMsgTimeseriesNodeConfiguration.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbMsgTimeseriesNodeConfiguration.java index 89abac99fe..6c9f7ac884 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbMsgTimeseriesNodeConfiguration.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbMsgTimeseriesNodeConfiguration.java @@ -23,14 +23,14 @@ public class TbMsgTimeseriesNodeConfiguration implements NodeConfiguration Date: Wed, 5 Jan 2022 14:48:45 +0200 Subject: [PATCH 337/432] improve node details and add license for test class --- .../sql/SequentialTimeseriesPersistenceTest.java | 15 +++++++++++++++ .../engine/telemetry/TbMsgTimeseriesNode.java | 15 ++++++++++----- 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/application/src/test/java/org/thingsboard/server/service/sql/SequentialTimeseriesPersistenceTest.java b/application/src/test/java/org/thingsboard/server/service/sql/SequentialTimeseriesPersistenceTest.java index 9e6b6f0bc1..c360adf509 100644 --- a/application/src/test/java/org/thingsboard/server/service/sql/SequentialTimeseriesPersistenceTest.java +++ b/application/src/test/java/org/thingsboard/server/service/sql/SequentialTimeseriesPersistenceTest.java @@ -1,3 +1,18 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.thingsboard.server.service.sql; import com.google.gson.JsonObject; diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbMsgTimeseriesNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbMsgTimeseriesNode.java index 47cf0f1bf2..2334851a08 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbMsgTimeseriesNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbMsgTimeseriesNode.java @@ -46,10 +46,15 @@ import java.util.concurrent.TimeUnit; configClazz = TbMsgTimeseriesNodeConfiguration.class, nodeDescription = "Saves timeseries data", nodeDetails = "Saves timeseries telemetry data based on configurable TTL parameter. Expects messages with 'POST_TELEMETRY_REQUEST' message type. " + - "Timestamp in milliseconds will be taken from metadata.ts, otherwise 'now' timestamp will be applied. " + - "Allows stopping updating values for incoming keys in the latest ts_kv table if 'skipLatestPersistence' is set to true.", + "Timestamp in milliseconds will be taken from metadata.ts, otherwise 'now' message timestamp will be applied. " + + "Allows stopping updating values for incoming keys in the latest ts_kv table if 'skipLatestPersistence' is set to true.\n " + + "Enable 'ignoreMetadataTs' param to ignore the timestamp that arrives from message metadata. " + + "Useful for all sorts of sequential processing if you merge messages from multiple sources (devices, assets, etc).\n" + + "For example, if you count number of messages from multiple devices into asset time-series value. " + + "Typically, you fetch the previous value of the counter, increment it and then save the value. " + + "If you use timestamp of the original message, the value may be ignored, since it has outdated timestamp comparing to the previous message.", uiResources = {"static/rulenode/rulenode-core-config.js"}, - configDirective = "tbActionNodeTimeseriesConfig!", + configDirective = "tbActionNodeTimeseriesConfig", icon = "file_upload" ) public class TbMsgTimeseriesNode implements TbNode { @@ -102,8 +107,8 @@ public class TbMsgTimeseriesNode implements TbNode { } } - public static long computeTs(TbMsg msg, boolean saveWithMsgTs) { - return saveWithMsgTs ? System.currentTimeMillis() : getTs(msg); + public static long computeTs(TbMsg msg, boolean ignoreMetadataTs) { + return ignoreMetadataTs ? System.currentTimeMillis() : getTs(msg); } public static long getTs(TbMsg msg) { From 93bf95c17a63cf5e40e898172fb2a91d3f8ce28b Mon Sep 17 00:00:00 2001 From: van-vanich Date: Wed, 5 Jan 2022 15:00:13 +0200 Subject: [PATCH 338/432] improve code style --- .../sql/SequentialTimeseriesPersistenceTest.java | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/application/src/test/java/org/thingsboard/server/service/sql/SequentialTimeseriesPersistenceTest.java b/application/src/test/java/org/thingsboard/server/service/sql/SequentialTimeseriesPersistenceTest.java index c360adf509..e4fb0318b4 100644 --- a/application/src/test/java/org/thingsboard/server/service/sql/SequentialTimeseriesPersistenceTest.java +++ b/application/src/test/java/org/thingsboard/server/service/sql/SequentialTimeseriesPersistenceTest.java @@ -17,7 +17,6 @@ package org.thingsboard.server.service.sql; import com.google.gson.JsonObject; import com.google.gson.JsonParser; -import lombok.extern.slf4j.Slf4j; import org.jetbrains.annotations.NotNull; import org.junit.After; import org.junit.Assert; @@ -55,7 +54,6 @@ import java.util.concurrent.TimeoutException; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @DaoSqlTest -@Slf4j public class SequentialTimeseriesPersistenceTest extends AbstractControllerTest { static final int TIMEOUT = 30; @@ -112,7 +110,7 @@ public class SequentialTimeseriesPersistenceTest extends AbstractControllerTest List devices = List.of(deviceA, deviceB, deviceC, deviceD); for (int i = 0; i < 2; i++) { - int idx = i * (devices.size()); + int idx = i * devices.size(); saveLatestTsForAssetAndDevice(devices, asset, idx); checkDiffBetweenLatestTsForDevicesAndAsset(devices, asset); } @@ -136,7 +134,7 @@ public class SequentialTimeseriesPersistenceTest extends AbstractControllerTest return savedAsset; } - private void saveLatestTsForAssetAndDevice(List devices, Asset asset, int idx) throws ExecutionException, InterruptedException, TimeoutException { + void saveLatestTsForAssetAndDevice(List devices, Asset asset, int idx) throws ExecutionException, InterruptedException, TimeoutException { for (Device device : devices) { TbMsg tbMsg = TbMsg.newMsg(SessionMsgType.POST_TELEMETRY_REQUEST.name(), device.getId(), @@ -185,7 +183,7 @@ public class SequentialTimeseriesPersistenceTest extends AbstractControllerTest } @NotNull - private JsonObject getJsonObject(String key, long value, Optional tsKvEntryOpt) { + JsonObject getJsonObject(String key, long value, Optional tsKvEntryOpt) { JsonObject jsonObject = new JsonObject(); if (tsKvEntryOpt.isPresent()) { jsonObject = new JsonParser().parse(tsKvEntryOpt.get()).getAsJsonObject(); @@ -194,7 +192,7 @@ public class SequentialTimeseriesPersistenceTest extends AbstractControllerTest return jsonObject; } - private void saveTimeseries(EntityId entityId, TsKvEntry saveTsKvEntry) throws InterruptedException, ExecutionException, TimeoutException { + void saveTimeseries(EntityId entityId, TsKvEntry saveTsKvEntry) throws InterruptedException, ExecutionException, TimeoutException { timeseriesService.save(savedTenant.getId(), entityId, List.of(saveTsKvEntry), TTL).get(TIMEOUT, TimeUnit.SECONDS); } From b64eccf3332a2812a931ef697af44a5463d7f0b7 Mon Sep 17 00:00:00 2001 From: desoliture Date: Wed, 5 Jan 2022 16:24:12 +0200 Subject: [PATCH 339/432] add noXss validation for ruleNodes name --- .../java/org/thingsboard/server/common/data/rule/RuleNode.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleNode.java b/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleNode.java index 8201807808..8904d2821d 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleNode.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleNode.java @@ -27,6 +27,7 @@ import org.thingsboard.server.common.data.SearchTextBasedWithAdditionalInfo; import org.thingsboard.server.common.data.id.RuleChainId; import org.thingsboard.server.common.data.id.RuleNodeId; import org.thingsboard.server.common.data.validation.Length; +import org.thingsboard.server.common.data.validation.NoXss; @ApiModel @Data @@ -41,6 +42,7 @@ public class RuleNode extends SearchTextBasedWithAdditionalInfo impl @Length(fieldName = "type") @ApiModelProperty(position = 4, value = "Full Java Class Name of the rule node implementation. ", example = "com.mycompany.iot.rule.engine.ProcessingNode") private String type; + @NoXss @Length(fieldName = "name") @ApiModelProperty(position = 5, value = "User defined name of the rule node. Used on UI and for logging. ", example = "Process sensor reading") private String name; From ec602248c0cc22da1461e50176fdbca2ebf75519 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Wed, 5 Jan 2022 16:28:37 +0200 Subject: [PATCH 340/432] lwm2m validate trust certs --- .../TbLwM2MDtlsCertificateVerifier.java | 50 ++++++++++--------- .../config/ssl/AbstractSslCredentials.java | 26 +++++++--- 2 files changed, 47 insertions(+), 29 deletions(-) diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MDtlsCertificateVerifier.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MDtlsCertificateVerifier.java index bae7522c78..babf385bc8 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MDtlsCertificateVerifier.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MDtlsCertificateVerifier.java @@ -50,13 +50,22 @@ import org.thingsboard.server.transport.lwm2m.server.store.TbMainSecurityStore; import javax.annotation.PostConstruct; import javax.security.auth.x500.X500Principal; +import java.security.InvalidAlgorithmParameterException; +import java.security.NoSuchAlgorithmException; import java.security.PublicKey; import java.security.cert.CertPath; +import java.security.cert.CertPathValidator; +import java.security.cert.CertPathValidatorException; import java.security.cert.CertificateEncodingException; +import java.security.cert.CertificateException; import java.security.cert.CertificateExpiredException; +import java.security.cert.CertificateFactory; import java.security.cert.CertificateNotYetValidException; +import java.security.cert.PKIXParameters; +import java.security.cert.TrustAnchor; import java.security.cert.X509Certificate; import java.util.Arrays; +import java.util.Collections; import java.util.List; import static org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mTypeServer.CLIENT; @@ -119,8 +128,8 @@ public class TbLwM2MDtlsCertificateVerifier implements NewAdvancedCertificateVer TbLwM2MSecurityInfo securityInfo = null; // verify if trust - if (config.getTrustSslCredentials().getTrustedCertificates().length > 0) { - if (verifyIssuer(cert, config.getTrustSslCredentials().getTrustedCertificates()) != null) { + if (config.getTrustSslCredentials() != null && config.getTrustSslCredentials().getTrustedCertificates().length > 0) { + if (verifyTrust(cert, config.getTrustSslCredentials().getTrustedCertificates()) != null) { String endpoint = config.getTrustSslCredentials().getValueFromSubjectNameByKey(cert.getSubjectX500Principal().getName(), "CN"); securityInfo = StringUtils.isNotEmpty(endpoint) ? securityInfoValidator.getEndpointSecurityInfoByCredentialsId(endpoint, CLIENT) : null; } @@ -193,31 +202,26 @@ public class TbLwM2MDtlsCertificateVerifier implements NewAdvancedCertificateVer } - private X509Certificate verifyIssuer(X509Certificate certificate, X509Certificate[] certificates) { - String issuerCN = config.getTrustSslCredentials().getValueFromSubjectNameByKey(certificate.getIssuerX500Principal().getName(), "CN"); - if (!StringUtils.isBlank(issuerCN)) { + private X509Certificate verifyTrust(X509Certificate certificate, X509Certificate[] certificates) { + try { + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + CertPath cp = cf.generateCertPath(Arrays.asList(new X509Certificate[]{certificate})); for (int index = 0; index < certificates.length; ++index) { - X509Certificate trust = certificates[index]; - String trustCN = config.getTrustSslCredentials().getValueFromSubjectNameByKey(trust.getSubjectX500Principal().getName(), "CN"); - if (!StringUtils.isBlank(trustCN) && issuerCN.length() >= trustCN.length() && issuerCN.substring(issuerCN.length()-trustCN.length()).equals(trustCN)) { - if (verifyCertificate(certificate)) { - return certificate; - } + X509Certificate caCert = certificates[index]; + try { + TrustAnchor trustAnchor = new TrustAnchor(caCert, null); + CertPathValidator cpv = CertPathValidator.getInstance("PKIX"); + PKIXParameters pkixParams = new PKIXParameters( + Collections.singleton(trustAnchor)); + pkixParams.setRevocationEnabled(false); + if (cpv.validate(cp, pkixParams) != null) return certificate; + } catch (NoSuchAlgorithmException | InvalidAlgorithmParameterException | CertPathValidatorException e) { + log.trace("[{}]. [{}]", certificate.getSubjectDN(), e.getMessage()); } } + } catch (CertificateException e) { + log.trace("[{}] certPath not valid. [{}]", certificate.getSubjectDN(), e.getMessage()); } return null; } - - private static boolean verifyCertificate(X509Certificate certificate) { - try { - // date - certificate.checkValidity(); - // Validate X509. - SecurityUtil.certificate.decode(certificate.getEncoded()); - return true; - } catch (Exception e) { - return false; - } - } } diff --git a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/config/ssl/AbstractSslCredentials.java b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/config/ssl/AbstractSslCredentials.java index 01b7242805..3170aea9a2 100644 --- a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/config/ssl/AbstractSslCredentials.java +++ b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/config/ssl/AbstractSslCredentials.java @@ -61,7 +61,7 @@ public abstract class AbstractSslCredentials implements SslCredentials { this.keyPasswordArray = keyPassword.toCharArray(); } this.keyStore = this.loadKeyStore(trustsOnly, this.keyPasswordArray); - Set trustedCerts = getTrustedCerts(this.keyStore); + Set trustedCerts = getTrustedCerts(this.keyStore, trustsOnly); this.trusts = trustedCerts.toArray(new X509Certificate[0]); if (!trustsOnly) { PrivateKeyEntry privateKeyEntry = null; @@ -179,7 +179,7 @@ public abstract class AbstractSslCredentials implements SslCredentials { return entry; } - private static Set getTrustedCerts(KeyStore ks) { + private static Set getTrustedCerts(KeyStore ks, boolean trustsOnly) { Set set = new HashSet<>(); try { for (Enumeration e = ks.aliases(); e.hasMoreElements(); ) { @@ -187,19 +187,33 @@ public abstract class AbstractSslCredentials implements SslCredentials { if (ks.isCertificateEntry(alias)) { Certificate cert = ks.getCertificate(alias); if (cert instanceof X509Certificate) { - set.add((X509Certificate)cert); + if (trustsOnly) { + // is CA certificate + if (((X509Certificate) cert).getBasicConstraints()>=0) { + set.add((X509Certificate) cert); + } + } else { + set.add((X509Certificate) cert); + } } } else if (ks.isKeyEntry(alias)) { Certificate[] certs = ks.getCertificateChain(alias); if ((certs != null) && (certs.length > 0) && (certs[0] instanceof X509Certificate)) { - set.add((X509Certificate)certs[0]); + if (trustsOnly) { + for (Certificate cert : certs) { + // is CA certificate + if (((X509Certificate) cert).getBasicConstraints()>=0) { + set.add((X509Certificate) cert); + } + } + } else { + set.add((X509Certificate)certs[0]); + } } } } } catch (KeyStoreException ignored) {} return Collections.unmodifiableSet(set); } - - } From 758933040658322c53848076928be8cb8c389ea6 Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Wed, 5 Jan 2022 16:50:48 +0200 Subject: [PATCH 341/432] Do not update ws lastActivity in case of general response - only on pong response. Clean up properly subscription map in case canceling subsription --- .../server/controller/plugin/TbWebSocketHandler.java | 1 - .../DefaultTbEntityDataSubscriptionService.java | 6 ++++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/plugin/TbWebSocketHandler.java b/application/src/main/java/org/thingsboard/server/controller/plugin/TbWebSocketHandler.java index 9fdda2215d..febb9ac998 100644 --- a/application/src/main/java/org/thingsboard/server/controller/plugin/TbWebSocketHandler.java +++ b/application/src/main/java/org/thingsboard/server/controller/plugin/TbWebSocketHandler.java @@ -290,7 +290,6 @@ public class TbWebSocketHandler extends TextWebSocketHandler implements Telemetr log.trace("[{}] Failed to send msg", session.getId(), result.getException()); closeSession(CloseStatus.SESSION_NOT_RELIABLE); } else { - lastActivityTime = System.currentTimeMillis(); String msg = msgQueue.poll(); if (msg != null) { sendMsgInternal(msg); diff --git a/application/src/main/java/org/thingsboard/server/service/subscription/DefaultTbEntityDataSubscriptionService.java b/application/src/main/java/org/thingsboard/server/service/subscription/DefaultTbEntityDataSubscriptionService.java index c0f882bfe8..89f0475bb7 100644 --- a/application/src/main/java/org/thingsboard/server/service/subscription/DefaultTbEntityDataSubscriptionService.java +++ b/application/src/main/java/org/thingsboard/server/service/subscription/DefaultTbEntityDataSubscriptionService.java @@ -499,6 +499,12 @@ public class DefaultTbEntityDataSubscriptionService implements TbEntityDataSubsc if (ctx != null) { ctx.cancelTasks(); ctx.clearSubscriptions(); + if (ctx.getSessionId() != null) { + Map sessionSubs = subscriptionsBySessionId.get(ctx.getSessionId()); + if (sessionSubs != null) { + sessionSubs.remove(ctx.getCmdId()); + } + } } } From 22f4589027f3813fbfd2d6ae04768cecbb15c4f6 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Wed, 5 Jan 2022 17:47:01 +0200 Subject: [PATCH 342/432] lwm2m add to test shell credentials --- ...cfssl_chain_trusts_and_clients_for_test.sh | 299 ++++++++++++++++++ .../shell/lwm2m_cfssl_chain_for_test_All.sh | 65 ++++ .../lwm2m_cfssl_chain_server_for_test.sh | 298 +++++++++++++++++ 3 files changed, 662 insertions(+) create mode 100755 application/src/test/resources/lwm2m/credentials/shell/lwM2M_cfssl_chain_trusts_and_clients_for_test.sh create mode 100755 application/src/test/resources/lwm2m/credentials/shell/lwm2m_cfssl_chain_for_test_All.sh create mode 100755 application/src/test/resources/lwm2m/credentials/shell/lwm2m_cfssl_chain_server_for_test.sh diff --git a/application/src/test/resources/lwm2m/credentials/shell/lwM2M_cfssl_chain_trusts_and_clients_for_test.sh b/application/src/test/resources/lwm2m/credentials/shell/lwM2M_cfssl_chain_trusts_and_clients_for_test.sh new file mode 100755 index 0000000000..26f47266a7 --- /dev/null +++ b/application/src/test/resources/lwm2m/credentials/shell/lwM2M_cfssl_chain_trusts_and_clients_for_test.sh @@ -0,0 +1,299 @@ +#!/usr/bin/env bash + +# Change working directory +cd -- "$( + dirname "${0}" +)" || exit 1 + +readonly TRUST_PATH="Trust" +readonly CA_ROOT_CERT_KEY="ca-root" +readonly CA_ROOT_ALIAS="root" +readonly CA_INTERMEDIATE_CERT_KEY_PREF="intermediate_ca" +CA_INTERMEDIATE_START=0 +CA_INTERMEDIATE_FINISH=2 +CA_INTERMEDIATE_NUMBER=${CA_INTERMEDIATE_START} +CA_INTERMEDIATE_CERT_SIGN=${CA_ROOT_CERT_KEY} +CA_LIST_CERT_FOR_CAT="" +readonly CA_TRUST_STORE_ALL_CHAIN="lwm2mtruststorechain" +readonly CA_TRUST_STORE_PWD="server_ks_password" +readonly CA_TRUST_CERT_ALIAS="root" +readonly CA_TRUST_CERT_CHAIN_JKS="lwm2mtruststorechain" +readonly CA_TRUST_STORE_CHAIN_ALIAS="trust_cert_chain_alias" + +readonly CLIENT_PATH="Client" +readonly CLIENT_JKS_FOR_TEST="lwm2mclient" +readonly CLIENT_CERT_KEY_PREF="LwX509" +readonly CLIENT_CERT_ALIAS_PREF="client_alias_" +readonly CLIENT_STORE_PWD="client_ks_password" +readonly CLIENT_HOST_NAME="thingsboard_test.io" +CLIENT_START=0 +CLIENT_FINISH=1 +CLIENT_NUMBER=${CLIENT_START} + +SERVER_HOST_NAME="localhost.localdomain" +SERVER_LOCAL_HOST_NAME="localhost" +SERVER_PUBLIC_HOST_NAMES="-" + +readonly CF_COMMANDS=" + cfssl + cfssljson +" + +if [ ! -z "$1" ]; then + CA_INTERMEDIATE_START=$1 + CA_INTERMEDIATE_NUMBER=${CA_INTERMEDIATE_START} +fi + +if [ ! -z "$2" ]; then + CA_INTERMEDIATE_FINISH=$2 +fi + +if [ ! -z "$3" ]; then + CLIENT_START=$1 + CLIENT_NUMBER=${CLIENT_START} +fi + +if [ ! -z "$4" ]; then + CLIENT_FINISH=$4 +fi + +# Change working directory +rm -rf ${TRUST_PATH} +mkdir -p ${TRUST_PATH} +rm -rf ${CLIENT_PATH} +mkdir -p ${CLIENT_PATH} +cd -- "$( + dirname "${0}" +)" || exit 1 + + +rm *.csr +rm *.p12 +rm *.json +rm *.pem +rm *.jks + +intermediate_common_name() { + echo "${CA_INTERMEDIATE_CERT_KEY_PREF}${CA_INTERMEDIATE_NUMBER}" +} + +set_list_sert_for_cat() { + local first="$1" + echo "$first ${CA_LIST_CERT_FOR_CAT}" +} + +client_common_name() { + echo "${CLIENT_CERT_KEY_PREF}$(printf "%08d" ${CLIENT_NUMBER})" +} + +client_alias_name() { + echo "${CLIENT_CERT_ALIAS_PREF}$(printf "%08d" ${CLIENT_NUMBER})" +} + +for COMMAND in ${CF_COMMANDS}; do + if ! command -v ${COMMAND} &> /dev/null; then + echo "ERROR: Missing command ${COMMAND}" >&2 + echo "Install the package from: https://pkg.cfssl.org/" >&2 + exit 1 + fi +done + +tee ./${TRUST_PATH}/ca-config.json 1> /dev/null <<-CONFIG +{ + "signing": { + "default": { + "expiry": "8760h", + "names": [ + { + "C": "UK", + "ST": "Kyiv city", + "L": "Kyiv", + "O": "Thingsboard", + "OU": "DEVELOPER_TEST" + } + ] + }, + "profiles": { + "server": { + "expiry": "43800h", + "key": { + "algo": "ecdsa", + "size": 256 + }, + "usages": [ + "signing", + "key encipherment", + "server auth" + ] + }, + "client": { + "expiry": "43800h", + "key": { + "algo": "ecdsa", + "size": 256 + }, + "usages": [ + "signing", + "key encipherment", + "client auth" + ] + }, + "client-server": { + "expiry": "43800h", + "key": { + "algo": "ecdsa", + "size": 256 + }, + "usages": [ + "signing", + "key encipherment", + "server auth", + "client auth" + ] + } + } + } +} +CONFIG + +tee ./${TRUST_PATH}/ca-root-to-intermediate-config.json 1> /dev/null <<-CONFIG +{ + "signing": { + "default": { + "expiry": "43800h", + "ca_constraint": { + "is_ca": true, + "max_path_len": 0, + "max_path_len_zero": true + }, + "key": { + "algo": "ecdsa", + "size": 256 + }, + "usages": [ + "digital signature", + "cert sign", + "crl sign", + "signing" + ] + } + } +} +CONFIG + +echo "====================================================" +echo -e "Generate the root of certificates: \n-${CA_ROOT_KEY}-key.pem (certificate key)\n-${CA_ROOT_KEY}.pem (certificate)\n-${CA_ROOT_KEY}.csr (sign request)" +echo "====================================================" +cfssl genkey \ + -initca \ + - \ + <<-CONFIG | cfssljson -bare ./${TRUST_PATH}/${CA_ROOT_CERT_KEY} +{ + "CN": "ROOT CA", + "key": { + "algo": "ecdsa", + "size": 256 + }, + "names": [ + { + "C": "UK", + "ST": "Kyiv city", + "L": "Kyiv", + "O": "Thingsboard", + "OU": "DEVELOPER_TEST" + } + ], + "ca": { + "expiry": "131400h" + } +} +CONFIG +CA_LIST_CERT_FOR_CAT=$(set_list_sert_for_cat ./${TRUST_PATH}/${CA_ROOT_CERT_KEY}.pem) + +echo "====================================================" +echo -e "Generate and Signed the intermediates of our certificates: \n-${CA_INTERMEDIATE_CERT_KEY_PREF}?-key.pem (certificate key)\n-${CA_INTERMEDIATE_CERT_KEY_PREF}?.pem (certificate)\n-${CA_INTERMEDIATE_CERT_KEY_PREF}?.csr (sign request)" +echo "====================================================" + +while [[ ${CA_INTERMEDIATE_NUMBER} -lt ${CA_INTERMEDIATE_FINISH} ]]; +do + CA_INTERMEDIATE_CERT_KEY=$(intermediate_common_name) + CA_INTERMEDIATE_NUMBER=$((${CA_INTERMEDIATE_NUMBER} + 1)) + + cfssl gencert \ + -ca ./${TRUST_PATH}/${CA_INTERMEDIATE_CERT_SIGN}.pem \ + -ca-key ./${TRUST_PATH}/${CA_INTERMEDIATE_CERT_SIGN}-key.pem \ + -config ./${TRUST_PATH}/ca-root-to-intermediate-config.json \ + -hostname "${SERVER_HOST_NAME},${SERVER_LOCAL_HOST_NAME}${SERVER_PUBLIC_HOST_NAMES:+, }${SERVER_PUBLIC_HOST_NAMES}" \ + - \ + <<-CONFIG | cfssljson -bare ./${TRUST_PATH}/${CA_INTERMEDIATE_CERT_KEY} + { + "CN": "${CA_INTERMEDIATE_CERT_KEY}", + "names": [ + { + "C": "UK", + "ST": "Kyiv city", + "L": "Kyiv", + "O": "Thingsboard", + "OU": "DEVELOPER_TEST" + } + ] + } +CONFIG + #openssl x509 -in ${CA_INTERMEDIATE_CERT_KEY}.pem -text -noout + CA_LIST_CERT_FOR_CAT=$(set_list_sert_for_cat ./${TRUST_PATH}/${CA_INTERMEDIATE_CERT_KEY}.pem) + CA_INTERMEDIATE_CERT_SIGN=${CA_INTERMEDIATE_CERT_KEY} +done + +echo "====================================================" +echo -e "Add the CA_certificate to keystore: ${CA_TRUST_CERT_CHAIN_JKS}.jks" +echo "====================================================" +cat ${CA_LIST_CERT_FOR_CAT} > ./${TRUST_PATH}/${CA_TRUST_STORE_ALL_CHAIN}.pem +openssl pkcs12 -export -in ./${TRUST_PATH}/${CA_TRUST_STORE_ALL_CHAIN}.pem -inkey ./${TRUST_PATH}/${CA_INTERMEDIATE_CERT_KEY}-key.pem -out ./${TRUST_PATH}/${CA_INTERMEDIATE_CERT_KEY}.p12 -name ${CA_TRUST_STORE_CHAIN_ALIAS} -CAfile ./${TRUST_PATH}/${CA_INTERMEDIATE_CERT_KEY}.pem -caname ${CA_ROOT_ALIAS} -passin pass:${CA_TRUST_STORE_PWD} -passout pass:${CA_TRUST_STORE_PWD} +keytool -importkeystore -deststorepass ${CA_TRUST_STORE_PWD} -destkeypass ${CA_TRUST_STORE_PWD} -destkeystore ./${TRUST_PATH}/${CA_TRUST_CERT_CHAIN_JKS}.jks -srckeystore ./${TRUST_PATH}/${CA_INTERMEDIATE_CERT_KEY}.p12 -srcstoretype PKCS12 -srcstorepass ${CA_TRUST_STORE_PWD} -alias ${CA_TRUST_STORE_CHAIN_ALIAS} + +keytool -list -v -keystore ./${TRUST_PATH}/lwm2mtruststorechain.jks -storepass server_ks_password -storetype PKCS12 + +echo "====================================================" +echo -e "Generate and Signed the clients of our certificates: \n-${CLIENT_CERT_KEY_PREF}?-key.pem (certificate key)\n-${CLIENT_CERT_KEY_PREF}?.pem (certificate)\n-${CCLIENT_CERT_KEY_PREF}?.csr (sign request)" +echo "====================================================" + + +while [[ ${CLIENT_NUMBER} -lt ${CLIENT_FINISH} ]]; +do + CLIENT_CERT_KEY=$(client_common_name) + CLIENT_CERT_ALIAS=$(client_alias_name) + CLIENT_NUMBER=$((${CLIENT_NUMBER} + 1)) + + cfssl gencert \ + -ca ./${TRUST_PATH}/${CA_INTERMEDIATE_CERT_KEY}.pem \ + -ca-key ./${TRUST_PATH}/${CA_INTERMEDIATE_CERT_KEY}-key.pem \ + -config ./${TRUST_PATH}/ca-config.json \ + -profile client \ + -hostname "${CLIENT_HOST_NAME}" \ + - \ + <<-CONFIG | cfssljson -bare ./${CLIENT_PATH}/${CLIENT_CERT_KEY} +{ + "CN": "${CLIENT_CERT_KEY}" +} +CONFIG + +echo "====================================================" +echo -e "Add the client certificate (${CLIENT_CERT_KEY}.pem) to keystore: ${CLIENT_JKS_FOR_TEST}.jks" +echo "====================================================" +cat ./${CLIENT_PATH}/${CLIENT_CERT_KEY}.pem ${CA_LIST_CERT_FOR_CAT} > ./${CLIENT_PATH}/${CLIENT_CERT_KEY}_chain.pem +openssl pkcs12 -export -in ./${CLIENT_PATH}/${CLIENT_CERT_KEY}_chain.pem -inkey ./${CLIENT_PATH}/${CLIENT_CERT_KEY}-key.pem -out ./${CLIENT_PATH}/${CLIENT_CERT_KEY}.p12 -name ${CLIENT_CERT_ALIAS} -CAfile ./${TRUST_PATH}/${CA_INTERMEDIATE_CERT_KEY}.pem -caname ${CA_ROOT_ALIAS} -passin pass:${CLIENT_STORE_PWD} -passout pass:${CLIENT_STORE_PWD} +keytool -importkeystore -deststorepass ${CLIENT_STORE_PWD} -destkeypass ${CLIENT_STORE_PWD} -destkeystore ./${CLIENT_PATH}/${CLIENT_JKS_FOR_TEST}.jks -srckeystore ./${CLIENT_PATH}/${CLIENT_CERT_KEY}.p12 -srcstoretype PKCS12 -srcstorepass ${CLIENT_STORE_PWD} -alias ${CLIENT_CERT_ALIAS} + +done + +keytool -list -v -keystore ./${CLIENT_PATH}/lwm2mclient.jks -storepass client_ks_password -storetype PKCS12 + +rm ./${TRUST_PATH}/*.p12 +rm ./${TRUST_PATH}/*.csr +rm ./${TRUST_PATH}/*.json +rm ./${TRUST_PATH}/${CA_ROOT_CERT_KEY}* +rm ./${TRUST_PATH}/${CA_INTERMEDIATE_CERT_KEY_PREF}* + + +rm ./${CLIENT_PATH}/*.p12 2> /dev/null +rm ./${CLIENT_PATH}/*.csr 2> /dev/null diff --git a/application/src/test/resources/lwm2m/credentials/shell/lwm2m_cfssl_chain_for_test_All.sh b/application/src/test/resources/lwm2m/credentials/shell/lwm2m_cfssl_chain_for_test_All.sh new file mode 100755 index 0000000000..b3b114cb28 --- /dev/null +++ b/application/src/test/resources/lwm2m/credentials/shell/lwm2m_cfssl_chain_for_test_All.sh @@ -0,0 +1,65 @@ +#!/usr/bin/env bash + +readonly INTERMEDIATE_START=0 +readonly INTERMEDIATE_FINISH=2 +readonly CLIENT_START=0 +readonly CLIENT_FINISH=5 + +IS_IHFO=false +IS_SERVER_CREATED_KEY=true +IS_TRUST_CLIENT_CREATED_KEY=true + +cd -- "$( + dirname "${0}" +)" || exit 1 + +Help() +{ + # Display Help + echo "Description of the script functions." + echo + echo "Syntax: scriptTemplate [-g|h|v|V]" + echo "options:" + echo "h Print this Help." + echo "v Verbose mode." + echo "V Print software version and exit." + echo +} + +if [ "$1" == "-h" ] ; then + echo -e "Usage 2: ./`basename $0` \"Information is not displayed\" : \"Keys for the server are generated\" : \"Keys for the clients and trusts are generated\"" + echo -e "Usage 1: ./`basename $0` true \"Information is displayed\" : \"Keys for the server are generated\" : \"Keys for the clients and trusts are generated\"" + echo -e "Usage 3: ./`basename $0` true false \"Information is displayed\" : \"Keys for the server are not generated\" : \"Keys for the clients and trusts are generated\"" + echo -e "Usage 4: ./`basename $0` true false false \"Information is displayed\" : \"Keys for the server are not generated\" : \"Keys for the clients and trusts are not generated\"" + echo -e "Usage 4: ./`basename $0` true true false \"Information is displayed\" : \"Keys for the server are generated\" : \"Keys for the clients and trusts are not generated\"" + echo "This Help File: ./`basename $0` -h" + exit 0 +fi + +if [ -n "$1" ]; then + IS_IHFO=$1 +fi + +if [ -n "$2" ]; then + IS_SERVER_CREATED_KEY=$2 +fi + +if [ -n "$3" ]; then + IS_TRUST_CLIENT_CREATED_KEY=$3 +fi + +if [ "$IS_IHFO" = false ] ; then + if [ "$IS_SERVER_CREATED_KEY" = true ] ; then + ./lwm2m_cfssl_chain_server_for_test.sh > /dev/null 2>&1 & + fi + if [ "$IS_TRUST_CLIENT_CREATED_KEY" = true ] ; then + ./lwM2M_cfssl_chain_trusts_and_clients_for_test.sh ${INTERMEDIATE_START} ${INTERMEDIATE_FINISH} ${CLIENT_START} ${CLIENT_FINISH} > /dev/null 2>&1 & + fi +else + if [ "$IS_SERVER_CREATED_KEY" = true ] ; then + ./lwm2m_cfssl_chain_server_for_test.sh + fi + if [ "$IS_TRUST_CLIENT_CREATED_KEY" = true ] ; then + ./lwM2M_cfssl_chain_trusts_and_clients_for_test.sh ${INTERMEDIATE_START} ${INTERMEDIATE_FINISH} ${CLIENT_START} ${CLIENT_FINISH} + fi +fi \ No newline at end of file diff --git a/application/src/test/resources/lwm2m/credentials/shell/lwm2m_cfssl_chain_server_for_test.sh b/application/src/test/resources/lwm2m/credentials/shell/lwm2m_cfssl_chain_server_for_test.sh new file mode 100755 index 0000000000..efe6ed46dd --- /dev/null +++ b/application/src/test/resources/lwm2m/credentials/shell/lwm2m_cfssl_chain_server_for_test.sh @@ -0,0 +1,298 @@ +#!/usr/bin/env bash + +# REF: https://github.com/cloudflare/cfssl + +# Change working directory +cd -- "$( + dirname "${0}" +)" || exit 1 + +readonly CA_ROOT_CERT_KEY="ca-root" +readonly CA_ROOT_ALIAS="root" +readonly CA_INTERMEDIATE_CERT_KEY_PREF="intermediate_ca" +CA_INTERMEDIATE_NUMBER=0 +CA_LIST_CERT_FOR_CAT="" + +readonly CF_COMMANDS=" + cfssl + cfssljson +" + +readonly SERVER_JKS_FOR_TEST="lwm2mserver" +readonly STORE_PASS_PWD="server_ks_password" +readonly SERVER_PATH="Server" +readonly SERVER_CERT_KEY="lwm2mserver" +readonly SERVER_CERT_CHAIN="lwm2mserver_chain" +readonly SERVER_CERT_ALIAS="server" +readonly BS_SERVER_CERT_KEY="lwm2mserverbs" +readonly BS_SERVER_CERT_CHAIN="lwm2mserverbs_chain" +readonly BS_SERVER_CERT_ALIAS="bootstrap" + +SERVER_HOST_NAME="localhost.localdomain" +SERVER_LOCAL_HOST_NAME="localhost" +SERVER_PUBLIC_HOST_NAMES="-" + +intermediate_common_name() { + echo "${CA_INTERMEDIATE_CERT_KEY_PREF}${CA_INTERMEDIATE_NUMBER}" +} + +set_list_sert_for_cat() { + local first="$1" + echo "$first ${CA_LIST_CERT_FOR_CAT}" +} + + +# Change working directory +rm -rf ${SERVER_PATH} +mkdir -p ${SERVER_PATH} + +cd -- "$( + dirname ./${SERVER_PATH} +)" || exit 1 + + +rm *.csr +rm *.p12 +rm *.json +rm *.pem +rm *.jks + +CA_INTERMEDIATE_CERT_SIGN=${CA_ROOT_CERT_KEY} +CA_INTERMEDIATE_CERT_KEY=$(intermediate_common_name) +CA_INTERMEDIATE_NUMBER=$((${CA_INTERMEDIATE_NUMBER} + 1)) +CA_LIST_CERT_FOR_CAT="" + +for COMMAND in ${CF_COMMANDS}; do + if ! command -v ${COMMAND} &> /dev/null; then + echo "ERROR: Missing command ${COMMAND}" >&2 + echo "Install the package from: https://pkg.cfssl.org/" >&2 + exit 1 + fi +done + +tee ./${SERVER_PATH}/ca-config.json 1> /dev/null <<-CONFIG +{ + "signing": { + "default": { + "expiry": "8760h", + "names": [ + { + "C": "UK", + "ST": "Kyiv city", + "L": "Kyiv", + "O": "Thingsboard", + "OU": "DEVELOPER_TEST" + } + ] + }, + "profiles": { + "server": { + "expiry": "43800h", + "key": { + "algo": "ecdsa", + "size": 256 + }, + "usages": [ + "signing", + "key encipherment", + "server auth" + ] + }, + "client": { + "expiry": "43800h", + "key": { + "algo": "ecdsa", + "size": 256 + }, + "usages": [ + "signing", + "key encipherment", + "client auth" + ] + }, + "client-server": { + "expiry": "43800h", + "key": { + "algo": "ecdsa", + "size": 256 + }, + "usages": [ + "signing", + "key encipherment", + "server auth", + "client auth" + ] + } + } + } +} +CONFIG + +tee ./${SERVER_PATH}/ca-root-to-intermediate-config.json 1> /dev/null <<-CONFIG +{ + "signing": { + "default": { + "expiry": "43800h", + "ca_constraint": { + "is_ca": true, + "max_path_len": 0, + "max_path_len_zero": true + }, + "key": { + "algo": "ecdsa", + "size": 256 + }, + "usages": [ + "digital signature", + "cert sign", + "crl sign", + "signing" + ] + } + } +} +CONFIG + +echo "====================================================" +echo -e "Generate the root of certificates: \n-${CA_ROOT_KEY}-key.pem (certificate key)\n-${CA_ROOT_KEY}.pem (certificate)\n-${CA_ROOT_KEY}.csr (sign request)" +echo "====================================================" +cfssl genkey \ + -initca \ + - \ + <<-CONFIG | cfssljson -bare ./${SERVER_PATH}/${CA_ROOT_CERT_KEY} +{ + "CN": "ROOT CA for servers", + "key": { + "algo": "ecdsa", + "size": 256 + }, + "names": [ + { + "C": "UK", + "ST": "Kyiv city", + "L": "Kyiv", + "O": "Thingsboard", + "OU": "DEVELOPER_TEST" + } + ], + "ca": { + "expiry": "131400h" + } +} +CONFIG +CA_LIST_CERT_FOR_CAT=$(set_list_sert_for_cat ./${SERVER_PATH}/${CA_ROOT_CERT_KEY}.pem) + +echo "====================================================" +echo -e "Generate and Signed the first intermediates of our certificates: \n-${CA_INTERMEDIATE_CERT_KEY}-key.pem (certificate key)\n-${CA_INTERMEDIATE_CERT_KEY}.pem (certificate)\n-${CA_INTERMEDIATE_CERT_KEY}.csr (sign request)" +echo "====================================================" +cfssl gencert \ + -ca ./${SERVER_PATH}/${CA_INTERMEDIATE_CERT_SIGN}.pem \ + -ca-key ./${SERVER_PATH}/${CA_INTERMEDIATE_CERT_SIGN}-key.pem \ + -config ./${SERVER_PATH}/ca-root-to-intermediate-config.json \ + -hostname "${SERVER_HOST_NAME},${SERVER_LOCAL_HOST_NAME}${SERVER_PUBLIC_HOST_NAMES:+, }${SERVER_PUBLIC_HOST_NAMES}" \ + - \ + <<-CONFIG | cfssljson -bare ./${SERVER_PATH}/${CA_INTERMEDIATE_CERT_KEY} +{ + "CN": "${CA_INTERMEDIATE_CERT_KEY}", + "names": [ + { + "C": "UK", + "ST": "Kyiv city", + "L": "Kyiv", + "O": "Thingsboard", + "OU": "DEVELOPER_TEST" + } + ] +} +CONFIG +CA_LIST_CERT_FOR_CAT=$(set_list_sert_for_cat ./${SERVER_PATH}/${CA_INTERMEDIATE_CERT_KEY}.pem) + + +## Lwm2m Server certificate +echo "====================================================" +echo -e "Generate and Signed the server certificate: \n-${SERVER_CERT_KEY}-key.pem (certificate key)\n-${SERVER_CERT_KEY}.pem (certificate)\n-${SERVER_CERT_KEY}.csr (sign request)" +echo "====================================================" +cfssl gencert \ + -ca ./${SERVER_PATH}/${CA_INTERMEDIATE_CERT_KEY}.pem \ + -ca-key ./${SERVER_PATH}/${CA_INTERMEDIATE_CERT_KEY}-key.pem \ + -config ./${SERVER_PATH}/ca-config.json \ + -profile server \ + -hostname "${SERVER_HOST_NAME},${SERVER_LOCAL_HOST_NAME}${SERVER_PUBLIC_HOST_NAMES:+, }${SERVER_PUBLIC_HOST_NAMES}" \ + - \ + <<-CONFIG | cfssljson -bare ./${SERVER_PATH}/${SERVER_CERT_KEY} +{ + "CN": "${SERVER_LOCAL_HOST_NAME}" +} +CONFIG + +echo "====================================================" +echo -e "Add the server certificate (${SERVER_CERT_KEY}.pem) to keystore: ${SERVER_JKS_FOR_TEST}.jks" +echo "====================================================" +cat ./${SERVER_PATH}/${SERVER_CERT_KEY}.pem ${CA_LIST_CERT_FOR_CAT} > ./${SERVER_PATH}/${SERVER_CERT_CHAIN}.pem +openssl pkcs12 -export -in ./${SERVER_PATH}/${SERVER_CERT_CHAIN}.pem -inkey ./${SERVER_PATH}/${SERVER_CERT_KEY}-key.pem -out ./${SERVER_PATH}/${SERVER_CERT_KEY}.p12 -name ${SERVER_CERT_ALIAS} -CAfile ./${SERVER_PATH}/${CA_INTERMEDIATE_CERT_KEY}.pem -caname ${CA_ROOT_ALIAS} -passin pass:${STORE_PASS_PWD} -passout pass:${STORE_PASS_PWD} +keytool -importkeystore -deststorepass ${STORE_PASS_PWD} -destkeypass ${STORE_PASS_PWD} -destkeystore ./${SERVER_PATH}/${SERVER_JKS_FOR_TEST}.jks -srckeystore ./${SERVER_PATH}/${SERVER_CERT_KEY}.p12 -srcstoretype PKCS12 -srcstorepass ${STORE_PASS_PWD} -alias ${SERVER_CERT_ALIAS} + + +CA_INTERMEDIATE_CERT_SIGN=${CA_INTERMEDIATE_CERT_KEY} +CA_INTERMEDIATE_CERT_KEY=$(intermediate_common_name) +CA_INTERMEDIATE_NUMBER=$((${CA_INTERMEDIATE_NUMBER} + 1)) +echo "====================================================" +echo -e "Generate and Signed the second intermediates of our certificates: \n-${CA_INTERMEDIATE_CERT_KEY}-key.pem (certificate key)\n-${CA_INTERMEDIATE_CERT_KEY}.pem (certificate)\n-${CA_INTERMEDIATE_CERT_KEY}.csr (sign request)" +echo "====================================================" +cfssl gencert \ + -ca ./${SERVER_PATH}/${CA_INTERMEDIATE_CERT_SIGN}.pem \ + -ca-key ./${SERVER_PATH}/${CA_INTERMEDIATE_CERT_SIGN}-key.pem \ + -config ./${SERVER_PATH}/ca-root-to-intermediate-config.json \ + -hostname "${SERVER_HOST_NAME},${SERVER_LOCAL_HOST_NAME}${SERVER_PUBLIC_HOST_NAMES:+, }${SERVER_PUBLIC_HOST_NAMES}" \ + - \ + <<-CONFIG | cfssljson -bare ./${SERVER_PATH}/${CA_INTERMEDIATE_CERT_KEY} +{ + "CN": "${CA_INTERMEDIATE_CERT_KEY}", + "names": [ + { + "C": "UK", + "ST": "Kyiv city", + "L": "Kyiv", + "O": "Thingsboard", + "OU": "DEVELOPER_TEST" + } + ] +} +CONFIG +CA_LIST_CERT_FOR_CAT=$(set_list_sert_for_cat ./${SERVER_PATH}/${CA_INTERMEDIATE_CERT_KEY}.pem) + +## Bootstrap server certificate +echo "====================================================" +echo -e "Generate and Signed the server certificate: \n-${BS_SERVER_CERT_KEY}-key.pem (certificate key)\n-${BS_SERVER_CERT_KEY}.pem (certificate)\n-${BS_SERVER_CERT_KEY}.csr (sign request)" +echo "====================================================" +cfssl gencert \ + -ca ./${SERVER_PATH}/${CA_INTERMEDIATE_CERT_KEY}.pem \ + -ca-key ./${SERVER_PATH}/${CA_INTERMEDIATE_CERT_KEY}-key.pem \ + -config ./${SERVER_PATH}/ca-config.json \ + -profile server \ + -hostname "${SERVER_HOST_NAME},${SERVER_LOCAL_HOST_NAME}${SERVER_PUBLIC_HOST_NAMES:+, }${SERVER_PUBLIC_HOST_NAMES}" \ + - \ + <<-CONFIG | cfssljson -bare ./${SERVER_PATH}/${BS_SERVER_CERT_KEY} +{ + "CN": "${SERVER_LOCAL_HOST_NAME}" +} +CONFIG + +echo "====================================================" +echo -e "Add the Bootstrap server certificate (${BS_SERVER_CERT_KEY}.pem) to keystore: ${SERVER_JKS_FOR_TEST}.jks" +echo "====================================================" +cat ./${SERVER_PATH}/${BS_SERVER_CERT_KEY}.pem ${CA_LIST_CERT_FOR_CAT} > ./${SERVER_PATH}/${BS_SERVER_CERT_CHAIN}.pem +openssl pkcs12 -export -in ./${SERVER_PATH}/${BS_SERVER_CERT_CHAIN}.pem -inkey ./${SERVER_PATH}/${BS_SERVER_CERT_KEY}-key.pem -out ./${SERVER_PATH}/${BS_SERVER_CERT_KEY}.p12 -name ${BS_SERVER_CERT_ALIAS} -CAfile ./${SERVER_PATH}/${CA_INTERMEDIATE_CERT_KEY}.pem -caname ${CA_ROOT_ALIAS} -passin pass:${STORE_PASS_PWD} -passout pass:${STORE_PASS_PWD} +keytool -importkeystore -deststorepass ${STORE_PASS_PWD} -destkeypass ${STORE_PASS_PWD} -destkeystore ./${SERVER_PATH}/${SERVER_JKS_FOR_TEST}.jks -srckeystore ./${SERVER_PATH}/${BS_SERVER_CERT_KEY}.p12 -srcstoretype PKCS12 -srcstorepass ${STORE_PASS_PWD} -alias ${BS_SERVER_CERT_ALIAS} + + +keytool -list -v -keystore ./${SERVER_PATH}/lwm2mserver.jks -storepass server_ks_password -storetype PKCS12 + +rm ./${SERVER_PATH}/*.p12 2> /dev/null +rm ./${SERVER_PATH}/*.csr 2> /dev/null +rm ./${SERVER_PATH}/*.json 2> /dev/null +rm ./${SERVER_PATH}/${CA_INTERMEDIATE_CERT_KEY_PREF}* 2> /dev/null +rm ./${SERVER_PATH}/${CA_ROOT_CERT_KEY}* 2> /dev/null +mv ./${SERVER_PATH}/${SERVER_CERT_KEY}-key.pem ./${SERVER_PATH}/${SERVER_CERT_KEY}_key.pem +mv ./${SERVER_PATH}/${BS_SERVER_CERT_KEY}-key.pem ./${SERVER_PATH}/${BS_SERVER_CERT_KEY}_key.pem + From e5e79a22f6e5ac0ae48634a77b67a841c61346f8 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Wed, 5 Jan 2022 18:11:34 +0200 Subject: [PATCH 343/432] lwm2m tests with credentials RPK and X509 - ignore --- .../security/sql/RpkLwM2MIntegrationTest.java | 2 ++ .../sql/X509_NoTrustLwM2MIntegrationTest.java | 2 ++ .../sql/X509_TrustLwM2MIntegrationTest.java | 2 ++ .../resources/application-test.properties | 34 +++++++++---------- 4 files changed, 23 insertions(+), 17 deletions(-) diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/RpkLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/RpkLwM2MIntegrationTest.java index 9e74beaa6b..87ca415bd0 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/RpkLwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/RpkLwM2MIntegrationTest.java @@ -16,6 +16,7 @@ package org.thingsboard.server.transport.lwm2m.security.sql; import org.eclipse.leshan.client.object.Security; +import org.junit.Ignore; import org.junit.Test; import org.thingsboard.server.common.data.device.credentials.lwm2m.RPKClientCredential; import org.thingsboard.server.transport.lwm2m.security.AbstractSecurityLwM2MIntegrationTest; @@ -29,6 +30,7 @@ import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SHORT_SERVE public class RpkLwM2MIntegrationTest extends AbstractSecurityLwM2MIntegrationTest { + @Ignore @Test public void testConnectWithRPKAndObserveTelemetry() throws Exception { RPKClientCredential rpkClientCredentials = new RPKClientCredential(); diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/X509_NoTrustLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/X509_NoTrustLwM2MIntegrationTest.java index f55c21dcc2..d1bc813b50 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/X509_NoTrustLwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/X509_NoTrustLwM2MIntegrationTest.java @@ -16,6 +16,7 @@ package org.thingsboard.server.transport.lwm2m.security.sql; import org.eclipse.leshan.client.object.Security; +import org.junit.Ignore; import org.junit.Test; import org.thingsboard.server.common.data.device.credentials.lwm2m.X509ClientCredential; import org.thingsboard.server.common.transport.util.SslUtil; @@ -28,6 +29,7 @@ import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SHORT_SERVE public class X509_NoTrustLwM2MIntegrationTest extends AbstractSecurityLwM2MIntegrationTest { + @Ignore @Test public void testConnectWithCertAndObserveTelemetry() throws Exception { X509ClientCredential credentials = new X509ClientCredential(); diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/X509_TrustLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/X509_TrustLwM2MIntegrationTest.java index 32d176d598..7c5e48a4b7 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/X509_TrustLwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/X509_TrustLwM2MIntegrationTest.java @@ -16,6 +16,7 @@ package org.thingsboard.server.transport.lwm2m.security.sql; import org.eclipse.leshan.client.object.Security; +import org.junit.Ignore; import org.junit.Test; import org.thingsboard.server.common.data.device.credentials.lwm2m.X509ClientCredential; import org.thingsboard.server.transport.lwm2m.security.AbstractSecurityLwM2MIntegrationTest; @@ -27,6 +28,7 @@ import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SHORT_SERVE public class X509_TrustLwM2MIntegrationTest extends AbstractSecurityLwM2MIntegrationTest { + @Ignore @Test public void testConnectAndObserveTelemetry() throws Exception { X509ClientCredential credentials = new X509ClientCredential(); diff --git a/application/src/test/resources/application-test.properties b/application/src/test/resources/application-test.properties index 651b00ed67..856745797a 100644 --- a/application/src/test/resources/application-test.properties +++ b/application/src/test/resources/application-test.properties @@ -1,20 +1,20 @@ -transport.lwm2m.server.security.credentials.enabled=true -transport.lwm2m.server.security.credentials.type=KEYSTORE -transport.lwm2m.server.security.credentials.keystore.store_file=lwm2m/credentials/serverKeyStore.jks -transport.lwm2m.server.security.credentials.keystore.store_password=server -transport.lwm2m.server.security.credentials.keystore.key_alias=server -transport.lwm2m.server.security.credentials.keystore.key_password=server -transport.lwm2m.bootstrap.enabled=false -transport.lwm2m.bootstrap.security.credentials.enabled=true -transport.lwm2m.bootstrap.security.credentials.type=KEYSTORE -transport.lwm2m.bootstrap.security.credentials.keystore.store_file=lwm2m/credentials/serverKeyStore.jks -transport.lwm2m.bootstrap.security.credentials.keystore.store_password=server -transport.lwm2m.bootstrap.security.credentials.keystore.key_alias=server -transport.lwm2m.bootstrap.security.credentials.keystore.key_password=server -transport.lwm2m.security.trust-credentials.enabled=true -transport.lwm2m.security.trust-credentials.type=KEYSTORE -transport.lwm2m.security.trust-credentials.keystore.store_file=lwm2m/credentials/serverKeyStore.jks -transport.lwm2m.security.trust-credentials.keystore.store_password=server +#transport.lwm2m.server.security.credentials.enabled=true +#transport.lwm2m.server.security.credentials.type=KEYSTORE +#transport.lwm2m.server.security.credentials.keystore.store_file=lwm2m/credentials/serverKeyStore.jks +#transport.lwm2m.server.security.credentials.keystore.store_password=server +#transport.lwm2m.server.security.credentials.keystore.key_alias=server +#transport.lwm2m.server.security.credentials.keystore.key_password=server +#transport.lwm2m.bootstrap.enabled=false +#transport.lwm2m.bootstrap.security.credentials.enabled=true +#transport.lwm2m.bootstrap.security.credentials.type=KEYSTORE +#transport.lwm2m.bootstrap.security.credentials.keystore.store_file=lwm2m/credentials/serverKeyStore.jks +#transport.lwm2m.bootstrap.security.credentials.keystore.store_password=server +#transport.lwm2m.bootstrap.security.credentials.keystore.key_alias=server +#transport.lwm2m.bootstrap.security.credentials.keystore.key_password=server +#transport.lwm2m.security.trust-credentials.enabled=true +#transport.lwm2m.security.trust-credentials.type=KEYSTORE +#transport.lwm2m.security.trust-credentials.keystore.store_file=lwm2m/credentials/serverKeyStore.jks +#transport.lwm2m.security.trust-credentials.keystore.store_password=server edges.enabled=true edges.storage.no_read_records_sleep=500 From 659d8abf35fa6f41024f70f299b88e96ce96e302 Mon Sep 17 00:00:00 2001 From: van-vanich Date: Wed, 5 Jan 2022 18:15:16 +0200 Subject: [PATCH 344/432] improve node details and improve field naming --- .../sql/SequentialTimeseriesPersistenceTest.java | 6 +++--- .../rule/engine/telemetry/TbMsgTimeseriesNode.java | 13 ++++++++----- .../telemetry/TbMsgTimeseriesNodeConfiguration.java | 4 ++-- 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/application/src/test/java/org/thingsboard/server/service/sql/SequentialTimeseriesPersistenceTest.java b/application/src/test/java/org/thingsboard/server/service/sql/SequentialTimeseriesPersistenceTest.java index e4fb0318b4..e0a0260f7f 100644 --- a/application/src/test/java/org/thingsboard/server/service/sql/SequentialTimeseriesPersistenceTest.java +++ b/application/src/test/java/org/thingsboard/server/service/sql/SequentialTimeseriesPersistenceTest.java @@ -74,7 +74,7 @@ public class SequentialTimeseriesPersistenceTest extends AbstractControllerTest @Before public void beforeTest() throws Exception { configuration = new TbMsgTimeseriesNodeConfiguration(); - configuration.setIgnoreMetadataTs(true); + configuration.setUseServerTs(true); loginSysAdmin(); @@ -142,7 +142,7 @@ public class SequentialTimeseriesPersistenceTest extends AbstractControllerTest TbMsgDataType.JSON, getTbMsgData(msgValue.get(idx))); saveDeviceTsEntry(device.getId(), tbMsg, msgValue.get(idx)); - saveAssetTsEntry(asset, device.getName(), msgValue.get(idx), TbMsgTimeseriesNode.computeTs(tbMsg, configuration.isIgnoreMetadataTs())); + saveAssetTsEntry(asset, device.getName(), msgValue.get(idx), TbMsgTimeseriesNode.computeTs(tbMsg, configuration.isUseServerTs())); idx++; } } @@ -172,7 +172,7 @@ public class SequentialTimeseriesPersistenceTest extends AbstractControllerTest } void saveDeviceTsEntry(EntityId entityId, TbMsg tbMsg, long value) throws ExecutionException, InterruptedException, TimeoutException { - TsKvEntry tsKvEntry = new BasicTsKvEntry(TbMsgTimeseriesNode.computeTs(tbMsg, configuration.isIgnoreMetadataTs()), new LongDataEntry(TOTALIZER, value)); + TsKvEntry tsKvEntry = new BasicTsKvEntry(TbMsgTimeseriesNode.computeTs(tbMsg, configuration.isUseServerTs()), new LongDataEntry(TOTALIZER, value)); saveTimeseries(entityId, tsKvEntry); } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbMsgTimeseriesNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbMsgTimeseriesNode.java index 2334851a08..2c426dfdec 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbMsgTimeseriesNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbMsgTimeseriesNode.java @@ -48,11 +48,14 @@ import java.util.concurrent.TimeUnit; nodeDetails = "Saves timeseries telemetry data based on configurable TTL parameter. Expects messages with 'POST_TELEMETRY_REQUEST' message type. " + "Timestamp in milliseconds will be taken from metadata.ts, otherwise 'now' message timestamp will be applied. " + "Allows stopping updating values for incoming keys in the latest ts_kv table if 'skipLatestPersistence' is set to true.\n " + - "Enable 'ignoreMetadataTs' param to ignore the timestamp that arrives from message metadata. " + + "
" + + "Enable 'useServerTs' param to use the timestamp of the message processing instead of the timestamp from the message. " + "Useful for all sorts of sequential processing if you merge messages from multiple sources (devices, assets, etc).\n" + - "For example, if you count number of messages from multiple devices into asset time-series value. " + - "Typically, you fetch the previous value of the counter, increment it and then save the value. " + - "If you use timestamp of the original message, the value may be ignored, since it has outdated timestamp comparing to the previous message.", + "
" + + "In the case of sequential processing, the platform guarantees that the messages are processed in the order of their submission to the queue. " + + "However, the timestamp of the messages originated by multiple devices/servers may be unsynchronized long before they are pushed to the queue. " + + "The DB layer has certain optimizations to ignore the updates of the \"attributes\" and \"latest values\" tables if the new record has a timestamp that is older than the previous record. " + + "So, to make sure that all the messages will be processed correctly, one should enable this parameter for sequential message processing scenarios.", uiResources = {"static/rulenode/rulenode-core-config.js"}, configDirective = "tbActionNodeTimeseriesConfig", icon = "file_upload" @@ -82,7 +85,7 @@ public class TbMsgTimeseriesNode implements TbNode { ctx.tellFailure(msg, new IllegalArgumentException("Unsupported msg type: " + msg.getType())); return; } - long ts = computeTs(msg, config.isIgnoreMetadataTs()); + long ts = computeTs(msg, config.isUseServerTs()); String src = msg.getData(); Map> tsKvMap = JsonConverter.convertToTelemetry(new JsonParser().parse(src), ts); if (tsKvMap.isEmpty()) { diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbMsgTimeseriesNodeConfiguration.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbMsgTimeseriesNodeConfiguration.java index 6c9f7ac884..0d59c325fa 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbMsgTimeseriesNodeConfiguration.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbMsgTimeseriesNodeConfiguration.java @@ -23,14 +23,14 @@ public class TbMsgTimeseriesNodeConfiguration implements NodeConfiguration Date: Wed, 5 Jan 2022 17:47:01 +0200 Subject: [PATCH 345/432] lwm2m add to test shell credentials --- ...cfssl_chain_trusts_and_clients_for_test.sh | 299 ++++++++++++++++++ .../shell/lwm2m_cfssl_chain_for_test_All.sh | 65 ++++ .../lwm2m_cfssl_chain_server_for_test.sh | 298 +++++++++++++++++ 3 files changed, 662 insertions(+) create mode 100755 application/src/test/resources/lwm2m/credentials/shell/lwM2M_cfssl_chain_trusts_and_clients_for_test.sh create mode 100755 application/src/test/resources/lwm2m/credentials/shell/lwm2m_cfssl_chain_for_test_All.sh create mode 100755 application/src/test/resources/lwm2m/credentials/shell/lwm2m_cfssl_chain_server_for_test.sh diff --git a/application/src/test/resources/lwm2m/credentials/shell/lwM2M_cfssl_chain_trusts_and_clients_for_test.sh b/application/src/test/resources/lwm2m/credentials/shell/lwM2M_cfssl_chain_trusts_and_clients_for_test.sh new file mode 100755 index 0000000000..26f47266a7 --- /dev/null +++ b/application/src/test/resources/lwm2m/credentials/shell/lwM2M_cfssl_chain_trusts_and_clients_for_test.sh @@ -0,0 +1,299 @@ +#!/usr/bin/env bash + +# Change working directory +cd -- "$( + dirname "${0}" +)" || exit 1 + +readonly TRUST_PATH="Trust" +readonly CA_ROOT_CERT_KEY="ca-root" +readonly CA_ROOT_ALIAS="root" +readonly CA_INTERMEDIATE_CERT_KEY_PREF="intermediate_ca" +CA_INTERMEDIATE_START=0 +CA_INTERMEDIATE_FINISH=2 +CA_INTERMEDIATE_NUMBER=${CA_INTERMEDIATE_START} +CA_INTERMEDIATE_CERT_SIGN=${CA_ROOT_CERT_KEY} +CA_LIST_CERT_FOR_CAT="" +readonly CA_TRUST_STORE_ALL_CHAIN="lwm2mtruststorechain" +readonly CA_TRUST_STORE_PWD="server_ks_password" +readonly CA_TRUST_CERT_ALIAS="root" +readonly CA_TRUST_CERT_CHAIN_JKS="lwm2mtruststorechain" +readonly CA_TRUST_STORE_CHAIN_ALIAS="trust_cert_chain_alias" + +readonly CLIENT_PATH="Client" +readonly CLIENT_JKS_FOR_TEST="lwm2mclient" +readonly CLIENT_CERT_KEY_PREF="LwX509" +readonly CLIENT_CERT_ALIAS_PREF="client_alias_" +readonly CLIENT_STORE_PWD="client_ks_password" +readonly CLIENT_HOST_NAME="thingsboard_test.io" +CLIENT_START=0 +CLIENT_FINISH=1 +CLIENT_NUMBER=${CLIENT_START} + +SERVER_HOST_NAME="localhost.localdomain" +SERVER_LOCAL_HOST_NAME="localhost" +SERVER_PUBLIC_HOST_NAMES="-" + +readonly CF_COMMANDS=" + cfssl + cfssljson +" + +if [ ! -z "$1" ]; then + CA_INTERMEDIATE_START=$1 + CA_INTERMEDIATE_NUMBER=${CA_INTERMEDIATE_START} +fi + +if [ ! -z "$2" ]; then + CA_INTERMEDIATE_FINISH=$2 +fi + +if [ ! -z "$3" ]; then + CLIENT_START=$1 + CLIENT_NUMBER=${CLIENT_START} +fi + +if [ ! -z "$4" ]; then + CLIENT_FINISH=$4 +fi + +# Change working directory +rm -rf ${TRUST_PATH} +mkdir -p ${TRUST_PATH} +rm -rf ${CLIENT_PATH} +mkdir -p ${CLIENT_PATH} +cd -- "$( + dirname "${0}" +)" || exit 1 + + +rm *.csr +rm *.p12 +rm *.json +rm *.pem +rm *.jks + +intermediate_common_name() { + echo "${CA_INTERMEDIATE_CERT_KEY_PREF}${CA_INTERMEDIATE_NUMBER}" +} + +set_list_sert_for_cat() { + local first="$1" + echo "$first ${CA_LIST_CERT_FOR_CAT}" +} + +client_common_name() { + echo "${CLIENT_CERT_KEY_PREF}$(printf "%08d" ${CLIENT_NUMBER})" +} + +client_alias_name() { + echo "${CLIENT_CERT_ALIAS_PREF}$(printf "%08d" ${CLIENT_NUMBER})" +} + +for COMMAND in ${CF_COMMANDS}; do + if ! command -v ${COMMAND} &> /dev/null; then + echo "ERROR: Missing command ${COMMAND}" >&2 + echo "Install the package from: https://pkg.cfssl.org/" >&2 + exit 1 + fi +done + +tee ./${TRUST_PATH}/ca-config.json 1> /dev/null <<-CONFIG +{ + "signing": { + "default": { + "expiry": "8760h", + "names": [ + { + "C": "UK", + "ST": "Kyiv city", + "L": "Kyiv", + "O": "Thingsboard", + "OU": "DEVELOPER_TEST" + } + ] + }, + "profiles": { + "server": { + "expiry": "43800h", + "key": { + "algo": "ecdsa", + "size": 256 + }, + "usages": [ + "signing", + "key encipherment", + "server auth" + ] + }, + "client": { + "expiry": "43800h", + "key": { + "algo": "ecdsa", + "size": 256 + }, + "usages": [ + "signing", + "key encipherment", + "client auth" + ] + }, + "client-server": { + "expiry": "43800h", + "key": { + "algo": "ecdsa", + "size": 256 + }, + "usages": [ + "signing", + "key encipherment", + "server auth", + "client auth" + ] + } + } + } +} +CONFIG + +tee ./${TRUST_PATH}/ca-root-to-intermediate-config.json 1> /dev/null <<-CONFIG +{ + "signing": { + "default": { + "expiry": "43800h", + "ca_constraint": { + "is_ca": true, + "max_path_len": 0, + "max_path_len_zero": true + }, + "key": { + "algo": "ecdsa", + "size": 256 + }, + "usages": [ + "digital signature", + "cert sign", + "crl sign", + "signing" + ] + } + } +} +CONFIG + +echo "====================================================" +echo -e "Generate the root of certificates: \n-${CA_ROOT_KEY}-key.pem (certificate key)\n-${CA_ROOT_KEY}.pem (certificate)\n-${CA_ROOT_KEY}.csr (sign request)" +echo "====================================================" +cfssl genkey \ + -initca \ + - \ + <<-CONFIG | cfssljson -bare ./${TRUST_PATH}/${CA_ROOT_CERT_KEY} +{ + "CN": "ROOT CA", + "key": { + "algo": "ecdsa", + "size": 256 + }, + "names": [ + { + "C": "UK", + "ST": "Kyiv city", + "L": "Kyiv", + "O": "Thingsboard", + "OU": "DEVELOPER_TEST" + } + ], + "ca": { + "expiry": "131400h" + } +} +CONFIG +CA_LIST_CERT_FOR_CAT=$(set_list_sert_for_cat ./${TRUST_PATH}/${CA_ROOT_CERT_KEY}.pem) + +echo "====================================================" +echo -e "Generate and Signed the intermediates of our certificates: \n-${CA_INTERMEDIATE_CERT_KEY_PREF}?-key.pem (certificate key)\n-${CA_INTERMEDIATE_CERT_KEY_PREF}?.pem (certificate)\n-${CA_INTERMEDIATE_CERT_KEY_PREF}?.csr (sign request)" +echo "====================================================" + +while [[ ${CA_INTERMEDIATE_NUMBER} -lt ${CA_INTERMEDIATE_FINISH} ]]; +do + CA_INTERMEDIATE_CERT_KEY=$(intermediate_common_name) + CA_INTERMEDIATE_NUMBER=$((${CA_INTERMEDIATE_NUMBER} + 1)) + + cfssl gencert \ + -ca ./${TRUST_PATH}/${CA_INTERMEDIATE_CERT_SIGN}.pem \ + -ca-key ./${TRUST_PATH}/${CA_INTERMEDIATE_CERT_SIGN}-key.pem \ + -config ./${TRUST_PATH}/ca-root-to-intermediate-config.json \ + -hostname "${SERVER_HOST_NAME},${SERVER_LOCAL_HOST_NAME}${SERVER_PUBLIC_HOST_NAMES:+, }${SERVER_PUBLIC_HOST_NAMES}" \ + - \ + <<-CONFIG | cfssljson -bare ./${TRUST_PATH}/${CA_INTERMEDIATE_CERT_KEY} + { + "CN": "${CA_INTERMEDIATE_CERT_KEY}", + "names": [ + { + "C": "UK", + "ST": "Kyiv city", + "L": "Kyiv", + "O": "Thingsboard", + "OU": "DEVELOPER_TEST" + } + ] + } +CONFIG + #openssl x509 -in ${CA_INTERMEDIATE_CERT_KEY}.pem -text -noout + CA_LIST_CERT_FOR_CAT=$(set_list_sert_for_cat ./${TRUST_PATH}/${CA_INTERMEDIATE_CERT_KEY}.pem) + CA_INTERMEDIATE_CERT_SIGN=${CA_INTERMEDIATE_CERT_KEY} +done + +echo "====================================================" +echo -e "Add the CA_certificate to keystore: ${CA_TRUST_CERT_CHAIN_JKS}.jks" +echo "====================================================" +cat ${CA_LIST_CERT_FOR_CAT} > ./${TRUST_PATH}/${CA_TRUST_STORE_ALL_CHAIN}.pem +openssl pkcs12 -export -in ./${TRUST_PATH}/${CA_TRUST_STORE_ALL_CHAIN}.pem -inkey ./${TRUST_PATH}/${CA_INTERMEDIATE_CERT_KEY}-key.pem -out ./${TRUST_PATH}/${CA_INTERMEDIATE_CERT_KEY}.p12 -name ${CA_TRUST_STORE_CHAIN_ALIAS} -CAfile ./${TRUST_PATH}/${CA_INTERMEDIATE_CERT_KEY}.pem -caname ${CA_ROOT_ALIAS} -passin pass:${CA_TRUST_STORE_PWD} -passout pass:${CA_TRUST_STORE_PWD} +keytool -importkeystore -deststorepass ${CA_TRUST_STORE_PWD} -destkeypass ${CA_TRUST_STORE_PWD} -destkeystore ./${TRUST_PATH}/${CA_TRUST_CERT_CHAIN_JKS}.jks -srckeystore ./${TRUST_PATH}/${CA_INTERMEDIATE_CERT_KEY}.p12 -srcstoretype PKCS12 -srcstorepass ${CA_TRUST_STORE_PWD} -alias ${CA_TRUST_STORE_CHAIN_ALIAS} + +keytool -list -v -keystore ./${TRUST_PATH}/lwm2mtruststorechain.jks -storepass server_ks_password -storetype PKCS12 + +echo "====================================================" +echo -e "Generate and Signed the clients of our certificates: \n-${CLIENT_CERT_KEY_PREF}?-key.pem (certificate key)\n-${CLIENT_CERT_KEY_PREF}?.pem (certificate)\n-${CCLIENT_CERT_KEY_PREF}?.csr (sign request)" +echo "====================================================" + + +while [[ ${CLIENT_NUMBER} -lt ${CLIENT_FINISH} ]]; +do + CLIENT_CERT_KEY=$(client_common_name) + CLIENT_CERT_ALIAS=$(client_alias_name) + CLIENT_NUMBER=$((${CLIENT_NUMBER} + 1)) + + cfssl gencert \ + -ca ./${TRUST_PATH}/${CA_INTERMEDIATE_CERT_KEY}.pem \ + -ca-key ./${TRUST_PATH}/${CA_INTERMEDIATE_CERT_KEY}-key.pem \ + -config ./${TRUST_PATH}/ca-config.json \ + -profile client \ + -hostname "${CLIENT_HOST_NAME}" \ + - \ + <<-CONFIG | cfssljson -bare ./${CLIENT_PATH}/${CLIENT_CERT_KEY} +{ + "CN": "${CLIENT_CERT_KEY}" +} +CONFIG + +echo "====================================================" +echo -e "Add the client certificate (${CLIENT_CERT_KEY}.pem) to keystore: ${CLIENT_JKS_FOR_TEST}.jks" +echo "====================================================" +cat ./${CLIENT_PATH}/${CLIENT_CERT_KEY}.pem ${CA_LIST_CERT_FOR_CAT} > ./${CLIENT_PATH}/${CLIENT_CERT_KEY}_chain.pem +openssl pkcs12 -export -in ./${CLIENT_PATH}/${CLIENT_CERT_KEY}_chain.pem -inkey ./${CLIENT_PATH}/${CLIENT_CERT_KEY}-key.pem -out ./${CLIENT_PATH}/${CLIENT_CERT_KEY}.p12 -name ${CLIENT_CERT_ALIAS} -CAfile ./${TRUST_PATH}/${CA_INTERMEDIATE_CERT_KEY}.pem -caname ${CA_ROOT_ALIAS} -passin pass:${CLIENT_STORE_PWD} -passout pass:${CLIENT_STORE_PWD} +keytool -importkeystore -deststorepass ${CLIENT_STORE_PWD} -destkeypass ${CLIENT_STORE_PWD} -destkeystore ./${CLIENT_PATH}/${CLIENT_JKS_FOR_TEST}.jks -srckeystore ./${CLIENT_PATH}/${CLIENT_CERT_KEY}.p12 -srcstoretype PKCS12 -srcstorepass ${CLIENT_STORE_PWD} -alias ${CLIENT_CERT_ALIAS} + +done + +keytool -list -v -keystore ./${CLIENT_PATH}/lwm2mclient.jks -storepass client_ks_password -storetype PKCS12 + +rm ./${TRUST_PATH}/*.p12 +rm ./${TRUST_PATH}/*.csr +rm ./${TRUST_PATH}/*.json +rm ./${TRUST_PATH}/${CA_ROOT_CERT_KEY}* +rm ./${TRUST_PATH}/${CA_INTERMEDIATE_CERT_KEY_PREF}* + + +rm ./${CLIENT_PATH}/*.p12 2> /dev/null +rm ./${CLIENT_PATH}/*.csr 2> /dev/null diff --git a/application/src/test/resources/lwm2m/credentials/shell/lwm2m_cfssl_chain_for_test_All.sh b/application/src/test/resources/lwm2m/credentials/shell/lwm2m_cfssl_chain_for_test_All.sh new file mode 100755 index 0000000000..b3b114cb28 --- /dev/null +++ b/application/src/test/resources/lwm2m/credentials/shell/lwm2m_cfssl_chain_for_test_All.sh @@ -0,0 +1,65 @@ +#!/usr/bin/env bash + +readonly INTERMEDIATE_START=0 +readonly INTERMEDIATE_FINISH=2 +readonly CLIENT_START=0 +readonly CLIENT_FINISH=5 + +IS_IHFO=false +IS_SERVER_CREATED_KEY=true +IS_TRUST_CLIENT_CREATED_KEY=true + +cd -- "$( + dirname "${0}" +)" || exit 1 + +Help() +{ + # Display Help + echo "Description of the script functions." + echo + echo "Syntax: scriptTemplate [-g|h|v|V]" + echo "options:" + echo "h Print this Help." + echo "v Verbose mode." + echo "V Print software version and exit." + echo +} + +if [ "$1" == "-h" ] ; then + echo -e "Usage 2: ./`basename $0` \"Information is not displayed\" : \"Keys for the server are generated\" : \"Keys for the clients and trusts are generated\"" + echo -e "Usage 1: ./`basename $0` true \"Information is displayed\" : \"Keys for the server are generated\" : \"Keys for the clients and trusts are generated\"" + echo -e "Usage 3: ./`basename $0` true false \"Information is displayed\" : \"Keys for the server are not generated\" : \"Keys for the clients and trusts are generated\"" + echo -e "Usage 4: ./`basename $0` true false false \"Information is displayed\" : \"Keys for the server are not generated\" : \"Keys for the clients and trusts are not generated\"" + echo -e "Usage 4: ./`basename $0` true true false \"Information is displayed\" : \"Keys for the server are generated\" : \"Keys for the clients and trusts are not generated\"" + echo "This Help File: ./`basename $0` -h" + exit 0 +fi + +if [ -n "$1" ]; then + IS_IHFO=$1 +fi + +if [ -n "$2" ]; then + IS_SERVER_CREATED_KEY=$2 +fi + +if [ -n "$3" ]; then + IS_TRUST_CLIENT_CREATED_KEY=$3 +fi + +if [ "$IS_IHFO" = false ] ; then + if [ "$IS_SERVER_CREATED_KEY" = true ] ; then + ./lwm2m_cfssl_chain_server_for_test.sh > /dev/null 2>&1 & + fi + if [ "$IS_TRUST_CLIENT_CREATED_KEY" = true ] ; then + ./lwM2M_cfssl_chain_trusts_and_clients_for_test.sh ${INTERMEDIATE_START} ${INTERMEDIATE_FINISH} ${CLIENT_START} ${CLIENT_FINISH} > /dev/null 2>&1 & + fi +else + if [ "$IS_SERVER_CREATED_KEY" = true ] ; then + ./lwm2m_cfssl_chain_server_for_test.sh + fi + if [ "$IS_TRUST_CLIENT_CREATED_KEY" = true ] ; then + ./lwM2M_cfssl_chain_trusts_and_clients_for_test.sh ${INTERMEDIATE_START} ${INTERMEDIATE_FINISH} ${CLIENT_START} ${CLIENT_FINISH} + fi +fi \ No newline at end of file diff --git a/application/src/test/resources/lwm2m/credentials/shell/lwm2m_cfssl_chain_server_for_test.sh b/application/src/test/resources/lwm2m/credentials/shell/lwm2m_cfssl_chain_server_for_test.sh new file mode 100755 index 0000000000..efe6ed46dd --- /dev/null +++ b/application/src/test/resources/lwm2m/credentials/shell/lwm2m_cfssl_chain_server_for_test.sh @@ -0,0 +1,298 @@ +#!/usr/bin/env bash + +# REF: https://github.com/cloudflare/cfssl + +# Change working directory +cd -- "$( + dirname "${0}" +)" || exit 1 + +readonly CA_ROOT_CERT_KEY="ca-root" +readonly CA_ROOT_ALIAS="root" +readonly CA_INTERMEDIATE_CERT_KEY_PREF="intermediate_ca" +CA_INTERMEDIATE_NUMBER=0 +CA_LIST_CERT_FOR_CAT="" + +readonly CF_COMMANDS=" + cfssl + cfssljson +" + +readonly SERVER_JKS_FOR_TEST="lwm2mserver" +readonly STORE_PASS_PWD="server_ks_password" +readonly SERVER_PATH="Server" +readonly SERVER_CERT_KEY="lwm2mserver" +readonly SERVER_CERT_CHAIN="lwm2mserver_chain" +readonly SERVER_CERT_ALIAS="server" +readonly BS_SERVER_CERT_KEY="lwm2mserverbs" +readonly BS_SERVER_CERT_CHAIN="lwm2mserverbs_chain" +readonly BS_SERVER_CERT_ALIAS="bootstrap" + +SERVER_HOST_NAME="localhost.localdomain" +SERVER_LOCAL_HOST_NAME="localhost" +SERVER_PUBLIC_HOST_NAMES="-" + +intermediate_common_name() { + echo "${CA_INTERMEDIATE_CERT_KEY_PREF}${CA_INTERMEDIATE_NUMBER}" +} + +set_list_sert_for_cat() { + local first="$1" + echo "$first ${CA_LIST_CERT_FOR_CAT}" +} + + +# Change working directory +rm -rf ${SERVER_PATH} +mkdir -p ${SERVER_PATH} + +cd -- "$( + dirname ./${SERVER_PATH} +)" || exit 1 + + +rm *.csr +rm *.p12 +rm *.json +rm *.pem +rm *.jks + +CA_INTERMEDIATE_CERT_SIGN=${CA_ROOT_CERT_KEY} +CA_INTERMEDIATE_CERT_KEY=$(intermediate_common_name) +CA_INTERMEDIATE_NUMBER=$((${CA_INTERMEDIATE_NUMBER} + 1)) +CA_LIST_CERT_FOR_CAT="" + +for COMMAND in ${CF_COMMANDS}; do + if ! command -v ${COMMAND} &> /dev/null; then + echo "ERROR: Missing command ${COMMAND}" >&2 + echo "Install the package from: https://pkg.cfssl.org/" >&2 + exit 1 + fi +done + +tee ./${SERVER_PATH}/ca-config.json 1> /dev/null <<-CONFIG +{ + "signing": { + "default": { + "expiry": "8760h", + "names": [ + { + "C": "UK", + "ST": "Kyiv city", + "L": "Kyiv", + "O": "Thingsboard", + "OU": "DEVELOPER_TEST" + } + ] + }, + "profiles": { + "server": { + "expiry": "43800h", + "key": { + "algo": "ecdsa", + "size": 256 + }, + "usages": [ + "signing", + "key encipherment", + "server auth" + ] + }, + "client": { + "expiry": "43800h", + "key": { + "algo": "ecdsa", + "size": 256 + }, + "usages": [ + "signing", + "key encipherment", + "client auth" + ] + }, + "client-server": { + "expiry": "43800h", + "key": { + "algo": "ecdsa", + "size": 256 + }, + "usages": [ + "signing", + "key encipherment", + "server auth", + "client auth" + ] + } + } + } +} +CONFIG + +tee ./${SERVER_PATH}/ca-root-to-intermediate-config.json 1> /dev/null <<-CONFIG +{ + "signing": { + "default": { + "expiry": "43800h", + "ca_constraint": { + "is_ca": true, + "max_path_len": 0, + "max_path_len_zero": true + }, + "key": { + "algo": "ecdsa", + "size": 256 + }, + "usages": [ + "digital signature", + "cert sign", + "crl sign", + "signing" + ] + } + } +} +CONFIG + +echo "====================================================" +echo -e "Generate the root of certificates: \n-${CA_ROOT_KEY}-key.pem (certificate key)\n-${CA_ROOT_KEY}.pem (certificate)\n-${CA_ROOT_KEY}.csr (sign request)" +echo "====================================================" +cfssl genkey \ + -initca \ + - \ + <<-CONFIG | cfssljson -bare ./${SERVER_PATH}/${CA_ROOT_CERT_KEY} +{ + "CN": "ROOT CA for servers", + "key": { + "algo": "ecdsa", + "size": 256 + }, + "names": [ + { + "C": "UK", + "ST": "Kyiv city", + "L": "Kyiv", + "O": "Thingsboard", + "OU": "DEVELOPER_TEST" + } + ], + "ca": { + "expiry": "131400h" + } +} +CONFIG +CA_LIST_CERT_FOR_CAT=$(set_list_sert_for_cat ./${SERVER_PATH}/${CA_ROOT_CERT_KEY}.pem) + +echo "====================================================" +echo -e "Generate and Signed the first intermediates of our certificates: \n-${CA_INTERMEDIATE_CERT_KEY}-key.pem (certificate key)\n-${CA_INTERMEDIATE_CERT_KEY}.pem (certificate)\n-${CA_INTERMEDIATE_CERT_KEY}.csr (sign request)" +echo "====================================================" +cfssl gencert \ + -ca ./${SERVER_PATH}/${CA_INTERMEDIATE_CERT_SIGN}.pem \ + -ca-key ./${SERVER_PATH}/${CA_INTERMEDIATE_CERT_SIGN}-key.pem \ + -config ./${SERVER_PATH}/ca-root-to-intermediate-config.json \ + -hostname "${SERVER_HOST_NAME},${SERVER_LOCAL_HOST_NAME}${SERVER_PUBLIC_HOST_NAMES:+, }${SERVER_PUBLIC_HOST_NAMES}" \ + - \ + <<-CONFIG | cfssljson -bare ./${SERVER_PATH}/${CA_INTERMEDIATE_CERT_KEY} +{ + "CN": "${CA_INTERMEDIATE_CERT_KEY}", + "names": [ + { + "C": "UK", + "ST": "Kyiv city", + "L": "Kyiv", + "O": "Thingsboard", + "OU": "DEVELOPER_TEST" + } + ] +} +CONFIG +CA_LIST_CERT_FOR_CAT=$(set_list_sert_for_cat ./${SERVER_PATH}/${CA_INTERMEDIATE_CERT_KEY}.pem) + + +## Lwm2m Server certificate +echo "====================================================" +echo -e "Generate and Signed the server certificate: \n-${SERVER_CERT_KEY}-key.pem (certificate key)\n-${SERVER_CERT_KEY}.pem (certificate)\n-${SERVER_CERT_KEY}.csr (sign request)" +echo "====================================================" +cfssl gencert \ + -ca ./${SERVER_PATH}/${CA_INTERMEDIATE_CERT_KEY}.pem \ + -ca-key ./${SERVER_PATH}/${CA_INTERMEDIATE_CERT_KEY}-key.pem \ + -config ./${SERVER_PATH}/ca-config.json \ + -profile server \ + -hostname "${SERVER_HOST_NAME},${SERVER_LOCAL_HOST_NAME}${SERVER_PUBLIC_HOST_NAMES:+, }${SERVER_PUBLIC_HOST_NAMES}" \ + - \ + <<-CONFIG | cfssljson -bare ./${SERVER_PATH}/${SERVER_CERT_KEY} +{ + "CN": "${SERVER_LOCAL_HOST_NAME}" +} +CONFIG + +echo "====================================================" +echo -e "Add the server certificate (${SERVER_CERT_KEY}.pem) to keystore: ${SERVER_JKS_FOR_TEST}.jks" +echo "====================================================" +cat ./${SERVER_PATH}/${SERVER_CERT_KEY}.pem ${CA_LIST_CERT_FOR_CAT} > ./${SERVER_PATH}/${SERVER_CERT_CHAIN}.pem +openssl pkcs12 -export -in ./${SERVER_PATH}/${SERVER_CERT_CHAIN}.pem -inkey ./${SERVER_PATH}/${SERVER_CERT_KEY}-key.pem -out ./${SERVER_PATH}/${SERVER_CERT_KEY}.p12 -name ${SERVER_CERT_ALIAS} -CAfile ./${SERVER_PATH}/${CA_INTERMEDIATE_CERT_KEY}.pem -caname ${CA_ROOT_ALIAS} -passin pass:${STORE_PASS_PWD} -passout pass:${STORE_PASS_PWD} +keytool -importkeystore -deststorepass ${STORE_PASS_PWD} -destkeypass ${STORE_PASS_PWD} -destkeystore ./${SERVER_PATH}/${SERVER_JKS_FOR_TEST}.jks -srckeystore ./${SERVER_PATH}/${SERVER_CERT_KEY}.p12 -srcstoretype PKCS12 -srcstorepass ${STORE_PASS_PWD} -alias ${SERVER_CERT_ALIAS} + + +CA_INTERMEDIATE_CERT_SIGN=${CA_INTERMEDIATE_CERT_KEY} +CA_INTERMEDIATE_CERT_KEY=$(intermediate_common_name) +CA_INTERMEDIATE_NUMBER=$((${CA_INTERMEDIATE_NUMBER} + 1)) +echo "====================================================" +echo -e "Generate and Signed the second intermediates of our certificates: \n-${CA_INTERMEDIATE_CERT_KEY}-key.pem (certificate key)\n-${CA_INTERMEDIATE_CERT_KEY}.pem (certificate)\n-${CA_INTERMEDIATE_CERT_KEY}.csr (sign request)" +echo "====================================================" +cfssl gencert \ + -ca ./${SERVER_PATH}/${CA_INTERMEDIATE_CERT_SIGN}.pem \ + -ca-key ./${SERVER_PATH}/${CA_INTERMEDIATE_CERT_SIGN}-key.pem \ + -config ./${SERVER_PATH}/ca-root-to-intermediate-config.json \ + -hostname "${SERVER_HOST_NAME},${SERVER_LOCAL_HOST_NAME}${SERVER_PUBLIC_HOST_NAMES:+, }${SERVER_PUBLIC_HOST_NAMES}" \ + - \ + <<-CONFIG | cfssljson -bare ./${SERVER_PATH}/${CA_INTERMEDIATE_CERT_KEY} +{ + "CN": "${CA_INTERMEDIATE_CERT_KEY}", + "names": [ + { + "C": "UK", + "ST": "Kyiv city", + "L": "Kyiv", + "O": "Thingsboard", + "OU": "DEVELOPER_TEST" + } + ] +} +CONFIG +CA_LIST_CERT_FOR_CAT=$(set_list_sert_for_cat ./${SERVER_PATH}/${CA_INTERMEDIATE_CERT_KEY}.pem) + +## Bootstrap server certificate +echo "====================================================" +echo -e "Generate and Signed the server certificate: \n-${BS_SERVER_CERT_KEY}-key.pem (certificate key)\n-${BS_SERVER_CERT_KEY}.pem (certificate)\n-${BS_SERVER_CERT_KEY}.csr (sign request)" +echo "====================================================" +cfssl gencert \ + -ca ./${SERVER_PATH}/${CA_INTERMEDIATE_CERT_KEY}.pem \ + -ca-key ./${SERVER_PATH}/${CA_INTERMEDIATE_CERT_KEY}-key.pem \ + -config ./${SERVER_PATH}/ca-config.json \ + -profile server \ + -hostname "${SERVER_HOST_NAME},${SERVER_LOCAL_HOST_NAME}${SERVER_PUBLIC_HOST_NAMES:+, }${SERVER_PUBLIC_HOST_NAMES}" \ + - \ + <<-CONFIG | cfssljson -bare ./${SERVER_PATH}/${BS_SERVER_CERT_KEY} +{ + "CN": "${SERVER_LOCAL_HOST_NAME}" +} +CONFIG + +echo "====================================================" +echo -e "Add the Bootstrap server certificate (${BS_SERVER_CERT_KEY}.pem) to keystore: ${SERVER_JKS_FOR_TEST}.jks" +echo "====================================================" +cat ./${SERVER_PATH}/${BS_SERVER_CERT_KEY}.pem ${CA_LIST_CERT_FOR_CAT} > ./${SERVER_PATH}/${BS_SERVER_CERT_CHAIN}.pem +openssl pkcs12 -export -in ./${SERVER_PATH}/${BS_SERVER_CERT_CHAIN}.pem -inkey ./${SERVER_PATH}/${BS_SERVER_CERT_KEY}-key.pem -out ./${SERVER_PATH}/${BS_SERVER_CERT_KEY}.p12 -name ${BS_SERVER_CERT_ALIAS} -CAfile ./${SERVER_PATH}/${CA_INTERMEDIATE_CERT_KEY}.pem -caname ${CA_ROOT_ALIAS} -passin pass:${STORE_PASS_PWD} -passout pass:${STORE_PASS_PWD} +keytool -importkeystore -deststorepass ${STORE_PASS_PWD} -destkeypass ${STORE_PASS_PWD} -destkeystore ./${SERVER_PATH}/${SERVER_JKS_FOR_TEST}.jks -srckeystore ./${SERVER_PATH}/${BS_SERVER_CERT_KEY}.p12 -srcstoretype PKCS12 -srcstorepass ${STORE_PASS_PWD} -alias ${BS_SERVER_CERT_ALIAS} + + +keytool -list -v -keystore ./${SERVER_PATH}/lwm2mserver.jks -storepass server_ks_password -storetype PKCS12 + +rm ./${SERVER_PATH}/*.p12 2> /dev/null +rm ./${SERVER_PATH}/*.csr 2> /dev/null +rm ./${SERVER_PATH}/*.json 2> /dev/null +rm ./${SERVER_PATH}/${CA_INTERMEDIATE_CERT_KEY_PREF}* 2> /dev/null +rm ./${SERVER_PATH}/${CA_ROOT_CERT_KEY}* 2> /dev/null +mv ./${SERVER_PATH}/${SERVER_CERT_KEY}-key.pem ./${SERVER_PATH}/${SERVER_CERT_KEY}_key.pem +mv ./${SERVER_PATH}/${BS_SERVER_CERT_KEY}-key.pem ./${SERVER_PATH}/${BS_SERVER_CERT_KEY}_key.pem + From 60758375ed02f06e06cce51c31ccf5171bd7c8e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emre=20Karda=C5=9Flar?= Date: Sat, 8 Jan 2022 01:03:54 +0300 Subject: [PATCH 346/432] fix problematic letters for different lang --- .../org/thingsboard/server/dao/audit/AuditLogLevelFilter.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dao/src/main/java/org/thingsboard/server/dao/audit/AuditLogLevelFilter.java b/dao/src/main/java/org/thingsboard/server/dao/audit/AuditLogLevelFilter.java index b73cafc121..effc79f711 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/audit/AuditLogLevelFilter.java +++ b/dao/src/main/java/org/thingsboard/server/dao/audit/AuditLogLevelFilter.java @@ -19,6 +19,7 @@ import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.audit.ActionType; import java.util.HashMap; +import java.util.Locale; import java.util.Map; public class AuditLogLevelFilter { @@ -28,7 +29,7 @@ public class AuditLogLevelFilter { public AuditLogLevelFilter(Map mask) { entityTypeMask.clear(); mask.forEach((entityTypeStr, logLevelMaskStr) -> { - EntityType entityType = EntityType.valueOf(entityTypeStr.toUpperCase()); + EntityType entityType = EntityType.valueOf(entityTypeStr.toUpperCase(Locale.ENGLISH)); AuditLogLevelMask logLevelMask = AuditLogLevelMask.valueOf(logLevelMaskStr.toUpperCase()); entityTypeMask.put(entityType, logLevelMask); }); From eccbd3290c5c443ae60fae111ce9539d28a6e85d Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Sat, 8 Jan 2022 13:06:46 +0200 Subject: [PATCH 347/432] lwm2m tests with NoSec, PSK, X509-trust. RPK, X509_NoTrust - ignore --- .../AbstractSecurityLwM2MIntegrationTest.java | 198 ++++++++++-------- 1 file changed, 105 insertions(+), 93 deletions(-) diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/AbstractSecurityLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/AbstractSecurityLwM2MIntegrationTest.java index ea30b43436..0c983f9dcf 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/AbstractSecurityLwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/AbstractSecurityLwM2MIntegrationTest.java @@ -15,7 +15,6 @@ */ package org.thingsboard.server.transport.lwm2m.security; -import org.eclipse.leshan.core.util.Hex; import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MBootstrapClientCredentials; import org.thingsboard.server.common.data.device.credentials.lwm2m.NoSecBootstrapClientCredential; import org.thingsboard.server.dao.service.DaoSqlTest; @@ -24,144 +23,157 @@ import org.thingsboard.server.transport.lwm2m.client.LwM2MTestClient; import java.io.IOException; import java.io.InputStream; -import java.math.BigInteger; -import java.security.AlgorithmParameters; import java.security.GeneralSecurityException; -import java.security.KeyFactory; import java.security.KeyStore; import java.security.PrivateKey; import java.security.PublicKey; import java.security.cert.Certificate; import java.security.cert.X509Certificate; -import java.security.spec.ECGenParameterSpec; -import java.security.spec.ECParameterSpec; -import java.security.spec.ECPoint; -import java.security.spec.ECPrivateKeySpec; -import java.security.spec.ECPublicKeySpec; -import java.security.spec.KeySpec; @DaoSqlTest public abstract class AbstractSecurityLwM2MIntegrationTest extends AbstractLwM2MIntegrationTest { + protected final String CREDENTIALS_PATH = "lwm2m/credentials/"; // client public key or id used for PSK protected final String pskIdentity; // client public key or id used for PSK protected final String pskKey; // client private/secret key used for PSK - protected final PublicKey clientPublicKey; // client public key used for RPK - protected final PrivateKey clientPrivateKey; // client private key used for RPK - protected final PublicKey serverPublicKey; // server public key used for RPK - protected final PrivateKey serverPrivateKey; // server private key used for RPK - - // client private key used for X509 - protected final PrivateKey clientPrivateKeyFromCert; - // server private key used for X509 - protected final PrivateKey serverPrivateKeyFromCert; - // client certificate signed by rootCA with a good CN (CN start by leshan_integration_test) - protected final X509Certificate clientX509Cert; - // client certificate signed by rootCA but with bad CN (CN does not start by leshan_integration_test) - protected final X509Certificate clientX509CertWithBadCN; - // client certificate self-signed with a good CN (CN start by leshan_integration_test) - protected final X509Certificate clientX509CertSelfSigned; - // client certificate signed by another CA (not rootCA) with a good CN (CN start by leshan_integration_test) - protected final X509Certificate clientX509CertNotTrusted; - // server certificate signed by rootCA - protected final X509Certificate serverX509Cert; +// protected final PublicKey clientPublicKey; // client public key used for RPK +// protected final PrivateKey clientPrivateKey; // client private key used for RPK + + + +// // client certificate signed by rootCA but with bad CN (CN does not start by leshan_integration_test) +// protected final X509Certificate clientX509CertWithBadCN; +// // client certificate self-signed with a good CN (CN start by leshan_integration_test) +// protected final X509Certificate clientX509CertSelfSigned; +// // client certificate signed by another CA (not rootCA) with a good CN (CN start by leshan_integration_test) +// protected final X509Certificate clientX509CertNotTrusted; + // self-signed server certificate - protected final X509Certificate serverX509CertSelfSigned; - // rootCA used by the server - protected final X509Certificate rootCAX509Cert; +// protected final X509Certificate serverX509CertSelfSigned; +// // rootCA used by the server +// protected final X509Certificate rootCAX509Cert; // certificates trustedby the server (should contain rootCA) - protected final Certificate[] trustedCertificates = new Certificate[1]; - protected static final String ENDPOINT = "deviceAEndpoint"; + // Server + protected static final String SERVER_JKS_FOR_TEST = "lwm2mserver"; + protected static final String SERVER_STORE_PWD = "server_ks_password"; + protected static final String SERVER_CERT_ALIAS = "server"; + protected final X509Certificate serverX509Cert; // server certificate signed by rootCA +// protected final PrivateKey serverPrivateKeyFromCert; // server private key used for RPK and X509 + protected final PublicKey serverPublicKeyFromCert; // server public key used for RPK +// // Server Trust +// protected final Certificate[] trustedCertificates = new Certificate[1]; + + // Client protected LwM2MTestClient client; + protected static final String CLIENT_ENDPOINT_NO_SEC = "deviceNoSec"; + protected static final String CLIENT_ENDPOINT_RPK = "deviceRPK"; + protected static final String CLIENT_ENDPOINT_NO_TRUST = "deviceAEndpoint"; + protected static final String CLIENT_ENDPOINT_TRUST = "LwX50900000000"; + protected static final String CLIENT_JKS_FOR_TEST = "lwm2mclient"; + protected static final String CLIENT_STORE_PWD = "client_ks_password"; + + protected static final String CLIENT_CERT_ALIAS = "client_alias_00000000"; + + protected final X509Certificate clientX509Cert; // client certificate signed by intermediate, rootCA with a good CN ("host name") + protected final PrivateKey clientPrivateKeyFromCert; // client private key used for X509 and RPK + protected final PublicKey clientPublicKeyFromCert; // client public key used for RPK + private final String[] resources = new String[]{"1.xml", "2.xml", "3.xml", "5.xml", "9.xml"}; + private final LwM2MBootstrapClientCredentials defaultBootstrapCredentials; - private final String[] resources = new String[]{"1.xml", "2.xml", "3.xml", "5.xml", "9.xml"}; + public AbstractSecurityLwM2MIntegrationTest() { // create client credentials setResources(this.resources); - setEndpoint(ENDPOINT); + setEndpoint(CLIENT_ENDPOINT_NO_TRUST); try { - // Get keys PSK +// Get keys PSK this.pskIdentity = "SOME_PSK_ID"; this.pskKey = "73656372657450534b73656372657450"; - // Get point values - byte[] publicX = Hex - .decodeHex("89c048261979208666f2bfb188be1968fc9021c416ce12828c06f4e314c167b5".toCharArray()); - byte[] publicY = Hex - .decodeHex("cbf1eb7587f08e01688d9ada4be859137ca49f79394bad9179326b3090967b68".toCharArray()); - byte[] privateS = Hex - .decodeHex("e67b68d2aaeb6550f19d98cade3ad62b39532e02e6b422e1f7ea189dabaea5d2".toCharArray()); - - // Get Elliptic Curve Parameter spec for secp256r1 - AlgorithmParameters algoParameters = AlgorithmParameters.getInstance("EC"); - algoParameters.init(new ECGenParameterSpec("secp256r1")); - ECParameterSpec parameterSpec = algoParameters.getParameterSpec(ECParameterSpec.class); - - // Create key specs - KeySpec publicKeySpec = new ECPublicKeySpec(new ECPoint(new BigInteger(publicX), new BigInteger(publicY)), - parameterSpec); - KeySpec privateKeySpec = new ECPrivateKeySpec(new BigInteger(privateS), parameterSpec); - - // Get keys RPK - clientPublicKey = KeyFactory.getInstance("EC").generatePublic(publicKeySpec); - clientPrivateKey = KeyFactory.getInstance("EC").generatePrivate(privateKeySpec); +// // Get point values +// byte[] publicX = Hex +// .decodeHex("89c048261979208666f2bfb188be1968fc9021c416ce12828c06f4e314c167b5".toCharArray()); +// byte[] publicY = Hex +// .decodeHex("cbf1eb7587f08e01688d9ada4be859137ca49f79394bad9179326b3090967b68".toCharArray()); +// byte[] privateS = Hex +// .decodeHex("e67b68d2aaeb6550f19d98cade3ad62b39532e02e6b422e1f7ea189dabaea5d2".toCharArray()); +// +// // Get Elliptic Curve Parameter spec for secp256r1 +// AlgorithmParameters algoParameters = AlgorithmParameters.getInstance("EC"); +// algoParameters.init(new ECGenParameterSpec("secp256r1")); +// ECParameterSpec parameterSpec = algoParameters.getParameterSpec(ECParameterSpec.class); +// +// // Create key specs +// KeySpec publicKeySpec = new ECPublicKeySpec(new ECPoint(new BigInteger(publicX), new BigInteger(publicY)), +// parameterSpec); +// KeySpec privateKeySpec = new ECPrivateKeySpec(new BigInteger(privateS), parameterSpec); +// +// // Get keys RPK +// clientPublicKey = KeyFactory.getInstance("EC").generatePublic(publicKeySpec); +// clientPrivateKey = KeyFactory.getInstance("EC").generatePrivate(privateKeySpec); // Get certificates from key store - char[] clientKeyStorePwd = "client".toCharArray(); + char[] clientKeyStorePwd = CLIENT_STORE_PWD.toCharArray(); KeyStore clientKeyStore = KeyStore.getInstance(KeyStore.getDefaultType()); - try (InputStream clientKeyStoreFile = this.getClass().getClassLoader().getResourceAsStream("lwm2m/credentials/clientKeyStore.jks")) { + try (InputStream clientKeyStoreFile = this.getClass().getClassLoader().getResourceAsStream(CREDENTIALS_PATH + CLIENT_JKS_FOR_TEST + ".jks")) { clientKeyStore.load(clientKeyStoreFile, clientKeyStorePwd); } - clientPrivateKeyFromCert = (PrivateKey) clientKeyStore.getKey("client", clientKeyStorePwd); - clientX509Cert = (X509Certificate) clientKeyStore.getCertificate("client"); - clientX509CertWithBadCN = (X509Certificate) clientKeyStore.getCertificate("client_bad_cn"); - clientX509CertSelfSigned = (X509Certificate) clientKeyStore.getCertificate("client_self_signed"); - clientX509CertNotTrusted = (X509Certificate) clientKeyStore.getCertificate("client_not_trusted"); + clientPrivateKeyFromCert = (PrivateKey) clientKeyStore.getKey(CLIENT_CERT_ALIAS, clientKeyStorePwd); + clientX509Cert = (X509Certificate) clientKeyStore.getCertificate(CLIENT_CERT_ALIAS); + clientPublicKeyFromCert = clientX509Cert.getPublicKey(); + +// clientX509CertWithBadCN = (X509Certificate) clientKeyStore.getCertificate("client_bad_cn"); +// clientX509CertSelfSigned = (X509Certificate) clientKeyStore.getCertificate("client_self_signed"); +// clientX509CertNotTrusted = (X509Certificate) clientKeyStore.getCertificate("client_not_trusted"); } catch (GeneralSecurityException | IOException e) { throw new RuntimeException(e); } // create server credentials try { - // Get point values - byte[] publicX = Hex - .decodeHex("fcc28728c123b155be410fc1c0651da374fc6ebe7f96606e90d927d188894a73".toCharArray()); - byte[] publicY = Hex - .decodeHex("d2ffaa73957d76984633fc1cc54d0b763ca0559a9dff9706e9f4557dacc3f52a".toCharArray()); - byte[] privateS = Hex - .decodeHex("1dae121ba406802ef07c193c1ee4df91115aabd79c1ed7f4c0ef7ef6a5449400".toCharArray()); - - // Get Elliptic Curve Parameter spec for secp256r1 - AlgorithmParameters algoParameters = AlgorithmParameters.getInstance("EC"); - algoParameters.init(new ECGenParameterSpec("secp256r1")); - ECParameterSpec parameterSpec = algoParameters.getParameterSpec(ECParameterSpec.class); - - // Create key specs - KeySpec publicKeySpec = new ECPublicKeySpec(new ECPoint(new BigInteger(publicX), new BigInteger(publicY)), - parameterSpec); - KeySpec privateKeySpec = new ECPrivateKeySpec(new BigInteger(privateS), parameterSpec); - - // Get keys - serverPublicKey = KeyFactory.getInstance("EC").generatePublic(publicKeySpec); - serverPrivateKey = KeyFactory.getInstance("EC").generatePrivate(privateKeySpec); +// // Get point values +// byte[] publicX = Hex +// .decodeHex("fcc28728c123b155be410fc1c0651da374fc6ebe7f96606e90d927d188894a73".toCharArray()); +// byte[] publicY = Hex +// .decodeHex("d2ffaa73957d76984633fc1cc54d0b763ca0559a9dff9706e9f4557dacc3f52a".toCharArray()); +// byte[] privateS = Hex +// .decodeHex("1dae121ba406802ef07c193c1ee4df91115aabd79c1ed7f4c0ef7ef6a5449400".toCharArray()); +// +// // Get Elliptic Curve Parameter spec for secp256r1 +// AlgorithmParameters algoParameters = AlgorithmParameters.getInstance("EC"); +// algoParameters.init(new ECGenParameterSpec("secp256r1")); +// ECParameterSpec parameterSpec = algoParameters.getParameterSpec(ECParameterSpec.class); +// +// // Create key specs +// KeySpec publicKeySpec = new ECPublicKeySpec(new ECPoint(new BigInteger(publicX), new BigInteger(publicY)), +// parameterSpec); +// KeySpec privateKeySpec = new ECPrivateKeySpec(new BigInteger(privateS), parameterSpec); +// +// // Get keys +// serverPublicKey = KeyFactory.getInstance("EC").generatePublic(publicKeySpec); +// serverPrivateKey = KeyFactory.getInstance("EC").generatePrivate(privateKeySpec); + // Get certificates from key store - char[] serverKeyStorePwd = "server".toCharArray(); + char[] serverKeyStorePwd = SERVER_STORE_PWD.toCharArray(); KeyStore serverKeyStore = KeyStore.getInstance(KeyStore.getDefaultType()); - try (InputStream serverKeyStoreFile = this.getClass().getClassLoader().getResourceAsStream("lwm2m/credentials/serverKeyStore.jks")) { + try (InputStream serverKeyStoreFile = this.getClass().getClassLoader().getResourceAsStream(CREDENTIALS_PATH + SERVER_JKS_FOR_TEST + ".jks")) { serverKeyStore.load(serverKeyStoreFile, serverKeyStorePwd); } - serverPrivateKeyFromCert = (PrivateKey) serverKeyStore.getKey("server", serverKeyStorePwd); - rootCAX509Cert = (X509Certificate) serverKeyStore.getCertificate("rootCA"); - serverX509Cert = (X509Certificate) serverKeyStore.getCertificate("server"); - serverX509CertSelfSigned = (X509Certificate) serverKeyStore.getCertificate("server_self_signed"); - trustedCertificates[0] = serverX509Cert; +// serverPrivateKeyFromCert = (PrivateKey) serverKeyStore.getKey("server", serverKeyStorePwd); + serverX509Cert = (X509Certificate) serverKeyStore.getCertificate(SERVER_CERT_ALIAS); + serverPublicKeyFromCert = serverX509Cert.getPublicKey(); +// rootCAX509Cert = (X509Certificate) serverKeyStore.getCertificate("rootCA"); + +// serverX509CertSelfSigned = (X509Certificate) serverKeyStore.getCertificate("server_self_signed"); +// trustedCertificates[0] = serverX509Cert; } catch (GeneralSecurityException | IOException e) { throw new RuntimeException(e); } From ba970c5d88eb1a723b12e2d8da7822e79c352554 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Sat, 8 Jan 2022 13:07:55 +0200 Subject: [PATCH 348/432] lwm2m tests with NoSec, PSK, X509-trust. RPK, X509_NoTrust - ignore --- .../sql/NoSecLwM2MIntegrationTest.java | 5 +++-- .../security/sql/PskLwm2mIntegrationTest.java | 5 +++-- .../security/sql/RpkLwM2MIntegrationTest.java | 12 ++++++------ .../sql/X509_NoTrustLwM2MIntegrationTest.java | 18 +++++++++--------- .../sql/X509_TrustLwM2MIntegrationTest.java | 6 ++---- .../resources/application-test.properties | 18 +++++++++--------- .../lwm2m/credentials/clientKeyStore.jks | Bin 4810 -> 0 bytes .../lwm2m/credentials/lwm2mclient.jks | Bin 0 -> 17660 bytes .../lwm2m/credentials/lwm2mserver.jks | Bin 0 -> 6432 bytes .../credentials/lwm2mtruststorechain.jks | Bin 0 -> 2982 bytes .../lwm2m/credentials/serverKeyStore.jks | Bin 3806 -> 0 bytes 11 files changed, 32 insertions(+), 32 deletions(-) delete mode 100644 application/src/test/resources/lwm2m/credentials/clientKeyStore.jks create mode 100644 application/src/test/resources/lwm2m/credentials/lwm2mclient.jks create mode 100644 application/src/test/resources/lwm2m/credentials/lwm2mserver.jks create mode 100644 application/src/test/resources/lwm2m/credentials/lwm2mtruststorechain.jks delete mode 100644 application/src/test/resources/lwm2m/credentials/serverKeyStore.jks diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/NoSecLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/NoSecLwM2MIntegrationTest.java index 0e86c6a438..8331b99fff 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/NoSecLwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/NoSecLwM2MIntegrationTest.java @@ -16,6 +16,7 @@ package org.thingsboard.server.transport.lwm2m.security.sql; import lombok.extern.slf4j.Slf4j; +import org.junit.Ignore; import org.junit.Test; import org.thingsboard.server.common.data.device.credentials.lwm2m.NoSecClientCredential; import org.thingsboard.server.transport.lwm2m.security.AbstractSecurityLwM2MIntegrationTest; @@ -28,8 +29,8 @@ public class NoSecLwM2MIntegrationTest extends AbstractSecurityLwM2MIntegrationT @Test public void testConnectAndObserveTelemetry() throws Exception { - NoSecClientCredential clientCredentials = createNoSecClientCredentials(ENDPOINT); - super.basicTestConnectionObserveTelemetry(SECURITY, clientCredentials, COAP_CONFIG, ENDPOINT); + NoSecClientCredential clientCredentials = createNoSecClientCredentials(CLIENT_ENDPOINT_NO_SEC); + super.basicTestConnectionObserveTelemetry(SECURITY, clientCredentials, COAP_CONFIG, CLIENT_ENDPOINT_NO_SEC); } } diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/PskLwm2mIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/PskLwm2mIntegrationTest.java index af9a668376..5850e52015 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/PskLwm2mIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/PskLwm2mIntegrationTest.java @@ -17,6 +17,7 @@ package org.thingsboard.server.transport.lwm2m.security.sql; import org.eclipse.leshan.client.object.Security; import org.eclipse.leshan.core.util.Hex; +import org.junit.Ignore; import org.junit.Test; import org.thingsboard.server.common.data.device.credentials.lwm2m.PSKClientCredential; import org.thingsboard.server.transport.lwm2m.security.AbstractSecurityLwM2MIntegrationTest; @@ -33,13 +34,13 @@ public class PskLwm2mIntegrationTest extends AbstractSecurityLwM2MIntegrationTes @Test public void testConnectWithPSKAndObserveTelemetry() throws Exception { PSKClientCredential clientCredentials = new PSKClientCredential(); - clientCredentials.setEndpoint(ENDPOINT); + clientCredentials.setEndpoint(CLIENT_ENDPOINT_NO_TRUST); clientCredentials.setKey(pskKey); clientCredentials.setIdentity(pskIdentity); Security security = psk(SECURE_URI, SHORT_SERVER_ID, pskIdentity.getBytes(StandardCharsets.UTF_8), Hex.decodeHex(pskKey.toCharArray())); - super.basicTestConnectionObserveTelemetry(security, clientCredentials, SECURE_COAP_CONFIG, ENDPOINT); + super.basicTestConnectionObserveTelemetry(security, clientCredentials, SECURE_COAP_CONFIG, CLIENT_ENDPOINT_NO_TRUST); } } diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/RpkLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/RpkLwM2MIntegrationTest.java index 87ca415bd0..e6c26a05d0 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/RpkLwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/RpkLwM2MIntegrationTest.java @@ -34,13 +34,13 @@ public class RpkLwM2MIntegrationTest extends AbstractSecurityLwM2MIntegrationTes @Test public void testConnectWithRPKAndObserveTelemetry() throws Exception { RPKClientCredential rpkClientCredentials = new RPKClientCredential(); - rpkClientCredentials.setEndpoint(ENDPOINT); - rpkClientCredentials.setKey(new String(Base64.encodeBase64(clientPublicKey.getEncoded()))); + rpkClientCredentials.setEndpoint(CLIENT_ENDPOINT_RPK); + rpkClientCredentials.setKey(new String(Base64.encodeBase64(clientPrivateKeyFromCert.getEncoded()))); Security security = rpk(SECURE_URI, SHORT_SERVER_ID, - clientPublicKey.getEncoded(), - clientPrivateKey.getEncoded(), - serverX509Cert.getPublicKey().getEncoded()); - super.basicTestConnectionObserveTelemetry(security, rpkClientCredentials, SECURE_COAP_CONFIG, ENDPOINT); + clientPublicKeyFromCert.getEncoded(), + clientPrivateKeyFromCert.getEncoded(), + serverPublicKeyFromCert.getEncoded()); + super.basicTestConnectionObserveTelemetry(security, rpkClientCredentials, SECURE_COAP_CONFIG, CLIENT_ENDPOINT_RPK); } } diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/X509_NoTrustLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/X509_NoTrustLwM2MIntegrationTest.java index d1bc813b50..6ca430327d 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/X509_NoTrustLwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/X509_NoTrustLwM2MIntegrationTest.java @@ -32,15 +32,15 @@ public class X509_NoTrustLwM2MIntegrationTest extends AbstractSecurityLwM2MInteg @Ignore @Test public void testConnectWithCertAndObserveTelemetry() throws Exception { - X509ClientCredential credentials = new X509ClientCredential(); - credentials.setEndpoint(ENDPOINT); - credentials.setCert(SslUtil.getCertificateString(clientX509CertNotTrusted)); - Security security = x509(SECURE_URI, - SHORT_SERVER_ID, - clientX509CertNotTrusted.getEncoded(), - clientPrivateKeyFromCert.getEncoded(), - serverX509Cert.getEncoded()); - super.basicTestConnectionObserveTelemetry(security, credentials, SECURE_COAP_CONFIG, ENDPOINT); +// X509ClientCredential credentials = new X509ClientCredential(); +// credentials.setEndpoint(CLIENT_ENDPOINT_NO_TRUST); +// credentials.setCert(SslUtil.getCertificateString(clientX509CertNotTrusted)); +// Security security = x509(SECURE_URI, +// SHORT_SERVER_ID, +// clientX509CertNotTrusted.getEncoded(), +// clientPrivateKeyNotTrustedFromCert.getEncoded(), +// serverX509Cert.getEncoded()); +// super.basicTestConnectionObserveTelemetry(security, credentials, SECURE_COAP_CONFIG, CLIENT_ENDPOINT_NO_TRUST); } } diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/X509_TrustLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/X509_TrustLwM2MIntegrationTest.java index 7c5e48a4b7..28a10fd278 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/X509_TrustLwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/X509_TrustLwM2MIntegrationTest.java @@ -16,7 +16,6 @@ package org.thingsboard.server.transport.lwm2m.security.sql; import org.eclipse.leshan.client.object.Security; -import org.junit.Ignore; import org.junit.Test; import org.thingsboard.server.common.data.device.credentials.lwm2m.X509ClientCredential; import org.thingsboard.server.transport.lwm2m.security.AbstractSecurityLwM2MIntegrationTest; @@ -28,17 +27,16 @@ import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SHORT_SERVE public class X509_TrustLwM2MIntegrationTest extends AbstractSecurityLwM2MIntegrationTest { - @Ignore @Test public void testConnectAndObserveTelemetry() throws Exception { X509ClientCredential credentials = new X509ClientCredential(); - credentials.setEndpoint(ENDPOINT); + credentials.setEndpoint(CLIENT_ENDPOINT_TRUST); Security security = x509(SECURE_URI, SHORT_SERVER_ID, clientX509Cert.getEncoded(), clientPrivateKeyFromCert.getEncoded(), serverX509Cert.getEncoded()); - super.basicTestConnectionObserveTelemetry(security, credentials, SECURE_COAP_CONFIG, ENDPOINT); + super.basicTestConnectionObserveTelemetry(security, credentials, SECURE_COAP_CONFIG, CLIENT_ENDPOINT_TRUST); } } diff --git a/application/src/test/resources/application-test.properties b/application/src/test/resources/application-test.properties index 856745797a..dd1cd2807c 100644 --- a/application/src/test/resources/application-test.properties +++ b/application/src/test/resources/application-test.properties @@ -1,19 +1,19 @@ -#transport.lwm2m.server.security.credentials.enabled=true -#transport.lwm2m.server.security.credentials.type=KEYSTORE -#transport.lwm2m.server.security.credentials.keystore.store_file=lwm2m/credentials/serverKeyStore.jks +transport.lwm2m.server.security.credentials.enabled=true +transport.lwm2m.server.security.credentials.type=KEYSTORE +transport.lwm2m.server.security.credentials.keystore.store_file=lwm2m/credentials/lwm2mserver.jks #transport.lwm2m.server.security.credentials.keystore.store_password=server #transport.lwm2m.server.security.credentials.keystore.key_alias=server #transport.lwm2m.server.security.credentials.keystore.key_password=server #transport.lwm2m.bootstrap.enabled=false -#transport.lwm2m.bootstrap.security.credentials.enabled=true -#transport.lwm2m.bootstrap.security.credentials.type=KEYSTORE -#transport.lwm2m.bootstrap.security.credentials.keystore.store_file=lwm2m/credentials/serverKeyStore.jks +transport.lwm2m.bootstrap.security.credentials.enabled=true +transport.lwm2m.bootstrap.security.credentials.type=KEYSTORE +transport.lwm2m.bootstrap.security.credentials.keystore.store_file=lwm2m/credentials/lwm2mserver.jks #transport.lwm2m.bootstrap.security.credentials.keystore.store_password=server #transport.lwm2m.bootstrap.security.credentials.keystore.key_alias=server #transport.lwm2m.bootstrap.security.credentials.keystore.key_password=server -#transport.lwm2m.security.trust-credentials.enabled=true -#transport.lwm2m.security.trust-credentials.type=KEYSTORE -#transport.lwm2m.security.trust-credentials.keystore.store_file=lwm2m/credentials/serverKeyStore.jks +transport.lwm2m.security.trust-credentials.enabled=true +transport.lwm2m.security.trust-credentials.type=KEYSTORE +transport.lwm2m.security.trust-credentials.keystore.store_file=lwm2m/credentials/lwm2mtruststorechain.jks #transport.lwm2m.security.trust-credentials.keystore.store_password=server edges.enabled=true diff --git a/application/src/test/resources/lwm2m/credentials/clientKeyStore.jks b/application/src/test/resources/lwm2m/credentials/clientKeyStore.jks deleted file mode 100644 index a6c9ae7faed05c48ec1218e23a42c3025ae852d2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4810 zcmeHKdpwls9)IVZ8?$1V+`8z^r7faoTyo7Kw~~aYeB{y?OqdySK}BLOgxw-rlBDFa z(TZxxaVZgsq;!#Oed=sfBHG$cn>de|>D0_gr#|2u2XxmVxY?(+F|Bkr}Xrw_K2ni-bWfz@s=6CB*GFPk0g!dufX^N|u{P18lHZ>cz+#X=+GmPnADKMv-z)w>@4JBhb z95ADsN(Mgk=M8{HB8%2Ragqh`I5OS=A$$_)db__`Kf&{*+vqJu#2QlLoO2`e+65gI z-$gJeM>`{JIjxqb>8Ge_!lDMXA86YTCXKbnuGg^n=F+^#I@_T_2Ve*0!Y$8LB&ZQ) z8fIy2sm?Jp&$_ZJ{#<&$?-nG%2PjVctc1f&65w0nNI+@oo;Gz)1bBFnJ_Nig0-VtK z$i+`9(rT0kqX*_j_w@*Fd+BSSSe=pDsrHJU_wP4v8bC4krd)?AT1kHN7-kN~$tF(BaxIDJ$Zha)0{i0J#> zovXR|mu?hxEl}b7x^;3Dt#7!s^lHm~yIG-8)Li9+;k)X(YBi1vEBDnnA>Ez!mT$3`Q4`n9W+^X!+{4QYO-S3QT6X}EDl&Ek_+k0!5+ zYpLBXV#z;PQ2-f{2g6>%3gV9>L+Jzg5U|p$u#jbig&&wj*8pl_N-2dfV^|EPy%Rfx z%VDtvV0v2U9!Lqw-7z#C_5+1q>%r{Zrb<@rA-bN~cDcLZR##D3?^iAxJ|7PzzqBvV z*yMKZMJcE6p^Zs|bIl@!0%}5XejyKV-=T%)i-5C@=hRPSl+Ag>Zzi$gZEP1x(*mCg z~3 zcUGX)I%_?*E_{3-ZJa+cD?i<-R#=W=gwmu2hr~i!y5^m%St(XSs=P&_3t+#~|>9H!PwQ{m$UWGO2k zOFy7X*9MqKKnj|XB2NyK>?oEc2$yW@k1ZvUBV)Y!3qJ=m9_lR#FWA#Q!FtBRKlEK@R$tJlo_n3b=vB)WQS;b+(7BZC~gcdc{5>TRX>Hkx@c6+Pa||hi){oR?wITG zsg(^leJ5-T^ZT;2SlX2DLO$JrktE@ie zV(3OUHZe6@YW@KxHl`D?&h_4cZl}NScqNqV38S?a8?N=awxM`xRG?1AJYVaiudOGe zpVML!quB?GvXVcrfBp2AXyKVh6d6+wN(pE9O zsn;F7ks3QNc{q&6s497^$v>WtV0af}+7+|4Ma=vf{-UO`3IbZ2(e6)Sd+W8OGKhnve&F{pX!=}TYj4pS)bm=q zHg>r3!Tw%uPva9JIo&dQB!vMD}d)xMoZa~hgv(AwfIo@}ty=^|8i z?n)v@R27DTkau$Rd!dmn;Z)#ji%U2;K!PP4ijz*-ZqJH)6dp%CKfEigBQr|i7~(ZE zSNc%JWgeC&#P;~!=vb~|O|B&94a$Fi-o|$Jf-!&9>IK^k`kO|fskCT;0hJLwRNGo% zCZ`=e)~M|P>N&lva`&9jLkU_gBIznXQxTUp{5Q4tLBl^m{$qix3_<2fg!XQil~?o@ z=_63e`7j(La*k_O?v!R8_|N5RCM#z%zkh4i=|vq~di=F*tao-9r*Ip2(xUaGp`_g-CJ{w$T`QZdmIwKlWK4#oVF!}tB|TGZ8X?OTd* z)Y^xIg29viIhbnLsgyi}V&_7UU{xeV6q_Rm6!3(60W(Bg+a1{O7R+)8WGRd{wH@(s zK${GhI`sLXb^*4`8j_Y-$d*hvP4oP|D)0ZkP5Rn*Om0!NWp4tgDGpG|L5z=m>HIMn zbp-;Pp~*g28Bx;KSa>euVO`z+-kczeW;a<=?+S=f1MQ;`&`d}d^5AfFY+egkWc!CP39AfyQ}=1VlHt()E_ z1M7$I_@8ZhJ%PtNiS+k2y&uujiVJc5Gsor4Iq{=&2E7sHiH7dql=}VmE~1%wAjS=W z-US%MD#xzn+KIdbuX4}O1#U6Evu~aWyJvEnGFWtBU;QUP+JGyKj%mKTb$|Y4AvgC` M^f%}Gep;{ccMhiIP5=M^ diff --git a/application/src/test/resources/lwm2m/credentials/lwm2mclient.jks b/application/src/test/resources/lwm2m/credentials/lwm2mclient.jks new file mode 100644 index 0000000000000000000000000000000000000000..490812c01ab483d3462a09cdd18bc405fa23abe5 GIT binary patch literal 17660 zcmbr_Q;aapx+vhWJ@bui+qP|+-`KWo+qP}nwr%VDIp<{W?5nl1cKV{a-s-BPp6*nq z-%im72)_XV0@DWw*MmV)hKPr}!UBQ=<^>2BfCLEV{1eWg4**yAA5GwbAOYaK|AaZ| z0|0Hnp#Og_7$`uXJpUhh|4(|;|GFL&mR^IN{lBX)^i&`yP`UBT(;ha*><Z#*DKPyl)yFi8CnaX=Gb5I{;01aQ{~^Lf*n;^*nhoTywq zGZ6o{KWuMA1xauf8CQ$NmRxK4wU)qN#p+}Y0z||rxMfcO?tD`%fhTAKHz-MkQM@ot z{ST*=Go@iZr&K0oc@0v^aTIi^$!CI2$HgewFy20D>DN# zD?JAz13fdxe<;phZw1$`R?_|=tj_&vt(@~IDKpk*Wye%IEA(ssxY#=8Nskfj2D*8E(53WAp0 zcQ0=_t0tjQ^$~9PaGG`u~kM&~X@{ZApwN+_f5fT0`$5>QBov}a>&r}>uotbGY{QrN zWr--T)G4_!rEubWxomU-z}OdXe@TC%{wSC}pnxMBsf<4%(czYes9NN+igaOL2QnEN z!A{?mmWEqjGvi79USqJ9wnmswP&An!Y)GqF#+&Z0&d$p}6-aEbPrlzj&k5=nt|8a` z#d?vd7z51O#8~i5=B|gAvZ(ssh%@~QaVBOK`v345H{gblldv8hyn2b;XNp5;p%F8K-j(U2HB&T z5#PDU=R0>42<~;F&{0E@iGM`WBfpt9`O6XHq7cLU^h=2?Q4z2t^OhL;Hz2d^!6|qe z^Jr!+4%jY1HspUJ&ipULnHgD`=>vEK{%f%Z2g?iKVf-gV3j_%8PeJzIEr9>(T{`)i zX>#=xf({&nw&UZV;gmcrPVw*D10v#Oc0#l(*~2e0f_lE89KQhWx-;_D3SVbCDSVJX za>GOf^OJ_n4UbmmWj=cXklPq+sls!q_#hg2oX921O)CKu*F(1AwNrS&)5H*w4vVYr zh{w|ljynorf~$~O^m{gV%whCmBi11mTOqJ$ekU@JIn5gRW6USw_=c%j*q4d$(#z-w zR$Wa!_aR)V5!<-iD@kNIc94ukA@@NB~9 zv=BMnn=5bKh3A#0eAfmrz^J7NA>aJ0ff`P`<5$hwL%X9^VZn3U^jL?><`X#f2 zzp!&}Ngu}Ovjle&tL{Om;V)`Qv@Q2R0c0#It$~MXnzPpW3ZqvLOD}|)2;Fld?B&5y z*Vt^GkV*AIF7u~Q_z}3$N`wjF>qB`q-)jmOS~tc{08<>Sn`o$s1Q={0;N4bA*O5@A zwo$pYw$6{26~S%?;d|qJFahyTu9ZE5q5R94YVctdLew4VfNta(gMZFa2kA>-}iuaCUzfWo%^sL$GG&xQc79Pq8t3DGJ(oRiNrw~ zyaYPDJh^RiI#Kc;&|ohNh99#;YY|6jI}=_EwSd+&=}%d?nS76e)pI>t52<^NtFsLGj8!t`5{1~+aw!%Y zs_&m$Wfoq{bQWI3Bc%)|tp3E$y95qg5*pa??!|=VLy?f-#S(0cLn9T_QsBn{)aJp5 z7w`qy0>tq3$IRiL01dHKBH!34=_M66JYWS#IW`t@h4zxV!K*#eX6e;?@?J^voyG>h zngMrJ%4b{PG_`&yuMBhJrL+%9X{-r|$Pw`}qntpr!NCdi>4A{4q)))O^aM^V7M;H; zg!+5Kab;r5#usI zGHB`nji`@evG`0PF*m&Fd&)==U; zs9UG%f(|WhNVrWd7`N#|&*(PEgLrlCSB`-Y0(?UQRaQ>4ocC3y$y{u9WX|M0usnfv z|H^>^eIq28j~Yd*&?U_)jHC$als0b|CJ=-B$#9dLOAJqhOt8` ziU7Et5dd;`t?{V3_C%&Uj ze3W?MyF(SI*%D+yG<8L~QSKF1jqFXLjZ;npHQ*s9^EEQ=BvvRV&>RH+Ru`?D>ihte z*~e)9kdc>H(M_J7}Ub+P(fUUaq1&j&L(Sr|p!_!&5k|vvdXxBE#fZzv8 z^KGaW?n1JM(`Jwfu79aXSWbi~gB$Xre9qxuo&FiI_Ct84$TEAtT45)U@zjPrl-`#b zD#=;vAM(}wCog37sENyMB%i91ea?Fqm`Vv0x>+~?Kb9EIC=E6u@HP@YpwBs&uwezF zbONQjM`H!5iI5DS4uK6&!rskUM;i)~wsY!go%Rs zc*+lsK1|-0H0X>}IuZ)9YqwA7S!=m&q_uyJFKe_KJ1PM^nxS8T_k3J@R71=CgeU?XE<{Ou=*5{6X{+PY_&zh&STzsgh~ zT}s4V?PJs@%RUfV`yKen2)4nk$$gZ)xQKSx-kwRDE_Bm`&Ysfgq>Pq4*=g`*hO(qM zA`)MOk8bH~XL)n99ANI!mZM6c*L>y=#S?1nknpt09Fn}qe|4>7?hyzYv4-jGc@YXT zsc-=6B}<-Nz_(LwL-oXE!+PhsPLUVXP~O*&$VT7ssS)^%yK0uh5{neT%3V4woOvJM z_xyzTaU-l}H{_SOW)<{Ys#tKfU!1{uY?43$M`C25Fw8XMldZ}rB&E!YeOON2bndEd z$@zcy?DP`>^%s4g1a}E-czPU+TA8$|_KQVA0mZ_V&9;Fu7=-n*|U_ zELkybz)erfIf0fq_YU%K3od_vYd55XBMQ0SfGR9+;k8|kR*l7SlE~&%b78};Q>DrFa_9V%Up&yPnL7lP3? zjaoJ?o)i-J?o(?r>4h`D5RX{ndQZ3t$T)DZ zM;+%XoKGSwKzF>ALW-j~VkEg(2@yKR0qp8I`{;eU}t+(DleenF>jB#n@fYi5qG>q7p`h1JY}v=Xzci z_?Kkd9qYlTxxE!`UA~D=6lt;PS;+>x;JOtD5M605+#HtEydR7(7h*C$Ac*jrZ|Qll zDpY)fNs-JYT~?IL393HAW&X}73H;ZaOmZEto>SRRb$x!KNSs&@FqaX(6}S?x8y<(2 z)a91Zmk6m*ef>p=a)9+!Y;Cwa5T|x#wQBcz_D0_5s}K?q3RuVLHg;&?1wzY~t%YhE zPBR#1Yye+KqASFu>UWR_Tgd_sT=Aq|4J$Q1JG`!m&UM6X?ECRi)s)<0=G)DfHuVSm zj@36rqJ-#i>XHfNGC!9z7L(T)<(6%9Gb>RzHSJQG3z;jQRFqQ@Ea!r}Kg;0ig^>=P zN8a=Nw7^cGz#jA)Uji?67m~>Pw#d0VQPh?uGfgg@c|(=@hyRRv7!OPwGt@3Sj7jRa zcm==|wK&UlfXFa^dQ+G>+9eKZe8^8gP@*I3$hYnOeM2AwxcR3}`OHeAP*j82B9^~6 z8a?GP5c{D9EUcWf=EAPiUTCvkZUIVhK4U2e%byrnPuh?tvBP2yBQ3UwjdqPor;V=i z2#yax?~eDd9%$0E^>K(qvBYo2e&S!XOkMqEvQ)@EpQfcqhS1BpGAsKb2i&uH?&7BL z+G6SVZmg@2jYuIgg!n0IhB7O|fwWM$7MDkKB`xESb{%x%3#b5ajtZm`-Z8M21zs+l zUyQ(paD;}DnRCa7Skg0qbN<=jb8xU9){C*UTyd6$WOF7$l$Zjg2eyk~w$4|@uv z(06oCI%4EK9QN|Q;ms*|v>IDdK30&Sc5~<85g8C(N*M#DwjMs&BKhmY?O=p!X(8;D z%-|cTalBFdOh7JgV|xA!YE(D^K*MU=hH0PzC%>?&_TNgLD}t*!M3#|fnH!5t;YwpT z&n~I-J0FJw`wHCIb)~3&-n}#n0g#pITXE$`6(WA|ogAojW$z?F{uc6G$XSFw!*zDk z2vHLE$f2a)SuRX5Cf~q1is#b!IG+}_lq-K)n)ZNBWy&;p^#<+(}v$@Cd zu8BA;!(3S*%AV4GZD^$RN&E7{1Ot;rrl1#v#tBb*gyJ%&kPE5;$i)&45yl*J{{#Ta z78eF?f)fz#?z>tFt^|30DAky$8JcyJ?F_)--;?1Q$Xi*~KISgW4@-F*hG#|Wb%Nc! z-U`eFyzW`&P*#uJ(BL`PNl(Jjh+mM5s@O-}hg}$POCRzbc-JQ2r-&rQUf=1EZ|}{$ zu?d*g0*GAi=a%bPWkepdNCq12@`ES`lB(){LieKYC_EaPcGfx-9o?!Su4=W@P~l1Z zA=ZFy+3@y-beSO4QpEUzrG>S?F`teipAdkA_&&%u_SlvojDUcw7c(NKcma2TjEe z6xW6*D?v|2(v^i0RC+#io6|*I$r-T}$^C;XMFR*L*)sI&mS1DPzwy4ALu*5efUDDZ z17(a7_ziPcH(Rj(8MBnEf3I#erN{JJxue}dc<3np;o#wlf#WA`vgCpIIz1t(l=vy?m8k59+sn*7 zZVDbUitt)aAsgpU2x#BHQr_6-fF&3fwWo~yTf+(naegx5bOGe?cPJFVKa;R#0vsG$ zjA#O0k2fOqm#8&nd!Y`Eai50paVm0d+#P(CJr739-)9L^37SqifMm#jcN>Cx)FH zJzEJZRpS^@rj0Jm6QeW83?yVB@5NxiNB2y&E)WZ$QK2C zIwr`2H3>zb*KGk7DveFe3r}KxL5I7{3`|AJu;l%EsdUq*>!G25ZI!}I^|1u;SkVpXL50Yt&*vD zFIgEzY#n7;=AR9oUYB6-74d0s8apJPipB#*HK5@BsLMGkW<$PmX#_rc&_=z+i(o>N zs74=kaRom1=N8)m<{?qD95q5G&7~LUQ&M8fT1FzmXk|VUS5<)L3sC^OpJ#7z!3hTC zI+7%^3MWHux)LuLPe5E3N?Ig*LSUP+D|oP8!O5y~9EL*wqQt*mX)McCD+hM)%mSY) z=;2eK@Q>BYN_9(hSHenVjKvu;fXYlXZ;YtSW)WFZt_9LF)e~D$_nn%LK~!| z0Up}nI{wCLB)q6#QL!_G^jNu#TAP%7Db}~qUD*%^pX8;ImM^ARM0l-XFlM+>08o`2 zL+4PO@tlzGu0m>hTra8f^kTK3dkjA_dXx=RsdDKT*(AJ}(xr~T=kQYe3Pe;@#06nN z?wFOZh#Z_CZf4$5;&uJWJt%JLYD>TFGLEvwL5DD!av>oadELw)q(Xpj3Aoq^kU91H{`_g1Xh;c!a&_( zKzb{*!qwC!dI9j$gvTM#E49CEJRx}lYoV`Ir+Ny>P!{CDo8O@@Vj`^*p#j338|DJM zIL3saO71*c2^bk==|B}M2b3ws0}5WAm703enN%rZxqlj8KL3%vD5%3A;0uImw z-Vh0K2wM?$KE$FyxRQD9!>BCa^xFRT1FjqA{dVe*k1L{BQ|ihoiwuZOdHa!IMgLW{ z`;vk-SP|^Q{TB42^i`O%rMFh`as9ioTFX$^}y&?89OZ_aI zsjMA2AH$*0w-EjGtDjfrJ+>u!!9c(@OL|*aOthu@1TC`aWOojHhJ!a3&TZI9>rz$p z_$n3cbIh9|xZ{CccgSkd*FQ17nu(!&uxz(qIug-D!cm@4zwU@Tpv2P!)TJI@U$UJpGikGW@iVBoNO?Up zZ)58S2+{MBak|N82zL9kp3A&q<#u|>mgr`LN~Lp>r)$%Bj?O%rmZs@oQ`|wQG)v2Y ztjDmD)GfPMt%-T$_+e5$g<4}!UQzW9r8U~L_Dv&5eBhdG6*N0K|)2` z?*Z-U)aw~#XbZ zDvT+6YrO!5elN`5S}F>tKBv4o&aWE?&XkcP@$h^XXjY-3JXO|2tRHNfAndZX9UvsA z3}|MT(h)ZIlg5!y#KQI_Rf1(Dm5@^#m)K2Y^4a)g_#N+aaRRQ-Be z#3A6SW&C98AF=s$q!8I%!+6A1{O=)B&%1#oSib_ETy7fB{yg3zRS--C380Uc0MD?S&mTWm zTsEj-u+xZD+3x2b84r-HzEf_+H4-*RWr(E#+Xp?I9c8|SiJ)gm6r4vCm_t@(yemTUJTF3wRGi3FM#hK>+Rx{u`F|v@P3D-?-gw85+ z;8}a8q4j9!m2bD!WWq>AmnqUn+SPL=?m%`z;T%vJyBefv?Ve6g+pUu2)8$ChwWbUPnQerRlmVOw$sy%J$o3flCC4 z`_eLkJ23Far+;uf^sj&o^|ymaDiUG1osPV5pda{gl2x0j@C|}ChQO1az%Z|DLW(ZRI z7#K76QM9;Kq)y;4A%8pFjBC#Mu7tX9Jff}LCti`cs$>@_g^R^uo-6$(Q5VijdMKDE z!79q-%Pr|S(XmznEH#Qbkq^Lpy_a15*t>*uckt(sRrU;aX`-SdW-Wtru}m9DB5kCI z`^qWW?-apfVX!8XIpSdLdY7*90PDA)&%gT($(D$jF2kS4dobmo5c&m3ip%^!f4@;B zd=A_q1EOi#yd(3R+-;X?agy|g(rFKv^w`H&SaOFqj6?4#bTE_ zA5vvcsm65R$kD5=!D=ZwVPdM6t5Lr>82mhG*(T$$Qg;G_k&FjM>t6kC#9eH!Wse|# z$bW$`F|!{}qvJKlfq!=AtK-!8Ffh&!|4cTD;|OKx36wX7;kZ7z8rSg@X^d|dMydHc z+Yv_~Lj*q;E1R74&g!F=;*#CmSa&*Iur{&ck=rYf);RXBW;w96$z2u7Z*Gl53&@Ey zv%c5iL4mi=pl9|sI#UD?Eg#KIJDenwYcwcS7kz6$adaL=IK5+KwIaIdVXZ;>&_QE+ z-Zr>sBScUUUbZn_Kucwad}>q6t!wz`N^ruUYp4^c^Qn(Vwb@mV#Sm78!&}XFRhz$> zLdFQm`mhkH8<}Ujx|a5bQ)IIYZSCYpkolB_o8csC`^3{~UTUOPPu^L2@WEQGlgCuq z=VL3`DM151Oo5eCvK4sB2+O zw5yrkq>(ioXC75%s-H##LB{Aj1(ve&0s2%PMaC-0rIadKFM4a7RFuu062ere;;e2v z(!EQiWkM8r9mc+KbJGHZ+vw4l>{(d&sKS(Ht-EF<3;5Pn;nZ}QT+if2;9uTE3qdYZ zS6@_iEOF^*6+%ZRc6hx=f02WXc3L2uh?9XnfqPQo%sR9RJNKf2Hm$02IGDa8cR@04 zNs(vN@2ucwaY=2GjgFsv@93g}cOPS23N5Ukrv2iG9@GX+8f#T&xv>_ zZsw{`TPk|=Pm;0b&eZOUFD}Q^@A?Vm3w`*~G?GRMR)w+9qTd##FPM64)M2SCC;e(pO2_-ZL zWX^joes!2a>ifqwq|pFH0Jf{;5o&xO3kZv<1z?Nnpp!3{xC~x?agRQ}#;-Lv4=A#;*g&F& zD8@VQF0)%{69ahW^tK=ogR|?VMH0G~o9rRVJdeCt`^_53a?>LzW_p@cFuB*m?9}kC zTTZ4Ydjv5cg~_Y}BVDGFF{P27EDLIFH`j_e!LPaezI7>TW|e&R!8PS1Bi$XqqXQKU ze_i@zXNtW~B}72T+luay|4Xk#roBJ!mC9L0p@g}S%fQ<@p;_%JGo-aUCy*vgDo4H_ z?&gn3vUon~$|h7NgyZ)quU#EXg{&jqLTir- zW9F0&C{XyZx9or@u&J!N7-1ji)%1Yyel0f;B{B8+}zE4~fS`wn^!ZaF`3j zXJnXsMs!iJmRps|T+M>@Rlo$)@m`Vs;XVXcjVbZntLpUGaKJ%PX!uEEb`uk007sFq5znG_Z3W|NVJ1q`> zi*u981sQ@bHKGK~>~mH#wMq!kmg?nWo-Pk;YBonlW*CO&#&rg^^e&&qO0T_PBOcu~ zx{&wd>{CO@^!6AjH=LMH7|kn3Lw-U)M0iQ`A>%)Lw-82D3m-V=!lKc@9_hmUX(r zMVkiS^V0PaE;Y9Aa?mpDy^cEst)+a$#UNXEmBrWai%)YSRzjV+vhMT&t;Z~tcz(mf z!nw4^o=n*-g3$N@SkUL_Op}^LabJLPhN}za)JFplJW7T4Gio1OBrg><&S7-7&z@*> zz9g|epB;yP4=%g*qkzzal3(pkLZaTDs(AmHsXBY^?W!i&PolGMJBNt3saZWzZf}CQ zh7)tX?pnkmmksy&)ggKIdH1}U6HEPx$Up!G|K8jih$*eVxZ3ks7Sr0}A;_eZdZ=h> z#A>PVusTPvRsMztVq}i};$N*kQ`YTJfZ(x@$haz2knw4=**i1K~BhNZsKXi#3<;nOKypyitO|o{uhM0UUv<&WY zTW0O5^TCNZnzLx1^bk z8{(r8RpCGTuMG8n)JKij^;ZwuC*K9px7cDzil9OKP#Hv?$&bg?+rqE&K|Dej+L;2! zbX6i1>}brDZ2Ft&d;5Jl|0a{fK_KMkX?lcmo`WFLFO$aL3j0vM!04pZS~u5HGhDCx zFInR{tkQU}(E_%9&0U5epqNl89EPMW07smeBsX^8+@AqXzfY49Tmugm4K7t29D=`V zJk)9ca(&m~8WFM}`L1FPgod&0lfRWh%x%R>rF4D(Q0GjIfolCNG_XPDf!?qd$bV%~ zsmdXO%mwpLQNE<4sJ>$pxrMWP5!|SU{qg}gWeVD77^^b4B-iHM1miE)F^tJeQ{a78 zx~iw0QtLe0#7aH20exE#_LGDzCp(po*-OQ#s1xbnhIdp5a5QyzX_rRa+M+K7_An{< z_M;ixXB~p?z1JNuD>JI5NE8X~*aCs$Y;gj};9(nRy}p|FP*djUc(%DTa^(%R%S3!429krhqquVX=Rrju%kmLE!VnpM=_TjftX+&@rD?eAu8 zWG{c4kNaysXf<-e3sM`K8p9dK?LY~b-eYe)>C2bmTELegq4#Z;Yz;-cS&Kt@o^e}g z7o$fgJUXGho|S>0e5sJL_FLBGS&kacR@}eiB^Cw5D-I8|aesO9#wUuE zRA4r9f89iK(7zd#?6k|1M;#mQ40)Ujl|oGduMgwSbzH_s9i4?Fg1!cx zG~@0N=RD?<33jh@?_>%#%22sd+HzGc6C41Lgl%U)vmwoEVgUT6*G;89K2SS#k?Vr* ztD;q+)ddb;9eoh4C^LRlR_m7U>tkgSWGO{Uq<4N(vR+p`J}7dBc?x^B3Y3TQVN?d`!|Y6BXly0HZWekw%ho=KRU{aLX?46F1r(}- zU6>-g(j{|rD*<_#1WNRd-PIi+LKLepK#v36DlI(*!4qrtSn?Wz5=$ILbX6N0tUTUP ze>u1zh_Yq<9D7H?7jM_a+9LE^M$5BZE7N+dl53(<*!99kSH(t^_0XsPz`@32J6Fh> z4%;sCD6|;>JlUf~C0+A_HfUT>66a2u0aq+1Pq}G&W~x?1SvmqpE|mV$8i&N&bb1`5 zT~l7#_Qs^R)`=}IeP=J*n6m8&Bt%ESwvZ41?Ca2d5SFH6d$1sn<%T|rx+(^Ya)C+4 z#`xf*lcE>7x_;2RawXP7rIo5{FH(L8;KTHLR8DR6C$ygf^nfkxz6j7Dorj@Pk;-<6 z0`#T01K(YAl`O?PW#*+0j&;f_d}F1Sr(~os12mJ=5QIHbn;nTb`4qpT8{* zH?rgYG!c}n&UlJ&Ysvwa{FAsP6%Qp}bCxhjdVi6#-yVnHgQ9w20)LbRJKtrC^F(F(eK;CYl(YQ;w<4%b}Qwt z&1&ICyDj~R&*w8|XuJe;md6b7O2+x<#rJ33$=b*1+ubYqFbf%8%eKq7?P7TDVg1<7 zzBDPoUIrV=gh(iIPys2dOOr-4UEFsL9d!mcv~#iSWdF_fET~xoNbV=6EFvX#kH&#- zcHar^v?~b+t2hA-`k78_o`13&YV5b7EFY??$O&q-!aVE9;(!QSpytpst|h>FlLL!R zo%cr*MxcM1Pz8Dbm06a~_;W2&s=2%A9>j)s+~cDZM|qG_@A312s>HY%#dL6U6lxW>aFho2jPkX0C}g=20fnzJcX!-XbN?7!+ob zi7Y!JgIy&aQ(VJ|$%~^M+IE(ycB=rw7^GsoT&l}}yfJ>yVQopCuH)*ksol0z5w&T| z-WBR0O{$C&Oe9Hcx=$-$QD>!NYqnj~w6lpP#o3{P%+?cj+m1$qvz2IXXQa?=&VD z2EgXLox_gHjkSZNu%zk?{j&mfYf{L1+B!w@fNn+GwN5L}puBoRh~Y8urw|vJqA|(t z;~*$6Gd6N%ciw96NEFHpK8`-n9}*)koxOv8Mkkza4@D^F-PBqJ~nMirzhzZWB z@X!VOS*ZmstU889>N6V`a*x_SNsZR=9aI+3Oy#Oj%hkg z<8s)MJ4lH54NLHBW?Vg$&Ht$nIoInr)DCP#@#VzYqzH9kPKAIwCeM;&mx*sD3{U({ zc%}#)AB*tC=~_Pau+LJkX`VX5JQC#m!4$OZsiDB_?g<#5Ibo8J5}@{@lB?1hQo`Up zL}p~Ml9}#HZ83jD$z)s`Es$bb>^}3MXn%zi+>aq-&u5CO;kiaAODI%L%8%0%q(jwK zHD*h?!Mz7T=JT!t-HL|7xg5j8#@lbp8n!M`7+x1u@2sZ2En@*`_|mJ4S!+rp07l7& zilU=~fCF$AD6iwy1)XtOmZIu~nz~*p>~9>>Txkdf$He==o0DeQA9AbYE@Ja7h1uWQ z{F9q($@-A4b#W2t)Hxwx_jFnL1Bu7((_UUELFqQaz9n`b&-~`-O{9+7a=1r8?v&6$ z5*pyU`jOvx7^-QN!oV#>v~79<3HdjD&lfeLO-AyQ8ws{l_JAg@2s^xnmUE1~e|9~}r3K7!Om1%)5GWP zAk@Gu2C^9{3UnADm8#Wid_-&;_fxeKg#1?o2uVs$In{E;3oiYuikiSY*B zF+tGP&QcRI&L1 z<*}Izyx|UNJvb+5>$N>eGL3Npd9q|Hq-(@q=$brD)7SJl=FB6f5~=rJ9p5->plggc z(?n-gLao{5zN)@Bb7BOC{$#E@m>4tzXa#q% z`Ze3y(>n*3K3^_+2R!PCMD7!l%s9>$Rl~r;quc1>Ho1{e1fj+X`}2orYKWK|xU4C0 z%oAC#r|lzhWxj#hfTcM3gEuh1lNN)^8jZ23IF}T|!qn$KvHLYU>F^6K=M8PeATe`) zQE5R@Y_$3nu$Q4S2*icOxqdE>vxYSe&o)hM>*hFVRS*0(Zw`9Uck0xp}S-F^3zt6cs&m_{7(#Zfg(A zH%23rYIWp8n4K|ahsMAi8x}E3I+|HyE2tgtPl zR_#yB7ix<#w||cx!o?O>d9Mft#gzGOr1%Q)HO+x+Nma$*(!3@1?JjtJSEqDU&!mr9 z>rmj#SmmGWx>BWwjSkpyNy^^5Tn(m-1KNbm9@eKttA_H$dIco-DHXhB=Bzti3}wpG zYELUFFQXr-zO;TzSXHxlRJP1pKx5lknV2n-#UXTgT&|_rIVT5=m8P*wFs?YJAPOPs z;aYtf(m{S|Z{`4-daU!ezP%u>*S--^v*z$s!$b?{n)jSO`=*k`DxId z)*HNj|KzY%^3428# z427|pa1tE*6hg5VZ-a^0`(Ty);SYPj6f2xAPd|S859%3PKwpZ7O*7-tkowIL1u*Mr z0xAO)Lt)AS&?!S}Wu}a0bsIKsz#isbZ;Q52v;AaDkXj{7*>4hM~egzn37M$to7yT!61&@jH5Wf<^#ev@g~i zHf(rRfMH8lRnIlfu6mPh(^A9e_Dzf%OXpNO(yXqqjN_d=z}Lr2uqfZRQnWN zRjlhj1n+ZTI;LkM)n`asrYtt~d#JY9We4fO`#>p6$g%!v;jn*dpFv1joe4vWRqXJB z5t4KuZQd!>SHijRs?;Pxq4yI$!bXs&Q(1196bHdE3x zhzWR$GWIf5_pbI%o$WzfqKk7F7)+Ey17du=@qME;b@c*8kz3tDWM_DH_)Q_RG z3@mDSEVqbB#1zfADr+~n;$^T%o~F_p^70cKBZdI8H|R_u8~CfwFnv#U-~CA6?EStw zN&O{7jSg5~b~>JmhFtL)fODFaR0n)3S*S4LJ%O4i($`rmj`|?Aslt40;B6EVx@3Vb z8E)h?a%15Ml(3VVi*qt1Y))g=P&>NB)Jv%hgUJOliXj`OzmU$Ug=>RwN!JwuS*tvh z-$FgZO>jJhNH}U3Arim>pTfFzEsAZG80BAa0^ruGSVp1r8x&%O>HVxgR;CjVtN6tmTn@qWeb#(r6m%^5%QaQ;JS)HfPvqb%z+p<7q@I;F5Na}XH1hv%+B*EC6f;_zkegU z%RJ9}{=K(WUk$*MbmneEaDINzkoO>6)EdY;FoHE?M8K1qbYH@sb)r7}2WJGikL_CRJUJfCdL4XxKG7@Tv#KofZuF94X#lk6+p`pK@fm&45j`7mneZg7BG?|Tb( zl?&3$q;CyE&yg1~-5fB{eJo$rRRo@$--bsR@VmTL*;B>Sd9G2d=W&5DNhzcFH&^p^ zLj@2fn|+!rscw}gh&e#82k%xF#Xp-T21k(qVIK z_4yiqj&}bAP5*ABAJ#{x4Z3Cr*tw^sprb2on|n`w{d=zi294qRE|=464RL^*abuUW z0;}|@N@drRKUFJ?k|UcDyvE8cjNB7JhOoXcb#x}dFjG$nwCJIjUNm&9(yBliLHF#O zo=(7(kTuhdO=`?Fl{vZ+)wCA^Gj@;`zwkuLGHe7pBR!0l5kpF#D>Kgy{95^c0&)S3 z{^op%0$VOPTm#xW!zx1tDTa+&hF*AAk5~Pn`s)Dug!jsm65`juZsLp&nc2nE%ojR*NCGn@#=YHsCUvCsh#dtbR* zDe)XO$g}_rLF>F2-+vzHs*oKPFZ4}6bd~9=O;aISt9do6_{HgulDR@mRo@fAZFMVS z4_BW>6bir7*2O11-%<_tod87})c_A33hATk-hHuq?1uIUN*I>%>EASCtC|fC3_G(2 zF@4t^dDuJMF~}AAX??BVQfXrVMVK}kl2lS~S=6Z8&nxpROzy$rG~?EJRqPd9Co)E# zcO<)EDobjzv4(?0SD*pCYei?MOu3ZRb;@JbunlnHnh>am#=Nt7j~&psXi6nFdfvwXd}b1Qe^47Q;6J?Lgy*av-MkenUa9 KeSQK10fwM$Q%GO{ literal 0 HcmV?d00001 diff --git a/application/src/test/resources/lwm2m/credentials/lwm2mserver.jks b/application/src/test/resources/lwm2m/credentials/lwm2mserver.jks new file mode 100644 index 0000000000000000000000000000000000000000..a1923e942f923b8d84a989055ec50c2441f79259 GIT binary patch literal 6432 zcmbW)bxa&gyC`rLcPYC#i?bA6q!@YtiC< zdU8&_@7&x!?#az0GnwakW|H}3lF2~BDQQpvXwYzqSxg-ENTtYY0ss~uFPx$eJ)ENZ zZ@3d0j@tWwq);2t!%=JhhAW}r04+?s|6YZU3qZ{adxD1DLv8+5k3j%6gbM$AiVx*L z2U6Q15bsYIme>Y!z041qhoW3B?om-8#HavzC_X0kf9;2ggMk92#l(3RsRXb_LkF;< z69<2=RD1lmyme__asL=|dW9Yq@8V&NxmtD6_bx(hAzw)a3 zp7kA$)lkLrx*}#0;d$tz;Q88;v;*<}HKYqOtSB3J)*M;Qp>Pm|t#@W|cK6P30)iRP zR^YqlEIxthOpGI4|7JpYBRPhdU+&hvR|>;h;a*;HEnp=vz~-)W@fmvB{k>&qY~0At z{SK^>5cJCDiB}3r{jbyF0C@?)_$VGI)+p{M-v8M{8UCFF@dD9b=-E42)AI@n@Cpb* zMR-MoUJ3m*)&Ku64T{6c=&LcU#ew1M-He7M?rkL@|2L+!nHsg_J831B#iV8hOVOYH znp*m8bmBLOdpVLyVn@&}K&K}29D_qEC1e7-m}@&@hNM_JOZ?Qu#jmFUGoqh|@nD_8 z(oIHTImsEb%S0!*x*BVfnpD-hLG{ANPA#a77W!J|tBOob@}PPhkS zWu*wYsV1J%*M`iQQrlnt??se9*hf90h&{W}Brf8F08 ztwPHF(dR2e&f4cB?ELMsGFsmMjkU}M<>89U2yduYEuf1JJvlTS^sbWWV?{&qp(mHc zDI0b15&xyb;I3^vw8`!8s$=j)4eZf^Wp`q+pRD)RgLXuB5lsw6iGl~AEbr(Jcl_<4 zd}q6QzPwLD*367)M*iC-n z*1|IEnqPMiO?tYnd{K5;-w>CBJuc(-)8J6BpeB(eS|G7{NPty~MeIWWxGlQ)CmqV0 zhJ*CUb?81(`jmcY*2;`8B1!*fAy9jj>F_me>yN8`zfq|SY-U+g79 zb!kRDvgAdqzYD?K7ZjJg0HPxA3Y=M01R!kZCdU7SB8Ky?Ysu$dG)M11v2&$E+rl}F z(C&GJb`}zaCB~S6E1V<-Z^g477sq}_(JV1G9|XHHfSclP z->B)Twr+8p@0A7OA-f}2+XuClyLY$UN6ZwSi@K*!GL9-u%0|iV-gPG63vIP({LaLQ zx_a*bx=&Zli_>oe@j=2*!u@9 zZ_YOk<)rL>YqphQZ_o1F~^#$0B`aZvKbf7M-^VZew)Y#YUaP!^g8mnsr+sh(6D6 zsrVk7Ikb`4PWp8+(@T0(kkCgB<)GdqLoJ7-?wfn}Y$Uf>>-$$kCSNqpge2Yu?y$T0 zdPa&&sP15J-V?4%uJ2nHZlGcBMv(ZOIDX+%eadeWHM}wQ*2HWlpWtKqBM^57Bo>|5 zzewy6y5FJKkxwUgXpF>qSO2JRCOmQ1>+>LE{O!21&J)8^Q~xN0C^VTO>E*fk2wk6R zdw%>JDN+Bqc`43USXgxsBONs7bwi0NxfI=obJ|DOB55@x^wrfu-?x=p*LyNPD4v(L zgR(d$zXs^!I*Zh z+yjvwq8*o(dZ9|HZgMOPXgT2=Pi*P1{sU6-CKj%^gCMD}rt@y1W1{e64XC-6*snjI zy%F1{%Sodr331_KGri3s_7QYLVj{b}+_WWh4z2XlbO{kuZ(gDl(|D}D(m}HE_mCCd z+JEI!I9BsVS4simJY1aRwaV*pXTZ?n+d zh$d^eFt1P0`ikG_YvouX{yd_y_j=V1kdoB4L?p<}4`OxGL?onK>=jH|M2|6kDq5haitcPf2k>UJId)PyCpuA~?*h^0uF(dDF<$gyFjP;lRo|k_t{LIU> z=-GnAS_i-v$F-@{z7}mllRY&4#-aJq7bEVIL2!H-l+c_4BgrWj`rM#+1Dj~zM$wtO z&4>c7wzM(Z3%6FZ^e(RF1KxqKfs4w5O3kOGTzb`Xe>KlDa8*1ZjFRrkJY#_t2@wEa z@k-A=MJK|vZX_x-Qunr+9u`YIo^I?i{c71g83qE7We1EiJ#YEzu>wD2%Vvn{y8U#M zqjc6}L{q8VA>B3c)NxT3o~IyB!rR zyikeF8-U~$QrOxA$c$q`BK>~C1AJO$DzGHM8(Z`m*0uuaEX5qPc?RhXY2cX|+SLfa z>m|cOWDca`6Lvbiyj#iTp6a-3Zj1XcD$>3b16P(84-a-)lv9NU*?1U#nL)NisY3V*T1U#k@AFJ3Y$NZ%~+r3cr)-T9o$7~?Lw=4B{4>R%CR zF}#*Yt$Yhrts*MNC32Hn%=NYj>C;|_@7#O$u^N4Ks4CajYC=Hz82%B2;}qQUi@?tZ zmPs4;!UKET2Di8A@-vrRDw)q$3N?BZksg+vEa z=B@D-&jAhhHj`(5%NB}|6l(1BVq)@z8Pjj5R2AZ{!D zb?YUHcuUTwktvf$NLicI*bZZxD{g73LBdm{W+mtOhJX#eGg_jg9JUVI=ovRr@~=^R zA@+p=J*A?SC%3l1)ovX4|Z0?3zctRZq0Bu0w)-n9Gq_#N*Oj>>fx;t3X2Uh6#Zs zqG3>SM5@sqfJRck;$7^nD`L0)_UzCskE|>!51lszX?8GqKzz1n8z5g^Z6IY?uUCRw zjl3?sh&RykFmS<_opKY2{wc_cSK6{IeLXMLu*5tjT0W7w^$*1`c|>QQkq?JO2usji zO3bTJxY8D_WG8#JmWjh%y+_k>Qi5ff3JXWz+*LLc_0|n%xMAxP-?BP^? z6GY#m%MZTtDtFoxf8_)i`lR==vyR_)kr>b+2hn|kZpJYMg_W_N#Saqmc1$?2(m?oCkxL!GwBs(RL#L=+7op}c9~L@hh8 zMJms7h{E3Y%9g@`*>e&w91>T9@VoDfHX_2oOkdacWyp@vMjd9SQOv6K4$0z}-GXUZ zgXYOR1cdcOFZQbL?pz9lC5%MHS1LB~z^zp-n?GnkeBEfQZ?fus|yq8QE2K5fk8bUjjLn$R9&;m=h|##$Fd1N zRRkM4*XMN*T@8%&eSyG09hgf4h3ZS0fePQT(-p)rR==Tt-vxbN1f`o*`7uk}sjQi_ z^HGNkb0zFaZNmRVbc#F0k>l46XRGgnctmg@$z+FuT7=c|(eo{tN=_b$Qq#uTP4p0D zk_(oWWROzJv;V15LOx>%Wz=hNti_iQL4DhfZ#rs{HwiJ#UnG!%T)FG%pc?cM&MfCjkwInO@obU>*7U zY>O8r--p1Q+*-78lO#^0vhs8TLk3Y@L1fuSPgLx!dT&^W`TAAw?7Aw7eD{U+nH zs36mAwQrd4%Npi^wXhO2pAZaxA6r|n>vpy#L`MgMlzfs%@G|!ln0ecTtze14ttT~X zXmtre2hq;OMhA>yul$Bf<-`yk{@`Ws{6ZYWCi#+>qImgCwIaqoOt8rKSb3P;kl(f0x+K?8B+o9}{GKj0n*{em}Zn>b0l39@pA94lgFVlSWtz8iV*xWbHqK%lIO7$(z(ipqaB&SX+)FS= zW-Q}&;|9)g*n2ga(XFS0b2l~Zv5`(>u^pR0{Q}Uf$=ieC zz6k!UKU$J*{;ilowc9=eGHMWlRGqvF))_BD!DaYPjBK|rjsos-ufpqPaGNn{L2d7d zrW}oW9O>$&Nt4aFs!@g;YQ~`d&yW@#HT7K6K(jL5Qht*^id~M5yX3Rz5ce7yckfzx ziw@$KDts>*kms^mn;rtl@jf`#(A_$aURoYmBwBU%2rd+sUv<->YaO{}9xv%dM68Z! z>-UNGf7S0JhswBadQFdrgQS=RgD^vi;nX|MA-K;2wOL0zocf}xWeM$Lq`?Yl4-RX7 zShtCaMGWJE-}*qGmHymy%<(Y=a=n2xe0mRwX|*qS_>uLkTmm`ZFe79xWxF226j9dL z888y7x?-uHd#}~r{|(+irFt3_i{c!*8( zn&uIHE$Ai^tFQfu%o&qO7vK0z>k@mp>moaBAIUPf= z3|hUML`S(GbP1UHxK`d)sHPIWs${F$ZW_+oie6gCdcwWmZ?({G&rDb(p&{b5%QFyY zX10(pzfiqAELf$gT99Oyq?<{RB_RazI4%Kuhq(e^2R zOuzH13m>|pKL8m`e~UGAYkbNtEQrhNObE0TLfLS`?*K;0`sFig7_PD4e)KA850UFI zkOcBWNuLep#vypHaDOttN>e=xH8BiSbkGGvQvkOK#}(-gVN zq=CE9abW^^47Q{~$s5<4R^8yL#>k`K9Q~Yn8h|N`ig_g`7O@L@bOS ze*He79`rbS=h^`sn=dho z#8%R;t~G-Mc3WEdR)9RYwdojhBZFwa0lWD&3B7R|#QqF3<00ubnvTrUG|!@6B!*}l zL1Ce`p|)vF2(s#Fq!#0ws7$@VyeD;GhGBDkx+$-c8*Mce73F(#;M00=36f2WzsQz8 zfHV7BhWCZq&B|SuN#eru_5)a9UG=$jNZqdl%d7IaX7WCUvryZkev)nji!WmuWDMzW zH9$>7 zj_K)q6}w&Ez#_av_>@EIvCdmYCC7LNEV#0xY!4uvZVlZ~9r^5|a~bxbtC^YmM~wSyU0v}Eu3|n-1qF8Etk&@dB&YqYd+WOyG@fFp zjE2ij<0f$c90d+$z+Fm24^Pq2F&;~ivKy=D3-qwh^o;p+^=EZBqmhUp-)-`SW1|=Z zSV#eXJ_IOoO1?qSY8}y@7^%>_0LFe=9^1mTuU_hsZj_%Z;S+tZP&xL9iGt&nNLU=h z85#hkM-2*}T4DjH0*9P$EK?xTz-Z-HR|yIiJd+UhyY$M26IKf=>Ky{WVWkT{>DS*!TABHlUi&eNt8Y?*M*XCNRtbX@R^1>Af5 zS?^6<3b{?nxfGPa!Q>0C1Ba$vZiPr5ejICBL!D}YJVOh;yP64`75(*{;jSNw3XGM5 z)%OvLyjQ0}G1YigCbzp0u`C-!Jh`PpM@ivgKa)<@3Zv2Q+$I)8OEaO ztvZ0U;V^|UnjhpVA%QBgST$^{JlI}!>ucKr5+?UF1z5>l<~JuO^(+xwvFcxz4BFF~ z2cv&M^AZ$GG>Glu&p19nT{t`M2&4$%IVIkB|0K)9Uh_h=>XQX;N%ucX1YwM0*RSG^ zqM)!Ngv{3EY-fpeY#`UoEP}e99q8l7(Iz~jO%8}%9AviHJ)H=Lz6{}6Y$V)wq`k#l zkYRfod%selw4;BK&ZOsU*dqixaDhvpK)T+(C0Kwrn4*7uwT&T5N(Usnym%~$=%{-x zkHvBfvE1R<4Y-j!V+1y2<5WoYx^Qq?b3s86Z)CsV{{e;PFTC#*U7~j zBJb!O9yVT&Nyw5X>m?rV!I6pxbnvzLdM*WS`rE>WS30_Q2WoIdcB-Hox>g%xP)h&A zCvLHtAPC}7%&o}?w$%2W-PJM72}P6WP|>Q=CLk5Q{g0UOitC_g=WKJv2+%-bo!8S2 z|D65@#J`@e>i6_|xt>mrnyh_A4}mD+@87ZohpDePM81xCE=QTS=9|dyI|O98ICmeT z<5Il5KupYd)W`FNu}L#$nn5hMXV>v?W~L{KHL#+3u33UxCk1j1q55rvurFB~8pj@IM1T zpb}69C=MnD2O%0N6$T1Ako_Minvgn>E!CBj4$2o61L-UqLUbU_YqAcVP7b)fKTY^v RQN&L>DX}M1G(cqDe*m!Z4OLQW;Rtal~*bu^s5~4&%aFwunh`xyxPXy6}Rf8Zx^o`!* zMu}dc1d*uGqAm8Bxo_^B_v^hMXU=!NQ)bS5b7l^L0L=vf!3YA>iVh-8yh%J@2GRqw z2~d3+0`%rNjYSZE(f^eK2GJ0J{^zvMxp~k*|I@|92n1z^pCQ622*cqgbrfFM@6SA5y9$$D)cr_KA9)2YZNP{4B3Ysazzeq#4S)?!Y`q7^z>Ry<`hqSTmjWxe^>)L2OpOE{9wkMLgQT|3`(wQSd~MWRp0sDSEJrEc`Ky0D(ukCO6L3 zz(AvOw#5|XbqaYh!RPp}yRsub;p1ykr1+|tGR9IOGRrJNCWy?yv-Tx}=-qaP?+YI2 z)#+H!u#ed&i_-}+cfgo|0K!LjG%xyhF;g%cGyruRC|ZW(h=;^xC(#lwNVbm}_~A3G zi^4b(IzyqkK60xVs(#Me%}L@yzI<_RSU~Cf&yh#1q{H{?*LGg*>n!igaqVRHZH=6g<7=f*R zv6S&L%wV5RJ`;7j?d%={OOd$pbF9RW?+}}7gn4x}8)}#>dF7L$vFrKmRRGDF;B}8d z3;?0!-9LPp!BP<|yQSR#t#x`8xyjw%vi;#>_0JzD^rYNW`Fh4{>qyV{_xucbizaK^ z9m(;(E4gOtX*8$ley6+4Y_ga(voXho^UT6`sk4KA3u-5yDp|fiEr8}?8pPb}UwQW{ zG^EX47T3cjwfond9ltCx7e6s@O&6+e32Uv9$%}rlV!^sCxj3)`HXYg;No5F)C9v}lh?%XtZ(*@=-%iA)p+Y(i9Br@LM=i-dI9bDUQ;ljpLYpF8z7#SG+RxL#` z$Bj?wr18F9Y*xI0d}ChhYirAwv`XvYGZuF1~LlQ zu)iBywd~772XeiAS$yKAOh%g9E@3V^BvM3&sPIq`gMipY6e)2cjO72ou?tWi_eExcEIRr{ef(A(Z$r*tTl*>N zSE$c9CH57`gJq%@Y(ANz1fpwkPNFhzPz3sk^jh&FVKn}9MB04lxH3g&klltnpX#~% zhb?gTc((pH&T#zdE-iF>0`flN#o2|oS)LnvTspqr)0fpNlXgJc2T|?OZ z=rJz{aL^dZB#xP1SKM}Np`>ZVezmfVD<}s>=y%~Ov06`}(3{KgBC%ojy6mGG3nU&$ zqYJ$kH1LG+?#040wFGN@tJh|%p}n(SQ`hevTTq`Y2gu+G#%Tq?YgG(b{it`l{Dw*l zvi@^6Y?sWUtW_syViMk{_C(+sJN6Lr*IByd+)v`PlrizIh+%a07`8B;YQceeS%q)w zsk$>Pp~X{Qqz=WYcldpl@}^(gM9e-OR(vQ`m~Rd0{(VbpBeRT%(@Oje3(mMa{8yB$(}X$ zh{(L8f)Otlgkgc0S_H~8Eoc#pT67#4;*;v{WwVjZ_1q~BKs%2O!?qc-_QO(<9b-@? z0?_y+yoX8CC?~2=-Yvga50FUlFYiKJidLIU-SIG~(5sguaJFlE4N^IJ+`k2mt_b=S z<;&~{D?Xm_W^kW=yaZIG`kNv%ps>QC{%dFZ-WK%I*`6nwr1|bOy^X;mGhqia8@o07 zF=9hP9La-RqU-T>FxI-nMROPt(*wdp+~6>@lV8X_Q%LA6&^X3%i7lE1v@_ILo>e>} z{G6*?g9$v6PwXhFr(!cJ^K@x zH@hOt^cDA~n};9N&8M?2q)r(e$l4x?rmh@El19M27sqnYWNGPlp7>Z=~l z^Bp!Gb*g_uzRe{TD{a(rO{FiwfH^NF?>lipBS@YJ3iOtCe!jx*{O;HYEaOGYcsBJk zR9lUutQ9JM^y%Z4M5Od&RGC?Q5k9i4-^dLC|t^ik}z z*^6ov2kUzE2Hto4Q`gh?e>tBXMTpEpS~b$3LflOUVc-n zJUmxjl;Ii9f2KKWuhfRk!|OC#aqwOhpP#)93EmQ`roF9wA|^U|J%8~djQ9fR@Nmz6 z$bINQlV1Uc;>K+ULA*~EJ_G9`CD5*P-_&JC}WtdF)KU&1GIq@q1K zhd4|?!w#5^kOz~`xGKY&-mIPkBO|phML|c`uW9yFNZ(O{u}|%4TbTZkGb{zn(9RoV zvJ8EVvAb_qX$ggBmV5&IM+eidkJq|PX1U*J^7=F z#eC_@BRJe7IWr9Y-R;?w*bO8gccyU?boT@iPLFtFj=i&*1KUi8{adkDv3`fKE;qPjjA z4+TFF7H_^Kf>)31UGn%Lm3fN3@UPuHA#Z?|4z_5d`6-vw)Fw{?K6hB$HcGDhX?BiD z!s$0^mBga=MNOqr?3?SnPp2i)O60WsOU7%v7vh|M!Pmt~2`vSn-hs01;bBfJO@5a; zqtP3^;khCc{@m{+Cip^r8rwqzWkoG})ICwMhQ~_1=J*am9U+W>(9z1UfI+;pfb$nv y*%f9#Wra&pUMfg^)SGG_*Q`dv>E$LWs-LtH9M}nF;19F-jF|W;4*~;;+5ZNgC0;TB literal 0 HcmV?d00001 diff --git a/application/src/test/resources/lwm2m/credentials/serverKeyStore.jks b/application/src/test/resources/lwm2m/credentials/serverKeyStore.jks deleted file mode 100644 index fc541a3b18111312545da774be682ddb893d72c2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3806 zcmezO_TO6u1_mY|W&_iFnRz9tMY*XdnTaK-$%zaMjFr!(OnJ+|8lh)uUJkHs&Ff*|-7)Tn58;G(ohq5pW^ZBF}XC&q+6y@ia zC^$PBD2VeK85)=wm>U`cNz*6^ej`JmfT^JgRKP&dP~JcmqFD^88QDo7Lm~}?+1SDM zF)>0dW@cn(c4A;T@VS|9lH1dLZ_jKt-`U6Fea+QH`BYo9IL#mhY`ZKUix`Ut^Mt&kdKuN{mQQtB zUi5*fk(H(TpaCDyakBi3jQ?4HzGY-H5CZXqL3|DaHXy~s$Y3B35>sZ8Fc51H(VZk$ zxqXJN`J@Z|H3z%zhgCAvhN1=-vnPXr8zz+tX`Lo>Xmwt;`4ciQ-RUJ$iP{g zT2z)=1Wd({+%)YhP`KWp7MPN_wAmP07`2!L85vm_Sh9C4soL}0b=E$Mg=v$soQ%&E ze-UkGh(7!8*z23GK6Ux3JW7}-CdGRxUb*$s#*H}>yS#3hWc=9SwbZeCr>?;9ccr&_ zYgxQJ(!V{(HT$V`QR>5%H$^P@+qt&id0fzvyI|3@t`COBEccC7VLd&rY7L^CxjgF5%vL_s_{?G7bKy zS)IAVKm?R*1X*|uxSKe0@{<#DGV+T{3^>7wiG|4kHQ!?`JcL1NRatlpxY#&=anH)i z&di7!(9G@(1};nrn!6{v?BTePd(kMjNR;uU^|$ugrFS$Q9umsi${YQ5&H^TdsFeM= z90yik-kWEXGgr=O`{J&$y|KM7LUoxI7hXH8CBN4cMod%AvKSoW?FOfOlv-vGHtp+D%Gs zJc(4Dp!3?mQ2w@XY2U+&4qJBf-UtR0M-HvV>(w&A3ge>joNbbJ!JgUYuAZ6QqPAQv zQ)->$ngpAsU+XTp#rL^@s{=MjR72u+>TO(gfe)|D(-6Qb2h|ya67LSJ{;U~ z=j!t7JN^Y!?~YK;neEaj@$>WA(44J%&My4R*S)D{)LMO8UGTuGsl5-*N3oSb>J z)Lvu@%h8K!V%cK1e3=wtzAp%{I$kwDp0DD0XHV~}Lt>(a&rX)h7S2h_+IP<}98nI8 zw&b9#Z#uT*m>7g0Sr@a2o|KM=nlfPCDFR|qSR>n^QvogiV9x@mC9xTLNo*EnfL$LA zvreFaKLuHbh@1iK`FxVtS7y-vtNrrlO-x^(POD+NzGweDCVTEHScmMzZ From 4450df292f73ce0b58ac52b95bd7a1366f47cbea Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Sat, 8 Jan 2022 18:24:10 +0200 Subject: [PATCH 349/432] lwm2m tests aad logs with NoSec, PSK, X509-trust. RPK, X509_NoTrust - ignore --- .../server/transport/lwm2m/AbstractLwM2MIntegrationTest.java | 3 +++ .../lwm2m/security/AbstractSecurityLwM2MIntegrationTest.java | 1 + .../transport/lwm2m/security/sql/PskLwm2mIntegrationTest.java | 4 ++-- application/src/test/resources/application-test.properties | 2 +- application/src/test/resources/logback.xml | 1 + 5 files changed, 8 insertions(+), 3 deletions(-) diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/AbstractLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/AbstractLwM2MIntegrationTest.java index 5d4c32641d..13e0858199 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/AbstractLwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/AbstractLwM2MIntegrationTest.java @@ -16,6 +16,7 @@ package org.thingsboard.server.transport.lwm2m; import com.fasterxml.jackson.core.type.TypeReference; +import lombok.extern.slf4j.Slf4j; import org.apache.commons.io.IOUtils; import org.eclipse.californium.core.network.config.NetworkConfig; import org.eclipse.leshan.client.object.Security; @@ -66,6 +67,7 @@ import java.util.concurrent.ScheduledExecutorService; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +@Slf4j @DaoSqlTest public abstract class AbstractLwM2MIntegrationTest extends AbstractWebsocketTest { @@ -199,6 +201,7 @@ public abstract class AbstractLwM2MIntegrationTest extends AbstractWebsocketTest createNewClient(security, coapConfig, false); String msg = wsClient.waitForUpdate(); + log.info("msg5555: [{}]", msg); EntityDataUpdate update = mapper.readValue(msg, EntityDataUpdate.class); Assert.assertEquals(1, update.getCmdId()); List eData = update.getUpdate(); diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/AbstractSecurityLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/AbstractSecurityLwM2MIntegrationTest.java index 0c983f9dcf..d537062def 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/AbstractSecurityLwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/AbstractSecurityLwM2MIntegrationTest.java @@ -68,6 +68,7 @@ public abstract class AbstractSecurityLwM2MIntegrationTest extends AbstractLwM2M // Client protected LwM2MTestClient client; protected static final String CLIENT_ENDPOINT_NO_SEC = "deviceNoSec"; + protected static final String CLIENT_ENDPOINT_PSK = "devicePSK"; protected static final String CLIENT_ENDPOINT_RPK = "deviceRPK"; protected static final String CLIENT_ENDPOINT_NO_TRUST = "deviceAEndpoint"; protected static final String CLIENT_ENDPOINT_TRUST = "LwX50900000000"; diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/PskLwm2mIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/PskLwm2mIntegrationTest.java index 5850e52015..d7296fd47c 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/PskLwm2mIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/PskLwm2mIntegrationTest.java @@ -34,13 +34,13 @@ public class PskLwm2mIntegrationTest extends AbstractSecurityLwM2MIntegrationTes @Test public void testConnectWithPSKAndObserveTelemetry() throws Exception { PSKClientCredential clientCredentials = new PSKClientCredential(); - clientCredentials.setEndpoint(CLIENT_ENDPOINT_NO_TRUST); + clientCredentials.setEndpoint(CLIENT_ENDPOINT_PSK); clientCredentials.setKey(pskKey); clientCredentials.setIdentity(pskIdentity); Security security = psk(SECURE_URI, SHORT_SERVER_ID, pskIdentity.getBytes(StandardCharsets.UTF_8), Hex.decodeHex(pskKey.toCharArray())); - super.basicTestConnectionObserveTelemetry(security, clientCredentials, SECURE_COAP_CONFIG, CLIENT_ENDPOINT_NO_TRUST); + super.basicTestConnectionObserveTelemetry(security, clientCredentials, SECURE_COAP_CONFIG, CLIENT_ENDPOINT_PSK); } } diff --git a/application/src/test/resources/application-test.properties b/application/src/test/resources/application-test.properties index dd1cd2807c..7f7cb6e8b9 100644 --- a/application/src/test/resources/application-test.properties +++ b/application/src/test/resources/application-test.properties @@ -4,7 +4,7 @@ transport.lwm2m.server.security.credentials.keystore.store_file=lwm2m/credential #transport.lwm2m.server.security.credentials.keystore.store_password=server #transport.lwm2m.server.security.credentials.keystore.key_alias=server #transport.lwm2m.server.security.credentials.keystore.key_password=server -#transport.lwm2m.bootstrap.enabled=false +transport.lwm2m.bootstrap.enabled=false transport.lwm2m.bootstrap.security.credentials.enabled=true transport.lwm2m.bootstrap.security.credentials.type=KEYSTORE transport.lwm2m.bootstrap.security.credentials.keystore.store_file=lwm2m/credentials/lwm2mserver.jks diff --git a/application/src/test/resources/logback.xml b/application/src/test/resources/logback.xml index d3301bf660..91ca9c2b6c 100644 --- a/application/src/test/resources/logback.xml +++ b/application/src/test/resources/logback.xml @@ -10,6 +10,7 @@ + From fe9b61586f3f907289d59a9ecca839965f26c07c Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Sat, 8 Jan 2022 20:11:39 +0200 Subject: [PATCH 350/432] lwm2m tests ignore test del 3/0/9 --- .../sql/RpcLwm2mIntegrationDeleteTest.java | 24 +++++++++---------- application/src/test/resources/logback.xml | 2 +- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationDeleteTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationDeleteTest.java index 6f24d7176c..90a9dd7a62 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationDeleteTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationDeleteTest.java @@ -74,18 +74,18 @@ public class RpcLwm2mIntegrationDeleteTest extends AbstractRpcLwM2MIntegrationTe } - /** - * delete resource - * Delete {"id":"/3/0/9"} - * {"result":"METHOD_NOT_ALLOWED"} - */ - @Test - public void testDeleteResourceByIdKey_Result_METHOD_NOT_ALLOWED() throws Exception { - String expectedPath = objectIdVer_3 + "/" + objectInstanceId_0 + resourceId_9; - String actualResult = sendRPCDeleteById(expectedPath); - ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); - assertEquals(ResponseCode.METHOD_NOT_ALLOWED.getName(), rpcActualResult.get("result").asText()); - } +// /** +// * delete resource +// * Delete {"id":"/3/0/9"} +// * {"result":"METHOD_NOT_ALLOWED"} +// */ +// @Test +// public void testDeleteResourceByIdKey_Result_METHOD_NOT_ALLOWED() throws Exception { +// String expectedPath = objectIdVer_3 + "/" + objectInstanceId_0 + resourceId_9; +// String actualResult = sendRPCDeleteById(expectedPath); +// ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); +// assertEquals(ResponseCode.METHOD_NOT_ALLOWED.getName(), rpcActualResult.get("result").asText()); +// } private String sendRPCDeleteById(String path) throws Exception { diff --git a/application/src/test/resources/logback.xml b/application/src/test/resources/logback.xml index 91ca9c2b6c..4cca303e8f 100644 --- a/application/src/test/resources/logback.xml +++ b/application/src/test/resources/logback.xml @@ -10,7 +10,7 @@ - + From 98331c79a0ccb70a4c8459e8bdc56eb92e50c07a Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Sat, 8 Jan 2022 23:48:24 +0200 Subject: [PATCH 351/432] lwm2m tests add RPK --- .../transport/lwm2m/Lwm2mTestHelper.java | 1 + .../sql/RpcLwm2mIntegrationDeleteTest.java | 25 ++++++++++--------- .../AbstractSecurityLwM2MIntegrationTest.java | 3 --- .../sql/NoSecLwM2MIntegrationTest.java | 4 +-- .../security/sql/PskLwm2mIntegrationTest.java | 4 +-- .../security/sql/RpkLwM2MIntegrationTest.java | 7 +++--- application/src/test/resources/logback.xml | 1 - 7 files changed, 21 insertions(+), 24 deletions(-) diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/Lwm2mTestHelper.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/Lwm2mTestHelper.java index 232332e554..0ea700d46c 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/Lwm2mTestHelper.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/Lwm2mTestHelper.java @@ -55,6 +55,7 @@ public class Lwm2mTestHelper { public static final int resourceId_2 = 2; public static final int resourceId_3 = 3; public static final int resourceId_4 = 4; + public static final int resourceId_7 = 7; public static final int resourceId_8 = 8; public static final int resourceId_9 = 9; public static final int resourceId_11 = 11; diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationDeleteTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationDeleteTest.java index 90a9dd7a62..ebc0f6d783 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationDeleteTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationDeleteTest.java @@ -26,6 +26,7 @@ import static org.junit.Assert.assertTrue; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.objectInstanceId_0; import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.objectInstanceId_12; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_7; import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_9; @@ -74,18 +75,18 @@ public class RpcLwm2mIntegrationDeleteTest extends AbstractRpcLwM2MIntegrationTe } -// /** -// * delete resource -// * Delete {"id":"/3/0/9"} -// * {"result":"METHOD_NOT_ALLOWED"} -// */ -// @Test -// public void testDeleteResourceByIdKey_Result_METHOD_NOT_ALLOWED() throws Exception { -// String expectedPath = objectIdVer_3 + "/" + objectInstanceId_0 + resourceId_9; -// String actualResult = sendRPCDeleteById(expectedPath); -// ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); -// assertEquals(ResponseCode.METHOD_NOT_ALLOWED.getName(), rpcActualResult.get("result").asText()); -// } + /** + * delete resource + * Delete {"id":"/3/0/7"} + * {"result":"METHOD_NOT_ALLOWED"} + */ + @Test + public void testDeleteResourceByIdKey_Result_METHOD_NOT_ALLOWED() throws Exception { + String expectedPath = objectIdVer_3 + "/" + objectInstanceId_0 + resourceId_7; + String actualResult = sendRPCDeleteById(expectedPath); + ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); + assertEquals(ResponseCode.METHOD_NOT_ALLOWED.getName(), rpcActualResult.get("result").asText()); + } private String sendRPCDeleteById(String path) throws Exception { diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/AbstractSecurityLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/AbstractSecurityLwM2MIntegrationTest.java index d537062def..b0fadf1d23 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/AbstractSecurityLwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/AbstractSecurityLwM2MIntegrationTest.java @@ -67,9 +67,6 @@ public abstract class AbstractSecurityLwM2MIntegrationTest extends AbstractLwM2M // Client protected LwM2MTestClient client; - protected static final String CLIENT_ENDPOINT_NO_SEC = "deviceNoSec"; - protected static final String CLIENT_ENDPOINT_PSK = "devicePSK"; - protected static final String CLIENT_ENDPOINT_RPK = "deviceRPK"; protected static final String CLIENT_ENDPOINT_NO_TRUST = "deviceAEndpoint"; protected static final String CLIENT_ENDPOINT_TRUST = "LwX50900000000"; protected static final String CLIENT_JKS_FOR_TEST = "lwm2mclient"; diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/NoSecLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/NoSecLwM2MIntegrationTest.java index 8331b99fff..4daac68f9a 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/NoSecLwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/NoSecLwM2MIntegrationTest.java @@ -29,8 +29,8 @@ public class NoSecLwM2MIntegrationTest extends AbstractSecurityLwM2MIntegrationT @Test public void testConnectAndObserveTelemetry() throws Exception { - NoSecClientCredential clientCredentials = createNoSecClientCredentials(CLIENT_ENDPOINT_NO_SEC); - super.basicTestConnectionObserveTelemetry(SECURITY, clientCredentials, COAP_CONFIG, CLIENT_ENDPOINT_NO_SEC); + NoSecClientCredential clientCredentials = createNoSecClientCredentials(CLIENT_ENDPOINT_TRUST); + super.basicTestConnectionObserveTelemetry(SECURITY, clientCredentials, COAP_CONFIG, CLIENT_ENDPOINT_TRUST); } } diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/PskLwm2mIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/PskLwm2mIntegrationTest.java index d7296fd47c..11b6f3f6e7 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/PskLwm2mIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/PskLwm2mIntegrationTest.java @@ -34,13 +34,13 @@ public class PskLwm2mIntegrationTest extends AbstractSecurityLwM2MIntegrationTes @Test public void testConnectWithPSKAndObserveTelemetry() throws Exception { PSKClientCredential clientCredentials = new PSKClientCredential(); - clientCredentials.setEndpoint(CLIENT_ENDPOINT_PSK); + clientCredentials.setEndpoint(CLIENT_ENDPOINT_TRUST); clientCredentials.setKey(pskKey); clientCredentials.setIdentity(pskIdentity); Security security = psk(SECURE_URI, SHORT_SERVER_ID, pskIdentity.getBytes(StandardCharsets.UTF_8), Hex.decodeHex(pskKey.toCharArray())); - super.basicTestConnectionObserveTelemetry(security, clientCredentials, SECURE_COAP_CONFIG, CLIENT_ENDPOINT_PSK); + super.basicTestConnectionObserveTelemetry(security, clientCredentials, SECURE_COAP_CONFIG, CLIENT_ENDPOINT_TRUST); } } diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/RpkLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/RpkLwM2MIntegrationTest.java index e6c26a05d0..1f73a2a739 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/RpkLwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/RpkLwM2MIntegrationTest.java @@ -30,17 +30,16 @@ import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SHORT_SERVE public class RpkLwM2MIntegrationTest extends AbstractSecurityLwM2MIntegrationTest { - @Ignore @Test public void testConnectWithRPKAndObserveTelemetry() throws Exception { RPKClientCredential rpkClientCredentials = new RPKClientCredential(); - rpkClientCredentials.setEndpoint(CLIENT_ENDPOINT_RPK); - rpkClientCredentials.setKey(new String(Base64.encodeBase64(clientPrivateKeyFromCert.getEncoded()))); + rpkClientCredentials.setEndpoint(CLIENT_ENDPOINT_TRUST); + rpkClientCredentials.setKey(new String(Base64.encodeBase64(clientPublicKeyFromCert.getEncoded()))); Security security = rpk(SECURE_URI, SHORT_SERVER_ID, clientPublicKeyFromCert.getEncoded(), clientPrivateKeyFromCert.getEncoded(), serverPublicKeyFromCert.getEncoded()); - super.basicTestConnectionObserveTelemetry(security, rpkClientCredentials, SECURE_COAP_CONFIG, CLIENT_ENDPOINT_RPK); + super.basicTestConnectionObserveTelemetry(security, rpkClientCredentials, SECURE_COAP_CONFIG, CLIENT_ENDPOINT_TRUST); } } diff --git a/application/src/test/resources/logback.xml b/application/src/test/resources/logback.xml index 4cca303e8f..d3301bf660 100644 --- a/application/src/test/resources/logback.xml +++ b/application/src/test/resources/logback.xml @@ -10,7 +10,6 @@ - From c981ff4c55016e4a8c153ed4121236c381dfa26c Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Sun, 9 Jan 2022 15:22:43 +0200 Subject: [PATCH 352/432] lwm2m tests add no trust --- .../controller/TbTestWebSocketClient.java | 2 +- .../lwm2m/AbstractLwM2MIntegrationTest.java | 16 +-- .../ota/AbstractOtaLwM2MIntegrationTest.java | 3 + .../ota/sql/OtaLwM2MIntegrationTest.java | 24 ++-- .../rpc/AbstractRpcLwM2MIntegrationTest.java | 6 +- .../AbstractSecurityLwM2MIntegrationTest.java | 38 +++--- .../sql/NoSecLwM2MIntegrationTest.java | 4 +- .../security/sql/PskLwm2mIntegrationTest.java | 4 +- .../security/sql/RpkLwM2MIntegrationTest.java | 10 +- .../sql/X509_NoTrustLwM2MIntegrationTest.java | 21 +-- .../sql/X509_TrustLwM2MIntegrationTest.java | 8 +- application/src/test/resources/logback.xml | 1 + .../lwm2m/credentials/lwm2mclient.jks | Bin 17660 -> 20462 bytes .../lwm2m/credentials/lwm2mserver.jks | Bin 6432 -> 6448 bytes .../credentials/lwm2mtruststorechain.jks | Bin 2982 -> 2982 bytes ... => lwM2M_cfssl_chain_clients_for_test.sh} | 120 +++++++++++++++++- ...l.sh => lwm2m_cfssl_chain_all_for_test.sh} | 10 +- 17 files changed, 194 insertions(+), 73 deletions(-) rename application/src/test/resources/lwm2m/credentials/shell/{lwM2M_cfssl_chain_trusts_and_clients_for_test.sh => lwM2M_cfssl_chain_clients_for_test.sh} (63%) rename application/src/test/resources/lwm2m/credentials/shell/{lwm2m_cfssl_chain_for_test_All.sh => lwm2m_cfssl_chain_all_for_test.sh} (78%) diff --git a/application/src/test/java/org/thingsboard/server/controller/TbTestWebSocketClient.java b/application/src/test/java/org/thingsboard/server/controller/TbTestWebSocketClient.java index ff6b004405..2bb68737ac 100644 --- a/application/src/test/java/org/thingsboard/server/controller/TbTestWebSocketClient.java +++ b/application/src/test/java/org/thingsboard/server/controller/TbTestWebSocketClient.java @@ -74,7 +74,7 @@ public class TbTestWebSocketClient extends WebSocketClient { } public String waitForUpdate() { - return waitForUpdate(TimeUnit.SECONDS.toMillis(3)); + return waitForUpdate(TimeUnit.SECONDS.toMillis(8)); } public String waitForUpdate(long ms) { diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/AbstractLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/AbstractLwM2MIntegrationTest.java index 13e0858199..0a95dfdbc9 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/AbstractLwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/AbstractLwM2MIntegrationTest.java @@ -135,7 +135,7 @@ public abstract class AbstractLwM2MIntegrationTest extends AbstractWebsocketTest protected LwM2MTestClient client; private final LwM2MBootstrapClientCredentials defaultBootstrapCredentials; private String[] resources; - protected String endpoint; +// protected String endpoint; public AbstractLwM2MIntegrationTest() { this.defaultBootstrapCredentials = new LwM2MBootstrapClientCredentials(); @@ -197,8 +197,8 @@ public abstract class AbstractLwM2MIntegrationTest extends AbstractWebsocketTest wsClient.waitForReply(); wsClient.registerWaitForUpdate(); - this.endpoint = endpoint; - createNewClient(security, coapConfig, false); +// this.endpoint = endpoint; + createNewClient(security, coapConfig, false, endpoint); String msg = wsClient.waitForUpdate(); log.info("msg5555: [{}]", msg); @@ -264,13 +264,13 @@ public abstract class AbstractLwM2MIntegrationTest extends AbstractWebsocketTest this.resources = resources; } - public void setEndpoint(String endpoint) { - this.endpoint = endpoint; - } +// public void setEndpoint(String endpoint) { +// this.endpoint = endpoint; +// } - public void createNewClient(Security security, NetworkConfig coapConfig, boolean isRpc) throws Exception { + public void createNewClient(Security security, NetworkConfig coapConfig, boolean isRpc, String endpoint) throws Exception { clientDestroy(); - client = new LwM2MTestClient(this.executor, this.endpoint); + client = new LwM2MTestClient(this.executor, endpoint); int clientPort = SocketUtils.findAvailableTcpPort(); client.init(security, coapConfig, clientPort, isRpc); } diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/ota/AbstractOtaLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/ota/AbstractOtaLwM2MIntegrationTest.java index e78d74bdcd..6cf35aeb94 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/ota/AbstractOtaLwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/ota/AbstractOtaLwM2MIntegrationTest.java @@ -30,6 +30,9 @@ import static org.thingsboard.server.common.data.ota.OtaPackageType.SOFTWARE; public abstract class AbstractOtaLwM2MIntegrationTest extends AbstractLwM2MIntegrationTest { private final String[] resources = new String[]{"3.xml", "5.xml", "9.xml"}; + protected static final String CLIENT_ENDPOINT_WITHOUT_FW_INFO = "WithoutFirmwareInfoDevice"; + protected static final String CLIENT_ENDPOINT_OTA5 = "Ota5_Device"; + protected static final String CLIENT_ENDPOINT_OTA9 = "Ota9_Device"; public AbstractOtaLwM2MIntegrationTest() { setResources(this.resources); diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/ota/sql/OtaLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/ota/sql/OtaLwM2MIntegrationTest.java index 903750663a..95a0a774a2 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/ota/sql/OtaLwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/ota/sql/OtaLwM2MIntegrationTest.java @@ -138,12 +138,12 @@ public class OtaLwM2MIntegrationTest extends AbstractOtaLwM2MIntegrationTest { @Test public void testFirmwareUpdateWithClientWithoutFirmwareOtaInfoFromProfile() throws Exception { - String endpoint = "WithoutFirmwareInfoDevice"; - setEndpoint(endpoint); +// String endpoint = "WithoutFirmwareInfoDevice"; +// setEndpoint(endpoint); createDeviceProfile(transportConfiguration); - NoSecClientCredential credentials = createNoSecClientCredentials(endpoint); + NoSecClientCredential credentials = createNoSecClientCredentials(this.CLIENT_ENDPOINT_WITHOUT_FW_INFO); final Device device = createDevice(credentials); - createNewClient(SECURITY, COAP_CONFIG, false); + createNewClient(SECURITY, COAP_CONFIG, false, this.CLIENT_ENDPOINT_WITHOUT_FW_INFO); Thread.sleep(1000); @@ -165,12 +165,12 @@ public class OtaLwM2MIntegrationTest extends AbstractOtaLwM2MIntegrationTest { @Test public void testFirmwareUpdateByObject5() throws Exception { - String endpoint = "Ota5_Device"; - setEndpoint(endpoint); +// String endpoint = "Ota5_Device"; +// setEndpoint(endpoint); createDeviceProfile(OTA_TRANSPORT_CONFIGURATION); - NoSecClientCredential credentials = createNoSecClientCredentials(endpoint); + NoSecClientCredential credentials = createNoSecClientCredentials(this.CLIENT_ENDPOINT_OTA5); final Device device = createDevice(credentials); - createNewClient(SECURITY, COAP_CONFIG, false); + createNewClient(SECURITY, COAP_CONFIG, false, this.CLIENT_ENDPOINT_OTA5); Thread.sleep(1000); @@ -204,12 +204,12 @@ public class OtaLwM2MIntegrationTest extends AbstractOtaLwM2MIntegrationTest { * */ @Test public void testSoftwareUpdateByObject9() throws Exception { - String endpoint = "Ota9_Device"; - setEndpoint(endpoint); +// String endpoint = "Ota9_Device"; +// setEndpoint(endpoint); createDeviceProfile(OTA_TRANSPORT_CONFIGURATION); - NoSecClientCredential credentials = createNoSecClientCredentials(endpoint); + NoSecClientCredential credentials = createNoSecClientCredentials(this.CLIENT_ENDPOINT_OTA9); final Device device = createDevice(credentials); - createNewClient(SECURITY, COAP_CONFIG, false); + createNewClient(SECURITY, COAP_CONFIG, false, this.CLIENT_ENDPOINT_OTA9); Thread.sleep(1000); diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/AbstractRpcLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/AbstractRpcLwM2MIntegrationTest.java index 95878b74d1..2310fe1659 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/AbstractRpcLwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/AbstractRpcLwM2MIntegrationTest.java @@ -73,6 +73,7 @@ public abstract class AbstractRpcLwM2MIntegrationTest extends AbstractLwM2MInteg protected String objectIdVer_50 = "/50"; protected String objectIdVer_3303; protected static AtomicInteger endpointSequence = new AtomicInteger(); + protected static String endpointRpcPref = "deviceEndpointRpc"; public AbstractRpcLwM2MIntegrationTest(){ setResources(resources); @@ -80,9 +81,10 @@ public abstract class AbstractRpcLwM2MIntegrationTest extends AbstractLwM2MInteg @Before public void beforeTest() throws Exception { - setEndpoint("deviceEndpointRpc" + endpointSequence.incrementAndGet()); + String endpoint = endpointRpcPref + endpointSequence.incrementAndGet(); +// setEndpoint(endpoint); init(); - createNewClient (SECURITY, COAP_CONFIG, true); + createNewClient (SECURITY, COAP_CONFIG, true, endpoint); expectedObjects = ConcurrentHashMap.newKeySet(); expectedObjectIdVers = ConcurrentHashMap.newKeySet(); diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/AbstractSecurityLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/AbstractSecurityLwM2MIntegrationTest.java index b0fadf1d23..c10eb46620 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/AbstractSecurityLwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/AbstractSecurityLwM2MIntegrationTest.java @@ -27,7 +27,6 @@ import java.security.GeneralSecurityException; import java.security.KeyStore; import java.security.PrivateKey; import java.security.PublicKey; -import java.security.cert.Certificate; import java.security.cert.X509Certificate; @DaoSqlTest @@ -67,16 +66,22 @@ public abstract class AbstractSecurityLwM2MIntegrationTest extends AbstractLwM2M // Client protected LwM2MTestClient client; - protected static final String CLIENT_ENDPOINT_NO_TRUST = "deviceAEndpoint"; - protected static final String CLIENT_ENDPOINT_TRUST = "LwX50900000000"; + protected static final String CLIENT_ENDPOINT_NO_SEC = "LwNoSec00000000"; + protected static final String CLIENT_ENDPOINT_PSK = "LwPsk00000000"; + protected static final String CLIENT_ENDPOINT_RPK = "LwRpk00000000"; + protected static final String CLIENT_ENDPOINT_X509_TRUST = "LwX50900000000"; + protected static final String CLIENT_ENDPOINT_X509_TRUST_NO = "LwX509TrustNo"; protected static final String CLIENT_JKS_FOR_TEST = "lwm2mclient"; protected static final String CLIENT_STORE_PWD = "client_ks_password"; - - protected static final String CLIENT_CERT_ALIAS = "client_alias_00000000"; - - protected final X509Certificate clientX509Cert; // client certificate signed by intermediate, rootCA with a good CN ("host name") - protected final PrivateKey clientPrivateKeyFromCert; // client private key used for X509 and RPK - protected final PublicKey clientPublicKeyFromCert; // client public key used for RPK + protected static final String CLIENT_ALIAS_CERT_TRUST = "client_alias_00000000"; + protected static final String CLIENT_ALIAS_CERT_TRUST_NO = "client_alias_trust_no"; + + protected final X509Certificate clientX509CertTrust; // client certificate signed by intermediate, rootCA with a good CN ("host name") + protected final PrivateKey clientPrivateKeyFromCertTrust; // client private key used for X509 and RPK + protected final PublicKey clientPublicKeyFromCertTrust; // client public key used for RPK + protected final X509Certificate clientX509CertTrustNo; // client certificate signed by intermediate, rootCA with a good CN ("host name") + protected final PrivateKey clientPrivateKeyFromCertTrustNo; // client private key used for X509 and RPK + protected final PublicKey clientPublicKeyFromCertTrustNo; // client public key used for RPK private final String[] resources = new String[]{"1.xml", "2.xml", "3.xml", "5.xml", "9.xml"}; @@ -87,7 +92,7 @@ public abstract class AbstractSecurityLwM2MIntegrationTest extends AbstractLwM2M public AbstractSecurityLwM2MIntegrationTest() { // create client credentials setResources(this.resources); - setEndpoint(CLIENT_ENDPOINT_NO_TRUST); +// setEndpoint(CLIENT_ENDPOINT_NO_TRUST); try { // Get keys PSK this.pskIdentity = "SOME_PSK_ID"; @@ -122,13 +127,14 @@ public abstract class AbstractSecurityLwM2MIntegrationTest extends AbstractLwM2M clientKeyStore.load(clientKeyStoreFile, clientKeyStorePwd); } - clientPrivateKeyFromCert = (PrivateKey) clientKeyStore.getKey(CLIENT_CERT_ALIAS, clientKeyStorePwd); - clientX509Cert = (X509Certificate) clientKeyStore.getCertificate(CLIENT_CERT_ALIAS); - clientPublicKeyFromCert = clientX509Cert.getPublicKey(); + clientPrivateKeyFromCertTrust = (PrivateKey) clientKeyStore.getKey(CLIENT_ALIAS_CERT_TRUST, clientKeyStorePwd); + clientX509CertTrust = (X509Certificate) clientKeyStore.getCertificate(CLIENT_ALIAS_CERT_TRUST); + clientPublicKeyFromCertTrust = clientX509CertTrust != null ? clientX509CertTrust.getPublicKey() : null; + + clientPrivateKeyFromCertTrustNo = (PrivateKey) clientKeyStore.getKey(CLIENT_ALIAS_CERT_TRUST_NO, clientKeyStorePwd); + clientX509CertTrustNo = (X509Certificate) clientKeyStore.getCertificate(CLIENT_ALIAS_CERT_TRUST_NO); + clientPublicKeyFromCertTrustNo = clientX509CertTrustNo != null ? clientX509CertTrustNo.getPublicKey() : null; -// clientX509CertWithBadCN = (X509Certificate) clientKeyStore.getCertificate("client_bad_cn"); -// clientX509CertSelfSigned = (X509Certificate) clientKeyStore.getCertificate("client_self_signed"); -// clientX509CertNotTrusted = (X509Certificate) clientKeyStore.getCertificate("client_not_trusted"); } catch (GeneralSecurityException | IOException e) { throw new RuntimeException(e); } diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/NoSecLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/NoSecLwM2MIntegrationTest.java index 4daac68f9a..8331b99fff 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/NoSecLwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/NoSecLwM2MIntegrationTest.java @@ -29,8 +29,8 @@ public class NoSecLwM2MIntegrationTest extends AbstractSecurityLwM2MIntegrationT @Test public void testConnectAndObserveTelemetry() throws Exception { - NoSecClientCredential clientCredentials = createNoSecClientCredentials(CLIENT_ENDPOINT_TRUST); - super.basicTestConnectionObserveTelemetry(SECURITY, clientCredentials, COAP_CONFIG, CLIENT_ENDPOINT_TRUST); + NoSecClientCredential clientCredentials = createNoSecClientCredentials(CLIENT_ENDPOINT_NO_SEC); + super.basicTestConnectionObserveTelemetry(SECURITY, clientCredentials, COAP_CONFIG, CLIENT_ENDPOINT_NO_SEC); } } diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/PskLwm2mIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/PskLwm2mIntegrationTest.java index 11b6f3f6e7..d7296fd47c 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/PskLwm2mIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/PskLwm2mIntegrationTest.java @@ -34,13 +34,13 @@ public class PskLwm2mIntegrationTest extends AbstractSecurityLwM2MIntegrationTes @Test public void testConnectWithPSKAndObserveTelemetry() throws Exception { PSKClientCredential clientCredentials = new PSKClientCredential(); - clientCredentials.setEndpoint(CLIENT_ENDPOINT_TRUST); + clientCredentials.setEndpoint(CLIENT_ENDPOINT_PSK); clientCredentials.setKey(pskKey); clientCredentials.setIdentity(pskIdentity); Security security = psk(SECURE_URI, SHORT_SERVER_ID, pskIdentity.getBytes(StandardCharsets.UTF_8), Hex.decodeHex(pskKey.toCharArray())); - super.basicTestConnectionObserveTelemetry(security, clientCredentials, SECURE_COAP_CONFIG, CLIENT_ENDPOINT_TRUST); + super.basicTestConnectionObserveTelemetry(security, clientCredentials, SECURE_COAP_CONFIG, CLIENT_ENDPOINT_PSK); } } diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/RpkLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/RpkLwM2MIntegrationTest.java index 1f73a2a739..0066014a9b 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/RpkLwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/RpkLwM2MIntegrationTest.java @@ -33,13 +33,13 @@ public class RpkLwM2MIntegrationTest extends AbstractSecurityLwM2MIntegrationTes @Test public void testConnectWithRPKAndObserveTelemetry() throws Exception { RPKClientCredential rpkClientCredentials = new RPKClientCredential(); - rpkClientCredentials.setEndpoint(CLIENT_ENDPOINT_TRUST); - rpkClientCredentials.setKey(new String(Base64.encodeBase64(clientPublicKeyFromCert.getEncoded()))); + rpkClientCredentials.setEndpoint(CLIENT_ENDPOINT_RPK); + rpkClientCredentials.setKey(new String(Base64.encodeBase64(clientPublicKeyFromCertTrust.getEncoded()))); Security security = rpk(SECURE_URI, SHORT_SERVER_ID, - clientPublicKeyFromCert.getEncoded(), - clientPrivateKeyFromCert.getEncoded(), + clientPublicKeyFromCertTrust.getEncoded(), + clientPrivateKeyFromCertTrust.getEncoded(), serverPublicKeyFromCert.getEncoded()); - super.basicTestConnectionObserveTelemetry(security, rpkClientCredentials, SECURE_COAP_CONFIG, CLIENT_ENDPOINT_TRUST); + super.basicTestConnectionObserveTelemetry(security, rpkClientCredentials, SECURE_COAP_CONFIG, CLIENT_ENDPOINT_RPK); } } diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/X509_NoTrustLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/X509_NoTrustLwM2MIntegrationTest.java index 6ca430327d..b2ce6c470d 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/X509_NoTrustLwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/X509_NoTrustLwM2MIntegrationTest.java @@ -15,6 +15,7 @@ */ package org.thingsboard.server.transport.lwm2m.security.sql; +import org.apache.commons.codec.binary.Base64; import org.eclipse.leshan.client.object.Security; import org.junit.Ignore; import org.junit.Test; @@ -29,18 +30,18 @@ import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SHORT_SERVE public class X509_NoTrustLwM2MIntegrationTest extends AbstractSecurityLwM2MIntegrationTest { - @Ignore @Test public void testConnectWithCertAndObserveTelemetry() throws Exception { -// X509ClientCredential credentials = new X509ClientCredential(); -// credentials.setEndpoint(CLIENT_ENDPOINT_NO_TRUST); -// credentials.setCert(SslUtil.getCertificateString(clientX509CertNotTrusted)); -// Security security = x509(SECURE_URI, -// SHORT_SERVER_ID, -// clientX509CertNotTrusted.getEncoded(), -// clientPrivateKeyNotTrustedFromCert.getEncoded(), -// serverX509Cert.getEncoded()); -// super.basicTestConnectionObserveTelemetry(security, credentials, SECURE_COAP_CONFIG, CLIENT_ENDPOINT_NO_TRUST); + X509ClientCredential credentials = new X509ClientCredential(); + credentials.setEndpoint(CLIENT_ENDPOINT_X509_TRUST_NO); +// rpkClientCredentials.setKey(new String(Base64.encodeBase64(clientPublicKeyFromCertTrust.getEncoded()))); + credentials.setCert(SslUtil.getCertificateString(clientX509CertTrustNo)); + Security security = x509(SECURE_URI, + SHORT_SERVER_ID, + clientX509CertTrustNo.getEncoded(), + clientPrivateKeyFromCertTrustNo.getEncoded(), + serverX509Cert.getEncoded()); + super.basicTestConnectionObserveTelemetry(security, credentials, SECURE_COAP_CONFIG, CLIENT_ENDPOINT_X509_TRUST_NO); } } diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/X509_TrustLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/X509_TrustLwM2MIntegrationTest.java index 28a10fd278..a51ea98be6 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/X509_TrustLwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/X509_TrustLwM2MIntegrationTest.java @@ -30,13 +30,13 @@ public class X509_TrustLwM2MIntegrationTest extends AbstractSecurityLwM2MIntegra @Test public void testConnectAndObserveTelemetry() throws Exception { X509ClientCredential credentials = new X509ClientCredential(); - credentials.setEndpoint(CLIENT_ENDPOINT_TRUST); + credentials.setEndpoint(CLIENT_ENDPOINT_X509_TRUST); Security security = x509(SECURE_URI, SHORT_SERVER_ID, - clientX509Cert.getEncoded(), - clientPrivateKeyFromCert.getEncoded(), + clientX509CertTrust.getEncoded(), + clientPrivateKeyFromCertTrust.getEncoded(), serverX509Cert.getEncoded()); - super.basicTestConnectionObserveTelemetry(security, credentials, SECURE_COAP_CONFIG, CLIENT_ENDPOINT_TRUST); + super.basicTestConnectionObserveTelemetry(security, credentials, SECURE_COAP_CONFIG, CLIENT_ENDPOINT_X509_TRUST); } } diff --git a/application/src/test/resources/logback.xml b/application/src/test/resources/logback.xml index d3301bf660..175eda993c 100644 --- a/application/src/test/resources/logback.xml +++ b/application/src/test/resources/logback.xml @@ -10,6 +10,7 @@ + diff --git a/application/src/test/resources/lwm2m/credentials/lwm2mclient.jks b/application/src/test/resources/lwm2m/credentials/lwm2mclient.jks index 490812c01ab483d3462a09cdd18bc405fa23abe5..ca8c8ed1d77f31bab0711a31eeb63ae952c933ef 100644 GIT binary patch literal 20462 zcmbr@Q;;alwkYbhZQHhO+qP}nwr$(CZFkRh_iWpJ{&Vk*y< z^R6g<+ruL7Dv=RT~Yo{Q>KFbfYCr zLPYiG?f?QJM*spOV1NOG_Y8-7oWb`&^5VkYFEd( zz8^saYzfmK+kCwq)I1+Ax|H4}ujyDbEcLsvKozwqmbDx&gkG_+V(kpPDAW%#jPB4_ zFclg+cY+|X7#apGG_1#Wdn1&Fa zYIc=_6FA|hpDiEhu8UKYiD=Qo8 ze<}XXE7f55=dmFfF>@q27VVlrRsFm8O%Y za@qeKag*^6teqx7o-IyjeGND2fq%qhiV2aG9CmI)xi+U;jyqYyvI`9-XACk)1-|!Y z?UC?|g_hIdG{_a@ba1PI*X0BparAAV&hA25hjLrA&{C9;Spr?gG^;m3jUFIK;;Ri3 zA~}ve|CWMkX1yPtParH;>dG6qOM`&h+0R?`k1;KbZbW!N=+8{_4>R;hKa=r zV(=9SZZ$XpumNTKZ^T*tg*ZDC(|@|FC~PE^QXKfOsMkl2lp>xdzjD6^{5#^1E$*`k z-&M*&xGsj&@!k>th=<#uZCVkA;=WR4U9;j5=8zXh`1!{GWI#rs1%CV z8=7A)*rU!dq+u6%(KVLbx=>gCG!b$X_(0>6i@UW=mbEdss8xK1tFBC9)J`SphBbUU z<5*v*M{r1YgvCmx`xCHFrgSvLp)t3%R|woa&**42>{;T3upj~DVb-8!LiLw_gE>ls zx8eVvxC?+2fa^aw^#5j5I{^ECCC<+I&#odi_+RN29IPNntm&Un9S|VEKTY|6j{yFw z>V<~lbP7GtdzxM7CGYv*0!8qTmCwKP4VqAD%u9RpTq|{_7S%K;V*`T37?LnZG!0r+ zIGX*AjgFSKz@|nkeRHrwlTS%Y^b5m&01k*6u-wKH=4dhh0R3qyI-F<7k@m`!tLYT{ zE1L$g(c#S)TS?vKZgf_HFigSgsft%_Qz0u8FLU@K>}nErdGj#2aek_nPqkcUC6Ybb z?Q*lyvv8qV*H?v=FP`iz7{$tx#6hq#oAKdooD7PHZNrA9GT_XrKuma8;r#p!FHYzz z-|ACL5pdJ{YV??yHIhZ@gBIHe{8v@2s9l~=pL6-)3BBZN0Mx$0qz6aj=^7j#eHFASvO_h$X}9X#8pc4wVLCC`7tl)6i)UC%g* z!_AzPPz5q0H($UP@e3gZxg)xjWnjIhRi);L%eH_5H9oYGX@pD(l^v~xv zC|a{?*n5bTzK#h~>$E;V(xrr~dKusHxv@uc78j_6+WnB{3#I8c4$HoV#cyI8KDBl)4}y7(7{`^F(<6>UlD6Y*)Mec zCEwQ|(=CaPzm_m2jRj)_*$a-H-@*o|f0ZgCTLHccYfBdXY+mJAj>p!q%~O}4R(7Z% zb!Z=4>RR`Z&+oUB%H#a)`fb*|sAGBC+%z>twrO8p$^Ytlq{50PTrIS^<+X5^Y zy6Zvm{|m5~1I*}Dq;DAfQd-D(b>xjBsNg*6L%=1g$8C@^nU8%y`Q1t%F&n_hAie~u z0WSrPNIP%oJXJC$0-Zlx0o=F_D?a3D6GLq4j;0LoJt#A#f_9EDi^J*9jyr$m{zF-x z`KC6n!1t3;|DlG%G^S_J$oFMRh8_KB%d{YwxfvhgoCq-DsD{KrYrbHET2&AwN;nuD z>(V;I&}oa7{{uxWEVLeTW5I_mxXM1jK;}LuKM$9U!r{{tP*(NT%{pFxU^B)Oed+9dujiQ7D^4hcU4; ztI7$Z-*5=wcF+rBiNFW%&5a-w9XePwhrgQ@$-?tZhi-S;+TbwD;Lb+f7at$hc-jug zO-%V6q?f-G2s4oHh+28|$meJCgea@P{%Ct-x*&Aq(*-THfd`ev#Kig5Z}rLdbTcx0 zpO9f$^)O%fc5Wwu_F&}a`gS_!q!0=DH1#rD9sKvQgHfsG0g-8MY(QTqS{ajl9?l7U zaOn->xAda69`%x4D3wbW`D;pZlD(hv0H8einK;Q+dDn`6curtP1Cs1*Mx&I0pdOEy?b@vMjjo)^V zs@P5}Z2pbX*5hC#9gXqD#0Jqz6QGclyZL2=>|7yv|A8_Br=H=j^qO+5QVKs90`*~H zi(r#q3|L!?dt5(GAjR-G_cw*2D{`Bm5x-9pP0UfgGJQgkLF5U9aC*$c`qPG29~3@;?|yQ5*RN2#;z_4z+9cRY z=?P7wA~Jh?p3Z1~SdR#*cIagK2t<_*OA#J>7ew~a{8G@urMh*%OYYuKn;$OUGBfU& zj(o-dhFQ8Rl=W)3)5Em|zZ9A-7)C?R4E7H!JE3=f7Efl_? zG>rxZ>-MZUB$h5R00&&30z=#UuYFd~OAvNF!S^%#_ID##mh3&KsL-(X?=f}--Twv{Xf?XwAaY*8e$J?z05kiZ*(PbviF^^Sp@;$@ok|` z)oen%U`Wr@^*VgwqDUA!Jy@zqK|P-W;1a=_#amFvFZMMkX*o+dq=;MgIln@RjN=z_ zyCptFuSb9A4}5+(v1hlC3Z0C0)Hy1fR`16bNa}aw7_K+Rm4_pbSQ{4OO{?gB($5rP zuz(~8>8EZ6Q=YPOL?PiBngca3Y5Ezw8{nHl_PIqSJ{4f!tJ9KR!9^MLX}Vb6pwp5F zA!A$sG$LN~`a}f)Yz~ag#|~hAaEOD^a54%&Q0O(H^p*7)vR-f8;ban=I&H~(!a#6T z=hxF&n_?(f8lK$i?=tu702;S~+<6Nc9pmH&_JjB{mqGoYRAhYk=O!BJ^Rs&Snc7(4 z#<_Sm3}j{Nu7O}7ym~X5fq>tJo5)R0Od6bIkC5|7YQ~cVJze3)>d$6xvEF_aRL7kM z38L3#tmr)HKsRL=VNssT*r$gs*iOgl71+OlP+s1n`%59ql3*S)<&mIbJNvZ9P$+yK zsIsksZvS|;vWbhQ!kc;lS%u;wsM}!>5YLh+_cuV)T8Q=lqHJ#@DTXWWk(Xnz^1r!d zdZ3WvS{21Pu|}cm_3#kaG+6`qD-N}cqvoJx7FZ3?LG|+0^fsPSW7#q=QeW+)w9b20 z_K9uLw-5`TUg*tjib=_=TMr$tmo@#B-vE1>zOGX%ncmTfh;-P?Y%#U4UAcfBZ9JH`VbN^8@-m5o;7l!GkBJ~s(0#V+S-2uw9 zh8{kmkb%in6OI!PN67dgmfzxR^YDOdOZP$%7h;@(jyC!7Lc z@Oag=%GfK_f@DD!8M$!-_H(mdX^*i3IJ?7+akbBs8#*^_1zdJ*ZEX!H>M|JkZH#T! zBkH5cGLJFo*w$^mg_LoV#!9$`U|B6e@(Kq7Q_#)FiGvD4l2q(5SclpcgVcdlz@01(q9va*ZqwIMbi5~o4{Zsl z>_{gOjW)01YYheN`mp~Edui*!au`L9&A`B}Z54nCkF32l1KczB-yB$+NN)|f#c)}< z`dgTatZ?5oAgbx;r0hl{h}gcWnu$&O(_m!F^G~H?rQzC@soX}2i22MzsAWx7mIY00 znJlA~WEkzWu@4aao~Dy2DTJ1o4H3)4-eoWYy^9#@jBJ^1Pd;1Hlg0n--VzW8?NU_z zhXwdGT~#KU3_ii?+oI7qC^*g)EPrVdt5a^vh2ii}tp2zor0WDM)7nD}?4-2hS!S{- z^!c+fF7Os98hSRO$YhAqgb|_a!%HU2%1W9kJKdtC@?uLcOX1WrM)dx1W@_q z_3}M&nCSWWC4aZ}OF}%{MT7Wv5mNx43`Gzq&fEsj4>_}h=sQ`;T+@b>$VXe=wSo;U zIt0~0tGK9f`4BntK)Ltg&j1J3DiuWZtb*$5tE!__`nmd6yfmEZW)0h6Sc*ovY(&W? zvfow%1k}TyQSn2#=Tc1cel%GCZonjNtFs)&vXQfxp_F;)!Irt(2YMPK^5wLrNeNaS zCXo!+-16UdC5nys!`5DcKD@WOH>2j=CVHcLiE#{Cqe1#@fYE-z7(a%9!iaQ}OazE7 z6Jc_^bi0oPmON9Zp6^3w=tAw1Y2^>PHY~NTXs1ZRzT-9`znqUyx*(lz%Ts`fQu=B%TD7<$OtO!LmC2kt!&a(z#~EZoW*~%=Bb89%WSz=#1iaB+|HpH8}O zau&$cF+7Z3O4PhUt|;S6r=jMut$UBF0~wP1X{v4#my`vGWQ7?j5Z%sP%)L&L29)7F zwq#%>v~j*@NDDGV8UpatRW*h`SL?4lGX(V6OR-%u%O=g<0#C|#s9q5V2%Bfd@iTaf zWL((PBoTK&77=*8Bf#+E^L;q(cK$@DH_jw+JBBubWq~(VgmvSuRSNg|=@v#sMCE;&vkk=V02@hoFk>J4fe2fOG@p z2IuHOxRY6Cprs2(G0NI!xjXGLsz!{u$NM6tqv#fENN2qJci}6^kwx)fVS9SyFQLUI zOkQurr`vk3Xq;afEh!c!H?-c$>gCo%lWF+8(8k(P>68^PnEFynfO>hW!;pP|cgh)W z3yeA6MWwUWg0Ac*4PnnLo$0mkgg@2hSU}9KVAnOSK-ujW{V7zurd-89+K}SnN>wfa zYGcyODhP$XVyifE%YDwNHhnO(8)C_*f|-<(3f?|>5z^xv4|iyjMfvjP4HgFtRH6$o zlS$^H_nEN|B4Cd{K^g0sbp>$NEFAV{*-%;cNJIBvIg`~GEc%OKJDD5~1*}PW-Y^>( z4{L>!pFI1q(tmzN3pH-(i|>skalRWj@aR<9_s7S#yeP+i5XAZxoY0epsK71kj%{s` z1B?#h5M}ebO2{xMjU3_Vi{x-=cA2Txkd)1P`o})=d?l1BiRtgBhJaoX4>4YrH~L8+ z#sj_dn(9o&_yjU^h%>nF8UTqKyg4uaFvrbF!5MYZ#0njPUptiZlS!QpQL$E4PED@7 zg6FJmmyh9OMkc?13^VlC)KwnlfZ}OrzL{htP?3!$=dd|EiOjWv)G9}-zH(eECTpc1 zDRMvjz2zDxA=rG_^5gL zXM?mL;P?t(Q0Qp7&+3Cp!H{d8q&6Z4r=!8rP0{_^_#_i8S0vxWD{k*w3;Juw!2&&c zB$)E!4AlM#Z9D^~wnaw3?X0nnP}@^JVU%=-=Ig1;3y+)&`c^>C1Cl~)PqMt1M){}4 z z8Ycse&LxPB6tj(~84FM=Ymk`uyhaOc1nPhjqtTVUuEPve(TnAH*8{gmfzk(e9|^nC zO&8dv0X@^?xRbtoX#HlQM3P%yl%fT-|Xshij+iQ&3{+cYb}op*0%%%FFVG`WXAnuzfs3vuZVyiwg+qhQ&#YfQmnOev3YR&Fs|`_w zvd6=6<22})n8JA-Pc`K5Xu|ITWkSh0{loqpH9TxHe5Q8#ZkA@M7}rRDd97vcr{(aK(_NO*AuoQXip%VO3*IND{R*i`{< z)R%+f)}YwwP^@Jsa4xv|@u4q5q%|6rsl5{(;mplDe5J}dYhn8@VG>ix_j5M!h~27f zp~PsH79uu#tr|%pj?%+;SmeA&?Y8eB7>_Z$TMI+WpRz@Sk*W}x4H_${CqBv#a zf>W*e-W}7yPptkfa~ov-1>zP|_UoGnmkUKZ6ujCTAd-1Z3pzcPP$`|&2h8Ag@9<+&Z*!iX)(*Q`Mjx{K\hylOan*;kqm$M}?1Cu_<6QnGg~ z@4c)8L2ihDiI_Dg$~_}ZmMSM00R;O!q{(3L%5{QgccZ$WDT;eQUC6u4{&3s}TUiEF zDrF2{xe`cVzW-F7uYXZn+l~UqERv{-?DEDn_AOJW4GR;dMS!L}$fTmxIWln{vk)y+ z7r3UsHv`E%lcDeG``N$e<0`V|w221HENbMn$@*t-x}hA-S^BSkB>p%MCZ%1`h4V>y zblRom4^)+FB)rd4I{2_W-w;z*8VM(Mi;U+eo`lwhf_`Q7A6R^O#x}fk8GQB(sH&A~ zEiKk$tEi`oO?J_Ql}l@bm@y@bmtPIMXoJd7QIb@dyE~*FQpu4&^+c;ATk~q=PIUgf z$od`Pc+{$dx1w5M3<~j0LuP;NZaqx7vPLbh!xl_mI_eam#moFkAu<)8z817p`OP8O zm0QGjeYZFPFc%_2Xz=}4Ct=!*$6wlJqp5;v`;oJepMYT4eWgx%S%>$Z(H*uA?R(^) z|2!Uc`-UoI&wnIeR9UrXBDT1(wi26onmeL_CWaT-o0}qd0-_MxN$ggSZc9T8`T(Mk zqCojr40so%!-p#sU`EO0U$$4Bj0Ci>Ju4wTlogY`ua?b1^DzQ|ujbn6$F2wQugwQ> z7I>#(yEWU<$BJZ)<17J;TknXDXPI)vv=l zbg+&Y{Hf?LwXa^^!R>Vo89r^bhvh|7^jTh#LYvCftw32^Lu&6iY}w3}#K@Z_Ah*Cu zQ9Ihg_~Z1xovZA$=IPp75ufYDyK4>9>E_K_@s}FwcL@!;EvPkhrGE`m8IY0d+fl%y zbLo?H&Y)S_Q2~hQRpq19JHu(NICAxh)^JUVBk>_*Uf=gf0A}ULJ&r1{bc8M(Y+Q ziG+RGIWZKV?moiL4(7|Fd^Hc{O@0nzy`)iQrHJVaIy^ z(h{Jd6>{%A>9KGAxH4D#*T}I$S2lT|+BAtH3&+ZYaPvKLxX&>~{T}FKQ%h;+yfbyaXK8QX^pJ91bu|6drLu%c$u zOxxhk<-wRgzn>1!#}xzy8z`QKnS@kLLgTk!FZyB(0dOn0;6*12*Lqe)E8Os9jPUN` zN~m1)@>U+j8nGmzSiz4CTJr*Vu2J9pxR7 z6Y)vlAH(~I5@1gq)armBGXBpjQg|qX?eTah=7lt7%IRu(<3tYv+^<09I#o_29s-Be z7SEx`*7B(JVX&h!g2_bsIA+rx#IQUw8suw?TD*O~hZ3evi?h;HXs#oy+&>7t1~y%_&;2@!R5S*NyJ7Wl_-`qXeo6rW zQ1?7+v$DdQY4Y|E{4^v6ro9-@M%{e|+>u&k6Ps`fbd-dTLw;KNbr+-DhH&YZz1kKUB(;J(# z1Y-&8uoP+tC-_^I$=l1T6m`G^&{Cq0VV1ZVtyoS5F0xQi75Pedf2H5nFnZzS$Ga7> zf=v^h^i_E3RenJ3U4-_w_9$6m&I)CfUiw8Kf53^J3`WqmZS=0~V3dx$`@}P84z?hc z;>=+wRk53=JtC9pvaMG@T@?)8YC)h09&BS%(}2)qpm@H0#NSR)iX9lV31|(iVqf8d z&|7y+GI34;l?XD%xxUHV(`cjlFrji$xvz-MV7_#onZgQ{gZ!=!AT&*6+0InW_Xq^I zLF#SbdO4{6jyq&+`65s%)o^6yJ-y&^aV1QWaT@if&zxgKKWqNRoguqrEGKqFSHr2g z9&+xva6Hia*BBO$fHtqUWO)%-x-}_1&Zx?Iby@rz^=h9moT7+*UKSE;xz3PG_atBf z&BzGIbkxf&N)58rI7^I{p1Fa1x)QO58KbR4r~;#$o2mOFH8#tz)))-Bv$Km7wQR`l zG5IT2&`8JBNj-}~ZOonS_QgbM;5%i;JeJpyC}q~rVx0-gnq&wIH;8Z+8Om}|DlPGE z7a$$#v+wA((KHqT6lq6yu)Pu^92i+V)mH zZ8n(1jcw3te^J3EtVn{+LrTlqzxU6}12bf)a7KAL^4ZMM@$k%hmuhlG2?p7P9x6yE zV9ylB5GGK2SdA`_cSwAg^wzI(nz@X#6`PJLBUDwg*Xeb2!0|CWV~IjRqY?MTOS)g` z&`-@DA)_?|Uk{Qmp$cHbK=bc9h%%Wqd~g?n0J(4dCdO85Fr>x4${Di^{2 zNn|GQIm!4&H-%AAI134^ee`Bf24z>jkM(kc3t){iu_q^8)d*`1;`PPlcD~xjznFrk zcN%s!77sjUJvGc2Ie!`EOB1X&xqne&j~oK&fe>3o-ajnWv|1zDbd6Iwm0{Gt1RebH zNeSdRxY*GCk*Lv98ES2mJHkb%&wuOV8Z;lth|TatK#Cth6}~(RTibZ5J$#;cVl;ky za4>xU?qrEfmTpl)c(I&xLk#PMd)uC5)+u&maNG@gnO?dYgx+STTHL8aS-Ll*5wW5) z#)9*J_=1?z*PLOCNE2wSwlBY$O|_O^lJcctZ?ysDHGtOs#l)694LSEHAUO3Eu0?n}HHOiy6jhL~aa~$YH16C$iB@OyYGs z&*1K`>)NvGYL+M^@kS1>qW=1+L&a<|k>^mw4QampfZSs?=4&@T(nMjFtk(oO_YtX2 za25VLcxr6r9_Y*(oV=D!7n z%y(Mxi&&Z)*+r_C`s5W_w#uR?n=hU%*vx`5TJki}#r_n6 ze8Ae}i*Hs(Q1D{$ciIW-m?sphWYu+Dg(!VZ?VVRg7Ol#xDK4|>9%SmYhlk%+CbDS# zZj1v?;i&+R`=@fz?>wfvjiz!PXr$t2jCb`?Pi}jkVam5kQfoaNV+Ea@L3Y;`nHq4s zm#1g>7zKcQ57pi&-AFUU3_}@m!|W$7Cod3ai#KMgyg3K+-Akxd_U%J^@M7SQP^oA9 zKJ=3v*Kn2Xv{^IqdMGu*6g=~kI;I{L1zHcw1Op%8`q_x(EB2&0gL;@V1*oJJO)u*MPJXELw$>e&U=!0rO>?MrK?rM>&p*-r?pg25)KgUoi}?0+DDiu z$%r_+`s!WT+*-UiJ`?hBMtQ-&uPJR}h*fG&~u#PG(PnbrQOn&P7GT zKzn;Uy-;$}+e3R`n>=tDz%U34O{+$nV`xDG&_}UdUUmw!8#8v6#STLfXT+tsJ}FNw zBq!32j-Jx?)>7d&O$o-cpgo8leHcMynggwZ20*t*O zo@dP7-J(z`Q)mUYo5%sQ1g_#LR9?=dO0me4+Ns+y3M?9uptc7B zP*Rj1D4=&Gbq2PkgM>NI1G%seJ`=XKQfUHCfMS^e`Bi1Y(090dL6DuOKWYo(mb#LF6vUrB z<)GAroE@S-3A6i-JTMCrqQ46*YF>BgfrY=D4|TV~?h`(bfo&h-caR4dw|%3KW@?}Z zc6#bB^6Sr68!+5R+s;l8%zdjEEIj7-!C5_^Uzmk8o9rI4Tn=Aw=q&^_l*bLt zGe7{})J&?Y)g^I>0N*gi`}uQjd15xx?MtqSEktxC1BX~OUZ;wVI1Lh;QcF!YNi|Rb zuR4$PyvZ=tt`jca@u_gmLL4V@WZabYnyP8Cjz1qIVKoZpEd!!MOu(U7KR^gW@v`o~ zX)k!CZAv*o{`Cv9ibcIpu}eax2rBGjO6$TH@=gNg@|1jlvDE_qPMwvjALX%<2{k-I z;S!31x^C;Pftn5`O$)UoM>_pH7X-x)7Zv2uxJ{+z3@a~DY0F(^YRWV5He^2X;`a@@ z_r9z0jYB#vdXM}(u9M;yJoiRfO~m{uZ2JT2<9ta35Mid^Q~8xTfDAkT?=-(46as{! zHH#5R`1gpIUYn)`PW3!d)jW>Z zkel1#j5Y7jy4;DNAnHOfHq4P9hI&{C_{Aj@eE?k^p5x!%X_O>i{SRJ`xJ|sh@NNf` zHC-TK*r1BkhKzQ;)wRRjO-qoKzJ*2hI4zimNETO255P6Ikxd9mzSR$`KL5RTFr!?` zA_D1BECr?*WE5?Z5%!X6Y~PAJT2w*7*&Upki~8w8@IThLvZbz1l!Q%$vqD+MP5t)i zw8HHcVVd!5Jk(Og>CT%JhUj2e=_jgqQFH)$V7w<;FAqrKf?uW8JbgQCh?gE_`fQ$f zh#%fix>(+*HPv4;GmO5J3f#-7qkws=Db_5>T zQxTEvhZA|LSyvdEAx}4a3X9Z?AS+?f3Xh%~+J$6@(CDT*UtN3t7JpHa`l3$5aBP9= zZgN)xJlhetpXh>6_DMTjayj5)2NWWYg6kE2%60cHuZ8V|uOOE|G*sW~jQ_qM%YiFG z0%?BTDNwBWz_?koE6IWq*Hg3aYqG*x2US}?l37*72!uy)FxdRc%ck)zYd?2LO|l%P zZIC>0pC|})s&RYGIvNH{qR9?{*A$wJdJJ0mM9I;Wo(G=t+yy~d_MkkiXtkF+xKT7D zO{*o$NEO=`H;rNtnw**pqF_EmUNHmi8=26x;fX7jHz8C425xG2BY+>>%Bh@y-q-D8>w-dVZS7*zOxibYS` zEl!UShaxF1xB3lF%)C@m)8y9?OP}dpu%>2CuoNpcjhGq6LqPXWnQu|2kJdGAazia- zKU|C0r>+aGDW@E=&CulGhb@LAb&awoBU`W3JvwC(0sgM$@BT9K^^5LfG@mr zEMVV%cFIi*4*p83hhD0|n#5F)%sXGTUV`PTL}h>M?)4ea>aOju+BuCm961wlkgpom zjE2FEnbmC|!pk4Jij8=~LoifSh_D8Yh<3C)2jLp-^CK;Ly6(!K9*|9{I`Ub#^FdKI zI_GTZ>G5C+$T#xkwC!Yyy6{PN*ImBp;K<8&QG9qOT0F_**Oz#`3nYy#TS1@wrS9f# zuqUtxzz*s#=SV*hGK~8XD6!xkvRc2Yfxb0mzjX6XSQsCEkVz1}?;D@8&Cza!b7nCj>pK#Hm zax>v?#bC+fzGs*Z9VghC_!v%8g>gSxz9W0E^24z^ZZF#ml|xpvJ1Fv%+a~1|sw{iL zND-yd9iCPDZrFEM+ms^q!%EdV8(8fkv*HCOBrh)>?@2F-CpER5dVp6wc)g#bE$L3; zy8F?D;krXs!ZVd0FkPUXj)MdXkC>;neT+)>cYh{g1IQZ~?Ub~~FSQp=2k|*%#PT8Y z6EZiEiC)vfj{^Rkg^M^`toFx)pW+RSq##cCd#rZvu=u^~T%YOG|E!eC==lpzH3l~m z<->zQ5KW4YX%+q_?tJ(On*ZF(0o7=I6#1iP0P-unotfZoP-4ve7mZ8Fg>o+S$me6< z^5x$9R$?)Ae&4l6HzbdAP}Fn+uQSFJ+N|q&2N#p=&)TP6$qMCdPQ&pldINmuIS`6895e3&;a(Ph$DE~gXjsO>HZqm8Lbic+&@3&9^~BmQ!AjYu$d*EvdzmJ zyGBS!Qp2-;s3OHCD1@>m24x4z$1KFGoEq1?u2>?_{Ae|Cbs>BRiT*i!#u$LAukj8? z6?+N!A39Cbe~7u=5;X~_Lzf_H$h?HStJ>2mU=k|`-1PEVz6Tm{V|$(Qu0Q%4vRdPE zHYSNP>LdARS_w&&woR)*ajvd19-tH(Js2D*QtI$@)=QZJ5b>DYQ<2Z`*ES>)#ZX}j z*il6em$c;AUTYj1;gTv_MX~`VuoSJb*Q<*vcOsr`Qrqah*2^r87u2LG7g=Fe67Fq~ z?jqik>A3UF#qCr$!4B2AiX#V~fiIsDm~x1?*&BI5vp7$fi@8{X@?M+udp zL@J^sH-7fmUIgZju)H0QZI>g<#fmg!t5h#0I9+kb8Cy~q-#!sQIGS7JO2O2xsfL{LNlei7H4K?YL~Qs{KHUV0h)&-0xGG9qv~l^z~!?9%A5!IM7D@6_^e z!9@XFOF@^Xl27X7z@ye^(C&s1`bs;X&VtIOgHRt7TB@g6imLG z)P~d#bG`1}Ztd^X{?!*#+~=hYL$NiNGf|LhacpZHS^F<&EF!+gVB zZaU*wf!iJg5KChVD$nTxs~q0k4<{{gm70D)K$jxd$kz$-yTju0;O{hyjEL z!!MIi1!cAi1ZLQ7KGbJWPlqv@PO_XFgeMVq+9L%QWaidpe0`5GrodQM9hcr9 z7(n!ePr9b($(rc0>kZm(b}mP*-1uA}XkYOiyu`5m>6ka?zPayG4tGuA$1qOx4r^X$_Ljvr zL-}pbp*mezfC%a^D_;*+-l-WG!-OiaT{v&gWpv{fGTW6RO8P%$l^DJzwONmOAYmGO zJtAz*YplpLkZlGESU7``jmdMbA$Fl#q}=!bRo{n8GR!@TkK3L2{j*S&o_3{Cz(Py{dVzjZ81GxIko zc_6J;MzwV@($MTIWT(mFTDL+zH`9s%WQSLH;Swlm==x^vQ8P@~Kg{cd-2_wU-SWl* z<(ve8w#&>7;fuIY6$>-7fiEdVWl?q)VHq^rhXqK4Ul|}SSy4Igpd`OCg+O56=bTdn zsBkfBhi^-F8QYeh*A}WU(1u(@v8Bf)>i|CjLm9?#z>|kYIOH2bqu_D%=LzAK5@M#x za{X@}RUbHvlKpC{5A)&c#`CTa{XL6#tUHY}xL+t_C+@shf@U4?K^;V_LDjuq<%5(H z3@x47<;;o*h3){%*RGtkK5GG@lfgwof?yW zYx^j5(-PKzhl#@katK|A{LrFBcovNjwKv8F;G`eBqUOHU6Hrd^4YcyF+eG=XQKgZ^ zWj<6^fBqhze@9mMPC&zscdIt-cXwFw z#kMzYG~v$+yGLJ2^IhWZ*+^6+)Arn(5+nj~)t} zv46>nF>KP}%lDoE@d+S5$~X7LQEk~wU} z8xRCVOWc7@N+oMi-l-%sTHP36`~W|OpL@cG z!|)E@?MD`Os(WOMt2sUz^@JlMkpQMGh+b*805@nT<~^S%Wr#ysdeAGo%}y-4UgCF2 zDc{u~-+&3YSOO^k*rLwIiy7Re0aZqjx`}Ak>yd_}YpS>LDDy4}b4!Uw>V+((7J;vk z#fo1yC6GV=MM4ASl4lC3uMIm~DAbRQ<+XKU<40doIGCRFVc z347rKduxiw3Ms7?5QmT=k|l8yI|{x!luib7&!g5HxJy8~{>(fgV2+Ndm>fMDB%nQf zN;vZXJT6cbyRrSMQ7tD@5i}DK!qGK+(fA{FhCCWn+=><_QW70H?ZZco6y2>-$eMPC zn?6d~eJts3X^yAY55Xx~H4m2o+n zmI$fg?&JIB!K23*XL!sz#nScB!Q#tuVjO`Vc^NW$S9>&*`)9Ezp1V|4?)6_GiA+t}ZYFxk> zGMsr^URa*Fg#rB?_VMBd{8HClk>J`8M*|Nv-l}mH9BW{9Z=_i2`cx^ft6b@X78O|b z$H7-n3YC{lDeB3<1BjV8PUQzCZ{sxXS23Y}^gfvvkgAg&&ewwu(98Th2Je-N>>0xI zgcD;v5*?|n+TCk3Y~_IPUUOD|cI8QJGTUe-&+PalN+7c> z>L^c0(W=eMbguz|EG}f7%wGpSfMQGRe3lB!d^aQinS=b68(kT!4Z5&1 zbys`%>rK;V{#Ul4dgh+zz=68>ScKF^iV2|Net~(G3U)!fdALq-4FJ8%I*LWby7eCg zPoEn@;uS%zEU;VnbQ)e3CxNHn6;hpaZj^oTu~o1Zb#5)jy00A)wSnDw84mbL^yh=^ zeG`%;1eOWM-|b*55-YXN2A!=Uf+VoEgvfSd?fT_2U0&effWaYiWnUB+m z%qn-GddA5Gmux$db{!0PgrT%#BOrZe=x~~kGKps*AP$wpUK)5@KmtS`KZ_1q`v%SI z$z*@Rf!x?5+!nZsxfY@TEVZ_|FUHD6Dc@JLc+M9Cj-m5ABajU-?!|o+hJ2eTfkqVJ zM`B*!S`-DoAtUoeXq-_7u>z(R9-RT#V+0!w`8pD!&>$_&#t@2cV9x{Ld@fwbmk*&M zAVlHLPl91F!?a|1I{P42ZA+3UIec7+hb=LA8`$GjY{$-wlq&Kl%rYWZ=@#OF`G7I1 zo`RV-2F$xNmov;?T{IvFc$J$4EbcovTjj5ZVq7+x1Ny_jUU{z>7$K@R2uhQP zkTK-D{}a3mL-gBU#CQJJ?s}c-YYOcf+AA!@j;;Y(qmi7|S&r6Q;lPSe$xuZJdd0ex zg1HCCuEb*vU~&l+F+pk7<*IGTbV@X>z0W~lTPU9iJv8(DOfzsjzfI%{a<$C8DQ3#r z!8!`wO{Qm%GAzuGhy8=Z$HKtMh0b8{axE$we4Ss8MDISN1)}FJ{?VDi%^aE6UQ=On zeK4Nb)`3x=tc3DhU7AZ5#N6u0Bei?zDcuTWflhKTgGkbVaAqFR)p)5ap^5B~6GxPN zhE%cG@8vaH!M`^TMU0W7q>_-o5|a|LwcGw_r4$1g|G8T7ALu<2M3atf$+^3WOM zs%!1j-40?C3V9UR$r+tywaO^;Ua;XgVm9o_R{r)uPH0V3|1gNr*d5_0GMo)}9VE{< zQNr#3psk?z(}f)z<4WAXWhbSJouDdcY9H^s&$8Y)KLN%-FcL2An&Qg1#qpU~Aps$k zSfb9z!*4U8;!A~eFq9mP9@Ng|{A9?;Ym+k5rHg0M7oODhht=1OJXf2z(#LhNCUD+$3!*S$bW3VY%O+?C9M+jp z3uwYSt2z9FRpPkDYdLpkci}suevG!f7`Y7X)G@Cw{-*bzvu-x7-{RQD)ruq=W z{jTNjy)jXN;d^H(4oJ|z;V!(A8;@O_{P(KKzUQdfI?&f0*68XY9GMVuJUn1Iz!`(l zHL{TlT*aHqvQ<&g0%|mit3Pc545k{a91O@C*atH{w6AmY9y|-RLNu6<*gbNF2BeBs zzCLp*8Ntnn(k}_lj8h9`>Cxk_w2G#DQxU!@Z`{?HRF#)9x~0b`_%FZdiYHmUQ+Huh zD+I*qgj{QNapz!tjYLi7BN#|>KJvZe*ke**=jeI+SHgq%ZiKDi?kAVNf~?vgZqN2;s(@_Y8;&{$ zFSC-tp`s-9dQ>ZEJYJBm{GqkMeyg28f=W$#Geqm`^OGeY3k1Q4ZlvGXhkDuejHNNA zC&UZq;J64ESnUt8R!EQCYi6Xgykf1QbYh=;F`P zfucvLv&|8IS8DR3h@_@U=m0)c+c_Bo=Rz^n@Uhv=v{295^D7IbO=&Rx02>)6i0)8p zgRvxP2#%@n?Khe7X3O;(Yf5Q9Qj01UcP`mssj~3yc=rGQBR6s3R%}RecVQpb4`_#V z$*bnZmX)N4k^+oM9K>6eMPq7AcHqdTN!;F1t(3$H{S~2_Zz1i6QafM++)$91;t-?g zQxBGS3lt*0B;!o3)n=7c^}s~-$PY}%YfOf$-}RMIhC+9D$d0_L=+LuZA($xbER@Y+ ziz=sqx*C(2Zb^8U_ZXEow}+7+KRSR@6B4cv8kmYp!L1Z-Bm4ukes(icu3hz263lcN z2NUK3n}3b+_dkK%-;okFRkg%*Nn$J48$BNplQKxu683(QYPO0LqnOeUJkRA@bTU(> z3(&`i_BbikI=*3i^@@-fI5^*O8sz zsNE|k@iqa7O#qnVgZ(}Ofg%X~y9igK`|+JT`x208c~%6V-Qw)oLdiU~<>NIq>*3au zKg5;70$K$x7q2}ZGHjRLd+88?Zc|$~qnm9U+3@AXq5=rnjrMNZ1*2g`24N7!UDd45z~**kcFX z$_mTTf`qZ|lnJ`(RI;f`-7q)%Yg@U&E7O0sgTyLu6jLeL3aX*gM`ryso=du;zM{b} zQ^`)sIYH?kkS*_1ii#4c#rG5L+-t% z*C$CnSqAkB#^eP01O%Uq-DlH(2!>KVop1L;_>6ya!a{(;&bK_iWQ_kBsESz8&++4LS5GK34w*E^TMvHx4WSlMM<>`+1Z5B{{oY0!3 z()I?ga>RB2H|*A)jOGZaI(qp0wLr`GQvTFzz7TCukd+-(%2spiR0EnupJvzle+wPj z5YTIA>D-1zSABH)oz=k`2}eU`Eu{TVtZsG+>4O89C|eb<{n||6f+30iJtkRUu1j&` z(oY6-=67(z)J0Z(u0=5xZCB4!Cd0s1zl;HP_J6w44fx~(4*UH+;<&Skk@Mn!-Cq*O zR&Jb;$Sq7&s);W1BH4YipUVb>D(>?Vh23-0=cfrO0l}}du6O{)epvEBZ>awTvMP;E z8!XWmRpamc#7iYU6|ZAKt(2dQ0jd(4Pm_=FVoZO4?DF=5JY>|}1S<1-zhqTHOYduo zfm$AD7b`+KPWkXP4TT7eC>dM{B)LDDMSZtvRcF{=03mh7tv&a}6ZLlr*Xpz}Kz-I0 zXt}P91y0f=Xih9DG;IdAcwO*w5Y#La$|95P`Ky(Gc%8ZL0lkZe|E!)!Ok`(BSn6~{ z_`KG!~ zq7GTrol(R*mvZqP%)~rdBil8!@$1wl*}r_2W7-HG~i!Y3#x!OaAs$OtOX9q2UwoMOLI+ zkKoeh^rsRp*Kj4}ue*cBS1|{ZSe2KKb>g6AhPXGimuCm+r45rh))g4T5()-zly~=m zocg(6AVR#~;eu{n!!%*(hfxkpl6dm@<_UcmADpr?#SzxySV+;Ag~Q)D#bNn(0At}c zUy-b%9oa^Wtef8*0E-6>B3Q);=g;up0DLlAz^hV50xr#S7~`ZV(=EKF5^Zk7N!sua z;@*m?;Em4+Ah|keG$oAL9UdFx2`V7q5fqrOI$sMIzO+%%%skWi>M{3xbdNSXdpPmH zc-*aBz@xwbZt?t(0KbF~@&oZ&sai!ZLyQej4F@KB!&SqQIA#a5 zuIYNCcNujy>6lcRqEf8xTcDnH^Llf8;3}PKz2fP6jejkJhAAItG^WVIqV!=-QheZN zU-=eV=^VtuZ@J2&Dab-OYXX|D(ABCT>zb9H)6v*Xkqcz2w>3Oy>gA158{O9P6R)uy zXz9Bb612*3Y;s1k#unsYTl)Y?t5_a|Ne&!Nacr+lO6}9@V4L91akpcq&hM+@a BIWPbK literal 17660 zcmbr_Q;aapx+vhWJ@bui+qP|+-`KWo+qP}nwr%VDIp<{W?5nl1cKV{a-s-BPp6*nq z-%im72)_XV0@DWw*MmV)hKPr}!UBQ=<^>2BfCLEV{1eWg4**yAA5GwbAOYaK|AaZ| z0|0Hnp#Og_7$`uXJpUhh|4(|;|GFL&mR^IN{lBX)^i&`yP`UBT(;ha*><Z#*DKPyl)yFi8CnaX=Gb5I{;01aQ{~^Lf*n;^*nhoTywq zGZ6o{KWuMA1xauf8CQ$NmRxK4wU)qN#p+}Y0z||rxMfcO?tD`%fhTAKHz-MkQM@ot z{ST*=Go@iZr&K0oc@0v^aTIi^$!CI2$HgewFy20D>DN# zD?JAz13fdxe<;phZw1$`R?_|=tj_&vt(@~IDKpk*Wye%IEA(ssxY#=8Nskfj2D*8E(53WAp0 zcQ0=_t0tjQ^$~9PaGG`u~kM&~X@{ZApwN+_f5fT0`$5>QBov}a>&r}>uotbGY{QrN zWr--T)G4_!rEubWxomU-z}OdXe@TC%{wSC}pnxMBsf<4%(czYes9NN+igaOL2QnEN z!A{?mmWEqjGvi79USqJ9wnmswP&An!Y)GqF#+&Z0&d$p}6-aEbPrlzj&k5=nt|8a` z#d?vd7z51O#8~i5=B|gAvZ(ssh%@~QaVBOK`v345H{gblldv8hyn2b;XNp5;p%F8K-j(U2HB&T z5#PDU=R0>42<~;F&{0E@iGM`WBfpt9`O6XHq7cLU^h=2?Q4z2t^OhL;Hz2d^!6|qe z^Jr!+4%jY1HspUJ&ipULnHgD`=>vEK{%f%Z2g?iKVf-gV3j_%8PeJzIEr9>(T{`)i zX>#=xf({&nw&UZV;gmcrPVw*D10v#Oc0#l(*~2e0f_lE89KQhWx-;_D3SVbCDSVJX za>GOf^OJ_n4UbmmWj=cXklPq+sls!q_#hg2oX921O)CKu*F(1AwNrS&)5H*w4vVYr zh{w|ljynorf~$~O^m{gV%whCmBi11mTOqJ$ekU@JIn5gRW6USw_=c%j*q4d$(#z-w zR$Wa!_aR)V5!<-iD@kNIc94ukA@@NB~9 zv=BMnn=5bKh3A#0eAfmrz^J7NA>aJ0ff`P`<5$hwL%X9^VZn3U^jL?><`X#f2 zzp!&}Ngu}Ovjle&tL{Om;V)`Qv@Q2R0c0#It$~MXnzPpW3ZqvLOD}|)2;Fld?B&5y z*Vt^GkV*AIF7u~Q_z}3$N`wjF>qB`q-)jmOS~tc{08<>Sn`o$s1Q={0;N4bA*O5@A zwo$pYw$6{26~S%?;d|qJFahyTu9ZE5q5R94YVctdLew4VfNta(gMZFa2kA>-}iuaCUzfWo%^sL$GG&xQc79Pq8t3DGJ(oRiNrw~ zyaYPDJh^RiI#Kc;&|ohNh99#;YY|6jI}=_EwSd+&=}%d?nS76e)pI>t52<^NtFsLGj8!t`5{1~+aw!%Y zs_&m$Wfoq{bQWI3Bc%)|tp3E$y95qg5*pa??!|=VLy?f-#S(0cLn9T_QsBn{)aJp5 z7w`qy0>tq3$IRiL01dHKBH!34=_M66JYWS#IW`t@h4zxV!K*#eX6e;?@?J^voyG>h zngMrJ%4b{PG_`&yuMBhJrL+%9X{-r|$Pw`}qntpr!NCdi>4A{4q)))O^aM^V7M;H; zg!+5Kab;r5#usI zGHB`nji`@evG`0PF*m&Fd&)==U; zs9UG%f(|WhNVrWd7`N#|&*(PEgLrlCSB`-Y0(?UQRaQ>4ocC3y$y{u9WX|M0usnfv z|H^>^eIq28j~Yd*&?U_)jHC$als0b|CJ=-B$#9dLOAJqhOt8` ziU7Et5dd;`t?{V3_C%&Uj ze3W?MyF(SI*%D+yG<8L~QSKF1jqFXLjZ;npHQ*s9^EEQ=BvvRV&>RH+Ru`?D>ihte z*~e)9kdc>H(M_J7}Ub+P(fUUaq1&j&L(Sr|p!_!&5k|vvdXxBE#fZzv8 z^KGaW?n1JM(`Jwfu79aXSWbi~gB$Xre9qxuo&FiI_Ct84$TEAtT45)U@zjPrl-`#b zD#=;vAM(}wCog37sENyMB%i91ea?Fqm`Vv0x>+~?Kb9EIC=E6u@HP@YpwBs&uwezF zbONQjM`H!5iI5DS4uK6&!rskUM;i)~wsY!go%Rs zc*+lsK1|-0H0X>}IuZ)9YqwA7S!=m&q_uyJFKe_KJ1PM^nxS8T_k3J@R71=CgeU?XE<{Ou=*5{6X{+PY_&zh&STzsgh~ zT}s4V?PJs@%RUfV`yKen2)4nk$$gZ)xQKSx-kwRDE_Bm`&Ysfgq>Pq4*=g`*hO(qM zA`)MOk8bH~XL)n99ANI!mZM6c*L>y=#S?1nknpt09Fn}qe|4>7?hyzYv4-jGc@YXT zsc-=6B}<-Nz_(LwL-oXE!+PhsPLUVXP~O*&$VT7ssS)^%yK0uh5{neT%3V4woOvJM z_xyzTaU-l}H{_SOW)<{Ys#tKfU!1{uY?43$M`C25Fw8XMldZ}rB&E!YeOON2bndEd z$@zcy?DP`>^%s4g1a}E-czPU+TA8$|_KQVA0mZ_V&9;Fu7=-n*|U_ zELkybz)erfIf0fq_YU%K3od_vYd55XBMQ0SfGR9+;k8|kR*l7SlE~&%b78};Q>DrFa_9V%Up&yPnL7lP3? zjaoJ?o)i-J?o(?r>4h`D5RX{ndQZ3t$T)DZ zM;+%XoKGSwKzF>ALW-j~VkEg(2@yKR0qp8I`{;eU}t+(DleenF>jB#n@fYi5qG>q7p`h1JY}v=Xzci z_?Kkd9qYlTxxE!`UA~D=6lt;PS;+>x;JOtD5M605+#HtEydR7(7h*C$Ac*jrZ|Qll zDpY)fNs-JYT~?IL393HAW&X}73H;ZaOmZEto>SRRb$x!KNSs&@FqaX(6}S?x8y<(2 z)a91Zmk6m*ef>p=a)9+!Y;Cwa5T|x#wQBcz_D0_5s}K?q3RuVLHg;&?1wzY~t%YhE zPBR#1Yye+KqASFu>UWR_Tgd_sT=Aq|4J$Q1JG`!m&UM6X?ECRi)s)<0=G)DfHuVSm zj@36rqJ-#i>XHfNGC!9z7L(T)<(6%9Gb>RzHSJQG3z;jQRFqQ@Ea!r}Kg;0ig^>=P zN8a=Nw7^cGz#jA)Uji?67m~>Pw#d0VQPh?uGfgg@c|(=@hyRRv7!OPwGt@3Sj7jRa zcm==|wK&UlfXFa^dQ+G>+9eKZe8^8gP@*I3$hYnOeM2AwxcR3}`OHeAP*j82B9^~6 z8a?GP5c{D9EUcWf=EAPiUTCvkZUIVhK4U2e%byrnPuh?tvBP2yBQ3UwjdqPor;V=i z2#yax?~eDd9%$0E^>K(qvBYo2e&S!XOkMqEvQ)@EpQfcqhS1BpGAsKb2i&uH?&7BL z+G6SVZmg@2jYuIgg!n0IhB7O|fwWM$7MDkKB`xESb{%x%3#b5ajtZm`-Z8M21zs+l zUyQ(paD;}DnRCa7Skg0qbN<=jb8xU9){C*UTyd6$WOF7$l$Zjg2eyk~w$4|@uv z(06oCI%4EK9QN|Q;ms*|v>IDdK30&Sc5~<85g8C(N*M#DwjMs&BKhmY?O=p!X(8;D z%-|cTalBFdOh7JgV|xA!YE(D^K*MU=hH0PzC%>?&_TNgLD}t*!M3#|fnH!5t;YwpT z&n~I-J0FJw`wHCIb)~3&-n}#n0g#pITXE$`6(WA|ogAojW$z?F{uc6G$XSFw!*zDk z2vHLE$f2a)SuRX5Cf~q1is#b!IG+}_lq-K)n)ZNBWy&;p^#<+(}v$@Cd zu8BA;!(3S*%AV4GZD^$RN&E7{1Ot;rrl1#v#tBb*gyJ%&kPE5;$i)&45yl*J{{#Ta z78eF?f)fz#?z>tFt^|30DAky$8JcyJ?F_)--;?1Q$Xi*~KISgW4@-F*hG#|Wb%Nc! z-U`eFyzW`&P*#uJ(BL`PNl(Jjh+mM5s@O-}hg}$POCRzbc-JQ2r-&rQUf=1EZ|}{$ zu?d*g0*GAi=a%bPWkepdNCq12@`ES`lB(){LieKYC_EaPcGfx-9o?!Su4=W@P~l1Z zA=ZFy+3@y-beSO4QpEUzrG>S?F`teipAdkA_&&%u_SlvojDUcw7c(NKcma2TjEe z6xW6*D?v|2(v^i0RC+#io6|*I$r-T}$^C;XMFR*L*)sI&mS1DPzwy4ALu*5efUDDZ z17(a7_ziPcH(Rj(8MBnEf3I#erN{JJxue}dc<3np;o#wlf#WA`vgCpIIz1t(l=vy?m8k59+sn*7 zZVDbUitt)aAsgpU2x#BHQr_6-fF&3fwWo~yTf+(naegx5bOGe?cPJFVKa;R#0vsG$ zjA#O0k2fOqm#8&nd!Y`Eai50paVm0d+#P(CJr739-)9L^37SqifMm#jcN>Cx)FH zJzEJZRpS^@rj0Jm6QeW83?yVB@5NxiNB2y&E)WZ$QK2C zIwr`2H3>zb*KGk7DveFe3r}KxL5I7{3`|AJu;l%EsdUq*>!G25ZI!}I^|1u;SkVpXL50Yt&*vD zFIgEzY#n7;=AR9oUYB6-74d0s8apJPipB#*HK5@BsLMGkW<$PmX#_rc&_=z+i(o>N zs74=kaRom1=N8)m<{?qD95q5G&7~LUQ&M8fT1FzmXk|VUS5<)L3sC^OpJ#7z!3hTC zI+7%^3MWHux)LuLPe5E3N?Ig*LSUP+D|oP8!O5y~9EL*wqQt*mX)McCD+hM)%mSY) z=;2eK@Q>BYN_9(hSHenVjKvu;fXYlXZ;YtSW)WFZt_9LF)e~D$_nn%LK~!| z0Up}nI{wCLB)q6#QL!_G^jNu#TAP%7Db}~qUD*%^pX8;ImM^ARM0l-XFlM+>08o`2 zL+4PO@tlzGu0m>hTra8f^kTK3dkjA_dXx=RsdDKT*(AJ}(xr~T=kQYe3Pe;@#06nN z?wFOZh#Z_CZf4$5;&uJWJt%JLYD>TFGLEvwL5DD!av>oadELw)q(Xpj3Aoq^kU91H{`_g1Xh;c!a&_( zKzb{*!qwC!dI9j$gvTM#E49CEJRx}lYoV`Ir+Ny>P!{CDo8O@@Vj`^*p#j338|DJM zIL3saO71*c2^bk==|B}M2b3ws0}5WAm703enN%rZxqlj8KL3%vD5%3A;0uImw z-Vh0K2wM?$KE$FyxRQD9!>BCa^xFRT1FjqA{dVe*k1L{BQ|ihoiwuZOdHa!IMgLW{ z`;vk-SP|^Q{TB42^i`O%rMFh`as9ioTFX$^}y&?89OZ_aI zsjMA2AH$*0w-EjGtDjfrJ+>u!!9c(@OL|*aOthu@1TC`aWOojHhJ!a3&TZI9>rz$p z_$n3cbIh9|xZ{CccgSkd*FQ17nu(!&uxz(qIug-D!cm@4zwU@Tpv2P!)TJI@U$UJpGikGW@iVBoNO?Up zZ)58S2+{MBak|N82zL9kp3A&q<#u|>mgr`LN~Lp>r)$%Bj?O%rmZs@oQ`|wQG)v2Y ztjDmD)GfPMt%-T$_+e5$g<4}!UQzW9r8U~L_Dv&5eBhdG6*N0K|)2` z?*Z-U)aw~#XbZ zDvT+6YrO!5elN`5S}F>tKBv4o&aWE?&XkcP@$h^XXjY-3JXO|2tRHNfAndZX9UvsA z3}|MT(h)ZIlg5!y#KQI_Rf1(Dm5@^#m)K2Y^4a)g_#N+aaRRQ-Be z#3A6SW&C98AF=s$q!8I%!+6A1{O=)B&%1#oSib_ETy7fB{yg3zRS--C380Uc0MD?S&mTWm zTsEj-u+xZD+3x2b84r-HzEf_+H4-*RWr(E#+Xp?I9c8|SiJ)gm6r4vCm_t@(yemTUJTF3wRGi3FM#hK>+Rx{u`F|v@P3D-?-gw85+ z;8}a8q4j9!m2bD!WWq>AmnqUn+SPL=?m%`z;T%vJyBefv?Ve6g+pUu2)8$ChwWbUPnQerRlmVOw$sy%J$o3flCC4 z`_eLkJ23Far+;uf^sj&o^|ymaDiUG1osPV5pda{gl2x0j@C|}ChQO1az%Z|DLW(ZRI z7#K76QM9;Kq)y;4A%8pFjBC#Mu7tX9Jff}LCti`cs$>@_g^R^uo-6$(Q5VijdMKDE z!79q-%Pr|S(XmznEH#Qbkq^Lpy_a15*t>*uckt(sRrU;aX`-SdW-Wtru}m9DB5kCI z`^qWW?-apfVX!8XIpSdLdY7*90PDA)&%gT($(D$jF2kS4dobmo5c&m3ip%^!f4@;B zd=A_q1EOi#yd(3R+-;X?agy|g(rFKv^w`H&SaOFqj6?4#bTE_ zA5vvcsm65R$kD5=!D=ZwVPdM6t5Lr>82mhG*(T$$Qg;G_k&FjM>t6kC#9eH!Wse|# z$bW$`F|!{}qvJKlfq!=AtK-!8Ffh&!|4cTD;|OKx36wX7;kZ7z8rSg@X^d|dMydHc z+Yv_~Lj*q;E1R74&g!F=;*#CmSa&*Iur{&ck=rYf);RXBW;w96$z2u7Z*Gl53&@Ey zv%c5iL4mi=pl9|sI#UD?Eg#KIJDenwYcwcS7kz6$adaL=IK5+KwIaIdVXZ;>&_QE+ z-Zr>sBScUUUbZn_Kucwad}>q6t!wz`N^ruUYp4^c^Qn(Vwb@mV#Sm78!&}XFRhz$> zLdFQm`mhkH8<}Ujx|a5bQ)IIYZSCYpkolB_o8csC`^3{~UTUOPPu^L2@WEQGlgCuq z=VL3`DM151Oo5eCvK4sB2+O zw5yrkq>(ioXC75%s-H##LB{Aj1(ve&0s2%PMaC-0rIadKFM4a7RFuu062ere;;e2v z(!EQiWkM8r9mc+KbJGHZ+vw4l>{(d&sKS(Ht-EF<3;5Pn;nZ}QT+if2;9uTE3qdYZ zS6@_iEOF^*6+%ZRc6hx=f02WXc3L2uh?9XnfqPQo%sR9RJNKf2Hm$02IGDa8cR@04 zNs(vN@2ucwaY=2GjgFsv@93g}cOPS23N5Ukrv2iG9@GX+8f#T&xv>_ zZsw{`TPk|=Pm;0b&eZOUFD}Q^@A?Vm3w`*~G?GRMR)w+9qTd##FPM64)M2SCC;e(pO2_-ZL zWX^joes!2a>ifqwq|pFH0Jf{;5o&xO3kZv<1z?Nnpp!3{xC~x?agRQ}#;-Lv4=A#;*g&F& zD8@VQF0)%{69ahW^tK=ogR|?VMH0G~o9rRVJdeCt`^_53a?>LzW_p@cFuB*m?9}kC zTTZ4Ydjv5cg~_Y}BVDGFF{P27EDLIFH`j_e!LPaezI7>TW|e&R!8PS1Bi$XqqXQKU ze_i@zXNtW~B}72T+luay|4Xk#roBJ!mC9L0p@g}S%fQ<@p;_%JGo-aUCy*vgDo4H_ z?&gn3vUon~$|h7NgyZ)quU#EXg{&jqLTir- zW9F0&C{XyZx9or@u&J!N7-1ji)%1Yyel0f;B{B8+}zE4~fS`wn^!ZaF`3j zXJnXsMs!iJmRps|T+M>@Rlo$)@m`Vs;XVXcjVbZntLpUGaKJ%PX!uEEb`uk007sFq5znG_Z3W|NVJ1q`> zi*u981sQ@bHKGK~>~mH#wMq!kmg?nWo-Pk;YBonlW*CO&#&rg^^e&&qO0T_PBOcu~ zx{&wd>{CO@^!6AjH=LMH7|kn3Lw-U)M0iQ`A>%)Lw-82D3m-V=!lKc@9_hmUX(r zMVkiS^V0PaE;Y9Aa?mpDy^cEst)+a$#UNXEmBrWai%)YSRzjV+vhMT&t;Z~tcz(mf z!nw4^o=n*-g3$N@SkUL_Op}^LabJLPhN}za)JFplJW7T4Gio1OBrg><&S7-7&z@*> zz9g|epB;yP4=%g*qkzzal3(pkLZaTDs(AmHsXBY^?W!i&PolGMJBNt3saZWzZf}CQ zh7)tX?pnkmmksy&)ggKIdH1}U6HEPx$Up!G|K8jih$*eVxZ3ks7Sr0}A;_eZdZ=h> z#A>PVusTPvRsMztVq}i};$N*kQ`YTJfZ(x@$haz2knw4=**i1K~BhNZsKXi#3<;nOKypyitO|o{uhM0UUv<&WY zTW0O5^TCNZnzLx1^bk z8{(r8RpCGTuMG8n)JKij^;ZwuC*K9px7cDzil9OKP#Hv?$&bg?+rqE&K|Dej+L;2! zbX6i1>}brDZ2Ft&d;5Jl|0a{fK_KMkX?lcmo`WFLFO$aL3j0vM!04pZS~u5HGhDCx zFInR{tkQU}(E_%9&0U5epqNl89EPMW07smeBsX^8+@AqXzfY49Tmugm4K7t29D=`V zJk)9ca(&m~8WFM}`L1FPgod&0lfRWh%x%R>rF4D(Q0GjIfolCNG_XPDf!?qd$bV%~ zsmdXO%mwpLQNE<4sJ>$pxrMWP5!|SU{qg}gWeVD77^^b4B-iHM1miE)F^tJeQ{a78 zx~iw0QtLe0#7aH20exE#_LGDzCp(po*-OQ#s1xbnhIdp5a5QyzX_rRa+M+K7_An{< z_M;ixXB~p?z1JNuD>JI5NE8X~*aCs$Y;gj};9(nRy}p|FP*djUc(%DTa^(%R%S3!429krhqquVX=Rrju%kmLE!VnpM=_TjftX+&@rD?eAu8 zWG{c4kNaysXf<-e3sM`K8p9dK?LY~b-eYe)>C2bmTELegq4#Z;Yz;-cS&Kt@o^e}g z7o$fgJUXGho|S>0e5sJL_FLBGS&kacR@}eiB^Cw5D-I8|aesO9#wUuE zRA4r9f89iK(7zd#?6k|1M;#mQ40)Ujl|oGduMgwSbzH_s9i4?Fg1!cx zG~@0N=RD?<33jh@?_>%#%22sd+HzGc6C41Lgl%U)vmwoEVgUT6*G;89K2SS#k?Vr* ztD;q+)ddb;9eoh4C^LRlR_m7U>tkgSWGO{Uq<4N(vR+p`J}7dBc?x^B3Y3TQVN?d`!|Y6BXly0HZWekw%ho=KRU{aLX?46F1r(}- zU6>-g(j{|rD*<_#1WNRd-PIi+LKLepK#v36DlI(*!4qrtSn?Wz5=$ILbX6N0tUTUP ze>u1zh_Yq<9D7H?7jM_a+9LE^M$5BZE7N+dl53(<*!99kSH(t^_0XsPz`@32J6Fh> z4%;sCD6|;>JlUf~C0+A_HfUT>66a2u0aq+1Pq}G&W~x?1SvmqpE|mV$8i&N&bb1`5 zT~l7#_Qs^R)`=}IeP=J*n6m8&Bt%ESwvZ41?Ca2d5SFH6d$1sn<%T|rx+(^Ya)C+4 z#`xf*lcE>7x_;2RawXP7rIo5{FH(L8;KTHLR8DR6C$ygf^nfkxz6j7Dorj@Pk;-<6 z0`#T01K(YAl`O?PW#*+0j&;f_d}F1Sr(~os12mJ=5QIHbn;nTb`4qpT8{* zH?rgYG!c}n&UlJ&Ysvwa{FAsP6%Qp}bCxhjdVi6#-yVnHgQ9w20)LbRJKtrC^F(F(eK;CYl(YQ;w<4%b}Qwt z&1&ICyDj~R&*w8|XuJe;md6b7O2+x<#rJ33$=b*1+ubYqFbf%8%eKq7?P7TDVg1<7 zzBDPoUIrV=gh(iIPys2dOOr-4UEFsL9d!mcv~#iSWdF_fET~xoNbV=6EFvX#kH&#- zcHar^v?~b+t2hA-`k78_o`13&YV5b7EFY??$O&q-!aVE9;(!QSpytpst|h>FlLL!R zo%cr*MxcM1Pz8Dbm06a~_;W2&s=2%A9>j)s+~cDZM|qG_@A312s>HY%#dL6U6lxW>aFho2jPkX0C}g=20fnzJcX!-XbN?7!+ob zi7Y!JgIy&aQ(VJ|$%~^M+IE(ycB=rw7^GsoT&l}}yfJ>yVQopCuH)*ksol0z5w&T| z-WBR0O{$C&Oe9Hcx=$-$QD>!NYqnj~w6lpP#o3{P%+?cj+m1$qvz2IXXQa?=&VD z2EgXLox_gHjkSZNu%zk?{j&mfYf{L1+B!w@fNn+GwN5L}puBoRh~Y8urw|vJqA|(t z;~*$6Gd6N%ciw96NEFHpK8`-n9}*)koxOv8Mkkza4@D^F-PBqJ~nMirzhzZWB z@X!VOS*ZmstU889>N6V`a*x_SNsZR=9aI+3Oy#Oj%hkg z<8s)MJ4lH54NLHBW?Vg$&Ht$nIoInr)DCP#@#VzYqzH9kPKAIwCeM;&mx*sD3{U({ zc%}#)AB*tC=~_Pau+LJkX`VX5JQC#m!4$OZsiDB_?g<#5Ibo8J5}@{@lB?1hQo`Up zL}p~Ml9}#HZ83jD$z)s`Es$bb>^}3MXn%zi+>aq-&u5CO;kiaAODI%L%8%0%q(jwK zHD*h?!Mz7T=JT!t-HL|7xg5j8#@lbp8n!M`7+x1u@2sZ2En@*`_|mJ4S!+rp07l7& zilU=~fCF$AD6iwy1)XtOmZIu~nz~*p>~9>>Txkdf$He==o0DeQA9AbYE@Ja7h1uWQ z{F9q($@-A4b#W2t)Hxwx_jFnL1Bu7((_UUELFqQaz9n`b&-~`-O{9+7a=1r8?v&6$ z5*pyU`jOvx7^-QN!oV#>v~79<3HdjD&lfeLO-AyQ8ws{l_JAg@2s^xnmUE1~e|9~}r3K7!Om1%)5GWP zAk@Gu2C^9{3UnADm8#Wid_-&;_fxeKg#1?o2uVs$In{E;3oiYuikiSY*B zF+tGP&QcRI&L1 z<*}Izyx|UNJvb+5>$N>eGL3Npd9q|Hq-(@q=$brD)7SJl=FB6f5~=rJ9p5->plggc z(?n-gLao{5zN)@Bb7BOC{$#E@m>4tzXa#q% z`Ze3y(>n*3K3^_+2R!PCMD7!l%s9>$Rl~r;quc1>Ho1{e1fj+X`}2orYKWK|xU4C0 z%oAC#r|lzhWxj#hfTcM3gEuh1lNN)^8jZ23IF}T|!qn$KvHLYU>F^6K=M8PeATe`) zQE5R@Y_$3nu$Q4S2*icOxqdE>vxYSe&o)hM>*hFVRS*0(Zw`9Uck0xp}S-F^3zt6cs&m_{7(#Zfg(A zH%23rYIWp8n4K|ahsMAi8x}E3I+|HyE2tgtPl zR_#yB7ix<#w||cx!o?O>d9Mft#gzGOr1%Q)HO+x+Nma$*(!3@1?JjtJSEqDU&!mr9 z>rmj#SmmGWx>BWwjSkpyNy^^5Tn(m-1KNbm9@eKttA_H$dIco-DHXhB=Bzti3}wpG zYELUFFQXr-zO;TzSXHxlRJP1pKx5lknV2n-#UXTgT&|_rIVT5=m8P*wFs?YJAPOPs z;aYtf(m{S|Z{`4-daU!ezP%u>*S--^v*z$s!$b?{n)jSO`=*k`DxId z)*HNj|KzY%^3428# z427|pa1tE*6hg5VZ-a^0`(Ty);SYPj6f2xAPd|S859%3PKwpZ7O*7-tkowIL1u*Mr z0xAO)Lt)AS&?!S}Wu}a0bsIKsz#isbZ;Q52v;AaDkXj{7*>4hM~egzn37M$to7yT!61&@jH5Wf<^#ev@g~i zHf(rRfMH8lRnIlfu6mPh(^A9e_Dzf%OXpNO(yXqqjN_d=z}Lr2uqfZRQnWN zRjlhj1n+ZTI;LkM)n`asrYtt~d#JY9We4fO`#>p6$g%!v;jn*dpFv1joe4vWRqXJB z5t4KuZQd!>SHijRs?;Pxq4yI$!bXs&Q(1196bHdE3x zhzWR$GWIf5_pbI%o$WzfqKk7F7)+Ey17du=@qME;b@c*8kz3tDWM_DH_)Q_RG z3@mDSEVqbB#1zfADr+~n;$^T%o~F_p^70cKBZdI8H|R_u8~CfwFnv#U-~CA6?EStw zN&O{7jSg5~b~>JmhFtL)fODFaR0n)3S*S4LJ%O4i($`rmj`|?Aslt40;B6EVx@3Vb z8E)h?a%15Ml(3VVi*qt1Y))g=P&>NB)Jv%hgUJOliXj`OzmU$Ug=>RwN!JwuS*tvh z-$FgZO>jJhNH}U3Arim>pTfFzEsAZG80BAa0^ruGSVp1r8x&%O>HVxgR;CjVtN6tmTn@qWeb#(r6m%^5%QaQ;JS)HfPvqb%z+p<7q@I;F5Na}XH1hv%+B*EC6f;_zkegU z%RJ9}{=K(WUk$*MbmneEaDINzkoO>6)EdY;FoHE?M8K1qbYH@sb)r7}2WJGikL_CRJUJfCdL4XxKG7@Tv#KofZuF94X#lk6+p`pK@fm&45j`7mneZg7BG?|Tb( zl?&3$q;CyE&yg1~-5fB{eJo$rRRo@$--bsR@VmTL*;B>Sd9G2d=W&5DNhzcFH&^p^ zLj@2fn|+!rscw}gh&e#82k%xF#Xp-T21k(qVIK z_4yiqj&}bAP5*ABAJ#{x4Z3Cr*tw^sprb2on|n`w{d=zi294qRE|=464RL^*abuUW z0;}|@N@drRKUFJ?k|UcDyvE8cjNB7JhOoXcb#x}dFjG$nwCJIjUNm&9(yBliLHF#O zo=(7(kTuhdO=`?Fl{vZ+)wCA^Gj@;`zwkuLGHe7pBR!0l5kpF#D>Kgy{95^c0&)S3 z{^op%0$VOPTm#xW!zx1tDTa+&hF*AAk5~Pn`s)Dug!jsm65`juZsLp&nc2nE%ojR*NCGn@#=YHsCUvCsh#dtbR* zDe)XO$g}_rLF>F2-+vzHs*oKPFZ4}6bd~9=O;aISt9do6_{HgulDR@mRo@fAZFMVS z4_BW>6bir7*2O11-%<_tod87})c_A33hATk-hHuq?1uIUN*I>%>EASCtC|fC3_G(2 zF@4t^dDuJMF~}AAX??BVQfXrVMVK}kl2lS~S=6Z8&nxpROzy$rG~?EJRqPd9Co)E# zcO<)EDobjzv4(?0SD*pCYei?MOu3ZRb;@JbunlnHnh>am#=Nt7j~&psXi6nFdfvwXd}b1Qe^47Q;6J?Lgy*av-MkenUa9 KeSQK10fwM$Q%GO{ diff --git a/application/src/test/resources/lwm2m/credentials/lwm2mserver.jks b/application/src/test/resources/lwm2m/credentials/lwm2mserver.jks index a1923e942f923b8d84a989055ec50c2441f79259..d16967343fe4d56689c12353dc34808625155eec 100644 GIT binary patch delta 6129 zcmVf2XzB#HIb@}V^#TtbzyyMVUT0{2e4v0~;<@VUt(UAY z5%)ShDIX)Q$$f>!bOwGHF%`Q={XPQt4clV2L?`*BDYO(WzW>Vh_KE18gcl^>o?306 zcMb27lQux?6&luohssz3@*Oze0tacnNxh!81z;@=i8;*oHmM|i^ofshBhe-Hn1J*CbY zi?%*{U_<6;HO!v&488jG~iITV|jI}^pW@P+8aL3(jb-O31mNW>js8J{+|QfUi|Rp7x@EUamO`(htNA( zB+z=$p;@Hbrhhf4=jOu75!G|ld6V&<^{bxi}KGTlcoi9KOzzk z?HK5HR<>J7YNa?HKdP?y(~ERd!qwWgf2|3;pzgqel1ADjy8zz_(cM@8Ih(`B1MMqP z(^ZV+T9mN2-m~|C_E?dZBPJt>erv7Eu?2hi@?|DyL08Hh0fGVKX6fOv<|&^Wpg4F-+tbB20cxLxw@^fUq>}GndCH@yek8=GDluRrf7-@3 zc!U{G3Q^2-`epuX*MV)dWxvJgE6hw--aTEVR7c!t6{=h6=HWh#Pz1Sjq>oZQeG(BC zg`wZO5JUb*P+>i0G7{71?ivO8K@XkZzJ~6JQ=dp^%51pP-)E<%%0f$%6_=-!1WleX zqNvkti51^#Q))3@uw70B20-|rf08yUMd#AxL4r(M8Jo7C-ve7tLTkO}xD`aliSctY z1hpNXY$nOcH*?M;l#1kx!N)UUD0Jn>7?5$OICfB8WBu`YET+Y?VS{@%+Es;-jx#=O z2lr}BL#;*4rjcQjpBl%VTiv5kGP8hp$(x{1i5WvvPorE=C_8Q5rJe+{f2LlI_8F$Z zwtoa-alCsybJTF0=|#XI>M9MmjNqSKRsn7O=;|Re?iosy#}0lKvAhavrj*s_NdjG5 z8Y!%OzlpT>o|jShP_1rktYo^b(x^F?^;SQy*vF1Tnx8rn^Fzb&PyBL?T0CuIs6<{s zEWC;QoVdRCkb~KyYecbMf7*GAnym0zi!%bPZw4LRCzvG%vEqMAMojEeV99*I7Fl1c zMEYQ|{ZXgeCkd6UJO$zt#6R)}Y=@x>#5E;$hoo^#9+>1uuLvI6rRTSSMjmmkz6j<# z(E48DStLXi-wPDj0d`T!tu?19>1P;wFt-rRH6Kw)eJ9*CH*GPPe~h3TK<2JBwH2QS zJFk`guly;ZUgx7ITh38nbLX-8dDu5ChxzW;YvE^;C7oBddLyr@NgC+Uu~YAJTVLv6 zN-Vk5E!l16vk}yqZ9)UBkC3Mx-_yD@Zi9X!)Rv;!lJWxRJr+uyWfa&3i8@uo=q5tt@N5=nmWHmS3vIO zMOx$G@jvnJ8IaoE$159L^L+OnwTnet6RjOCT`x$4SOhI~f6B<~-~Tt zyM9m}1yc*DR~?72kpx7NBCT^motVxem!{ zTd2w%4rjypf7deg8Qf9DR&!EUsD`cRmfVg(FABI+I9dhsHUj5EXb%mM9N1-J=yk#8{$y3EOtZf6zesEENkx%nBRERH-fVRxZtc zT8$4>^SW5Wh;T2hzRvy%Cv64sR_X@Gb!tn@7+wJ!hlAHrcoEwdN;2b&xhJXDDqO19 z!r{9nmv3JGC7~K8CtUS6MW`091R}Szl3cBhJ13^@g9D90eSyklw2x(t#X5FP1f0wT zHp8+Ef0zM4WIjgVAZnunHBDnhC&?5WdxinFE8J?bn5E#t;Jq;Kf59o;R`$YfgV>Vw z)Exu6_hV|1!B9>Ti~FE!^?JH^s^j_ToTIL*g1t(iIwXCnhE@cRo@)FbGClV6@@Hz{ z+-Vf59NhNx7IT7Is?FS4_422#C#&n*^7mXRe=oJrYl!vk0Dv)da&V3);{^;wAaN*e zM=`S0k8MEzw$`1=nBfq931P~!%9JCZLl5dhLUV&_C6;hL=I?B!1m=pzCy^pT zC)v2f4FpTUpL#Ey_d-@iqmWQjv!rBTYvmN;{Jk%*^HG{y)s)&aP|B!GCt=r0>_y33w<@IvY*aEr| zzE2~tzj;%NhS|OwfFZZz7NkG-0U+6UD50tOGxlwNmlbIj8QNdxXe-}4x zd_S2Ywt+M&@!Iosp(_1OnC8>LMcCyPK!wEraR9tq%p;4Almm}y;;@=V;Gz5JCK!HA z3f7csq)at-29D}vH8$tHQT5H1Jcr#6l~czol$t6e^NW^}ROIy)A7Hgh$lYu_*lrq6tyi`2h4ATgKAQnNs&69rBy7HPPqCj&g(TIJKQh zgHiPX6-+G{*q^==X$|S}auUY3q*5GhP;4M`%wr=28HR?i>%?=fOA?3Tf9yn2L`_N$ z9t-3q5i4@z-FMC_I$}S4$8J7e!?$sut71ODSMOf+B9!Q2P|j@=ji>js;UkI;>T*E{ zA|8vZ)u)8IP~0xceTs^`57}!Y_>9&RXKKjyY>_2j{Tuv{p9K2t?<}7;K8svJ_01s_ zE4i7|%wW8$a_75Y`QCJ^f1@-iGZ7bQeds*>LmYICdS2F^2>@o%?ZDI)j6&1bF-^&H z%`opR5A5)al77Z1U-JOtgHo%RTQ86#V@gtb9C76&$at3|YT_8Jef1oIT;}yZ-u>d5% zKi~x$1w0YdE(>lcxX82Z+=R5{l8Z!`v^VEli??Rbc*FqeG@nERp3=PPrK$?X!+6mN8^kOfe7>)Fs-1=vO;RwRwz3&vd3KDn;PqraKQxM!3}3sH zLl+_Ectdr2o?N-Ll5>x{F$%SS^ci~SBF7xP#@(chdTFeef8`zqtDB+UwygLdFNA^s zi+ItIdPGaPv*+`O15v^9FFW)|L&WvdwK->7aHF#P5gV0^{4D8|lvOX|c>KVv;&Oda z^&f_-G-|E9U4$~3{xm9bMif=zMZmjG-cGw)ggGhB6jLEv5P=2pLyS?O=&5oK-_Va@ zm@=2t5cI||e`obeyiw?-+in7PFIwN5Ct0UqL)Rzz`5BGTe z&^9})LRbL4eLuYYx$?ur<)@>+9s&p@iL;|0tEg=%iu>5kw75#DCbPn(So9(OQGYmZ zK>n{C22ak1D287b?;7z};R{-!(kUIIsVz?Iu(hc4e?is%vpi9zEs|CFcfUwv{D!;^ zAU&B5J?)?p1d)Z=ZmyGzRn8I5%=+Nz1&eyUS6mO$KWF~K$MhD0eVG$knxHQam-5N* za0lNp&r~%+^-~1+h=T&%n3NVY{jGVPhO2>%+mc&n)cu0`)O9k`v!Dx8TIdnm>z?}0 z{I{lmf8T-vsIdab{ls6>d*A}2XnqZr_q`kf%2Mg#82rw1pX+$WanFN=h#nrhce!>j zCmh;otxG80#OkCznd6~vLg{@QPNe%d*ngSMFhgp>tl#E5=n!;{w=zhEI{~k}0n8Z> zBAWSKRCek2#y}K|V>t^ni~G3^$Bs&o{~M)rWG+LsLx)vroUufR=A^R_v< zg07Fcd8-2YEJ3HUWE6OIW3nkoherrbF9ULm-I74}`jet0cd3Iw>I@8zS4Zn>BJjJU zf8#<21BXmZ(e^J)io=!8qy#-D^=UFHtXIk*dRyuCH|gT;TEeFG(OprJ!tz--euMs; z8_@lu0D#3m+)(ThA5;7Ud^Lh;u8Ho^w$^4P#gRsWVfz&9#O(f?{BwHV7yfKLyF4Ju zfSOl!WZZJ*E4`WK-}G$jw}!OV1C<+Ye>(P@VJrE@g2L8bz89ygLa&URHvf{DTBqkj z>1Lq(BFZG(r<7HZv@PzQO=+v+&Nnn7?c%g2LaU{>m{aIQ_Ii*|{*&cc{$ya$1L6~* zJT6S+5Po#cy(-3~-z9Ci)>R$AtdD}E!mbU6qd{J`2&Nn11B4*)YILB5A$b0`e^JYG zQ}vt;+2y~E6M_D~bgZFQyR(iQP*gx=)~O5LS?>#oGG|!eg{2L3FOSS2ZDCCS^)_&< zubbx1hUm*mP8`s#yo;>iGTY7{e96nRTOS3MX;)FaM@}4%jY;*@oY5PNDAlM!k|=u0 za#Te)Qyi@M*)*Z0U#GdXn@p+_e;rW(f=v9y=Y+NedkDv(!!zVIiu9|%HL1V3#=A1z z4Z39tvJZebizMKcid=OtGT#yHc2(MEiW&4c{wfGXenJ0tLUcTp*)6CyH3mf?pt)dy z{FY7m0UgR}PQD+vJfxf7n&Db@NI_ z?Vm9R$$u@%`&stQVAavUUS0Cf2VWUooPOtU=dfjSG^JVhm}5JHq~boeZRj!br;{~% zcdvXq*%=ynl_pIo28;)6NfP(yK|fG)F$-IfBcJ=PB|rILohMLNeq!qe#~Q{YDs@UF66@mP(3I2+l#V^0GEhO=Jg|B@Q0C6u+>YXoP>_orf2FnrmFkAez!=M< z>h9(het(JTHqJzq@i1lpO~knb+S-KO)Hm3$>n)H*dTzwKFuTjH{gk8!jJkldWnJ9! z@uZ2}0@#qSleXKrzwi7MZ)4OP4-%hYkd=H7BbG-=1%2cT<>?BSPhN zw?|u2GN$j>glUGF{U2a~CFLE5gXt%H!CSdwK^vCY& zh9&99nLw0-uAIo&ucTsL29<0K!ZEA*0tjVIje!{%*t)kuj@Ue`Whei42}8*ZH$Pbq zeydB!DaI=ZYs)#3uIUxODpWvm-#+*z6u4vwFG(o~%YA(s+GrW>vIv0R%an(rani0A zMTq3wiFNjue+#BXU(|ZoKmoshi!A2e*#6c5!+^TOBYn0kXb4PDTR4Qua7~PQ~ z>|I_523$cWHh)7@6HkBCJAfm9$8xK*Ruek+|)g4EVGGoNv~cr6R{{Mso9U$?3pqXpOMAl1UZtI z1|gp}*rj6JPqR&*-ARO#=d6Tuel~ZRzaDiB9txF>n7c5tmm2`}Xs$c3vGP6fm&u7W z0|G5U1Zi1|4Pg8)gc!Pb6JUVUg}mbBS%HA&f6L{HiT;38!LyPq^4kLEiCQq`oA(Bl z^0nL=*`^{D6gx%Rh=SSClZU*?ivr-bZE-G7|D(I#&aJ1f!a~+BUR{=pq?21O*j^VH z6~p<3L)8{NEN1;@Kj>4xq|bB``S=dnWE(c3o>I4rzeYMjxd`AmoK^FGqk_!2z;K+i zf0Um6vtx$iD&aYebbdWagN({;pH0LsHCWw_+Qd)gBmv$qw9VyS~dc^`E#9=cI~&b z12L`fmd8<9_<(-}U-T^Rc8JO7Yql)Qf5bz4hSiC#kDgY4dw$0lFX27WK6$@K5P{o8 zSMYDD)tF}ULZXD6G^+f;Gg}fcW1xjJYKn3?JIrZ}oq&OH^4`>*j3WVr8J>udgxdyn z4^=tNpnlzZ=%z@?_%(cnmxIEuGn{I;!mzAU%RWb(xTHQPunN3p4K&c(7e@-tf5SU4 zA+&?`?9!pGcwidjk!vUP=Y3?{w56QVG3t1?-;>72tW~cUKUV$APmOFN*7*2S^9UM; zE0#gPQ=nsAY?_rDtgavupNhyod?WUGnN=zk4@UlAAM|B~7|{gEQ>CUue=uUgPY7>H zpoy=&xw~q@@z<7DbxCys0|ADh DGMenJ delta 6113 zcmV<77ar)aGN3XdFoGEz0s#Xsf*92X2`Yw2hW8Bt2LYgh7{&yG7{V}u7`~ArQWP6# zjErjUA=@a)pLJpCxXOoc^!thV)6Q5SQ3F!FEfs*LtlfaYQ0VIF2n@+N;=9s5rrW0SH+lh(eNdzs$IbutSuC>ulL(>Z@v0p$liUF$ ze?sCJ?A>q7F@SZl0lzW?lz@U2V6G#GthJQvbS+}=C>y5jGxcl9=Vy>Gw{h(Dy~z@> zRsCWm=g`{67RC8<9n4eO13Oh201GD>tG&X4Z0mDL`e)zs-02Y(xFiN&7wcx4^LjC* zN=|NH$o|}2f5MnOfc^!g+(X|$JR{H0Eejboa)-T- zc|P$~S!~X}cFQgcdzqTvfG`_e$qB&p*y)2N7obZ>A8~l2r;Ins+1u-?J)!12{ZoJA z`9gbuQC~LdA-9rCsv+97=@_m5$Or7lDC=)gb^kDetnZ_+jksSprFXO+5EZ!ycJ zO9{iGCr2!o(;B2gel|}JV*`8;O@Di2f4O3g{Cgg|iKf;c09du^nbF}e=?|IGR;irb)Od`O zR_)n*QQsr%JsrBl_F!mxxi2mb2eExL(8d#P#^0l9K7dmk&2yYZIc32&RdU%!+jRjt zIbfo0CQ39XDDz!hmVk`Qq4%;E*b=yj<}e7KL4do0D_aBmFE{4dk~lukf6{%CQ*ey^ zu*`yJF0;oiC}xh`ED={)Je>X7&g+L9+akE?esCckw~+Z*OjAp`!qNbm?XF#_%@+D#zL5+!ZYHc)019rm?iJ!w%EGC0e zy(0!wAnmNnXECn@6>~^Df8whTy%^JS77TV)t(i!L=#~SZ*LaTr@2dOc)w&qn^E-xD z_hNFN4qHqAxCIlBNHsuil5 zC*t>LB|-XOVe%kn1TnXRW?T8cC>xV6GB4m0ocW?Q1lTiUM`{Qpe}J|mXhA)cBPk#P z6*q`ZNqxnWSx{?}!ub1goxmLbPX@df&@v`fe5IWda^pe9j`{p20MVS|CwuT2_ zwEaf$IMDjVcl<(Jf35DWvvdV?Pgd=J4}g>ylPU9I%pb;ZyrGcS6A#DpVW|nIRe`X5 zA|EiGJ+-Gx7eF84ZkUL0r9n(c1mEAJcv`OH_vk`*0Ce?d$wLY6-pC(BzNJj|iP)8H z2&$QY#;n@@RWY3YXxKLC+C#E>ss%UFF(EMjyFrR^p4h4b} z_k+@C8V&<>z}xIclAgib)OWDq^N1>*ML9GIv-ynye}~0doCI+X(XlNC_wNJ7reIc3 zo@0#i{RAq-b+X745wf|3kwVzX2f`eMk(Ko5qS9iC&LWDXArEzX9t%SSYN+}VgjFA? zEgk1Ni=FjB|I90Pm07$)=99D;N+-=ye1GOj+z>ISYj{K7H$Y{?0WQ-WUl48Xu*rV& zMvNtgf8CPu0S9B?Kt#h z${j<%f-@uN2+AK7pwmW<^>iFNTXx||$80MF;f;GQDe_`@VXIIeD1AG+$R70WvX>ip zV!Jod!yI~CfT4->%yQ9vgA76dfS#gTKhkd?f1iDjS7wP6;-&F&X3RzkQ9)cN5^=f% znZGUn>M_WH$n>tFu225kpCC(_dQ5cj9X>RA_GnNhUXbc ze?Y*WDiF<`1n(LX=!50uDG+$1l&hr9@%3DOw3|0oV}H4DfoZ~QM`CpX5Mi|x7py=C zQ4PSF?hX%D#}4WY9V8kaKMh!C1hFQ&qCuQTo=n&wLE=Fa@m~Y>%mH;NA^e7(C%uXY znIJ`Rr}gMd&v2i)a?1k1X{iMYLoo{re^v0Mp05SS6TIN}4F~^o9T}I_+6iZ_#`#sm^d=C2e2?IMzY1CiOv$roTh4>YMFzjoRFEVLvoe5<$rqPKG*b+i0_aM zFJ1^6Se>k--YAgwN~BiW^(00?_}em>ezaQVi=QHmaysC3Svt*ntbk(6;F23jfB7&= zuMevV4{=1=pLS+{#!=ajzUW|xums=Aub+5i&@@5rgNPLgZGOYv4S9D}n;nl5a|q>T z3dOhei!ErE7I(>ltGj@lHOjoOFPJlYw%1;HPIosiB8A7Drj!jvl51Wh{CGAAr(>Ayu4NCqLxfXK2ICif?7W?nl)$qKq4fA_le06e*# zip!eb&tphF9;^w?bDibu&td9&lyi zej0DrP#k)9M%Hn0wrClbf0VA91rbzXUOTg=5I&@jZCpAyT|W}m!24@72kLs*jaAl~ z4{9j2Yz@HYXWE;))lZJ#bF^f`iCj}_k!gW%?O%oc+t-fh6+lp;K2-Q4j0ZVRSEub0 zPP}^q5wzWQrgBp`XyID%>|dZ3s+^z%F@L~c>e1>D@!Ds5MXRt^e?VijRHq8C!1t;2 zkXKN1S8ohM(s4P7);1;!sk!Ar_t-$S+a%69tI(I^mKe(yg}%mHcPnClC4KspjWvLS zNaP(qzABwiU2FQZbGO`+kz=Y#B`bW__MIaq^-szOI{fwG02OygAG=mKb8V~meIUbA zGamMJt8L>vHEjXPe~MHozOyrU+7JP~L?=`JFyoISeSxYf@sP<7GYQp+!oLw%^VS8o$*^^HC_O?n9Ax zuMOf-_w%zSQ%(ip=`?(NQdMuY7)vQa$gFtI@ZF5u2gg}@#`GY@g&A>VtL`O_@Izlg zZtcB7B(7EdOwfAoI?^tcY%AX8EV_97JcWLI5z)Oye@umB-0lDQ7D}F=5lFY<;P{Ek z8Ix}ZP(OW0x&M0bNRgo;e;J28JO|n-CpK1Ry{%GAKlqW2xT8OlmPS(UC5-#e)X{cN z81@l(?38mPV=E;g(`8pd#x(qpWm<@;eOF{ei^LaC0m%Env?jDDe5!cgZy=Wh9XKWN z7A+7pe-G*bO^d!S{bqAvm4xBL(MQg)E*nMerTo;IY%rjbCkym^K{7rtf>mDjXv8MW zc8ujbq?G%ARc&#(Q3{hj??9ZOQ+$8P0&o=;o$dY_D!Noy-*IUyW@_yfjwUC=$pPuN zT=9o}Ugb=!27~pnB*@@_rvrC?1$uX9XC83nf1OV!Qc?vI7ts$k^`Gz*oB6j0Mq>po zR6xsFWc4Qm6&=@(iF?fm-Rpxuo{bLd#4#asqY!;4KPeCx!q37~h$RBx&wXZrWui9H zIcNG|C@*X?3<=AK{rEpW{zye+a;B7LL8+6kN=wKo*l2P5A(ZxTa=8#p$9I z`CVG-rpARcl`FLU7}C)66^-KqNMO27ji58|H3*3jfHmob4|xRyyCRk-W|m zeny!5Yv6eY`I1MaAl6aJlZ0`{a zq-?jg>89l$ixKsxYwJlOGw`H}wJ1h~TTcq)bYJ-$-Xmyk3GPx&*1DChsok$7I>ZX(SG% zK2AAp=P$^7Ut!>%1X1N;VDrL1`x&eFaL@`O7{K|!oRFVhRUT;5ZEGNk^`Tq)bZeaSXi_heLUxBu-i2 zB?^djrM!Pcy;naJGcXZAJR6RtOaR_vO70%>xGoYH+E+b^#r>COy=nYgWb!}8Iu%(c zhP6Zu#SGj8xAmpeCHxD??5?#BrFUVD2tbD z16+O;M_`-07sK^VEmhi#g9%9dLh)$f0<@a zY$QP(|2m^S${cJJfq-X#XPCE)7O>O6P$F1|n^ei5{!KU`%VAa@(sif!QA|ooN&8_G z{^5S7z$iO2rDq^}ES;^IcJxg6-TJ>>lG*>|{2oT(OaHpce@%I(2X(IhvC;dDETmC$ zw9y~p2Qr$|6m=(r#SE{Q2n!ZLQ0-o<{mcP=1FM*6VtkY;!Dhn zcT)FzbfCh1f3}af2s-cb&14)ANU)GEe_9ok3xL14Bre2_a@Di5rql{Yp&YCj2$I!M z?u5WBY58)xVAKOIrZ7TIZ|1h+5PO3FgB~FY+mZx=l~Ph%&XquD&aB3Kb7`A&jo$Y1 z-^-e|4-KJl(fBLkrWFC%l^%=i0Y@x9SO8GE%u&$Hf2>dR6po7A&g2Sdu-m^uwnf*c zGCKTXO73%whl2{IK4R{JA+-Ui?X^aVxsCw>H0&%`W0faC6p2YS_K`;PFVTo|fbOdv zCoh;(2GAZvv2OajtL;1ny;io~hU^IU_QcWR2@{dX5Cid=F7jtM@Ay9$*}u{+A;RH^vE^Syi+e=qP5;%fdwFDkJT ze@m~5Vlk(}mfH=1BF^_UkL`yrRqc#I zXqkQak;f#EjZ)e)?%K0_CjRFdxKgTP0O1RnQc;hz`^f0eeM&U7ZXbkfp#3y>RGOz2?;j2_qo=ih&tiugDjGaT8xd|i2 zrhi4V8`qvmF|n;V%V3Nr+@_!De+9kuJgcHRJ6z3oboe5-PoC2uJAT9GZ0yw3!-pn( ztgzR(J}y#~C-)~B>syRzr`bAHbXDM4Gn0bP>6rABG(WG-1FKZ80x>cR-_*^=c%gPl zd4UXam%NU{g*KFaUkcGe^lh6PVT?oFiRby3C+p8)RXd)i&VZ}0t8y^LUpw#E|Drrk zuqB%-u=Sw_8H_D#YsP2_7W&JCIF`u7Fg`FLFbM_)D-Ht!8U+9Z6e^ZL9DlPFXBzfE nQUIeRS3#U+4g?e&Jr=!EzAJ-PdK`l2rG?gLKs){d0|ADhwvw&E diff --git a/application/src/test/resources/lwm2m/credentials/lwm2mtruststorechain.jks b/application/src/test/resources/lwm2m/credentials/lwm2mtruststorechain.jks index 2e46c718898093e907b646f2aa3051d7309d117c..b97f3629cda96a9c428c2556c4728310d0fbf431 100644 GIT binary patch delta 2678 zcmV-+3W@cm7p51GbQE{rbtP9;20wjO)NQ8~sGAdmyh99PQ zpAhH-fshA;Bk1!qfaFu8%alna)uK!xi#5vPXv#WJb`|OEf&50GeKl-dwnhw=KLN)`7W&leCi_Mk}k2v9sc&wU1+kN5c$7O()oIH3ex zC&6BUseS`0EFB~)uxrmiADFoP-n|V0SfDB}^8o$|@hsnx_p|&~3*~dD^>Ve7PXSp7 zH#0LgFf%weldu6w6n0Kq@vjCQ53KMK4^T&s!;-s^Z<7uJB!4h4M4n@BCI)H3C(s)a zje&rI2_VllZ>wkQ!D4yI1JSXg6-1y5lxZhgbc*%Atm4rd)78{x+N6OSEz~h`LZaE- zc_3gs`<#1F^q639Ezmlx794tXv%VzzD|WOKy_YiOvy!Mu>=W!Wa%KLjyrm51Tu}s$ zye5!9qfdO)Hh&_OnV6sX)}>U|kTDtk48eQ-S{lLXY{RJFQj9Gi8M`RGw00P+H=mdo zrihG1$ zAUXI-_=5$itFIl(VS>JF+#wvjC>KcGZSUWHs^c|ti9qB1p;b4TNNGC6N;hXsXF2-Z zq4@|yMyB2|)qU6MFl^M zjQ^>5&ws8=*tj;ejG|zC6R{Q!FMR0?HakRcv4K_TPk2^Zr`Nx&Z2$8e1rF&Wfhp$r zSCFSQpZFN+orDgYf+yu1$zrB#=K@BxsMfSKp<;&*E^v&ZS2&kA8~Ye`{6*UC?J86; z)pp^g&cEjQOScMy5gMjDhkCe~mO&_=sS4)|6n`1F0p7VFdG-T23BxZ~?3ve0?=s?G z{@0?ouo;u!c2rWN$Hyk25pff?=heQK*-iOl$6ki4vk)^iK*#inm9m&JRO#K@Wzk$S zZJNnS0@UQ;DWKo|`AeU8yjdUuDaXYzG3E4o#{;*^Ba&4%OUK}xawj4px7%!^vE91W zsDCEial_}$%{eD!g&KOEKUt~N%mOsQJ%wc|M$L9kYdubC7@utsx+ZrNctR>^4Id#g zIod+At%sO&P$f#GK(!Kw0tlgC@;D5813VeFPycJsA*V$9ywSi~$X`T`ADC!Kg zS%}&sAdF6FXxL8H`#UZxH*qI+S%kI=Q-7(g=ZlZ!wrjdK_QRjEbJrBxA(Mr(;9W4o zNXtmOuTViL{0X;N-8LR<(r~6bdEd@6O)JixzB>?^PD=uP@3o0GTe>=K^93l`^@h5^ zYjq6SXEs~j39o1dgvj**93H<+@Ui~X6@lYH@WpB+(X_-*iEg zqfk|nkOQACoab6N2AE6Di?lH98=2_G+$KmE&H78?-VcEBJ@vHeAK)SO%;ZEt$>#zs zr>s3H<4-*yW<4&AAI}tk#lr_+`ziI$0Ib11g67@KXX^G9^TO_9#+fjd?|S}(U3HyE_{&su|bt{=LO#oAp++bSl>j}Crl zSPLTrSgqKv;aUg|sL0Jv^aQ>qnGKh-_Z>u<3p}zd)A*`u{KmZ&_G4&H-*b$Ik7MC` z2GH`yM{lp*_s$YjzPUTV1Aoq65BKWOG)OZ*_Y)>U*L&0M@FCxx~(d` zFr)kyF2ong`}FRjx^K#MThP%WfNYsY!sXQ@gOK zP#q(bYaM{NeW4~5CgaEYh5UZdl}AMb?_;XYLoxluECpvy>xktnVSf!*505u^0;X1ha^SJNSw_*kB$DO& zg-Z%FC$^BWEe6>c_Fd`%gkdW1}h zn1wYz2Uhp*oDMo4xUKOp9SUu{gXPD|utN#h)Mi?MbwBoPKq0?+)PGIlckj0=$WIwY z24fZi?3zyWK-$vtvu!_*jbvVK+!j&`uR)LVGoA6@x`ZY;j0<;UdaZ@RIv6R8TO|(m z+@+!l0rK8dHQ9M-&Wq%q&u-PR9@jgVEZpSw|E zz0%{;87J2ZfK-D;XYOm2|U7_MNM{Te;KGj z35MTGsu%lDwcUsyU6QB79{0WXvIXs;!vQs~`pqiAEeC-IYUVu|zsaBMpE>fFN~I?K znDA2O*B(XKsVkg>U~&mM#;t*-*Dx~$JaJPsU9#wGU0GZW z3=m3`6MqkLm6gb%RLH8pDnd6Y51lieqgz??Rpk6<1dixRzI( zF1<)AsRMDoA)Ej_ufG{%qE7$J>8zk4#mlhQ&iH`=VCwF12+^B zfJz5bEN_EKY13p(fajRNHJ%5Xi*7$LY+*b4})LK#Tc9jrnph_M_ zt}f3KHETlZ^ipZ$BRt7K0>g<}HJyIOW^gFrwq4r1ww)rC1`%BJRA|Z^l$wfx7L78ts`!^a&~1JeDR01>|mG}NX?{i{F@ndbg8n#_jsCt&c*|+r~^?v9X}wy zoPP|hkB_oAQ=yKuJ?cyqwY9RDLct#aVBr%?4AHdKo72+0ew$SwyGROV(!+$EXQlwh z@cbSirsj{h^u1vwOc;9Ef3%P(Fg`FLFbM_)D-Ht!8U+9Z6ft8ca17GGr$$e!zf-Q$t~cN^xFxY00P?@e%0?gzb10s{etpqAVfod5s; delta 2678 zcmV-+3W@cm7p51GbQH(aO-Y7;ZV!Mmb11W#!hXk~Say>R0wjMDmSBc)Q*o^d7$Tu3 z!?ha(fsjs=7DFSwS{-rKtSe?&p!$d=UXb_$IX+f-rWmOBAQ zxFrJxRGIJ!*epSfaM2n38bLH@Y<|n<>Byo@u}T;FRe@VyT;*Z*C%}SxkF<4-^72V6 zNx-y+O?*3-I}9X#c&I-izaq_lLix*6K5{+yme=YMNf$)$nc|D3I^wd$SN}?rPXSp7 zG&V3fF*!Fildu6w6kH7b&1-^XYXT5kb!zw(6Q~(R0h0~_B!8#X1K7wYz9s>_i_pfp zA-jNr2_T1Smc8D#76R4ZV5<8!?EAXelXUv{$Fszdle?OphbHP)H$7S>ho4r3D}1^L z8SBxUhI7LHZ_Rzr%16ZFKV*&Vu8>E7S7kj`0stZTZ#x=0^{NbgAOg<|X3wbR385x_ zkD!$Wh7l;k)qhQPZ=77HfD@C&e+!~?F6ur1Orh&Y*@ohzGOD70d91I@hxx&t_^<3h z@{;yPD5IZ@z&h3pb$z>QM0Wa2WmiD|fEM16ib_q?>_y)!D84}Uu) z?q6w9OZyrW7`<1>wowCH?+&gS2;D@3*@Pr*P-$+B7MCY4=+>)G8~8+`Q9Y74pbJl+ zC@;x1Qh#fF1cI>vxNp<%6aRqCLDNZDf*j&NRH4-z_FeM3uvMxPSioj;L2A{7q|{AGN@M!L}=-i(=_n z5Ai7D&+-FQ((u%n2z)62tIi*4MAd1kDN-}O$++fco<;)+x9;JrXxyltA{}6~F>TQE z?gJQLx{ekZi0to(^hr~`Y-hH>z+<;0rkxm6ej>W zv42bJVk)fd!xpzJcZpldd=CDT(o2#fZ~{$s7^0aVz7Y+sT2L!%@h7w(F)@)%=;Pf! zVIW3!;t}oI!K^p``Z0TbsXUh`p=}!}{JmdFkDrkpGQFdZnp|3r1vcz~-B~qTy0rEN z0X-8Jh_c^UJFvHvsb-LadkP`860O$iT7S)>J9`zWj;j1^H@Y!bVB|e5Wt96Q(*GcT zB29UZ<1;gSPNv66?l02TuDC-V0v?II;w4dKhtwWjo7Ko#f>I2>p%c_N2@NqEvJ>+F zKG$_IodQ|J&Lnhp>Sj<0{uc1|m+UY9h!iLGHM-EQBoSW8S2G=pw@zpzE2T4n2Y=X` zw`-nsgaPuDo}1q<=m39p=t{t>C4aqaXK zM|I_!=03BQ8lSuPP2MC)q^njyFkt7%SEhMoKh&Lu)>lF`@n*pLnLm%*TVRl;umOck z#&5GkLwboj?&gsqkAPjqWQo0|Cx2opJEwEvKW~E9$K$8|Jd<2ZTbfo6f6Cr++Co_R zS^s+Gc`Ht)*99H}>$C_&Oo^@Y98Wd~EO_5u5F=KJTsqhUjgzH1$c0Y5#Pl#SLJr3+ zZv2o#H$9P(hJXfSJrIBywI0v8EHvTlm`U9Zf2!KiDflM;RUCBWquZKZg@4|6(=}r$ zr=(m0$Ms7zo|gJQ*fCRM)g=cK%2PxmST^9m8+UaB<N8|r zIVjNN82(Yp?cQt933Lss7A{Qv0@=vxZiR=Vm8R5kYA{cxB|L>QRGEC^12f}h)Y2O% z&dLy8ETVDpuz5Ra*3%a83V)yWfS57F)(Z@R0aA`2$P7VIp^2w5ZKSG70F?W9u*NVW zi#*ww@^DkJO1UV46vIYx(Ek(2ZsB{?=^l2dq$~0vHFw=}2yWYV`p5VvpO6}13Rv~3pUSaD8)`q;3ke+b5t4VO&(0`9yt7<{hFpbCp zJ%vRRPhm3Rp#C(I#il>{P8B8NR(Zn+wp#wNgo5bbv+EWeY%-L@sJR9X4jys^$WI%8 zv^3IiR``;=+V)LSlnw62g;q>8_S?VHVz}U&58{~GP4_Hd z_#~L=`iGv>1In;dpnvV7g+sEwCaRHT6VEm__KZ4NhFZ=PH^J(8-{_udz2tLp^#FRk zGfgw-<34FGRbCzDZz5J1?n*y8!BQz)G=H<_%}h?_)YzN>=|S4& zXB%7~jXA^@$JDGp+A!^2`+iZC#Kq7_N^otb2Z<5|pyNFIWn8&Fyc(?>+CrQ5@05M? zU%Eu$JzCDfM@{?eSh#JwFOW{{3RsSLZsun7KV%gWn=Vs(r(iCK^!zrGZ;?sd>;>-cL zh5JpnNdyh2Gr{0!@p(m`sWL>XtJ}DnWiqxEIkq`@)V2f0Z_{ebx@iP@d~FC69&yPJ z=?C{8Ng=M^o>fn{=_fr1D8=n^m!G>}e$j#1p(%@S#edQhQv%avJ;Z)u*@P9dfxe~c z{CzQpMk9#})$Bk)$gwI_HWm`v^F~=z=PpmI0Nn-PO`Q(X+>K#hVY5;JbbI^|vFx!f zhaal2s_>x<`?Ljl`-#V&i)m}?ra48p$6471_D;2N5WOWI@-1;Ufgm59yw(-Ui`(s(`FBUyqRg2;o--T<75AC1CvzGU9FP0Cy1P?Z;H-}MARtqgoq!6hMzN6jFil<*^o8pbmg92tnPVVCJ@zc{3L /dev/null <<-CONFIG CONFIG echo "====================================================" -echo -e "Generate the root of certificates: \n-${CA_ROOT_KEY}-key.pem (certificate key)\n-${CA_ROOT_KEY}.pem (certificate)\n-${CA_ROOT_KEY}.csr (sign request)" +echo -e "Generate the root of certificates: \n-${CA_ROOT_CERT_KEY}-key.pem (certificate key)\n-${CA_ROOT_CERT_KEY}.pem (certificate)\n-${CA_ROOT_CERT_KEY}.csr (sign request)" echo "====================================================" cfssl genkey \ -initca \ @@ -286,14 +294,114 @@ keytool -importkeystore -deststorepass ${CLIENT_STORE_PWD} -destkeypass ${CLIENT done +#keytool -list -v -keystore ./${CLIENT_PATH}/lwm2mclient.jks -storepass client_ks_password -storetype PKCS12 + +echo "====================================================" +echo -e "Generate the root no trust in ${TRUST_NO_PATH} of certificates: \n-${CA_ROOT_CERT_KEY}-key.pem (certificate key)\n-${CA_ROOT_CERT_KEY}.pem (certificate)\n-${CA_ROOT_CERT_KEY}.csr (sign request)" +echo "====================================================" +cfssl genkey \ + -initca \ + - \ + <<-CONFIG | cfssljson -bare ./${TRUST_NO_PATH}/${CA_ROOT_CERT_KEY} +{ + "CN": "ROOT CA NO TRUST", + "key": { + "algo": "ecdsa", + "size": 256 + }, + "names": [ + { + "C": "UK", + "ST": "Kyiv city", + "L": "Kyiv", + "O": "Thingsboard", + "OU": "DEVELOPER_TEST" + } + ], + "ca": { + "expiry": "131400h" + } +} +CONFIG + +CA_LIST_CERT_FOR_CAT=$(set_list_sert_for_cat ./${TRUST_NO_PATH}/${CA_ROOT_CERT_KEY}.pem) + +echo "====================================================" +echo -e "Generate and Signed the intermediates of our no trust in ${TRUST_NO_PATH} certificate: \n-${CA_INTERMEDIATE_CERT_KEY_PREF}?-key.pem (certificate key)\n-${CA_INTERMEDIATE_CERT_KEY_PREF}?.pem (certificate)\n-${CA_INTERMEDIATE_CERT_KEY_PREF}?.csr (sign request)" +echo "====================================================" + +CA_INTERMEDIATE_CERT_SIGN=${CA_ROOT_CERT_KEY} +CA_LIST_CERT_FOR_CAT="" +CA_INTERMEDIATE_NUMBER=0 +while [[ ${CA_INTERMEDIATE_NUMBER} -lt ${CA_INTERMEDIATE_FINISH} ]]; +do + CA_INTERMEDIATE_CERT_KEY=$(intermediate_common_name) + CA_INTERMEDIATE_NUMBER=$((${CA_INTERMEDIATE_NUMBER} + 1)) + + cfssl gencert \ + -ca ./${TRUST_NO_PATH}/${CA_INTERMEDIATE_CERT_SIGN}.pem \ + -ca-key ./${TRUST_NO_PATH}/${CA_INTERMEDIATE_CERT_SIGN}-key.pem \ + -config ./${TRUST_PATH}/ca-root-to-intermediate-config.json \ + -hostname "${SERVER_HOST_NAME},${SERVER_LOCAL_HOST_NAME}${SERVER_PUBLIC_HOST_NAMES:+, }${SERVER_PUBLIC_HOST_NAMES}" \ + - \ + <<-CONFIG | cfssljson -bare ./${TRUST_NO_PATH}/${CA_INTERMEDIATE_CERT_KEY} + { + "CN": "${CA_INTERMEDIATE_CERT_KEY}_TRUST_NO", + "names": [ + { + "C": "UK", + "ST": "Kyiv city", + "L": "Kyiv", + "O": "Thingsboard", + "OU": "DEVELOPER_TEST" + } + ] + } +CONFIG + #openssl x509 -in ${CA_INTERMEDIATE_CERT_KEY}.pem -text -noout + CA_LIST_CERT_FOR_CAT=$(set_list_sert_for_cat ./${TRUST_NO_PATH}/${CA_INTERMEDIATE_CERT_KEY}.pem) + CA_INTERMEDIATE_CERT_SIGN=${CA_INTERMEDIATE_CERT_KEY} +done + +echo "====================================================" +echo -e "Generate and Signed the client no trust of our certificate: \n-${CLIENT_CERT_TRUST_NO_KEY}-key.pem (certificate key)\n-${CLIENT_CERT_TRUST_NO_KEY}.pem (certificate)\n-${CLIENT_CERT_TRUST_NO_KEY}.csr (sign request)" +echo "====================================================" + + CLIENT_CERT_ALIAS=$(client_alias_name) + CLIENT_NUMBER=$((${CLIENT_NUMBER} + 1)) + + cfssl gencert \ + -ca ./${TRUST_NO_PATH}/${CA_INTERMEDIATE_CERT_KEY}.pem \ + -ca-key ./${TRUST_NO_PATH}/${CA_INTERMEDIATE_CERT_KEY}-key.pem \ + -config ./${TRUST_PATH}/ca-config.json \ + -profile client \ + -hostname "${CLIENT_HOST_NAME}" \ + - \ + <<-CONFIG | cfssljson -bare ./${CLIENT_PATH}/${CLIENT_CERT_TRUST_NO_KEY} +{ + "CN": "${CLIENT_CERT_TRUST_NO_KEY}" +} +CONFIG + +echo "====================================================" +echo -e "Add the client certificate no trust (${CLIENT_CERT_TRUST_NO_KEY}.pem) to keystore: ${CLIENT_JKS_FOR_TEST}.jks" +echo "====================================================" +cat ./${CLIENT_PATH}/${CLIENT_CERT_TRUST_NO_KEY}.pem ${CA_LIST_CERT_FOR_CAT} > ./${CLIENT_PATH}/${CLIENT_CERT_TRUST_NO_KEY}_chain.pem +openssl pkcs12 -export -in ./${CLIENT_PATH}/${CLIENT_CERT_TRUST_NO_KEY}_chain.pem -inkey ./${CLIENT_PATH}/${CLIENT_CERT_TRUST_NO_KEY}-key.pem -out ./${CLIENT_PATH}/${CLIENT_CERT_TRUST_NO_KEY}.p12 -name ${CLIENT_CERT_ALIAS_TRUST_NO} -CAfile ./${TRUST_NO_PATH}/${CA_INTERMEDIATE_CERT_KEY}.pem -caname ${CA_ROOT_NO_ALIAS} -passin pass:${CLIENT_STORE_PWD} -passout pass:${CLIENT_STORE_PWD} +keytool -importkeystore -deststorepass ${CLIENT_STORE_PWD} -destkeypass ${CLIENT_STORE_PWD} -destkeystore ./${CLIENT_PATH}/${CLIENT_JKS_FOR_TEST}.jks -srckeystore ./${CLIENT_PATH}/${CLIENT_CERT_TRUST_NO_KEY}.p12 -srcstoretype PKCS12 -srcstorepass ${CLIENT_STORE_PWD} -alias ${CLIENT_CERT_ALIAS_TRUST_NO} + + + keytool -list -v -keystore ./${CLIENT_PATH}/lwm2mclient.jks -storepass client_ks_password -storetype PKCS12 -rm ./${TRUST_PATH}/*.p12 -rm ./${TRUST_PATH}/*.csr -rm ./${TRUST_PATH}/*.json -rm ./${TRUST_PATH}/${CA_ROOT_CERT_KEY}* -rm ./${TRUST_PATH}/${CA_INTERMEDIATE_CERT_KEY_PREF}* +rm ./${TRUST_PATH}/*.p12 2> /dev/null +rm ./${TRUST_PATH}/*.csr 2> /dev/null +rm ./${TRUST_PATH}/*.json 2> /dev/null +rm ./${TRUST_PATH}/${CA_ROOT_CERT_KEY}* 2> /dev/null +rm ./${TRUST_PATH}/${CA_INTERMEDIATE_CERT_KEY_PREF}* 2> /dev/null + +rm -rf ${TRUST_NO_PATH} 2> /dev/null rm ./${CLIENT_PATH}/*.p12 2> /dev/null rm ./${CLIENT_PATH}/*.csr 2> /dev/null diff --git a/application/src/test/resources/lwm2m/credentials/shell/lwm2m_cfssl_chain_for_test_All.sh b/application/src/test/resources/lwm2m/credentials/shell/lwm2m_cfssl_chain_all_for_test.sh similarity index 78% rename from application/src/test/resources/lwm2m/credentials/shell/lwm2m_cfssl_chain_for_test_All.sh rename to application/src/test/resources/lwm2m/credentials/shell/lwm2m_cfssl_chain_all_for_test.sh index b3b114cb28..c869366ac2 100755 --- a/application/src/test/resources/lwm2m/credentials/shell/lwm2m_cfssl_chain_for_test_All.sh +++ b/application/src/test/resources/lwm2m/credentials/shell/lwm2m_cfssl_chain_all_for_test.sh @@ -27,11 +27,11 @@ Help() } if [ "$1" == "-h" ] ; then - echo -e "Usage 2: ./`basename $0` \"Information is not displayed\" : \"Keys for the server are generated\" : \"Keys for the clients and trusts are generated\"" - echo -e "Usage 1: ./`basename $0` true \"Information is displayed\" : \"Keys for the server are generated\" : \"Keys for the clients and trusts are generated\"" + echo -e "Usage 1: ./`basename $0` \"Information is not displayed\" : \"Keys for the server are generated\" : \"Keys for the clients and trusts are generated\"" + echo -e "Usage 2: ./`basename $0` true \"Information is displayed\" : \"Keys for the server are generated\" : \"Keys for the clients and trusts are generated\"" echo -e "Usage 3: ./`basename $0` true false \"Information is displayed\" : \"Keys for the server are not generated\" : \"Keys for the clients and trusts are generated\"" echo -e "Usage 4: ./`basename $0` true false false \"Information is displayed\" : \"Keys for the server are not generated\" : \"Keys for the clients and trusts are not generated\"" - echo -e "Usage 4: ./`basename $0` true true false \"Information is displayed\" : \"Keys for the server are generated\" : \"Keys for the clients and trusts are not generated\"" + echo -e "Usage 5: ./`basename $0` true true false \"Information is displayed\" : \"Keys for the server are generated\" : \"Keys for the clients and trusts are not generated\"" echo "This Help File: ./`basename $0` -h" exit 0 fi @@ -53,13 +53,13 @@ if [ "$IS_IHFO" = false ] ; then ./lwm2m_cfssl_chain_server_for_test.sh > /dev/null 2>&1 & fi if [ "$IS_TRUST_CLIENT_CREATED_KEY" = true ] ; then - ./lwM2M_cfssl_chain_trusts_and_clients_for_test.sh ${INTERMEDIATE_START} ${INTERMEDIATE_FINISH} ${CLIENT_START} ${CLIENT_FINISH} > /dev/null 2>&1 & + ./lwM2M_cfssl_chain_clients_for_test.sh ${INTERMEDIATE_START} ${INTERMEDIATE_FINISH} ${CLIENT_START} ${CLIENT_FINISH} > /dev/null 2>&1 & fi else if [ "$IS_SERVER_CREATED_KEY" = true ] ; then ./lwm2m_cfssl_chain_server_for_test.sh fi if [ "$IS_TRUST_CLIENT_CREATED_KEY" = true ] ; then - ./lwM2M_cfssl_chain_trusts_and_clients_for_test.sh ${INTERMEDIATE_START} ${INTERMEDIATE_FINISH} ${CLIENT_START} ${CLIENT_FINISH} + ./lwM2M_cfssl_chain_clients_for_test.sh ${INTERMEDIATE_START} ${INTERMEDIATE_FINISH} ${CLIENT_START} ${CLIENT_FINISH} fi fi \ No newline at end of file From be23dd2f7cfa43c1de39730d7a371208da06d454 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Sun, 9 Jan 2022 20:04:42 +0200 Subject: [PATCH 353/432] lwm2m tests add no trust and clear comments --- .../lwm2m/AbstractLwM2MIntegrationTest.java | 8 -- .../transport/lwm2m/Lwm2mTestHelper.java | 13 ++- .../ota/sql/OtaLwM2MIntegrationTest.java | 4 - .../rpc/AbstractRpcLwM2MIntegrationTest.java | 9 +- .../AbstractSecurityLwM2MIntegrationTest.java | 89 ++----------------- .../sql/NoSecLwM2MIntegrationTest.java | 1 - .../security/sql/PskLwm2mIntegrationTest.java | 9 +- .../security/sql/RpkLwM2MIntegrationTest.java | 1 - .../sql/X509_NoTrustLwM2MIntegrationTest.java | 4 - application/src/test/resources/logback.xml | 1 - 10 files changed, 18 insertions(+), 121 deletions(-) diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/AbstractLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/AbstractLwM2MIntegrationTest.java index 0a95dfdbc9..09495402f3 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/AbstractLwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/AbstractLwM2MIntegrationTest.java @@ -67,7 +67,6 @@ import java.util.concurrent.ScheduledExecutorService; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; -@Slf4j @DaoSqlTest public abstract class AbstractLwM2MIntegrationTest extends AbstractWebsocketTest { @@ -135,7 +134,6 @@ public abstract class AbstractLwM2MIntegrationTest extends AbstractWebsocketTest protected LwM2MTestClient client; private final LwM2MBootstrapClientCredentials defaultBootstrapCredentials; private String[] resources; -// protected String endpoint; public AbstractLwM2MIntegrationTest() { this.defaultBootstrapCredentials = new LwM2MBootstrapClientCredentials(); @@ -197,11 +195,9 @@ public abstract class AbstractLwM2MIntegrationTest extends AbstractWebsocketTest wsClient.waitForReply(); wsClient.registerWaitForUpdate(); -// this.endpoint = endpoint; createNewClient(security, coapConfig, false, endpoint); String msg = wsClient.waitForUpdate(); - log.info("msg5555: [{}]", msg); EntityDataUpdate update = mapper.readValue(msg, EntityDataUpdate.class); Assert.assertEquals(1, update.getCmdId()); List eData = update.getUpdate(); @@ -264,10 +260,6 @@ public abstract class AbstractLwM2MIntegrationTest extends AbstractWebsocketTest this.resources = resources; } -// public void setEndpoint(String endpoint) { -// this.endpoint = endpoint; -// } - public void createNewClient(Security security, NetworkConfig coapConfig, boolean isRpc, String endpoint) throws Exception { clientDestroy(); client = new LwM2MTestClient(this.executor, endpoint); diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/Lwm2mTestHelper.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/Lwm2mTestHelper.java index 0ea700d46c..8dd44d25ae 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/Lwm2mTestHelper.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/Lwm2mTestHelper.java @@ -25,18 +25,16 @@ public class Lwm2mTestHelper { // Server public static final int SECURE_PORT = 5686; public static final int SECURE_PORT_BS = 5688; - public static final String HOST = "localhost"; - public static final String HOST_BS = "localhost"; - public static final NetworkConfig SECURE_COAP_CONFIG = new NetworkConfig().setString("COAP_SECURE_PORT", Integer.toString(SECURE_PORT)); - public static final String ENDPOINT_SECURITY = "deviceAEndpoint"; - public static final String SECURE_URI = "coaps://localhost:" + SECURE_PORT; - public static final int PORT = 5685; public static final int PORT_BS = 5687; + public static final String HOST = "localhost"; + public static final String HOST_BS = "localhost"; public static final int SHORT_SERVER_ID = 123; public static final int SHORT_SERVER_ID_BS = 111; - public static final Security SECURITY = noSec("coap://localhost:" + PORT, SHORT_SERVER_ID); + public static final NetworkConfig SECURE_COAP_CONFIG = new NetworkConfig().setString("COAP_SECURE_PORT", Integer.toString(SECURE_PORT)); + public static final String SECURE_URI = "coaps://" + HOST + ":" + SECURE_PORT; + public static final Security SECURITY = noSec("coap://"+ HOST +":" + PORT, SHORT_SERVER_ID); public static final NetworkConfig COAP_CONFIG = new NetworkConfig().setString("COAP_PORT", Integer.toString(PORT)); // Models @@ -67,5 +65,4 @@ public class Lwm2mTestHelper { public static final String resourceIdName_3_14 = "UtfOffset"; public static final String resourceIdName_19_0_0 = "dataRead"; public static final String resourceIdName_19_1_0 = "dataWrite"; - } diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/ota/sql/OtaLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/ota/sql/OtaLwM2MIntegrationTest.java index 95a0a774a2..e3c538c928 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/ota/sql/OtaLwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/ota/sql/OtaLwM2MIntegrationTest.java @@ -138,8 +138,6 @@ public class OtaLwM2MIntegrationTest extends AbstractOtaLwM2MIntegrationTest { @Test public void testFirmwareUpdateWithClientWithoutFirmwareOtaInfoFromProfile() throws Exception { -// String endpoint = "WithoutFirmwareInfoDevice"; -// setEndpoint(endpoint); createDeviceProfile(transportConfiguration); NoSecClientCredential credentials = createNoSecClientCredentials(this.CLIENT_ENDPOINT_WITHOUT_FW_INFO); final Device device = createDevice(credentials); @@ -165,8 +163,6 @@ public class OtaLwM2MIntegrationTest extends AbstractOtaLwM2MIntegrationTest { @Test public void testFirmwareUpdateByObject5() throws Exception { -// String endpoint = "Ota5_Device"; -// setEndpoint(endpoint); createDeviceProfile(OTA_TRANSPORT_CONFIGURATION); NoSecClientCredential credentials = createNoSecClientCredentials(this.CLIENT_ENDPOINT_OTA5); final Device device = createDevice(credentials); diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/AbstractRpcLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/AbstractRpcLwM2MIntegrationTest.java index 2310fe1659..4303c5e6eb 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/AbstractRpcLwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/AbstractRpcLwM2MIntegrationTest.java @@ -18,12 +18,10 @@ package org.thingsboard.server.transport.lwm2m.rpc; import org.junit.Before; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.device.credentials.lwm2m.NoSecClientCredential; -import org.thingsboard.server.controller.TbTestWebSocketClient; import org.thingsboard.server.dao.service.DaoSqlTest; import org.thingsboard.server.transport.lwm2m.AbstractLwM2MIntegrationTest; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Predicate; @@ -53,8 +51,6 @@ public abstract class AbstractRpcLwM2MIntegrationTest extends AbstractLwM2MInteg protected String RPC_TRANSPORT_CONFIGURATION; - protected ScheduledExecutorService executor; - protected TbTestWebSocketClient wsClient; protected String deviceId; public Set expectedObjects; public Set expectedObjectIdVers; @@ -73,7 +69,7 @@ public abstract class AbstractRpcLwM2MIntegrationTest extends AbstractLwM2MInteg protected String objectIdVer_50 = "/50"; protected String objectIdVer_3303; protected static AtomicInteger endpointSequence = new AtomicInteger(); - protected static String endpointRpcPref = "deviceEndpointRpc"; + protected static String DEVICE_ENDPOINT_RPC_PREF = "deviceEndpointRpc"; public AbstractRpcLwM2MIntegrationTest(){ setResources(resources); @@ -81,8 +77,7 @@ public abstract class AbstractRpcLwM2MIntegrationTest extends AbstractLwM2MInteg @Before public void beforeTest() throws Exception { - String endpoint = endpointRpcPref + endpointSequence.incrementAndGet(); -// setEndpoint(endpoint); + String endpoint = DEVICE_ENDPOINT_RPC_PREF + endpointSequence.incrementAndGet(); init(); createNewClient (SECURITY, COAP_CONFIG, true, endpoint); diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/AbstractSecurityLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/AbstractSecurityLwM2MIntegrationTest.java index c10eb46620..c9d2b556af 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/AbstractSecurityLwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/AbstractSecurityLwM2MIntegrationTest.java @@ -33,36 +33,16 @@ import java.security.cert.X509Certificate; public abstract class AbstractSecurityLwM2MIntegrationTest extends AbstractLwM2MIntegrationTest { protected final String CREDENTIALS_PATH = "lwm2m/credentials/"; // client public key or id used for PSK - protected final String pskIdentity; // client public key or id used for PSK - protected final String pskKey; // client private/secret key used for PSK -// protected final PublicKey clientPublicKey; // client public key used for RPK -// protected final PrivateKey clientPrivateKey; // client private key used for RPK - - - -// // client certificate signed by rootCA but with bad CN (CN does not start by leshan_integration_test) -// protected final X509Certificate clientX509CertWithBadCN; -// // client certificate self-signed with a good CN (CN start by leshan_integration_test) -// protected final X509Certificate clientX509CertSelfSigned; -// // client certificate signed by another CA (not rootCA) with a good CN (CN start by leshan_integration_test) -// protected final X509Certificate clientX509CertNotTrusted; - - // self-signed server certificate -// protected final X509Certificate serverX509CertSelfSigned; -// // rootCA used by the server -// protected final X509Certificate rootCAX509Cert; - // certificates trustedby the server (should contain rootCA) + // Get keys PSK + protected final String CLIENT_PSK_IDENTITY = "SOME_PSK_ID"; // client public key or id used for PSK + protected final String CLIENT_PSK_KEY = "73656372657450534b73656372657450"; // client private/secret key used for PSK // Server protected static final String SERVER_JKS_FOR_TEST = "lwm2mserver"; protected static final String SERVER_STORE_PWD = "server_ks_password"; protected static final String SERVER_CERT_ALIAS = "server"; - protected final X509Certificate serverX509Cert; // server certificate signed by rootCA -// protected final PrivateKey serverPrivateKeyFromCert; // server private key used for RPK and X509 - protected final PublicKey serverPublicKeyFromCert; // server public key used for RPK - -// // Server Trust -// protected final Certificate[] trustedCertificates = new Certificate[1]; +protected final X509Certificate serverX509Cert; // server certificate signed by rootCA + protected final PublicKey serverPublicKeyFromCert; // server public key used for RPK // Client protected LwM2MTestClient client; @@ -92,45 +72,18 @@ public abstract class AbstractSecurityLwM2MIntegrationTest extends AbstractLwM2M public AbstractSecurityLwM2MIntegrationTest() { // create client credentials setResources(this.resources); -// setEndpoint(CLIENT_ENDPOINT_NO_TRUST); try { -// Get keys PSK - this.pskIdentity = "SOME_PSK_ID"; - this.pskKey = "73656372657450534b73656372657450"; - -// // Get point values -// byte[] publicX = Hex -// .decodeHex("89c048261979208666f2bfb188be1968fc9021c416ce12828c06f4e314c167b5".toCharArray()); -// byte[] publicY = Hex -// .decodeHex("cbf1eb7587f08e01688d9ada4be859137ca49f79394bad9179326b3090967b68".toCharArray()); -// byte[] privateS = Hex -// .decodeHex("e67b68d2aaeb6550f19d98cade3ad62b39532e02e6b422e1f7ea189dabaea5d2".toCharArray()); -// -// // Get Elliptic Curve Parameter spec for secp256r1 -// AlgorithmParameters algoParameters = AlgorithmParameters.getInstance("EC"); -// algoParameters.init(new ECGenParameterSpec("secp256r1")); -// ECParameterSpec parameterSpec = algoParameters.getParameterSpec(ECParameterSpec.class); -// -// // Create key specs -// KeySpec publicKeySpec = new ECPublicKeySpec(new ECPoint(new BigInteger(publicX), new BigInteger(publicY)), -// parameterSpec); -// KeySpec privateKeySpec = new ECPrivateKeySpec(new BigInteger(privateS), parameterSpec); -// -// // Get keys RPK -// clientPublicKey = KeyFactory.getInstance("EC").generatePublic(publicKeySpec); -// clientPrivateKey = KeyFactory.getInstance("EC").generatePrivate(privateKeySpec); - // Get certificates from key store char[] clientKeyStorePwd = CLIENT_STORE_PWD.toCharArray(); KeyStore clientKeyStore = KeyStore.getInstance(KeyStore.getDefaultType()); try (InputStream clientKeyStoreFile = this.getClass().getClassLoader().getResourceAsStream(CREDENTIALS_PATH + CLIENT_JKS_FOR_TEST + ".jks")) { clientKeyStore.load(clientKeyStoreFile, clientKeyStorePwd); } - + // Trust clientPrivateKeyFromCertTrust = (PrivateKey) clientKeyStore.getKey(CLIENT_ALIAS_CERT_TRUST, clientKeyStorePwd); clientX509CertTrust = (X509Certificate) clientKeyStore.getCertificate(CLIENT_ALIAS_CERT_TRUST); clientPublicKeyFromCertTrust = clientX509CertTrust != null ? clientX509CertTrust.getPublicKey() : null; - + // No trust clientPrivateKeyFromCertTrustNo = (PrivateKey) clientKeyStore.getKey(CLIENT_ALIAS_CERT_TRUST_NO, clientKeyStorePwd); clientX509CertTrustNo = (X509Certificate) clientKeyStore.getCertificate(CLIENT_ALIAS_CERT_TRUST_NO); clientPublicKeyFromCertTrustNo = clientX509CertTrustNo != null ? clientX509CertTrustNo.getPublicKey() : null; @@ -141,29 +94,6 @@ public abstract class AbstractSecurityLwM2MIntegrationTest extends AbstractLwM2M // create server credentials try { -// // Get point values -// byte[] publicX = Hex -// .decodeHex("fcc28728c123b155be410fc1c0651da374fc6ebe7f96606e90d927d188894a73".toCharArray()); -// byte[] publicY = Hex -// .decodeHex("d2ffaa73957d76984633fc1cc54d0b763ca0559a9dff9706e9f4557dacc3f52a".toCharArray()); -// byte[] privateS = Hex -// .decodeHex("1dae121ba406802ef07c193c1ee4df91115aabd79c1ed7f4c0ef7ef6a5449400".toCharArray()); -// -// // Get Elliptic Curve Parameter spec for secp256r1 -// AlgorithmParameters algoParameters = AlgorithmParameters.getInstance("EC"); -// algoParameters.init(new ECGenParameterSpec("secp256r1")); -// ECParameterSpec parameterSpec = algoParameters.getParameterSpec(ECParameterSpec.class); -// -// // Create key specs -// KeySpec publicKeySpec = new ECPublicKeySpec(new ECPoint(new BigInteger(publicX), new BigInteger(publicY)), -// parameterSpec); -// KeySpec privateKeySpec = new ECPrivateKeySpec(new BigInteger(privateS), parameterSpec); -// -// // Get keys -// serverPublicKey = KeyFactory.getInstance("EC").generatePublic(publicKeySpec); -// serverPrivateKey = KeyFactory.getInstance("EC").generatePrivate(privateKeySpec); - - // Get certificates from key store char[] serverKeyStorePwd = SERVER_STORE_PWD.toCharArray(); KeyStore serverKeyStore = KeyStore.getInstance(KeyStore.getDefaultType()); @@ -171,13 +101,8 @@ public abstract class AbstractSecurityLwM2MIntegrationTest extends AbstractLwM2M serverKeyStore.load(serverKeyStoreFile, serverKeyStorePwd); } -// serverPrivateKeyFromCert = (PrivateKey) serverKeyStore.getKey("server", serverKeyStorePwd); serverX509Cert = (X509Certificate) serverKeyStore.getCertificate(SERVER_CERT_ALIAS); serverPublicKeyFromCert = serverX509Cert.getPublicKey(); -// rootCAX509Cert = (X509Certificate) serverKeyStore.getCertificate("rootCA"); - -// serverX509CertSelfSigned = (X509Certificate) serverKeyStore.getCertificate("server_self_signed"); -// trustedCertificates[0] = serverX509Cert; } catch (GeneralSecurityException | IOException e) { throw new RuntimeException(e); } diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/NoSecLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/NoSecLwM2MIntegrationTest.java index 8331b99fff..c3af57ae71 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/NoSecLwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/NoSecLwM2MIntegrationTest.java @@ -16,7 +16,6 @@ package org.thingsboard.server.transport.lwm2m.security.sql; import lombok.extern.slf4j.Slf4j; -import org.junit.Ignore; import org.junit.Test; import org.thingsboard.server.common.data.device.credentials.lwm2m.NoSecClientCredential; import org.thingsboard.server.transport.lwm2m.security.AbstractSecurityLwM2MIntegrationTest; diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/PskLwm2mIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/PskLwm2mIntegrationTest.java index d7296fd47c..52a85ecf2a 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/PskLwm2mIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/PskLwm2mIntegrationTest.java @@ -17,7 +17,6 @@ package org.thingsboard.server.transport.lwm2m.security.sql; import org.eclipse.leshan.client.object.Security; import org.eclipse.leshan.core.util.Hex; -import org.junit.Ignore; import org.junit.Test; import org.thingsboard.server.common.data.device.credentials.lwm2m.PSKClientCredential; import org.thingsboard.server.transport.lwm2m.security.AbstractSecurityLwM2MIntegrationTest; @@ -35,12 +34,12 @@ public class PskLwm2mIntegrationTest extends AbstractSecurityLwM2MIntegrationTes public void testConnectWithPSKAndObserveTelemetry() throws Exception { PSKClientCredential clientCredentials = new PSKClientCredential(); clientCredentials.setEndpoint(CLIENT_ENDPOINT_PSK); - clientCredentials.setKey(pskKey); - clientCredentials.setIdentity(pskIdentity); + clientCredentials.setKey(CLIENT_PSK_KEY); + clientCredentials.setIdentity(CLIENT_PSK_IDENTITY); Security security = psk(SECURE_URI, SHORT_SERVER_ID, - pskIdentity.getBytes(StandardCharsets.UTF_8), - Hex.decodeHex(pskKey.toCharArray())); + CLIENT_PSK_IDENTITY.getBytes(StandardCharsets.UTF_8), + Hex.decodeHex(CLIENT_PSK_KEY.toCharArray())); super.basicTestConnectionObserveTelemetry(security, clientCredentials, SECURE_COAP_CONFIG, CLIENT_ENDPOINT_PSK); } } diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/RpkLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/RpkLwM2MIntegrationTest.java index 0066014a9b..05933019bf 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/RpkLwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/RpkLwM2MIntegrationTest.java @@ -16,7 +16,6 @@ package org.thingsboard.server.transport.lwm2m.security.sql; import org.eclipse.leshan.client.object.Security; -import org.junit.Ignore; import org.junit.Test; import org.thingsboard.server.common.data.device.credentials.lwm2m.RPKClientCredential; import org.thingsboard.server.transport.lwm2m.security.AbstractSecurityLwM2MIntegrationTest; diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/X509_NoTrustLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/X509_NoTrustLwM2MIntegrationTest.java index b2ce6c470d..af7282bdb7 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/X509_NoTrustLwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/X509_NoTrustLwM2MIntegrationTest.java @@ -15,9 +15,7 @@ */ package org.thingsboard.server.transport.lwm2m.security.sql; -import org.apache.commons.codec.binary.Base64; import org.eclipse.leshan.client.object.Security; -import org.junit.Ignore; import org.junit.Test; import org.thingsboard.server.common.data.device.credentials.lwm2m.X509ClientCredential; import org.thingsboard.server.common.transport.util.SslUtil; @@ -34,7 +32,6 @@ public class X509_NoTrustLwM2MIntegrationTest extends AbstractSecurityLwM2MInteg public void testConnectWithCertAndObserveTelemetry() throws Exception { X509ClientCredential credentials = new X509ClientCredential(); credentials.setEndpoint(CLIENT_ENDPOINT_X509_TRUST_NO); -// rpkClientCredentials.setKey(new String(Base64.encodeBase64(clientPublicKeyFromCertTrust.getEncoded()))); credentials.setCert(SslUtil.getCertificateString(clientX509CertTrustNo)); Security security = x509(SECURE_URI, SHORT_SERVER_ID, @@ -43,5 +40,4 @@ public class X509_NoTrustLwM2MIntegrationTest extends AbstractSecurityLwM2MInteg serverX509Cert.getEncoded()); super.basicTestConnectionObserveTelemetry(security, credentials, SECURE_COAP_CONFIG, CLIENT_ENDPOINT_X509_TRUST_NO); } - } diff --git a/application/src/test/resources/logback.xml b/application/src/test/resources/logback.xml index 175eda993c..d3301bf660 100644 --- a/application/src/test/resources/logback.xml +++ b/application/src/test/resources/logback.xml @@ -10,7 +10,6 @@ - From d3987d1c670350d68cdf8578ad54051c897b0869 Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Mon, 10 Jan 2022 12:58:32 +0200 Subject: [PATCH 354/432] device actor checkSessionsTimeout refactored to improve performance and reduce memory pressure --- .../device/DeviceActorMessageProcessor.java | 49 ++++++++++++++----- 1 file changed, 37 insertions(+), 12 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/actors/device/DeviceActorMessageProcessor.java b/application/src/main/java/org/thingsboard/server/actors/device/DeviceActorMessageProcessor.java index 369d371286..d8f0c38975 100644 --- a/application/src/main/java/org/thingsboard/server/actors/device/DeviceActorMessageProcessor.java +++ b/application/src/main/java/org/thingsboard/server/actors/device/DeviceActorMessageProcessor.java @@ -97,6 +97,7 @@ import javax.annotation.Nullable; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.ConcurrentModificationException; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; @@ -116,6 +117,7 @@ import java.util.stream.Collectors; @Slf4j class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { + static final String SESSION_TIMEOUT_MESSAGE = "session timeout!"; final TenantId tenantId; final DeviceId deviceId; final LinkedHashMapRemoveEldest sessions; @@ -961,19 +963,42 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { } void checkSessionsTimeout() { - log.debug("[{}] checkSessionsTimeout started. Size before check {}", deviceId, sessions.size()); - long expTime = System.currentTimeMillis() - systemContext.getSessionInactivityTimeout(); - Map sessionsToRemove = sessions.entrySet().stream().filter(kv -> kv.getValue().getLastActivityTime() < expTime).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); - sessionsToRemove.forEach((sessionId, sessionMD) -> { - sessions.remove(sessionId); - rpcSubscriptions.remove(sessionId); - attributeSubscriptions.remove(sessionId); - notifyTransportAboutClosedSession(sessionId, sessionMD, "session timeout!"); - }); - if (!sessionsToRemove.isEmpty()) { - dumpSessions(); + final long expTime = System.currentTimeMillis() - systemContext.getSessionInactivityTimeout(); + List expiredIds = null; + + try { + for (Map.Entry kv : sessions.entrySet()) { //entry set are cached for stable sessions + if (kv.getValue().getLastActivityTime() < expTime) { + final UUID id = kv.getKey(); + if (expiredIds == null) { + expiredIds = new ArrayList<>(1); //most of the expired sessions is a single event + } + expiredIds.add(id); + + } + } + } catch (ConcurrentModificationException ignored) { + //Sessions are not thread safe and possible exceptions + //It is an extremely rare event + //Complete session check will perform on the next check + } + + if (expiredIds != null) { + int removed = 0; + for (UUID id : expiredIds) { + final SessionInfoMetaData session = sessions.remove(id); + rpcSubscriptions.remove(id); + attributeSubscriptions.remove(id); + if (session != null) { + removed++; + notifyTransportAboutClosedSession(id, session, SESSION_TIMEOUT_MESSAGE); + } + } + if (removed != 0) { + dumpSessions(); + } } - log.debug("[{}] checkSessionsTimeout finished. Size after check {}", deviceId, sessions.size()); + } } From 6f19efd5397279e44ea76d5c73edb1136f22fc2d Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Mon, 10 Jan 2022 13:07:07 +0200 Subject: [PATCH 355/432] TenantId for SYS_TENANT_ID refactored (new instances replaced with constant) --- .../java/org/thingsboard/server/actors/app/AppActor.java | 2 +- .../thingsboard/server/service/install/DatabaseHelper.java | 2 +- .../thingsboard/server/service/install/InstallScripts.java | 4 ++-- .../thingsboard/server/service/mail/DefaultMailService.java | 2 +- .../auth/jwt/RefreshTokenAuthenticationProvider.java | 4 ++-- .../thingsboard/server/service/sms/DefaultSmsService.java | 2 +- .../server/queue/discovery/HashPartitionService.java | 2 +- .../dao/component/BaseComponentDescriptorService.java | 2 +- .../server/dao/device/DeviceCredentialsServiceImpl.java | 2 +- .../thingsboard/server/dao/tenant/TenantServiceImpl.java | 6 +++--- .../thingsboard/server/dao/service/AbstractServiceTest.java | 2 +- .../server/dao/sql/widget/JpaWidgetsBundleDaoTest.java | 2 +- 12 files changed, 16 insertions(+), 16 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/actors/app/AppActor.java b/application/src/main/java/org/thingsboard/server/actors/app/AppActor.java index 223fb94937..aac0220d07 100644 --- a/application/src/main/java/org/thingsboard/server/actors/app/AppActor.java +++ b/application/src/main/java/org/thingsboard/server/actors/app/AppActor.java @@ -222,7 +222,7 @@ public class AppActor extends ContextAwareActor { @Override public TbActorId createActorId() { - return new TbEntityActorId(new TenantId(EntityId.NULL_UUID)); + return new TbEntityActorId(TenantId.SYS_TENANT_ID); } @Override diff --git a/application/src/main/java/org/thingsboard/server/service/install/DatabaseHelper.java b/application/src/main/java/org/thingsboard/server/service/install/DatabaseHelper.java index f9ea9afa67..44828c3630 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/DatabaseHelper.java +++ b/application/src/main/java/org/thingsboard/server/service/install/DatabaseHelper.java @@ -99,7 +99,7 @@ public class DatabaseHelper { } } for (CustomerId customerId : customerIds) { - dashboardService.assignDashboardToCustomer(new TenantId(EntityId.NULL_UUID), dashboardId, customerId); + dashboardService.assignDashboardToCustomer(TenantId.SYS_TENANT_ID, dashboardId, customerId); } }); } diff --git a/application/src/main/java/org/thingsboard/server/service/install/InstallScripts.java b/application/src/main/java/org/thingsboard/server/service/install/InstallScripts.java index d5a4365963..f4e046bcd5 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/InstallScripts.java +++ b/application/src/main/java/org/thingsboard/server/service/install/InstallScripts.java @@ -169,7 +169,7 @@ public class InstallScripts { ruleChain = ruleChainService.saveRuleChain(ruleChain); ruleChainMetaData.setRuleChainId(ruleChain.getId()); - ruleChainService.saveRuleChainMetaData(new TenantId(EntityId.NULL_UUID), ruleChainMetaData); + ruleChainService.saveRuleChainMetaData(TenantId.SYS_TENANT_ID, ruleChainMetaData); return ruleChain; } @@ -217,7 +217,7 @@ public class InstallScripts { dashboard.setTenantId(tenantId); Dashboard savedDashboard = dashboardService.saveDashboard(dashboard); if (customerId != null && !customerId.isNullUid()) { - dashboardService.assignDashboardToCustomer(new TenantId(EntityId.NULL_UUID), savedDashboard.getId(), customerId); + dashboardService.assignDashboardToCustomer(TenantId.SYS_TENANT_ID, savedDashboard.getId(), customerId); } } catch (Exception e) { log.error("Unable to load dashboard from json: [{}]", path.toString()); diff --git a/application/src/main/java/org/thingsboard/server/service/mail/DefaultMailService.java b/application/src/main/java/org/thingsboard/server/service/mail/DefaultMailService.java index 0b261436b4..f18fae4ef2 100644 --- a/application/src/main/java/org/thingsboard/server/service/mail/DefaultMailService.java +++ b/application/src/main/java/org/thingsboard/server/service/mail/DefaultMailService.java @@ -95,7 +95,7 @@ public class DefaultMailService implements MailService { @Override public void updateMailConfiguration() { - AdminSettings settings = adminSettingsService.findAdminSettingsByKey(new TenantId(EntityId.NULL_UUID), "mail"); + AdminSettings settings = adminSettingsService.findAdminSettingsByKey(TenantId.SYS_TENANT_ID, "mail"); if (settings != null) { JsonNode jsonConfig = settings.getJsonValue(); mailSender = createMailSender(jsonConfig); diff --git a/application/src/main/java/org/thingsboard/server/service/security/auth/jwt/RefreshTokenAuthenticationProvider.java b/application/src/main/java/org/thingsboard/server/service/security/auth/jwt/RefreshTokenAuthenticationProvider.java index 7899c15b70..428fe8adc8 100644 --- a/application/src/main/java/org/thingsboard/server/service/security/auth/jwt/RefreshTokenAuthenticationProvider.java +++ b/application/src/main/java/org/thingsboard/server/service/security/auth/jwt/RefreshTokenAuthenticationProvider.java @@ -75,7 +75,7 @@ public class RefreshTokenAuthenticationProvider implements AuthenticationProvide } private SecurityUser authenticateByUserId(UserId userId) { - TenantId systemId = new TenantId(EntityId.NULL_UUID); + TenantId systemId = TenantId.SYS_TENANT_ID; User user = userService.findUserById(systemId, userId); if (user == null) { throw new UsernameNotFoundException("User not found by refresh token"); @@ -99,7 +99,7 @@ public class RefreshTokenAuthenticationProvider implements AuthenticationProvide } private SecurityUser authenticateByPublicId(String publicId) { - TenantId systemId = new TenantId(EntityId.NULL_UUID); + TenantId systemId = TenantId.SYS_TENANT_ID; CustomerId customerId; try { customerId = new CustomerId(UUID.fromString(publicId)); diff --git a/application/src/main/java/org/thingsboard/server/service/sms/DefaultSmsService.java b/application/src/main/java/org/thingsboard/server/service/sms/DefaultSmsService.java index f0b3eb174e..7fdda75144 100644 --- a/application/src/main/java/org/thingsboard/server/service/sms/DefaultSmsService.java +++ b/application/src/main/java/org/thingsboard/server/service/sms/DefaultSmsService.java @@ -71,7 +71,7 @@ public class DefaultSmsService implements SmsService { @Override public void updateSmsConfiguration() { - AdminSettings settings = adminSettingsService.findAdminSettingsByKey(new TenantId(EntityId.NULL_UUID), "sms"); + AdminSettings settings = adminSettingsService.findAdminSettingsByKey(TenantId.SYS_TENANT_ID, "sms"); if (settings != null) { try { JsonNode jsonConfig = settings.getJsonValue(); diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/discovery/HashPartitionService.java b/common/queue/src/main/java/org/thingsboard/server/queue/discovery/HashPartitionService.java index 06c635761c..1e657aac29 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/discovery/HashPartitionService.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/discovery/HashPartitionService.java @@ -279,7 +279,7 @@ public class HashPartitionService implements PartitionService { tpi.tenantId(tenantId); myPartitionsSearchKey = new ServiceQueueKey(serviceQueue, tenantId); } else { - myPartitionsSearchKey = new ServiceQueueKey(serviceQueue, new TenantId(TenantId.NULL_UUID)); + myPartitionsSearchKey = new ServiceQueueKey(serviceQueue, TenantId.SYS_TENANT_ID); } List partitions = myPartitions.get(myPartitionsSearchKey); if (partitions != null) { diff --git a/dao/src/main/java/org/thingsboard/server/dao/component/BaseComponentDescriptorService.java b/dao/src/main/java/org/thingsboard/server/dao/component/BaseComponentDescriptorService.java index c00c5fbe56..ac92aa3f67 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/component/BaseComponentDescriptorService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/component/BaseComponentDescriptorService.java @@ -51,7 +51,7 @@ public class BaseComponentDescriptorService implements ComponentDescriptorServic @Override public ComponentDescriptor saveComponent(TenantId tenantId, ComponentDescriptor component) { - componentValidator.validate(component, data -> new TenantId(EntityId.NULL_UUID)); + componentValidator.validate(component, data -> TenantId.SYS_TENANT_ID); Optional result = componentDescriptorDao.saveIfNotExist(tenantId, component); return result.orElseGet(() -> componentDescriptorDao.findByClazz(tenantId, component.getClazz())); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsServiceImpl.java index e131dd34a4..28ab143d6a 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsServiceImpl.java @@ -73,7 +73,7 @@ public class DeviceCredentialsServiceImpl extends AbstractEntityService implemen public DeviceCredentials findDeviceCredentialsByCredentialsId(String credentialsId) { log.trace("Executing findDeviceCredentialsByCredentialsId [{}]", credentialsId); validateString(credentialsId, "Incorrect credentialsId " + credentialsId); - return deviceCredentialsDao.findByCredentialsId(new TenantId(EntityId.NULL_UUID), credentialsId); + return deviceCredentialsDao.findByCredentialsId(TenantId.SYS_TENANT_ID, credentialsId); } @Override diff --git a/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java index 7314f54b39..4ccaa4e5c9 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java @@ -168,20 +168,20 @@ public class TenantServiceImpl extends AbstractEntityService implements TenantSe public PageData findTenants(PageLink pageLink) { log.trace("Executing findTenants pageLink [{}]", pageLink); Validator.validatePageLink(pageLink); - return tenantDao.findTenantsByRegion(new TenantId(EntityId.NULL_UUID), DEFAULT_TENANT_REGION, pageLink); + return tenantDao.findTenantsByRegion(TenantId.SYS_TENANT_ID, DEFAULT_TENANT_REGION, pageLink); } @Override public PageData findTenantInfos(PageLink pageLink) { log.trace("Executing findTenantInfos pageLink [{}]", pageLink); Validator.validatePageLink(pageLink); - return tenantDao.findTenantInfosByRegion(new TenantId(EntityId.NULL_UUID), DEFAULT_TENANT_REGION, pageLink); + return tenantDao.findTenantInfosByRegion(TenantId.SYS_TENANT_ID, DEFAULT_TENANT_REGION, pageLink); } @Override public void deleteTenants() { log.trace("Executing deleteTenants"); - tenantsRemover.removeEntities(new TenantId(EntityId.NULL_UUID), DEFAULT_TENANT_REGION); + tenantsRemover.removeEntities(TenantId.SYS_TENANT_ID, DEFAULT_TENANT_REGION); } private DataValidator tenantValidator = diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/AbstractServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/AbstractServiceTest.java index 2d4fd72179..c99beb9251 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/AbstractServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/AbstractServiceTest.java @@ -86,7 +86,7 @@ public abstract class AbstractServiceTest { protected ObjectMapper mapper = new ObjectMapper(); - public static final TenantId SYSTEM_TENANT_ID = new TenantId(EntityId.NULL_UUID); + public static final TenantId SYSTEM_TENANT_ID = TenantId.SYS_TENANT_ID; @Autowired protected UserService userService; diff --git a/dao/src/test/java/org/thingsboard/server/dao/sql/widget/JpaWidgetsBundleDaoTest.java b/dao/src/test/java/org/thingsboard/server/dao/sql/widget/JpaWidgetsBundleDaoTest.java index 7aa1521978..11e2a47af0 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/sql/widget/JpaWidgetsBundleDaoTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/sql/widget/JpaWidgetsBundleDaoTest.java @@ -158,7 +158,7 @@ public class JpaWidgetsBundleDaoTest extends AbstractJpaDaoTest { WidgetsBundle widgetsBundle = new WidgetsBundle(); widgetsBundle.setAlias(prefix + i); widgetsBundle.setTitle(prefix + i); - widgetsBundle.setTenantId(new TenantId(NULL_UUID)); + widgetsBundle.setTenantId(TenantId.SYS_TENANT_ID); widgetsBundle.setId(new WidgetsBundleId(Uuids.timeBased())); widgetsBundleDao.save(AbstractServiceTest.SYSTEM_TENANT_ID, widgetsBundle); } From 48ac1a256e102bcb9bc62a60b3a2ffbf2a6d05a8 Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Mon, 10 Jan 2022 13:39:54 +0200 Subject: [PATCH 356/432] TenantId factory method fromUUID added to reduce optimize TenantId instances count in heap memory. Factory as default @JsonCreator --- .../server/common/data/id/TenantId.java | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/id/TenantId.java b/common/data/src/main/java/org/thingsboard/server/common/data/id/TenantId.java index a785ac03d5..efba010507 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/id/TenantId.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/id/TenantId.java @@ -15,23 +15,31 @@ */ package org.thingsboard.server.common.data.id; -import java.util.UUID; - import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.annotations.ApiModelProperty; +import org.springframework.util.ConcurrentReferenceHashMap; +import org.springframework.util.ConcurrentReferenceHashMap.ReferenceType; import org.thingsboard.server.common.data.EntityType; +import java.util.UUID; + public final class TenantId extends UUIDBased implements EntityId { @JsonIgnore public static final TenantId SYS_TENANT_ID = new TenantId(EntityId.NULL_UUID); + static final ConcurrentReferenceHashMap tenants = new ConcurrentReferenceHashMap<>(16, ReferenceType.SOFT); + private static final long serialVersionUID = 1L; @JsonCreator - public TenantId(@JsonProperty("id") UUID id) { + public static TenantId fromUUID(@JsonProperty("id") UUID id) { + return tenants.computeIfAbsent(id, TenantId::new); + } + + public TenantId(UUID id) { super(id); } From 7d78437258ff55f4dc94ea0dfb3f25a1154ca333 Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Mon, 10 Jan 2022 13:55:25 +0200 Subject: [PATCH 357/432] TenantId new instance replaced with factory method call fromUUID --- .../server/actors/app/AppActor.java | 2 +- .../server/controller/BaseController.java | 2 +- .../controller/DashboardController.java | 2 +- .../server/controller/DeviceController.java | 2 +- .../server/controller/EventController.java | 6 +++--- .../server/controller/TenantController.java | 6 +++--- .../server/controller/UserController.java | 2 +- .../controller/WidgetTypeController.java | 2 +- .../DefaultTbApiUsageStateService.java | 2 +- .../edge/DefaultEdgeNotificationService.java | 2 +- .../rpc/processor/TelemetryEdgeProcessor.java | 4 ++-- .../ota/DefaultOtaPackageStateService.java | 2 +- .../queue/DefaultTbClusterService.java | 2 +- .../queue/DefaultTbCoreConsumerService.java | 12 +++++------ .../DefaultTbRuleEngineConsumerService.java | 6 +++--- ...lByTenantIdTbRuleEngineSubmitStrategy.java | 2 +- .../service/security/AccessValidator.java | 2 +- .../security/model/token/JwtTokenFactory.java | 2 +- .../state/DefaultDeviceStateService.java | 2 +- .../DefaultRuleEngineStatisticsService.java | 2 +- .../subscription/TbSubscriptionUtils.java | 6 +++--- .../transport/DefaultTransportApiService.java | 8 ++++---- .../msg/TransportToDeviceActorMsgWrapper.java | 2 +- .../sql/BaseTbResourceServiceTest.java | 2 +- .../common/data/id/EntityIdFactory.java | 2 +- .../server/common/data/id/TenantId.java | 3 ++- .../DefaultTbServiceInfoProvider.java | 2 +- .../queue/discovery/HashPartitionService.java | 2 +- .../lwm2m/server/client/LwM2mClient.java | 2 +- .../uplink/DefaultLwM2mUplinkMsgHandler.java | 4 ++-- .../service/DefaultTransportService.java | 12 +++++------ .../server/dao/entity/BaseEntityService.java | 2 +- .../server/dao/model/ModelConstants.java | 2 +- .../dao/model/sql/AbstractAlarmEntity.java | 2 +- .../dao/model/sql/AbstractAssetEntity.java | 2 +- .../dao/model/sql/AbstractDeviceEntity.java | 2 +- .../dao/model/sql/AbstractEdgeEntity.java | 2 +- .../model/sql/AbstractEntityViewEntity.java | 2 +- .../dao/model/sql/AbstractTenantEntity.java | 2 +- .../model/sql/AbstractWidgetTypeEntity.java | 2 +- .../dao/model/sql/ApiUsageStateEntity.java | 2 +- .../server/dao/model/sql/AuditLogEntity.java | 2 +- .../server/dao/model/sql/CustomerEntity.java | 2 +- .../server/dao/model/sql/DashboardEntity.java | 2 +- .../dao/model/sql/DashboardInfoEntity.java | 2 +- .../dao/model/sql/DeviceProfileEntity.java | 2 +- .../server/dao/model/sql/EdgeEventEntity.java | 2 +- .../dao/model/sql/EntityAlarmEntity.java | 2 +- .../server/dao/model/sql/EventEntity.java | 2 +- .../dao/model/sql/OAuth2ParamsEntity.java | 2 +- .../dao/model/sql/OtaPackageEntity.java | 2 +- .../dao/model/sql/OtaPackageInfoEntity.java | 2 +- .../server/dao/model/sql/RpcEntity.java | 2 +- .../server/dao/model/sql/RuleChainEntity.java | 2 +- .../dao/model/sql/TbResourceEntity.java | 2 +- .../dao/model/sql/TbResourceInfoEntity.java | 2 +- .../server/dao/model/sql/UserEntity.java | 2 +- .../dao/model/sql/WidgetsBundleEntity.java | 2 +- .../dao/resource/BaseResourceService.java | 2 +- .../server/dao/sql/asset/JpaAssetDao.java | 2 +- .../server/dao/sql/device/JpaDeviceDao.java | 2 +- .../server/dao/sql/edge/JpaEdgeDao.java | 2 +- .../dao/sql/entityview/JpaEntityViewDao.java | 2 +- .../dao/sql/query/AlarmDataAdapter.java | 2 +- .../server/dao/sql/tenant/JpaTenantDao.java | 2 +- .../server/dao/tenant/TenantServiceImpl.java | 2 +- .../server/dao/user/UserServiceImpl.java | 2 +- .../dao/widget/WidgetTypeServiceImpl.java | 2 +- .../dao/widget/WidgetsBundleServiceImpl.java | 2 +- .../nosql/CassandraPartitionsCacheTest.java | 2 +- .../dao/service/AbstractServiceTest.java | 2 +- .../dao/service/BaseAssetServiceTest.java | 2 +- .../dao/service/BaseCustomerServiceTest.java | 2 +- .../dao/service/BaseDashboardServiceTest.java | 2 +- .../dao/service/BaseDeviceServiceTest.java | 2 +- .../dao/service/BaseEdgeEventServiceTest.java | 6 +++--- .../dao/service/BaseEdgeServiceTest.java | 2 +- .../service/BaseOtaPackageServiceTest.java | 2 +- .../dao/service/BaseRuleChainServiceTest.java | 2 +- .../service/BaseWidgetTypeServiceTest.java | 4 ++-- .../service/BaseWidgetsBundleServiceTest.java | 12 +++++------ .../service/event/BaseEventServiceTest.java | 4 ++-- .../server/dao/sql/alarm/JpaAlarmDaoTest.java | 8 ++++---- .../server/dao/sql/asset/JpaAssetDaoTest.java | 6 +++--- .../dao/sql/customer/JpaCustomerDaoTest.java | 4 ++-- .../dashboard/JpaDashboardInfoDaoTest.java | 2 +- .../dao/sql/device/JpaDeviceDaoTest.java | 20 +++++++++---------- .../dao/sql/event/JpaBaseEventDaoTest.java | 10 +++++----- .../dao/sql/tenant/JpaTenantDaoTest.java | 2 +- .../server/dao/sql/user/JpaUserDaoTest.java | 4 ++-- .../sql/widget/JpaWidgetsBundleDaoTest.java | 2 +- .../engine/action/TbCreateRelationNode.java | 2 +- .../rule/engine/action/TbAlarmNodeTest.java | 2 +- .../metadata/AbstractAttributeNodeTest.java | 2 +- .../profile/TbDeviceProfileNodeTest.java | 2 +- 95 files changed, 148 insertions(+), 147 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/actors/app/AppActor.java b/application/src/main/java/org/thingsboard/server/actors/app/AppActor.java index aac0220d07..d64456fba8 100644 --- a/application/src/main/java/org/thingsboard/server/actors/app/AppActor.java +++ b/application/src/main/java/org/thingsboard/server/actors/app/AppActor.java @@ -160,7 +160,7 @@ public class AppActor extends ContextAwareActor { } } else { if (EntityType.TENANT.equals(msg.getEntityId().getEntityType())) { - TenantId tenantId = new TenantId(msg.getEntityId().getId()); + TenantId tenantId = TenantId.fromUUID(msg.getEntityId().getId()); if (msg.getEvent() == ComponentLifecycleEvent.DELETED) { log.info("[{}] Handling tenant deleted notification: {}", msg.getTenantId(), msg); deletedTenants.add(tenantId); diff --git a/application/src/main/java/org/thingsboard/server/controller/BaseController.java b/application/src/main/java/org/thingsboard/server/controller/BaseController.java index c077d5aef5..533d9bb9d1 100644 --- a/application/src/main/java/org/thingsboard/server/controller/BaseController.java +++ b/application/src/main/java/org/thingsboard/server/controller/BaseController.java @@ -482,7 +482,7 @@ public abstract class BaseController { checkCustomerId(new CustomerId(entityId.getId()), operation); return; case TENANT: - checkTenantId(new TenantId(entityId.getId()), operation); + checkTenantId(TenantId.fromUUID(entityId.getId()), operation); return; case TENANT_PROFILE: checkTenantProfileId(new TenantProfileId(entityId.getId()), operation); diff --git a/application/src/main/java/org/thingsboard/server/controller/DashboardController.java b/application/src/main/java/org/thingsboard/server/controller/DashboardController.java index 1d3265053d..bc532c183a 100644 --- a/application/src/main/java/org/thingsboard/server/controller/DashboardController.java +++ b/application/src/main/java/org/thingsboard/server/controller/DashboardController.java @@ -585,7 +585,7 @@ public class DashboardController extends BaseController { @ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES) @RequestParam(required = false) String sortOrder) throws ThingsboardException { try { - TenantId tenantId = new TenantId(toUUID(strTenantId)); + TenantId tenantId = TenantId.fromUUID(toUUID(strTenantId)); checkTenantId(tenantId, Operation.READ); PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder); return checkNotNull(dashboardService.findDashboardsByTenantId(tenantId, pageLink)); diff --git a/application/src/main/java/org/thingsboard/server/controller/DeviceController.java b/application/src/main/java/org/thingsboard/server/controller/DeviceController.java index 6ea6bdd880..38239c9a8b 100644 --- a/application/src/main/java/org/thingsboard/server/controller/DeviceController.java +++ b/application/src/main/java/org/thingsboard/server/controller/DeviceController.java @@ -807,7 +807,7 @@ public class DeviceController extends BaseController { DeviceId deviceId = new DeviceId(toUUID(strDeviceId)); Device device = checkDeviceId(deviceId, Operation.ASSIGN_TO_TENANT); - TenantId newTenantId = new TenantId(toUUID(strTenantId)); + TenantId newTenantId = TenantId.fromUUID(toUUID(strTenantId)); Tenant newTenant = tenantService.findTenantById(newTenantId); if (newTenant == null) { throw new ThingsboardException("Could not find the specified Tenant!", ThingsboardErrorCode.BAD_REQUEST_PARAMS); diff --git a/application/src/main/java/org/thingsboard/server/controller/EventController.java b/application/src/main/java/org/thingsboard/server/controller/EventController.java index ea77fce94c..5819ac3cb7 100644 --- a/application/src/main/java/org/thingsboard/server/controller/EventController.java +++ b/application/src/main/java/org/thingsboard/server/controller/EventController.java @@ -136,7 +136,7 @@ public class EventController extends BaseController { checkParameter("EntityId", strEntityId); checkParameter("EntityType", strEntityType); try { - TenantId tenantId = new TenantId(toUUID(strTenantId)); + TenantId tenantId = TenantId.fromUUID(toUUID(strTenantId)); EntityId entityId = EntityIdFactory.getByTypeAndId(strEntityType, strEntityId); checkEntityId(entityId, Operation.READ); @@ -177,7 +177,7 @@ public class EventController extends BaseController { checkParameter("EntityId", strEntityId); checkParameter("EntityType", strEntityType); try { - TenantId tenantId = new TenantId(toUUID(strTenantId)); + TenantId tenantId = TenantId.fromUUID(toUUID(strTenantId)); EntityId entityId = EntityIdFactory.getByTypeAndId(strEntityType, strEntityId); checkEntityId(entityId, Operation.READ); @@ -224,7 +224,7 @@ public class EventController extends BaseController { checkParameter("EntityId", strEntityId); checkParameter("EntityType", strEntityType); try { - TenantId tenantId = new TenantId(toUUID(strTenantId)); + TenantId tenantId = TenantId.fromUUID(toUUID(strTenantId)); EntityId entityId = EntityIdFactory.getByTypeAndId(strEntityType, strEntityId); checkEntityId(entityId, Operation.READ); diff --git a/application/src/main/java/org/thingsboard/server/controller/TenantController.java b/application/src/main/java/org/thingsboard/server/controller/TenantController.java index 0cfc8f3865..72f5422a0b 100644 --- a/application/src/main/java/org/thingsboard/server/controller/TenantController.java +++ b/application/src/main/java/org/thingsboard/server/controller/TenantController.java @@ -82,7 +82,7 @@ public class TenantController extends BaseController { @PathVariable(TENANT_ID) String strTenantId) throws ThingsboardException { checkParameter(TENANT_ID, strTenantId); try { - TenantId tenantId = new TenantId(toUUID(strTenantId)); + TenantId tenantId = TenantId.fromUUID(toUUID(strTenantId)); Tenant tenant = checkTenantId(tenantId, Operation.READ); if (!tenant.getAdditionalInfo().isNull()) { processDashboardIdFromAdditionalInfo((ObjectNode) tenant.getAdditionalInfo(), HOME_DASHBOARD); @@ -104,7 +104,7 @@ public class TenantController extends BaseController { @PathVariable(TENANT_ID) String strTenantId) throws ThingsboardException { checkParameter(TENANT_ID, strTenantId); try { - TenantId tenantId = new TenantId(toUUID(strTenantId)); + TenantId tenantId = TenantId.fromUUID(toUUID(strTenantId)); return checkTenantInfoId(tenantId, Operation.READ); } catch (Exception e) { throw handleException(e); @@ -154,7 +154,7 @@ public class TenantController extends BaseController { @PathVariable(TENANT_ID) String strTenantId) throws ThingsboardException { checkParameter(TENANT_ID, strTenantId); try { - TenantId tenantId = new TenantId(toUUID(strTenantId)); + TenantId tenantId = TenantId.fromUUID(toUUID(strTenantId)); Tenant tenant = checkTenantId(tenantId, Operation.DELETE); tenantService.deleteTenant(tenantId); tenantProfileCache.evict(tenantId); diff --git a/application/src/main/java/org/thingsboard/server/controller/UserController.java b/application/src/main/java/org/thingsboard/server/controller/UserController.java index e83bc8970c..6007d1831e 100644 --- a/application/src/main/java/org/thingsboard/server/controller/UserController.java +++ b/application/src/main/java/org/thingsboard/server/controller/UserController.java @@ -371,7 +371,7 @@ public class UserController extends BaseController { @RequestParam(required = false) String sortOrder) throws ThingsboardException { checkParameter("tenantId", strTenantId); try { - TenantId tenantId = new TenantId(toUUID(strTenantId)); + TenantId tenantId = TenantId.fromUUID(toUUID(strTenantId)); PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder); return checkNotNull(userService.findTenantAdmins(tenantId, pageLink)); } catch (Exception e) { diff --git a/application/src/main/java/org/thingsboard/server/controller/WidgetTypeController.java b/application/src/main/java/org/thingsboard/server/controller/WidgetTypeController.java index b7f8b28b28..5f7c9ec6c9 100644 --- a/application/src/main/java/org/thingsboard/server/controller/WidgetTypeController.java +++ b/application/src/main/java/org/thingsboard/server/controller/WidgetTypeController.java @@ -216,7 +216,7 @@ public class WidgetTypeController extends BaseController { try { TenantId tenantId; if (isSystem) { - tenantId = new TenantId(ModelConstants.NULL_UUID); + tenantId = TenantId.fromUUID(ModelConstants.NULL_UUID); } else { tenantId = getCurrentUser().getTenantId(); } diff --git a/application/src/main/java/org/thingsboard/server/service/apiusage/DefaultTbApiUsageStateService.java b/application/src/main/java/org/thingsboard/server/service/apiusage/DefaultTbApiUsageStateService.java index bb768a15d7..9a9b0ff6a3 100644 --- a/application/src/main/java/org/thingsboard/server/service/apiusage/DefaultTbApiUsageStateService.java +++ b/application/src/main/java/org/thingsboard/server/service/apiusage/DefaultTbApiUsageStateService.java @@ -164,7 +164,7 @@ public class DefaultTbApiUsageStateService extends TbApplicationEventListener msg, TbCallback callback) { ToUsageStatsServiceMsg statsMsg = msg.getValue(); - TenantId tenantId = new TenantId(new UUID(statsMsg.getTenantIdMSB(), statsMsg.getTenantIdLSB())); + TenantId tenantId = TenantId.fromUUID(new UUID(statsMsg.getTenantIdMSB(), statsMsg.getTenantIdLSB())); EntityId entityId; if (statsMsg.getCustomerIdMSB() != 0 && statsMsg.getCustomerIdLSB() != 0) { entityId = new CustomerId(new UUID(statsMsg.getCustomerIdMSB(), statsMsg.getCustomerIdLSB())); diff --git a/application/src/main/java/org/thingsboard/server/service/edge/DefaultEdgeNotificationService.java b/application/src/main/java/org/thingsboard/server/service/edge/DefaultEdgeNotificationService.java index d25e63183c..0ae07631b5 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/DefaultEdgeNotificationService.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/DefaultEdgeNotificationService.java @@ -124,7 +124,7 @@ public class DefaultEdgeNotificationService implements EdgeNotificationService { public void pushNotificationToEdge(TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg, TbCallback callback) { log.trace("Pushing notification to edge {}", edgeNotificationMsg); try { - TenantId tenantId = new TenantId(new UUID(edgeNotificationMsg.getTenantIdMSB(), edgeNotificationMsg.getTenantIdLSB())); + TenantId tenantId = TenantId.fromUUID(new UUID(edgeNotificationMsg.getTenantIdMSB(), edgeNotificationMsg.getTenantIdLSB())); EdgeEventType type = EdgeEventType.valueOf(edgeNotificationMsg.getType()); switch (type) { case EDGE: diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/TelemetryEdgeProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/TelemetryEdgeProcessor.java index 7aea556544..16af076b3a 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/TelemetryEdgeProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/TelemetryEdgeProcessor.java @@ -276,7 +276,7 @@ public class TelemetryEdgeProcessor extends BaseEdgeProcessor { case DASHBOARD: return new DashboardId(new UUID(entityData.getEntityIdMSB(), entityData.getEntityIdLSB())); case TENANT: - return new TenantId(new UUID(entityData.getEntityIdMSB(), entityData.getEntityIdLSB())); + return TenantId.fromUUID(new UUID(entityData.getEntityIdMSB(), entityData.getEntityIdLSB())); case CUSTOMER: return new CustomerId(new UUID(entityData.getEntityIdMSB(), entityData.getEntityIdLSB())); case USER: @@ -303,7 +303,7 @@ public class TelemetryEdgeProcessor extends BaseEdgeProcessor { entityId = new DashboardId(edgeEvent.getEntityId()); break; case TENANT: - entityId = new TenantId(edgeEvent.getEntityId()); + entityId = TenantId.fromUUID(edgeEvent.getEntityId()); break; case CUSTOMER: entityId = new CustomerId(edgeEvent.getEntityId()); diff --git a/application/src/main/java/org/thingsboard/server/service/ota/DefaultOtaPackageStateService.java b/application/src/main/java/org/thingsboard/server/service/ota/DefaultOtaPackageStateService.java index 883745e643..bfb46ea75d 100644 --- a/application/src/main/java/org/thingsboard/server/service/ota/DefaultOtaPackageStateService.java +++ b/application/src/main/java/org/thingsboard/server/service/ota/DefaultOtaPackageStateService.java @@ -206,7 +206,7 @@ public class DefaultOtaPackageStateService implements OtaPackageStateService { boolean isSuccess = false; OtaPackageId targetOtaPackageId = new OtaPackageId(new UUID(msg.getOtaPackageIdMSB(), msg.getOtaPackageIdLSB())); DeviceId deviceId = new DeviceId(new UUID(msg.getDeviceIdMSB(), msg.getDeviceIdLSB())); - TenantId tenantId = new TenantId(new UUID(msg.getTenantIdMSB(), msg.getTenantIdLSB())); + TenantId tenantId = TenantId.fromUUID(new UUID(msg.getTenantIdMSB(), msg.getTenantIdLSB())); OtaPackageType firmwareType = OtaPackageType.valueOf(msg.getType()); long ts = msg.getTs(); diff --git a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbClusterService.java b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbClusterService.java index 0a82994a42..834a59811f 100644 --- a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbClusterService.java +++ b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbClusterService.java @@ -140,7 +140,7 @@ public class DefaultTbClusterService implements TbClusterService { public void pushMsgToRuleEngine(TenantId tenantId, EntityId entityId, TbMsg tbMsg, TbQueueCallback callback) { if (tenantId.isNullUid()) { if (entityId.getEntityType().equals(EntityType.TENANT)) { - tenantId = new TenantId(entityId.getId()); + tenantId = TenantId.fromUUID(entityId.getId()); } else { log.warn("[{}][{}] Received invalid message: {}", tenantId, entityId, tbMsg); return; diff --git a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbCoreConsumerService.java b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbCoreConsumerService.java index 3602aa804e..88649272be 100644 --- a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbCoreConsumerService.java +++ b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbCoreConsumerService.java @@ -453,37 +453,37 @@ public class DefaultTbCoreConsumerService extends AbstractConsumerService msg) { log.trace("[{}] Creating callback for topic {} message: {}", id, configuration.getName(), msg.getValue()); ToRuleEngineMsg toRuleEngineMsg = msg.getValue(); - TenantId tenantId = new TenantId(new UUID(toRuleEngineMsg.getTenantIdMSB(), toRuleEngineMsg.getTenantIdLSB())); + TenantId tenantId = TenantId.fromUUID(new UUID(toRuleEngineMsg.getTenantIdMSB(), toRuleEngineMsg.getTenantIdLSB())); TbMsgCallback callback = prometheusStatsEnabled ? new TbMsgPackCallback(id, tenantId, ctx, stats.getTimer(tenantId, SUCCESSFUL_STATUS), stats.getTimer(tenantId, FAILED_STATUS)) : new TbMsgPackCallback(id, tenantId, ctx); @@ -344,9 +344,9 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService< TbMsg tmpMsg = TbMsg.fromBytes(configuration.getName(), tmp.getTbMsg().toByteArray(), TbMsgCallback.EMPTY); RuleNodeInfo ruleNodeInfo = ctx.getLastVisitedRuleNode(pending.getKey()); if (printAll) { - log.trace("[{}] {} to process message: {}, Last Rule Node: {}", new TenantId(new UUID(tmp.getTenantIdMSB(), tmp.getTenantIdLSB())), prefix, tmpMsg, ruleNodeInfo); + log.trace("[{}] {} to process message: {}, Last Rule Node: {}", TenantId.fromUUID(new UUID(tmp.getTenantIdMSB(), tmp.getTenantIdLSB())), prefix, tmpMsg, ruleNodeInfo); } else { - log.info("[{}] {} to process message: {}, Last Rule Node: {}", new TenantId(new UUID(tmp.getTenantIdMSB(), tmp.getTenantIdLSB())), prefix, tmpMsg, ruleNodeInfo); + log.info("[{}] {} to process message: {}, Last Rule Node: {}", TenantId.fromUUID(new UUID(tmp.getTenantIdMSB(), tmp.getTenantIdLSB())), prefix, tmpMsg, ruleNodeInfo); break; } } diff --git a/application/src/main/java/org/thingsboard/server/service/queue/processing/SequentialByTenantIdTbRuleEngineSubmitStrategy.java b/application/src/main/java/org/thingsboard/server/service/queue/processing/SequentialByTenantIdTbRuleEngineSubmitStrategy.java index 7c7d076d94..fba60ea6fb 100644 --- a/application/src/main/java/org/thingsboard/server/service/queue/processing/SequentialByTenantIdTbRuleEngineSubmitStrategy.java +++ b/application/src/main/java/org/thingsboard/server/service/queue/processing/SequentialByTenantIdTbRuleEngineSubmitStrategy.java @@ -29,6 +29,6 @@ public class SequentialByTenantIdTbRuleEngineSubmitStrategy extends SequentialBy @Override protected EntityId getEntityId(TransportProtos.ToRuleEngineMsg msg) { - return new TenantId(new UUID(msg.getTenantIdMSB(), msg.getTenantIdLSB())); + return TenantId.fromUUID(new UUID(msg.getTenantIdMSB(), msg.getTenantIdLSB())); } } diff --git a/application/src/main/java/org/thingsboard/server/service/security/AccessValidator.java b/application/src/main/java/org/thingsboard/server/service/security/AccessValidator.java index ab9d0de231..829ef08865 100644 --- a/application/src/main/java/org/thingsboard/server/service/security/AccessValidator.java +++ b/application/src/main/java/org/thingsboard/server/service/security/AccessValidator.java @@ -450,7 +450,7 @@ public class AccessValidator { } else if (currentUser.isSystemAdmin()) { callback.onSuccess(ValidationResult.ok(null)); } else { - ListenableFuture tenantFuture = tenantService.findTenantByIdAsync(currentUser.getTenantId(), new TenantId(entityId.getId())); + ListenableFuture tenantFuture = tenantService.findTenantByIdAsync(currentUser.getTenantId(), TenantId.fromUUID(entityId.getId())); Futures.addCallback(tenantFuture, getCallback(callback, tenant -> { if (tenant == null) { return ValidationResult.entityNotFound("Tenant with requested id wasn't found!"); diff --git a/application/src/main/java/org/thingsboard/server/service/security/model/token/JwtTokenFactory.java b/application/src/main/java/org/thingsboard/server/service/security/model/token/JwtTokenFactory.java index 9315b3bcc1..f8afd4932c 100644 --- a/application/src/main/java/org/thingsboard/server/service/security/model/token/JwtTokenFactory.java +++ b/application/src/main/java/org/thingsboard/server/service/security/model/token/JwtTokenFactory.java @@ -126,7 +126,7 @@ public class JwtTokenFactory { securityUser.setUserPrincipal(principal); String tenantId = claims.get(TENANT_ID, String.class); if (tenantId != null) { - securityUser.setTenantId(new TenantId(UUID.fromString(tenantId))); + securityUser.setTenantId(TenantId.fromUUID(UUID.fromString(tenantId))); } String customerId = claims.get(CUSTOMER_ID, String.class); if (customerId != null) { diff --git a/application/src/main/java/org/thingsboard/server/service/state/DefaultDeviceStateService.java b/application/src/main/java/org/thingsboard/server/service/state/DefaultDeviceStateService.java index 97c22d69c9..2c68414369 100644 --- a/application/src/main/java/org/thingsboard/server/service/state/DefaultDeviceStateService.java +++ b/application/src/main/java/org/thingsboard/server/service/state/DefaultDeviceStateService.java @@ -237,7 +237,7 @@ public class DefaultDeviceStateService extends TbApplicationEventListener { - TenantId tenantId = new TenantId(id); + TenantId tenantId = TenantId.fromUUID(id); try { AssetId serviceAssetId = getServiceAssetId(tenantId, queueName); if (stats.getTotalMsgCounter().get() > 0) { diff --git a/application/src/main/java/org/thingsboard/server/service/subscription/TbSubscriptionUtils.java b/application/src/main/java/org/thingsboard/server/service/subscription/TbSubscriptionUtils.java index 82e0b17f67..023e961451 100644 --- a/application/src/main/java/org/thingsboard/server/service/subscription/TbSubscriptionUtils.java +++ b/application/src/main/java/org/thingsboard/server/service/subscription/TbSubscriptionUtils.java @@ -125,7 +125,7 @@ public class TbSubscriptionUtils { .sessionId(subProto.getSessionId()) .subscriptionId(subProto.getSubscriptionId()) .entityId(EntityIdFactory.getByTypeAndUuid(subProto.getEntityType(), new UUID(subProto.getEntityIdMSB(), subProto.getEntityIdLSB()))) - .tenantId(new TenantId(new UUID(subProto.getTenantIdMSB(), subProto.getTenantIdLSB()))); + .tenantId(TenantId.fromUUID(new UUID(subProto.getTenantIdMSB(), subProto.getTenantIdLSB()))); builder.scope(TbAttributeSubscriptionScope.valueOf(attributeSub.getScope())); builder.allKeys(attributeSub.getAllKeys()); @@ -142,7 +142,7 @@ public class TbSubscriptionUtils { .sessionId(subProto.getSessionId()) .subscriptionId(subProto.getSubscriptionId()) .entityId(EntityIdFactory.getByTypeAndUuid(subProto.getEntityType(), new UUID(subProto.getEntityIdMSB(), subProto.getEntityIdLSB()))) - .tenantId(new TenantId(new UUID(subProto.getTenantIdMSB(), subProto.getTenantIdLSB()))); + .tenantId(TenantId.fromUUID(new UUID(subProto.getTenantIdMSB(), subProto.getTenantIdLSB()))); builder.allKeys(telemetrySub.getAllKeys()); Map keyStates = new HashMap<>(); @@ -161,7 +161,7 @@ public class TbSubscriptionUtils { .sessionId(subProto.getSessionId()) .subscriptionId(subProto.getSubscriptionId()) .entityId(EntityIdFactory.getByTypeAndUuid(subProto.getEntityType(), new UUID(subProto.getEntityIdMSB(), subProto.getEntityIdLSB()))) - .tenantId(new TenantId(new UUID(subProto.getTenantIdMSB(), subProto.getTenantIdLSB()))); + .tenantId(TenantId.fromUUID(new UUID(subProto.getTenantIdMSB(), subProto.getTenantIdLSB()))); builder.ts(alarmSub.getTs()); return builder.build(); } diff --git a/application/src/main/java/org/thingsboard/server/service/transport/DefaultTransportApiService.java b/application/src/main/java/org/thingsboard/server/service/transport/DefaultTransportApiService.java index 1cefefd5d1..80fb062c90 100644 --- a/application/src/main/java/org/thingsboard/server/service/transport/DefaultTransportApiService.java +++ b/application/src/main/java/org/thingsboard/server/service/transport/DefaultTransportApiService.java @@ -380,7 +380,7 @@ public class DefaultTransportApiService implements TransportApiService { DeviceProfile deviceProfile = deviceProfileCache.find(deviceProfileId); builder.setData(ByteString.copyFrom(dataDecodingEncodingService.encode(deviceProfile))); } else if (entityType.equals(EntityType.TENANT)) { - TenantId tenantId = new TenantId(entityUuid); + TenantId tenantId = TenantId.fromUUID(entityUuid); TenantProfile tenantProfile = tenantProfileCache.get(tenantId); ApiUsageState state = apiUsageStateService.getApiUsageState(tenantId); builder.setData(ByteString.copyFrom(dataDecodingEncodingService.encode(tenantProfile))); @@ -425,7 +425,7 @@ public class DefaultTransportApiService implements TransportApiService { private ListenableFuture handle(GetResourceRequestMsg requestMsg) { - TenantId tenantId = new TenantId(new UUID(requestMsg.getTenantIdMSB(), requestMsg.getTenantIdLSB())); + TenantId tenantId = TenantId.fromUUID(new UUID(requestMsg.getTenantIdMSB(), requestMsg.getTenantIdLSB())); ResourceType resourceType = ResourceType.valueOf(requestMsg.getResourceType()); String resourceKey = requestMsg.getResourceKey(); TransportProtos.GetResourceResponseMsg.Builder builder = TransportProtos.GetResourceResponseMsg.newBuilder(); @@ -542,7 +542,7 @@ public class DefaultTransportApiService implements TransportApiService { } private ListenableFuture handle(TransportProtos.GetOtaPackageRequestMsg requestMsg) { - TenantId tenantId = new TenantId(new UUID(requestMsg.getTenantIdMSB(), requestMsg.getTenantIdLSB())); + TenantId tenantId = TenantId.fromUUID(new UUID(requestMsg.getTenantIdMSB(), requestMsg.getTenantIdLSB())); DeviceId deviceId = new DeviceId(new UUID(requestMsg.getDeviceIdMSB(), requestMsg.getDeviceIdLSB())); OtaPackageType otaPackageType = OtaPackageType.valueOf(requestMsg.getType()); Device device = deviceService.findDeviceById(tenantId, deviceId); @@ -592,7 +592,7 @@ public class DefaultTransportApiService implements TransportApiService { } private ListenableFuture handleRegistration(TransportProtos.LwM2MRegistrationRequestMsg msg) { - TenantId tenantId = new TenantId(UUID.fromString(msg.getTenantId())); + TenantId tenantId = TenantId.fromUUID(UUID.fromString(msg.getTenantId())); String deviceName = msg.getEndpoint(); Lock deviceCreationLock = deviceCreationLocks.computeIfAbsent(deviceName, id -> new ReentrantLock()); deviceCreationLock.lock(); diff --git a/application/src/main/java/org/thingsboard/server/service/transport/msg/TransportToDeviceActorMsgWrapper.java b/application/src/main/java/org/thingsboard/server/service/transport/msg/TransportToDeviceActorMsgWrapper.java index 74d81c0307..e2aba53bf1 100644 --- a/application/src/main/java/org/thingsboard/server/service/transport/msg/TransportToDeviceActorMsgWrapper.java +++ b/application/src/main/java/org/thingsboard/server/service/transport/msg/TransportToDeviceActorMsgWrapper.java @@ -44,7 +44,7 @@ public class TransportToDeviceActorMsgWrapper implements TbActorMsg, DeviceAware public TransportToDeviceActorMsgWrapper(TransportToDeviceActorMsg msg, TbCallback callback) { this.msg = msg; this.callback = callback; - this.tenantId = new TenantId(new UUID(msg.getSessionInfo().getTenantIdMSB(), msg.getSessionInfo().getTenantIdLSB())); + this.tenantId = TenantId.fromUUID(new UUID(msg.getSessionInfo().getTenantIdMSB(), msg.getSessionInfo().getTenantIdLSB())); this.deviceId = new DeviceId(new UUID(msg.getSessionInfo().getDeviceIdMSB(), msg.getSessionInfo().getDeviceIdLSB())); } diff --git a/application/src/test/java/org/thingsboard/server/service/resource/sql/BaseTbResourceServiceTest.java b/application/src/test/java/org/thingsboard/server/service/resource/sql/BaseTbResourceServiceTest.java index caf4431e7d..035dc82e75 100644 --- a/application/src/test/java/org/thingsboard/server/service/resource/sql/BaseTbResourceServiceTest.java +++ b/application/src/test/java/org/thingsboard/server/service/resource/sql/BaseTbResourceServiceTest.java @@ -277,7 +277,7 @@ public class BaseTbResourceServiceTest extends AbstractControllerTest { @Test(expected = DataValidationException.class) public void testSaveTbResourceWithInvalidTenant() throws Exception { TbResource resource = new TbResource(); - resource.setTenantId(new TenantId(Uuids.timeBased())); + resource.setTenantId(TenantId.fromUUID(Uuids.timeBased())); resource.setResourceType(ResourceType.JKS); resource.setTitle("My resource"); resource.setFileName(DEFAULT_FILE_NAME); diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/id/EntityIdFactory.java b/common/data/src/main/java/org/thingsboard/server/common/data/id/EntityIdFactory.java index 6d8ddfdd18..519ac4d4b8 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/id/EntityIdFactory.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/id/EntityIdFactory.java @@ -40,7 +40,7 @@ public class EntityIdFactory { public static EntityId getByTypeAndUuid(EntityType type, UUID uuid) { switch (type) { case TENANT: - return new TenantId(uuid); + return TenantId.fromUUID(uuid); case CUSTOMER: return new CustomerId(uuid); case USER: diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/id/TenantId.java b/common/data/src/main/java/org/thingsboard/server/common/data/id/TenantId.java index efba010507..665edc0ca9 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/id/TenantId.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/id/TenantId.java @@ -28,7 +28,7 @@ import java.util.UUID; public final class TenantId extends UUIDBased implements EntityId { @JsonIgnore - public static final TenantId SYS_TENANT_ID = new TenantId(EntityId.NULL_UUID); + public static final TenantId SYS_TENANT_ID = TenantId.fromUUID(EntityId.NULL_UUID); static final ConcurrentReferenceHashMap tenants = new ConcurrentReferenceHashMap<>(16, ReferenceType.SOFT); @@ -39,6 +39,7 @@ public final class TenantId extends UUIDBased implements EntityId { return tenants.computeIfAbsent(id, TenantId::new); } + //default constructor is still available due to possible usage in extensions public TenantId(UUID id) { super(id); } diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/discovery/DefaultTbServiceInfoProvider.java b/common/queue/src/main/java/org/thingsboard/server/queue/discovery/DefaultTbServiceInfoProvider.java index 6988bef9e1..b94c009ad7 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/discovery/DefaultTbServiceInfoProvider.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/discovery/DefaultTbServiceInfoProvider.java @@ -88,7 +88,7 @@ public class DefaultTbServiceInfoProvider implements TbServiceInfoProvider { UUID tenantId; if (!StringUtils.isEmpty(tenantIdStr)) { tenantId = UUID.fromString(tenantIdStr); - isolatedTenant = new TenantId(tenantId); + isolatedTenant = TenantId.fromUUID(tenantId); } else { tenantId = TenantId.NULL_UUID; } diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/discovery/HashPartitionService.java b/common/queue/src/main/java/org/thingsboard/server/queue/discovery/HashPartitionService.java index 1e657aac29..59693732c8 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/discovery/HashPartitionService.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/discovery/HashPartitionService.java @@ -327,7 +327,7 @@ public class HashPartitionService implements PartitionService { } private TenantId getSystemOrIsolatedTenantId(TransportProtos.ServiceInfo serviceInfo) { - return new TenantId(new UUID(serviceInfo.getTenantIdMSB(), serviceInfo.getTenantIdLSB())); + return TenantId.fromUUID(new UUID(serviceInfo.getTenantIdMSB(), serviceInfo.getTenantIdLSB())); } private void addNode(Map> queueServiceList, ServiceInfo instance) { diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java index e1565d5be2..83fdf51787 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java @@ -148,7 +148,7 @@ public class LwM2mClient implements Serializable { public void init(ValidateDeviceCredentialsResponse credentials, UUID sessionId) { this.session = createSession(nodeId, sessionId, credentials); - this.tenantId = new TenantId(new UUID(session.getTenantIdMSB(), session.getTenantIdLSB())); + this.tenantId = TenantId.fromUUID(new UUID(session.getTenantIdMSB(), session.getTenantIdLSB())); this.deviceId = new UUID(session.getDeviceIdMSB(), session.getDeviceIdLSB()); this.profileId = new UUID(session.getDeviceProfileIdMSB(), session.getDeviceProfileIdLSB()); this.powerMode = credentials.getDeviceInfo().getPowerMode(); diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/DefaultLwM2mUplinkMsgHandler.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/DefaultLwM2mUplinkMsgHandler.java index db1390768e..6a31a650df 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/DefaultLwM2mUplinkMsgHandler.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/DefaultLwM2mUplinkMsgHandler.java @@ -428,7 +428,7 @@ public class DefaultLwM2mUplinkMsgHandler extends LwM2MExecutorAwareService impl @Override public void onResourceUpdate(TransportProtos.ResourceUpdateMsg resourceUpdateMsgOpt) { String idVer = resourceUpdateMsgOpt.getResourceKey(); - TenantId tenantId = new TenantId(new UUID(resourceUpdateMsgOpt.getTenantIdMSB(), resourceUpdateMsgOpt.getTenantIdLSB())); + TenantId tenantId = TenantId.fromUUID(new UUID(resourceUpdateMsgOpt.getTenantIdMSB(), resourceUpdateMsgOpt.getTenantIdLSB())); modelProvider.evict(tenantId, idVer); clientContext.getLwM2mClients().forEach(e -> e.updateResourceModel(idVer, modelProvider)); } @@ -436,7 +436,7 @@ public class DefaultLwM2mUplinkMsgHandler extends LwM2MExecutorAwareService impl @Override public void onResourceDelete(TransportProtos.ResourceDeleteMsg resourceDeleteMsgOpt) { String pathIdVer = resourceDeleteMsgOpt.getResourceKey(); - TenantId tenantId = new TenantId(new UUID(resourceDeleteMsgOpt.getTenantIdMSB(), resourceDeleteMsgOpt.getTenantIdLSB())); + TenantId tenantId = TenantId.fromUUID(new UUID(resourceDeleteMsgOpt.getTenantIdMSB(), resourceDeleteMsgOpt.getTenantIdLSB())); modelProvider.evict(tenantId, pathIdVer); clientContext.getLwM2mClients().forEach(e -> e.deleteResources(pathIdVer, modelProvider)); } diff --git a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java index 36e1a68daa..57d1da63b4 100644 --- a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java +++ b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java @@ -451,7 +451,7 @@ public class DefaultTransportService implements TransportService { private TransportDeviceInfo getTransportDeviceInfo(TransportProtos.DeviceInfoProto di) { TransportDeviceInfo tdi = new TransportDeviceInfo(); - tdi.setTenantId(new TenantId(new UUID(di.getTenantIdMSB(), di.getTenantIdLSB()))); + tdi.setTenantId(TenantId.fromUUID(new UUID(di.getTenantIdMSB(), di.getTenantIdLSB()))); tdi.setCustomerId(new CustomerId(new UUID(di.getCustomerIdMSB(), di.getCustomerIdLSB()))); tdi.setDeviceId(new DeviceId(new UUID(di.getDeviceIdMSB(), di.getDeviceIdLSB()))); tdi.setDeviceProfileId(new DeviceProfileId(new UUID(di.getDeviceProfileIdMSB(), di.getDeviceProfileIdLSB()))); @@ -805,7 +805,7 @@ public class DefaultTransportService implements TransportService { if (log.isTraceEnabled()) { log.trace("[{}] Processing msg: {}", toSessionId(sessionInfo), msg); } - TenantId tenantId = new TenantId(new UUID(sessionInfo.getTenantIdMSB(), sessionInfo.getTenantIdLSB())); + TenantId tenantId = TenantId.fromUUID(new UUID(sessionInfo.getTenantIdMSB(), sessionInfo.getTenantIdLSB())); DeviceId deviceId = new DeviceId(new UUID(sessionInfo.getDeviceIdMSB(), sessionInfo.getDeviceIdLSB())); EntityType rateLimitedEntityType = rateLimitService.checkLimits(tenantId, deviceId, dataPoints); @@ -895,14 +895,14 @@ public class DefaultTransportService implements TransportService { } else if (EntityType.TENANT_PROFILE.equals(entityType)) { tenantProfileCache.remove(new TenantProfileId(entityUuid)); } else if (EntityType.TENANT.equals(entityType)) { - rateLimitService.remove(new TenantId(entityUuid)); + rateLimitService.remove(TenantId.fromUUID(entityUuid)); } else if (EntityType.DEVICE.equals(entityType)) { rateLimitService.remove(new DeviceId(entityUuid)); onDeviceDeleted(new DeviceId(entityUuid)); } } else if (toSessionMsg.hasResourceUpdateMsg()) { TransportProtos.ResourceUpdateMsg msg = toSessionMsg.getResourceUpdateMsg(); - TenantId tenantId = new TenantId(new UUID(msg.getTenantIdMSB(), msg.getTenantIdLSB())); + TenantId tenantId = TenantId.fromUUID(new UUID(msg.getTenantIdMSB(), msg.getTenantIdLSB())); ResourceType resourceType = ResourceType.valueOf(msg.getResourceType()); String resourceId = msg.getResourceKey(); transportResourceCache.update(tenantId, resourceType, resourceId); @@ -913,7 +913,7 @@ public class DefaultTransportService implements TransportService { } else if (toSessionMsg.hasResourceDeleteMsg()) { TransportProtos.ResourceDeleteMsg msg = toSessionMsg.getResourceDeleteMsg(); - TenantId tenantId = new TenantId(new UUID(msg.getTenantIdMSB(), msg.getTenantIdLSB())); + TenantId tenantId = TenantId.fromUUID(new UUID(msg.getTenantIdMSB(), msg.getTenantIdLSB())); ResourceType resourceType = ResourceType.valueOf(msg.getResourceType()); String resourceId = msg.getResourceKey(); transportResourceCache.evict(tenantId, resourceType, resourceId); @@ -1001,7 +1001,7 @@ public class DefaultTransportService implements TransportService { } protected TenantId getTenantId(TransportProtos.SessionInfoProto sessionInfo) { - return new TenantId(new UUID(sessionInfo.getTenantIdMSB(), sessionInfo.getTenantIdLSB())); + return TenantId.fromUUID(new UUID(sessionInfo.getTenantIdMSB(), sessionInfo.getTenantIdLSB())); } protected CustomerId getCustomerId(TransportProtos.SessionInfoProto sessionInfo) { diff --git a/dao/src/main/java/org/thingsboard/server/dao/entity/BaseEntityService.java b/dao/src/main/java/org/thingsboard/server/dao/entity/BaseEntityService.java index 06e19a7730..948ed549f3 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/entity/BaseEntityService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/entity/BaseEntityService.java @@ -139,7 +139,7 @@ public class BaseEntityService extends AbstractEntityService implements EntitySe hasName = entityViewService.findEntityViewByIdAsync(tenantId, new EntityViewId(entityId.getId())); break; case TENANT: - hasName = tenantService.findTenantByIdAsync(tenantId, new TenantId(entityId.getId())); + hasName = tenantService.findTenantByIdAsync(tenantId, TenantId.fromUUID(entityId.getId())); break; case CUSTOMER: hasName = customerService.findCustomerByIdAsync(tenantId, new CustomerId(entityId.getId())); diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java b/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java index 6f7a3c2567..ec25ed26a7 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java @@ -28,7 +28,7 @@ public class ModelConstants { } public static final UUID NULL_UUID = Uuids.startOf(0); - public static final TenantId SYSTEM_TENANT = new TenantId(ModelConstants.NULL_UUID); + public static final TenantId SYSTEM_TENANT = TenantId.fromUUID(ModelConstants.NULL_UUID); // this is the difference between midnight October 15, 1582 UTC and midnight January 1, 1970 UTC as 100 nanosecond units public static final long EPOCH_DIFF = 122192928000000000L; diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/AbstractAlarmEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/AbstractAlarmEntity.java index 8ade2b78d5..afa5d06215 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/sql/AbstractAlarmEntity.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/sql/AbstractAlarmEntity.java @@ -166,7 +166,7 @@ public abstract class AbstractAlarmEntity extends BaseSqlEntity Alarm alarm = new Alarm(new AlarmId(id)); alarm.setCreatedTime(createdTime); if (tenantId != null) { - alarm.setTenantId(new TenantId(tenantId)); + alarm.setTenantId(TenantId.fromUUID(tenantId)); } if (customerId != null) { alarm.setCustomerId(new CustomerId(customerId)); diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/AbstractAssetEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/AbstractAssetEntity.java index 07d24020ff..1984dea60c 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/sql/AbstractAssetEntity.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/sql/AbstractAssetEntity.java @@ -119,7 +119,7 @@ public abstract class AbstractAssetEntity extends BaseSqlEntity Asset asset = new Asset(new AssetId(id)); asset.setCreatedTime(createdTime); if (tenantId != null) { - asset.setTenantId(new TenantId(tenantId)); + asset.setTenantId(TenantId.fromUUID(tenantId)); } if (customerId != null) { asset.setCustomerId(new CustomerId(customerId)); diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/AbstractDeviceEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/AbstractDeviceEntity.java index c9913565e4..14a71cad48 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/sql/AbstractDeviceEntity.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/sql/AbstractDeviceEntity.java @@ -145,7 +145,7 @@ public abstract class AbstractDeviceEntity extends BaseSqlEnti Device device = new Device(new DeviceId(getUuid())); device.setCreatedTime(createdTime); if (tenantId != null) { - device.setTenantId(new TenantId(tenantId)); + device.setTenantId(TenantId.fromUUID(tenantId)); } if (customerId != null) { device.setCustomerId(new CustomerId(customerId)); diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/AbstractEdgeEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/AbstractEdgeEntity.java index bb9e9d98ff..4929e6a8ab 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/sql/AbstractEdgeEntity.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/sql/AbstractEdgeEntity.java @@ -153,7 +153,7 @@ public abstract class AbstractEdgeEntity extends BaseSqlEntity extends Bas entityView.setEntityId(EntityIdFactory.getByTypeAndUuid(entityType.name(), entityId)); } if (tenantId != null) { - entityView.setTenantId(new TenantId(tenantId)); + entityView.setTenantId(TenantId.fromUUID(tenantId)); } if (customerId != null) { entityView.setCustomerId(new CustomerId(customerId)); diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/AbstractTenantEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/AbstractTenantEntity.java index 7ba0fc0871..8445e6c4bf 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/sql/AbstractTenantEntity.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/sql/AbstractTenantEntity.java @@ -138,7 +138,7 @@ public abstract class AbstractTenantEntity extends BaseSqlEnti } protected Tenant toTenant() { - Tenant tenant = new Tenant(new TenantId(this.getUuid())); + Tenant tenant = new Tenant(TenantId.fromUUID(this.getUuid())); tenant.setCreatedTime(createdTime); tenant.setTitle(title); tenant.setRegion(region); diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/AbstractWidgetTypeEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/AbstractWidgetTypeEntity.java index 803d1604f8..52f6f6f486 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/sql/AbstractWidgetTypeEntity.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/sql/AbstractWidgetTypeEntity.java @@ -75,7 +75,7 @@ public abstract class AbstractWidgetTypeEntity extends BaseWidgetType widgetType = new BaseWidgetType(new WidgetTypeId(getUuid())); widgetType.setCreatedTime(createdTime); if (tenantId != null) { - widgetType.setTenantId(new TenantId(tenantId)); + widgetType.setTenantId(TenantId.fromUUID(tenantId)); } widgetType.setBundleAlias(bundleAlias); widgetType.setAlias(alias); diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/ApiUsageStateEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/ApiUsageStateEntity.java index 40b56c0095..7919d64eec 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/sql/ApiUsageStateEntity.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/sql/ApiUsageStateEntity.java @@ -102,7 +102,7 @@ public class ApiUsageStateEntity extends BaseSqlEntity implements ApiUsageState ur = new ApiUsageState(new ApiUsageStateId(this.getUuid())); ur.setCreatedTime(createdTime); if (tenantId != null) { - ur.setTenantId(new TenantId(tenantId)); + ur.setTenantId(TenantId.fromUUID(tenantId)); } if (entityId != null) { ur.setEntityId(EntityIdFactory.getByTypeAndUuid(entityType, entityId)); diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/AuditLogEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/AuditLogEntity.java index 17e30a817f..b1447467d2 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/sql/AuditLogEntity.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/sql/AuditLogEntity.java @@ -132,7 +132,7 @@ public class AuditLogEntity extends BaseSqlEntity implements BaseEntit AuditLog auditLog = new AuditLog(new AuditLogId(this.getUuid())); auditLog.setCreatedTime(createdTime); if (tenantId != null) { - auditLog.setTenantId(new TenantId(tenantId)); + auditLog.setTenantId(TenantId.fromUUID(tenantId)); } if (customerId != null) { auditLog.setCustomerId(new CustomerId(customerId)); diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/CustomerEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/CustomerEntity.java index 6ed9a3ff51..252cb096a2 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/sql/CustomerEntity.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/sql/CustomerEntity.java @@ -113,7 +113,7 @@ public final class CustomerEntity extends BaseSqlEntity implements Sea public Customer toData() { Customer customer = new Customer(new CustomerId(this.getUuid())); customer.setCreatedTime(createdTime); - customer.setTenantId(new TenantId(tenantId)); + customer.setTenantId(TenantId.fromUUID(tenantId)); customer.setTitle(title); customer.setCountry(country); customer.setState(state); diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/DashboardEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/DashboardEntity.java index 518a45e5fd..5c01f3f3b4 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/sql/DashboardEntity.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/sql/DashboardEntity.java @@ -119,7 +119,7 @@ public final class DashboardEntity extends BaseSqlEntity implements S Dashboard dashboard = new Dashboard(new DashboardId(this.getUuid())); dashboard.setCreatedTime(this.getCreatedTime()); if (tenantId != null) { - dashboard.setTenantId(new TenantId(tenantId)); + dashboard.setTenantId(TenantId.fromUUID(tenantId)); } dashboard.setTitle(title); dashboard.setImage(image); diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/DashboardInfoEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/DashboardInfoEntity.java index 8d202b2dad..a8f9efba4f 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/sql/DashboardInfoEntity.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/sql/DashboardInfoEntity.java @@ -113,7 +113,7 @@ public class DashboardInfoEntity extends BaseSqlEntity implements DashboardInfo dashboardInfo = new DashboardInfo(new DashboardId(this.getUuid())); dashboardInfo.setCreatedTime(createdTime); if (tenantId != null) { - dashboardInfo.setTenantId(new TenantId(tenantId)); + dashboardInfo.setTenantId(TenantId.fromUUID(tenantId)); } dashboardInfo.setTitle(title); dashboardInfo.setImage(image); diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/DeviceProfileEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/DeviceProfileEntity.java index a3d6c491c0..1ae936810e 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/sql/DeviceProfileEntity.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/sql/DeviceProfileEntity.java @@ -158,7 +158,7 @@ public final class DeviceProfileEntity extends BaseSqlEntity impl DeviceProfile deviceProfile = new DeviceProfile(new DeviceProfileId(this.getUuid())); deviceProfile.setCreatedTime(createdTime); if (tenantId != null) { - deviceProfile.setTenantId(new TenantId(tenantId)); + deviceProfile.setTenantId(TenantId.fromUUID(tenantId)); } deviceProfile.setName(name); deviceProfile.setType(type); diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/EdgeEventEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/EdgeEventEntity.java index b30d40470b..90a1f2a137 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/sql/EdgeEventEntity.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/sql/EdgeEventEntity.java @@ -111,7 +111,7 @@ public class EdgeEventEntity extends BaseSqlEntity implements BaseEnt public EdgeEvent toData() { EdgeEvent edgeEvent = new EdgeEvent(new EdgeEventId(this.getUuid())); edgeEvent.setCreatedTime(createdTime); - edgeEvent.setTenantId(new TenantId(tenantId)); + edgeEvent.setTenantId(TenantId.fromUUID(tenantId)); edgeEvent.setEdgeId(new EdgeId(edgeId)); if (entityId != null) { edgeEvent.setEntityId(entityId); diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/EntityAlarmEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/EntityAlarmEntity.java index 50d57cf61c..0a2842ca8e 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/sql/EntityAlarmEntity.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/sql/EntityAlarmEntity.java @@ -85,7 +85,7 @@ public final class EntityAlarmEntity implements ToData { @Override public EntityAlarm toData() { EntityAlarm result = new EntityAlarm(); - result.setTenantId(new TenantId(tenantId)); + result.setTenantId(TenantId.fromUUID(tenantId)); result.setEntityId(EntityIdFactory.getByTypeAndUuid(entityType, entityId)); result.setAlarmId(new AlarmId(alarmId)); result.setAlarmType(alarmType); diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/EventEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/EventEntity.java index 2d1e5b555d..15bb01df6a 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/sql/EventEntity.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/sql/EventEntity.java @@ -103,7 +103,7 @@ public class EventEntity extends BaseSqlEntity implements BaseEntity { OAuth2Params oauth2Params = new OAuth2Params(); oauth2Params.setId(new OAuth2ParamsId(id)); oauth2Params.setCreatedTime(createdTime); - oauth2Params.setTenantId(new TenantId(tenantId)); + oauth2Params.setTenantId(TenantId.fromUUID(tenantId)); oauth2Params.setEnabled(enabled); return oauth2Params; } diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/OtaPackageEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/OtaPackageEntity.java index 7e6f9a2aff..e6d14c588d 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/sql/OtaPackageEntity.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/sql/OtaPackageEntity.java @@ -151,7 +151,7 @@ public class OtaPackageEntity extends BaseSqlEntity implements Searc public OtaPackage toData() { OtaPackage otaPackage = new OtaPackage(new OtaPackageId(id)); otaPackage.setCreatedTime(createdTime); - otaPackage.setTenantId(new TenantId(tenantId)); + otaPackage.setTenantId(TenantId.fromUUID(tenantId)); if (deviceProfileId != null) { otaPackage.setDeviceProfileId(new DeviceProfileId(deviceProfileId)); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/OtaPackageInfoEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/OtaPackageInfoEntity.java index b4909a6d2d..1eb94ddc96 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/sql/OtaPackageInfoEntity.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/sql/OtaPackageInfoEntity.java @@ -170,7 +170,7 @@ public class OtaPackageInfoEntity extends BaseSqlEntity implemen public OtaPackageInfo toData() { OtaPackageInfo otaPackageInfo = new OtaPackageInfo(new OtaPackageId(id)); otaPackageInfo.setCreatedTime(createdTime); - otaPackageInfo.setTenantId(new TenantId(tenantId)); + otaPackageInfo.setTenantId(TenantId.fromUUID(tenantId)); if (deviceProfileId != null) { otaPackageInfo.setDeviceProfileId(new DeviceProfileId(deviceProfileId)); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/RpcEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/RpcEntity.java index d68aa1afb8..aadbf1e686 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/sql/RpcEntity.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/sql/RpcEntity.java @@ -97,7 +97,7 @@ public class RpcEntity extends BaseSqlEntity implements BaseEntity { public Rpc toData() { Rpc rpc = new Rpc(new RpcId(id)); rpc.setCreatedTime(createdTime); - rpc.setTenantId(new TenantId(tenantId)); + rpc.setTenantId(TenantId.fromUUID(tenantId)); rpc.setDeviceId(new DeviceId(deviceId)); rpc.setExpirationTime(expirationTime); rpc.setRequest(request); diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/RuleChainEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/RuleChainEntity.java index be195723bd..6c4f85294c 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/sql/RuleChainEntity.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/sql/RuleChainEntity.java @@ -110,7 +110,7 @@ public class RuleChainEntity extends BaseSqlEntity implements SearchT public RuleChain toData() { RuleChain ruleChain = new RuleChain(new RuleChainId(this.getUuid())); ruleChain.setCreatedTime(createdTime); - ruleChain.setTenantId(new TenantId(tenantId)); + ruleChain.setTenantId(TenantId.fromUUID(tenantId)); ruleChain.setName(name); ruleChain.setType(type); if (firstRuleNodeId != null) { diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/TbResourceEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/TbResourceEntity.java index 5b22b6e012..206da7bcf3 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/sql/TbResourceEntity.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/sql/TbResourceEntity.java @@ -88,7 +88,7 @@ public class TbResourceEntity extends BaseSqlEntity implements Searc public TbResource toData() { TbResource resource = new TbResource(new TbResourceId(id)); resource.setCreatedTime(createdTime); - resource.setTenantId(new TenantId(tenantId)); + resource.setTenantId(TenantId.fromUUID(tenantId)); resource.setTitle(title); resource.setResourceType(ResourceType.valueOf(resourceType)); resource.setResourceKey(resourceKey); diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/TbResourceInfoEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/TbResourceInfoEntity.java index 78c36861c4..d063ececc7 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/sql/TbResourceInfoEntity.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/sql/TbResourceInfoEntity.java @@ -76,7 +76,7 @@ public class TbResourceInfoEntity extends BaseSqlEntity implemen public TbResourceInfo toData() { TbResourceInfo resource = new TbResourceInfo(new TbResourceId(id)); resource.setCreatedTime(createdTime); - resource.setTenantId(new TenantId(tenantId)); + resource.setTenantId(TenantId.fromUUID(tenantId)); resource.setTitle(title); resource.setResourceType(ResourceType.valueOf(resourceType)); resource.setResourceKey(resourceKey); diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/UserEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/UserEntity.java index ba6e7ec042..bbe08b7eac 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/sql/UserEntity.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/sql/UserEntity.java @@ -110,7 +110,7 @@ public class UserEntity extends BaseSqlEntity implements SearchTextEntity< user.setCreatedTime(createdTime); user.setAuthority(authority); if (tenantId != null) { - user.setTenantId(new TenantId(tenantId)); + user.setTenantId(TenantId.fromUUID(tenantId)); } if (customerId != null) { user.setCustomerId(new CustomerId(customerId)); diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/WidgetsBundleEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/WidgetsBundleEntity.java index 205ebf23f9..bd556c9605 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/sql/WidgetsBundleEntity.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/sql/WidgetsBundleEntity.java @@ -87,7 +87,7 @@ public final class WidgetsBundleEntity extends BaseSqlEntity impl WidgetsBundle widgetsBundle = new WidgetsBundle(new WidgetsBundleId(id)); widgetsBundle.setCreatedTime(createdTime); if (tenantId != null) { - widgetsBundle.setTenantId(new TenantId(tenantId)); + widgetsBundle.setTenantId(TenantId.fromUUID(tenantId)); } widgetsBundle.setAlias(alias); widgetsBundle.setTitle(title); diff --git a/dao/src/main/java/org/thingsboard/server/dao/resource/BaseResourceService.java b/dao/src/main/java/org/thingsboard/server/dao/resource/BaseResourceService.java index f442f5acea..d4e5f3b5b7 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/resource/BaseResourceService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/resource/BaseResourceService.java @@ -180,7 +180,7 @@ public class BaseResourceService implements ResourceService { throw new DataValidationException("Resource key should be specified!"); } if (resource.getTenantId() == null) { - resource.setTenantId(new TenantId(ModelConstants.NULL_UUID)); + resource.setTenantId(TenantId.fromUUID(ModelConstants.NULL_UUID)); } if (!resource.getTenantId().getId().equals(ModelConstants.NULL_UUID)) { Tenant tenant = tenantDao.findById(tenantId, resource.getTenantId().getId()); diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/asset/JpaAssetDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/asset/JpaAssetDao.java index 2f8dbe5b02..9a78ac28e4 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/asset/JpaAssetDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/asset/JpaAssetDao.java @@ -182,7 +182,7 @@ public class JpaAssetDao extends JpaAbstractSearchTextDao im if (types != null && !types.isEmpty()) { list = new ArrayList<>(); for (String type : types) { - list.add(new EntitySubtype(new TenantId(tenantId), EntityType.ASSET, type)); + list.add(new EntitySubtype(TenantId.fromUUID(tenantId), EntityType.ASSET, type)); } } return list; diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/device/JpaDeviceDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/device/JpaDeviceDao.java index 163a03857a..76468c4155 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/device/JpaDeviceDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/device/JpaDeviceDao.java @@ -274,7 +274,7 @@ public class JpaDeviceDao extends JpaAbstractSearchTextDao if (types != null && !types.isEmpty()) { list = new ArrayList<>(); for (String type : types) { - list.add(new EntitySubtype(new TenantId(tenantId), EntityType.DEVICE, type)); + list.add(new EntitySubtype(TenantId.fromUUID(tenantId), EntityType.DEVICE, type)); } } return list; diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/edge/JpaEdgeDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/edge/JpaEdgeDao.java index 1049a35775..6365064dde 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/edge/JpaEdgeDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/edge/JpaEdgeDao.java @@ -187,7 +187,7 @@ public class JpaEdgeDao extends JpaAbstractSearchTextDao imple if (types != null && !types.isEmpty()) { list = new ArrayList<>(); for (String type : types) { - list.add(new EntitySubtype(new TenantId(tenantId), EntityType.EDGE, type)); + list.add(new EntitySubtype(TenantId.fromUUID(tenantId), EntityType.EDGE, type)); } } return list; diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/entityview/JpaEntityViewDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/entityview/JpaEntityViewDao.java index 35f81a860c..451a141c8d 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/entityview/JpaEntityViewDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/entityview/JpaEntityViewDao.java @@ -172,7 +172,7 @@ public class JpaEntityViewDao extends JpaAbstractSearchTextDao(); for (String type : types) { - list.add(new EntitySubtype(new TenantId(tenantId), EntityType.ENTITY_VIEW, type)); + list.add(new EntitySubtype(TenantId.fromUUID(tenantId), EntityType.ENTITY_VIEW, type)); } } return list; diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/query/AlarmDataAdapter.java b/dao/src/main/java/org/thingsboard/server/dao/sql/query/AlarmDataAdapter.java index df2d00fdbb..40a2cb972f 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/query/AlarmDataAdapter.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/query/AlarmDataAdapter.java @@ -86,7 +86,7 @@ public class AlarmDataAdapter { alarm.setType(row.get(ModelConstants.ALARM_TYPE_PROPERTY).toString()); alarm.setSeverity(AlarmSeverity.valueOf(row.get(ModelConstants.ALARM_SEVERITY_PROPERTY).toString())); alarm.setStatus(AlarmStatus.valueOf(row.get(ModelConstants.ALARM_STATUS_PROPERTY).toString())); - alarm.setTenantId(new TenantId((UUID) row.get(ModelConstants.TENANT_ID_PROPERTY))); + alarm.setTenantId(TenantId.fromUUID((UUID) row.get(ModelConstants.TENANT_ID_PROPERTY))); Object customerIdObj = row.get(ModelConstants.CUSTOMER_ID_PROPERTY); CustomerId customerId = customerIdObj != null ? new CustomerId((UUID) customerIdObj) : null; alarm.setCustomerId(customerId); diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/tenant/JpaTenantDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/tenant/JpaTenantDao.java index ff9dce6c96..d963e57eab 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/tenant/JpaTenantDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/tenant/JpaTenantDao.java @@ -77,7 +77,7 @@ public class JpaTenantDao extends JpaAbstractSearchTextDao @Override public PageData findTenantsIds(PageLink pageLink) { - return DaoUtil.pageToPageData(tenantRepository.findTenantsIds(DaoUtil.toPageable(pageLink))).mapData(TenantId::new); + return DaoUtil.pageToPageData(tenantRepository.findTenantsIds(DaoUtil.toPageable(pageLink))).mapData(TenantId::fromUUID); } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java index 4ccaa4e5c9..6b0e1bb182 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java @@ -224,7 +224,7 @@ public class TenantServiceImpl extends AbstractEntityService implements TenantSe @Override protected void removeEntity(TenantId tenantId, Tenant entity) { - deleteTenant(new TenantId(entity.getUuidId())); + deleteTenant(TenantId.fromUUID(entity.getUuidId())); } }; } diff --git a/dao/src/main/java/org/thingsboard/server/dao/user/UserServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/user/UserServiceImpl.java index 1ed5811ffa..3b4eb70e41 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/user/UserServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/user/UserServiceImpl.java @@ -409,7 +409,7 @@ public class UserServiceImpl extends AbstractEntityService implements UserServic } TenantId tenantId = user.getTenantId(); if (tenantId == null) { - tenantId = new TenantId(ModelConstants.NULL_UUID); + tenantId = TenantId.fromUUID(ModelConstants.NULL_UUID); user.setTenantId(tenantId); } CustomerId customerId = user.getCustomerId(); diff --git a/dao/src/main/java/org/thingsboard/server/dao/widget/WidgetTypeServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/widget/WidgetTypeServiceImpl.java index d8a8ea3e35..44850ccd34 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/widget/WidgetTypeServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/widget/WidgetTypeServiceImpl.java @@ -135,7 +135,7 @@ public class WidgetTypeServiceImpl implements WidgetTypeService { throw new DataValidationException("Widgets type descriptor can't be empty!"); } if (widgetTypeDetails.getTenantId() == null) { - widgetTypeDetails.setTenantId(new TenantId(ModelConstants.NULL_UUID)); + widgetTypeDetails.setTenantId(TenantId.fromUUID(ModelConstants.NULL_UUID)); } if (!widgetTypeDetails.getTenantId().getId().equals(ModelConstants.NULL_UUID)) { Tenant tenant = tenantDao.findById(tenantId, widgetTypeDetails.getTenantId().getId()); diff --git a/dao/src/main/java/org/thingsboard/server/dao/widget/WidgetsBundleServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/widget/WidgetsBundleServiceImpl.java index 4f7bd93eca..dd6a1e8961 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/widget/WidgetsBundleServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/widget/WidgetsBundleServiceImpl.java @@ -159,7 +159,7 @@ public class WidgetsBundleServiceImpl implements WidgetsBundleService { throw new DataValidationException("Widgets bundle title should be specified!"); } if (widgetsBundle.getTenantId() == null) { - widgetsBundle.setTenantId(new TenantId(ModelConstants.NULL_UUID)); + widgetsBundle.setTenantId(TenantId.fromUUID(ModelConstants.NULL_UUID)); } if (!widgetsBundle.getTenantId().getId().equals(ModelConstants.NULL_UUID)) { Tenant tenant = tenantDao.findById(tenantId, widgetsBundle.getTenantId().getId()); diff --git a/dao/src/test/java/org/thingsboard/server/dao/nosql/CassandraPartitionsCacheTest.java b/dao/src/test/java/org/thingsboard/server/dao/nosql/CassandraPartitionsCacheTest.java index ef371569dd..cf214990b6 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/nosql/CassandraPartitionsCacheTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/nosql/CassandraPartitionsCacheTest.java @@ -96,7 +96,7 @@ public class CassandraPartitionsCacheTest { cassandraBaseTimeseriesDao.init(); UUID id = UUID.randomUUID(); - TenantId tenantId = new TenantId(id); + TenantId tenantId = TenantId.fromUUID(id); long tsKvEntryTs = System.currentTimeMillis(); for (int i = 0; i < 50000; i++) { diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/AbstractServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/AbstractServiceTest.java index c99beb9251..2f524eaa50 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/AbstractServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/AbstractServiceTest.java @@ -173,7 +173,7 @@ public abstract class AbstractServiceTest { protected Event generateEvent(TenantId tenantId, EntityId entityId, String eventType, String eventUid) throws IOException { if (tenantId == null) { - tenantId = new TenantId(Uuids.timeBased()); + tenantId = TenantId.fromUUID(Uuids.timeBased()); } Event event = new Event(); event.setTenantId(tenantId); diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseAssetServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseAssetServiceTest.java index a4a88d24ea..b7c9feb493 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseAssetServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseAssetServiceTest.java @@ -104,7 +104,7 @@ public abstract class BaseAssetServiceTest extends AbstractServiceTest { Asset asset = new Asset(); asset.setName("My asset"); asset.setType("default"); - asset.setTenantId(new TenantId(Uuids.timeBased())); + asset.setTenantId(TenantId.fromUUID(Uuids.timeBased())); assetService.saveAsset(asset); } diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseCustomerServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseCustomerServiceTest.java index 5991f6de2c..3b795fe09f 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseCustomerServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseCustomerServiceTest.java @@ -105,7 +105,7 @@ public abstract class BaseCustomerServiceTest extends AbstractServiceTest { public void testSaveCustomerWithInvalidTenant() { Customer customer = new Customer(); customer.setTitle("My customer"); - customer.setTenantId(new TenantId(Uuids.timeBased())); + customer.setTenantId(TenantId.fromUUID(Uuids.timeBased())); customerService.saveCustomer(customer); } diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseDashboardServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseDashboardServiceTest.java index ce307b74b0..15b39b1aa7 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseDashboardServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseDashboardServiceTest.java @@ -102,7 +102,7 @@ public abstract class BaseDashboardServiceTest extends AbstractServiceTest { public void testSaveDashboardWithInvalidTenant() { Dashboard dashboard = new Dashboard(); dashboard.setTitle("My dashboard"); - dashboard.setTenantId(new TenantId(Uuids.timeBased())); + dashboard.setTenantId(TenantId.fromUUID(Uuids.timeBased())); dashboardService.saveDashboard(dashboard); } diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseDeviceServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseDeviceServiceTest.java index 1a9432419e..dfb0434136 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseDeviceServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseDeviceServiceTest.java @@ -267,7 +267,7 @@ public abstract class BaseDeviceServiceTest extends AbstractServiceTest { Device device = new Device(); device.setName("My device"); device.setType("default"); - device.setTenantId(new TenantId(Uuids.timeBased())); + device.setTenantId(TenantId.fromUUID(Uuids.timeBased())); deviceService.saveDevice(device); } diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseEdgeEventServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseEdgeEventServiceTest.java index 51a4975dcd..e5e62384c0 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseEdgeEventServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseEdgeEventServiceTest.java @@ -53,7 +53,7 @@ public abstract class BaseEdgeEventServiceTest extends AbstractServiceTest { protected EdgeEvent generateEdgeEvent(TenantId tenantId, EdgeId edgeId, EntityId entityId, EdgeEventActionType edgeEventAction) throws IOException { if (tenantId == null) { - tenantId = new TenantId(Uuids.timeBased()); + tenantId = TenantId.fromUUID(Uuids.timeBased()); } EdgeEvent edgeEvent = new EdgeEvent(); edgeEvent.setTenantId(tenantId); @@ -76,7 +76,7 @@ public abstract class BaseEdgeEventServiceTest extends AbstractServiceTest { EdgeId edgeId = new EdgeId(Uuids.timeBased()); DeviceId deviceId = new DeviceId(Uuids.timeBased()); - TenantId tenantId = new TenantId(Uuids.timeBased()); + TenantId tenantId = TenantId.fromUUID(Uuids.timeBased()); saveEdgeEventWithProvidedTime(timeBeforeStartTime, edgeId, deviceId, tenantId); EdgeEvent savedEdgeEvent = saveEdgeEventWithProvidedTime(eventTime, edgeId, deviceId, tenantId); EdgeEvent savedEdgeEvent2 = saveEdgeEventWithProvidedTime(eventTime + 1, edgeId, deviceId, tenantId); @@ -105,7 +105,7 @@ public abstract class BaseEdgeEventServiceTest extends AbstractServiceTest { public void findEdgeEventsWithTsUpdateAndWithout() throws Exception { EdgeId edgeId = new EdgeId(Uuids.timeBased()); DeviceId deviceId = new DeviceId(Uuids.timeBased()); - TenantId tenantId = new TenantId(Uuids.timeBased()); + TenantId tenantId = TenantId.fromUUID(Uuids.timeBased()); TimePageLink pageLink = new TimePageLink(1, 0, null, new SortOrder("createdTime", SortOrder.Direction.ASC)); EdgeEvent edgeEventWithTsUpdate = generateEdgeEvent(tenantId, edgeId, deviceId, EdgeEventActionType.TIMESERIES_UPDATED); diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseEdgeServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseEdgeServiceTest.java index 631fcff8da..340afefc6d 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseEdgeServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseEdgeServiceTest.java @@ -100,7 +100,7 @@ public abstract class BaseEdgeServiceTest extends AbstractServiceTest { Edge edge = new Edge(); edge.setName("My edge"); edge.setType("default"); - edge.setTenantId(new TenantId(Uuids.timeBased())); + edge.setTenantId(TenantId.fromUUID(Uuids.timeBased())); edgeService.saveEdge(edge, true); } diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseOtaPackageServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseOtaPackageServiceTest.java index 8fcadcd812..3dc7130981 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseOtaPackageServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseOtaPackageServiceTest.java @@ -342,7 +342,7 @@ public abstract class BaseOtaPackageServiceTest extends AbstractServiceTest { @Test public void testSaveFirmwareWithInvalidTenant() { OtaPackage firmware = new OtaPackage(); - firmware.setTenantId(new TenantId(Uuids.timeBased())); + firmware.setTenantId(TenantId.fromUUID(Uuids.timeBased())); firmware.setDeviceProfileId(deviceProfileId); firmware.setType(FIRMWARE); firmware.setTitle(TITLE); diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseRuleChainServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseRuleChainServiceTest.java index c1635a6281..deaab55ac2 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseRuleChainServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseRuleChainServiceTest.java @@ -97,7 +97,7 @@ public abstract class BaseRuleChainServiceTest extends AbstractServiceTest { public void testSaveRuleChainWithInvalidTenant() { RuleChain ruleChain = new RuleChain(); ruleChain.setName("My RuleChain"); - ruleChain.setTenantId(new TenantId(Uuids.timeBased())); + ruleChain.setTenantId(TenantId.fromUUID(Uuids.timeBased())); ruleChainService.saveRuleChain(ruleChain); } diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseWidgetTypeServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseWidgetTypeServiceTest.java index ba500f950d..024745dc9e 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseWidgetTypeServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseWidgetTypeServiceTest.java @@ -142,7 +142,7 @@ public abstract class BaseWidgetTypeServiceTest extends AbstractServiceTest { WidgetsBundle savedWidgetsBundle = widgetsBundleService.saveWidgetsBundle(widgetsBundle); WidgetTypeDetails widgetType = new WidgetTypeDetails(); - widgetType.setTenantId(new TenantId(Uuids.timeBased())); + widgetType.setTenantId(TenantId.fromUUID(Uuids.timeBased())); widgetType.setBundleAlias(savedWidgetsBundle.getAlias()); widgetType.setName("Widget Type"); widgetType.setDescriptor(new ObjectMapper().readValue("{ \"someKey\": \"someValue\" }", JsonNode.class)); @@ -176,7 +176,7 @@ public abstract class BaseWidgetTypeServiceTest extends AbstractServiceTest { widgetType.setName("Widget Type"); widgetType.setDescriptor(new ObjectMapper().readValue("{ \"someKey\": \"someValue\" }", JsonNode.class)); WidgetTypeDetails savedWidgetType = widgetTypeService.saveWidgetType(widgetType); - savedWidgetType.setTenantId(new TenantId(ModelConstants.NULL_UUID)); + savedWidgetType.setTenantId(TenantId.fromUUID(ModelConstants.NULL_UUID)); try { widgetTypeService.saveWidgetType(savedWidgetType); } finally { diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseWidgetsBundleServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseWidgetsBundleServiceTest.java index 76f67c3c48..3573fbcaaf 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseWidgetsBundleServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseWidgetsBundleServiceTest.java @@ -88,7 +88,7 @@ public abstract class BaseWidgetsBundleServiceTest extends AbstractServiceTest { public void testSaveWidgetsBundleWithInvalidTenant() { WidgetsBundle widgetsBundle = new WidgetsBundle(); widgetsBundle.setTitle("My widgets bundle"); - widgetsBundle.setTenantId(new TenantId(Uuids.timeBased())); + widgetsBundle.setTenantId(TenantId.fromUUID(Uuids.timeBased())); widgetsBundleService.saveWidgetsBundle(widgetsBundle); } @@ -98,7 +98,7 @@ public abstract class BaseWidgetsBundleServiceTest extends AbstractServiceTest { widgetsBundle.setTitle("My widgets bundle"); widgetsBundle.setTenantId(tenantId); WidgetsBundle savedWidgetsBundle = widgetsBundleService.saveWidgetsBundle(widgetsBundle); - savedWidgetsBundle.setTenantId(new TenantId(ModelConstants.NULL_UUID)); + savedWidgetsBundle.setTenantId(TenantId.fromUUID(ModelConstants.NULL_UUID)); try { widgetsBundleService.saveWidgetsBundle(savedWidgetsBundle); } finally { @@ -160,7 +160,7 @@ public abstract class BaseWidgetsBundleServiceTest extends AbstractServiceTest { @Test public void testFindSystemWidgetsBundlesByPageLink() { - TenantId tenantId = new TenantId(ModelConstants.NULL_UUID); + TenantId tenantId = TenantId.fromUUID(ModelConstants.NULL_UUID); List systemWidgetsBundles = widgetsBundleService.findSystemWidgetsBundles(tenantId); List createdWidgetsBundles = new ArrayList<>(); @@ -204,7 +204,7 @@ public abstract class BaseWidgetsBundleServiceTest extends AbstractServiceTest { @Test public void testFindSystemWidgetsBundles() { - TenantId tenantId = new TenantId(ModelConstants.NULL_UUID); + TenantId tenantId = TenantId.fromUUID(ModelConstants.NULL_UUID); List systemWidgetsBundles = widgetsBundleService.findSystemWidgetsBundles(tenantId); @@ -290,7 +290,7 @@ public abstract class BaseWidgetsBundleServiceTest extends AbstractServiceTest { tenant = tenantService.saveTenant(tenant); TenantId tenantId = tenant.getId(); - TenantId systemTenantId = new TenantId(ModelConstants.NULL_UUID); + TenantId systemTenantId = TenantId.fromUUID(ModelConstants.NULL_UUID); List createdWidgetsBundles = new ArrayList<>(); List createdSystemWidgetsBundles = new ArrayList<>(); @@ -376,7 +376,7 @@ public abstract class BaseWidgetsBundleServiceTest extends AbstractServiceTest { tenant = tenantService.saveTenant(tenant); TenantId tenantId = tenant.getId(); - TenantId systemTenantId = new TenantId(ModelConstants.NULL_UUID); + TenantId systemTenantId = TenantId.fromUUID(ModelConstants.NULL_UUID); List createdWidgetsBundles = new ArrayList<>(); List createdSystemWidgetsBundles = new ArrayList<>(); diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/event/BaseEventServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/event/BaseEventServiceTest.java index 13b97ea9b1..9d17e5e3e8 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/event/BaseEventServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/event/BaseEventServiceTest.java @@ -68,7 +68,7 @@ public abstract class BaseEventServiceTest extends AbstractServiceTest { long timeAfterEndTime = LocalDateTime.of(2016, Month.NOVEMBER, 1, 13, 30).toEpochSecond(ZoneOffset.UTC); CustomerId customerId = new CustomerId(Uuids.timeBased()); - TenantId tenantId = new TenantId(Uuids.timeBased()); + TenantId tenantId = TenantId.fromUUID(Uuids.timeBased()); saveEventWithProvidedTime(timeBeforeStartTime, customerId, tenantId); Event savedEvent = saveEventWithProvidedTime(eventTime, customerId, tenantId); Event savedEvent2 = saveEventWithProvidedTime(eventTime+1, customerId, tenantId); @@ -103,7 +103,7 @@ public abstract class BaseEventServiceTest extends AbstractServiceTest { long timeAfterEndTime = LocalDateTime.of(2016, Month.NOVEMBER, 1, 13, 30).toEpochSecond(ZoneOffset.UTC); CustomerId customerId = new CustomerId(Uuids.timeBased()); - TenantId tenantId = new TenantId(Uuids.timeBased()); + TenantId tenantId = TenantId.fromUUID(Uuids.timeBased()); saveEventWithProvidedTime(timeBeforeStartTime, customerId, tenantId); Event savedEvent = saveEventWithProvidedTime(eventTime, customerId, tenantId); Event savedEvent2 = saveEventWithProvidedTime(eventTime+1, customerId, tenantId); diff --git a/dao/src/test/java/org/thingsboard/server/dao/sql/alarm/JpaAlarmDaoTest.java b/dao/src/test/java/org/thingsboard/server/dao/sql/alarm/JpaAlarmDaoTest.java index d5e743e5af..23ec137dac 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/sql/alarm/JpaAlarmDaoTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/sql/alarm/JpaAlarmDaoTest.java @@ -53,9 +53,9 @@ public class JpaAlarmDaoTest extends AbstractJpaDaoTest { saveAlarm(alarm1Id, tenantId, originator1Id, "TEST_ALARM"); saveAlarm(alarm2Id, tenantId, originator1Id, "TEST_ALARM"); saveAlarm(alarm3Id, tenantId, originator2Id, "TEST_ALARM"); - assertEquals(3, alarmDao.find(new TenantId(tenantId)).size()); + assertEquals(3, alarmDao.find(TenantId.fromUUID(tenantId)).size()); ListenableFuture future = alarmDao - .findLatestByOriginatorAndType(new TenantId(tenantId), new DeviceId(originator1Id), "TEST_ALARM"); + .findLatestByOriginatorAndType(TenantId.fromUUID(tenantId), new DeviceId(originator1Id), "TEST_ALARM"); Alarm alarm = future.get(); assertNotNull(alarm); assertEquals(alarm2Id, alarm.getId().getId()); @@ -64,13 +64,13 @@ public class JpaAlarmDaoTest extends AbstractJpaDaoTest { private void saveAlarm(UUID id, UUID tenantId, UUID deviceId, String type) { Alarm alarm = new Alarm(); alarm.setId(new AlarmId(id)); - alarm.setTenantId(new TenantId(tenantId)); + alarm.setTenantId(TenantId.fromUUID(tenantId)); alarm.setOriginator(new DeviceId(deviceId)); alarm.setType(type); alarm.setPropagate(true); alarm.setStartTs(System.currentTimeMillis()); alarm.setEndTs(System.currentTimeMillis()); alarm.setStatus(AlarmStatus.ACTIVE_UNACK); - alarmDao.save(new TenantId(tenantId), alarm); + alarmDao.save(TenantId.fromUUID(tenantId), alarm); } } diff --git a/dao/src/test/java/org/thingsboard/server/dao/sql/asset/JpaAssetDaoTest.java b/dao/src/test/java/org/thingsboard/server/dao/sql/asset/JpaAssetDaoTest.java index a2a8adc927..db563639a6 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/sql/asset/JpaAssetDaoTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/sql/asset/JpaAssetDaoTest.java @@ -60,7 +60,7 @@ public class JpaAssetDaoTest extends AbstractJpaDaoTest { UUID customerId = i % 2 == 0 ? customerId1 : customerId2; saveAsset(assetId, tenantId, customerId, "ASSET_" + i, "TYPE_1"); } - assertEquals(60, assetDao.find(new TenantId(tenantId1)).size()); + assertEquals(60, assetDao.find(TenantId.fromUUID(tenantId1)).size()); PageLink pageLink = new PageLink(20, 0, "ASSET_"); PageData assets1 = assetDao.findAssetsByTenantId(tenantId1, pageLink); @@ -213,10 +213,10 @@ public class JpaAssetDaoTest extends AbstractJpaDaoTest { private void saveAsset(UUID id, UUID tenantId, UUID customerId, String name, String type) { Asset asset = new Asset(); asset.setId(new AssetId(id)); - asset.setTenantId(new TenantId(tenantId)); + asset.setTenantId(TenantId.fromUUID(tenantId)); asset.setCustomerId(new CustomerId(customerId)); asset.setName(name); asset.setType(type); - assetDao.save(new TenantId(tenantId), asset); + assetDao.save(TenantId.fromUUID(tenantId), asset); } } diff --git a/dao/src/test/java/org/thingsboard/server/dao/sql/customer/JpaCustomerDaoTest.java b/dao/src/test/java/org/thingsboard/server/dao/sql/customer/JpaCustomerDaoTest.java index 9e62116225..e00f6a1dca 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/sql/customer/JpaCustomerDaoTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/sql/customer/JpaCustomerDaoTest.java @@ -76,8 +76,8 @@ public class JpaCustomerDaoTest extends AbstractJpaDaoTest { private void createCustomer(UUID tenantId, int index) { Customer customer = new Customer(); customer.setId(new CustomerId(Uuids.timeBased())); - customer.setTenantId(new TenantId(tenantId)); + customer.setTenantId(TenantId.fromUUID(tenantId)); customer.setTitle("CUSTOMER_" + index); - customerDao.save(new TenantId(tenantId), customer); + customerDao.save(TenantId.fromUUID(tenantId), customer); } } diff --git a/dao/src/test/java/org/thingsboard/server/dao/sql/dashboard/JpaDashboardInfoDaoTest.java b/dao/src/test/java/org/thingsboard/server/dao/sql/dashboard/JpaDashboardInfoDaoTest.java index 174317ec00..aa23d3dff4 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/sql/dashboard/JpaDashboardInfoDaoTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/sql/dashboard/JpaDashboardInfoDaoTest.java @@ -60,7 +60,7 @@ public class JpaDashboardInfoDaoTest extends AbstractJpaDaoTest { private void createDashboard(UUID tenantId, int index) { DashboardInfo dashboardInfo = new DashboardInfo(); dashboardInfo.setId(new DashboardId(Uuids.timeBased())); - dashboardInfo.setTenantId(new TenantId(tenantId)); + dashboardInfo.setTenantId(TenantId.fromUUID(tenantId)); dashboardInfo.setTitle("DASHBOARD_" + index); dashboardInfoDao.save(AbstractServiceTest.SYSTEM_TENANT_ID, dashboardInfo); } diff --git a/dao/src/test/java/org/thingsboard/server/dao/sql/device/JpaDeviceDaoTest.java b/dao/src/test/java/org/thingsboard/server/dao/sql/device/JpaDeviceDaoTest.java index 9d9d128966..8c83a2050b 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/sql/device/JpaDeviceDaoTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/sql/device/JpaDeviceDaoTest.java @@ -81,15 +81,15 @@ public class JpaDeviceDaoTest extends AbstractJpaDaoTest { UUID tenantId = Uuids.timeBased(); UUID customerId = Uuids.timeBased(); Device device = getDevice(tenantId, customerId); - deviceDao.save(new TenantId(tenantId), device); + deviceDao.save(TenantId.fromUUID(tenantId), device); UUID uuid = device.getId().getId(); - Device entity = deviceDao.findById(new TenantId(tenantId), uuid); + Device entity = deviceDao.findById(TenantId.fromUUID(tenantId), uuid); assertNotNull(entity); assertEquals(uuid, entity.getId().getId()); executor = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(10, ThingsBoardThreadFactory.forName(getClass().getSimpleName() + "-test-scope"))); - ListenableFuture future = executor.submit(() -> deviceDao.findById(new TenantId(tenantId), uuid)); + ListenableFuture future = executor.submit(() -> deviceDao.findById(TenantId.fromUUID(tenantId), uuid)); Device asyncDevice = future.get(); assertNotNull("Async device expected to be not null", asyncDevice); } @@ -106,8 +106,8 @@ public class JpaDeviceDaoTest extends AbstractJpaDaoTest { for(int i = 0; i < 5; i++) { UUID deviceId1 = Uuids.timeBased(); UUID deviceId2 = Uuids.timeBased(); - deviceDao.save(new TenantId(tenantId1), getDevice(tenantId1, customerId1, deviceId1)); - deviceDao.save(new TenantId(tenantId2), getDevice(tenantId2, customerId2, deviceId2)); + deviceDao.save(TenantId.fromUUID(tenantId1), getDevice(tenantId1, customerId1, deviceId1)); + deviceDao.save(TenantId.fromUUID(tenantId2), getDevice(tenantId2, customerId2, deviceId2)); deviceIds.add(deviceId1); deviceIds.add(deviceId2); } @@ -129,8 +129,8 @@ public class JpaDeviceDaoTest extends AbstractJpaDaoTest { for(int i = 0; i < 20; i++) { UUID deviceId1 = Uuids.timeBased(); UUID deviceId2 = Uuids.timeBased(); - deviceDao.save(new TenantId(tenantId1), getDevice(tenantId1, customerId1, deviceId1)); - deviceDao.save(new TenantId(tenantId2), getDevice(tenantId2, customerId2, deviceId2)); + deviceDao.save(TenantId.fromUUID(tenantId1), getDevice(tenantId1, customerId1, deviceId1)); + deviceDao.save(TenantId.fromUUID(tenantId2), getDevice(tenantId2, customerId2, deviceId2)); deviceIds.add(deviceId1); deviceIds.add(deviceId2); } @@ -142,8 +142,8 @@ public class JpaDeviceDaoTest extends AbstractJpaDaoTest { private void createDevices(UUID tenantId1, UUID tenantId2, UUID customerId1, UUID customerId2, int count) { for (int i = 0; i < count / 2; i++) { - deviceDao.save(new TenantId(tenantId1), getDevice(tenantId1, customerId1)); - deviceDao.save(new TenantId(tenantId2), getDevice(tenantId2, customerId2)); + deviceDao.save(TenantId.fromUUID(tenantId1), getDevice(tenantId1, customerId1)); + deviceDao.save(TenantId.fromUUID(tenantId2), getDevice(tenantId2, customerId2)); } } @@ -154,7 +154,7 @@ public class JpaDeviceDaoTest extends AbstractJpaDaoTest { private Device getDevice(UUID tenantId, UUID customerID, UUID deviceId) { Device device = new Device(); device.setId(new DeviceId(deviceId)); - device.setTenantId(new TenantId(tenantId)); + device.setTenantId(TenantId.fromUUID(tenantId)); device.setCustomerId(new CustomerId(customerID)); device.setName("SEARCH_TEXT"); return device; diff --git a/dao/src/test/java/org/thingsboard/server/dao/sql/event/JpaBaseEventDaoTest.java b/dao/src/test/java/org/thingsboard/server/dao/sql/event/JpaBaseEventDaoTest.java index 57b9519f44..41f0c6985c 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/sql/event/JpaBaseEventDaoTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/sql/event/JpaBaseEventDaoTest.java @@ -149,10 +149,10 @@ public class JpaBaseEventDaoTest extends AbstractJpaDaoTest { String type = i % 2 == 0 ? STATS : ALARM; UUID eventId1 = Uuids.timeBased(); Event event1 = getEvent(eventId1, tenantId, entityId1, type); - eventDao.save(new TenantId(tenantId), event1); + eventDao.save(TenantId.fromUUID(tenantId), event1); UUID eventId2 = Uuids.timeBased(); Event event2 = getEvent(eventId2, tenantId, entityId2, type); - eventDao.save(new TenantId(tenantId), event2); + eventDao.save(TenantId.fromUUID(tenantId), event2); } return System.currentTimeMillis(); } @@ -161,10 +161,10 @@ public class JpaBaseEventDaoTest extends AbstractJpaDaoTest { for (int i = 0; i < count / 2; i++) { UUID eventId1 = Uuids.timeBased(); Event event1 = getEvent(eventId1, tenantId, entityId1); - eventDao.save(new TenantId(tenantId), event1); + eventDao.save(TenantId.fromUUID(tenantId), event1); UUID eventId2 = Uuids.timeBased(); Event event2 = getEvent(eventId2, tenantId, entityId2); - eventDao.save(new TenantId(tenantId), event2); + eventDao.save(TenantId.fromUUID(tenantId), event2); } return System.currentTimeMillis(); } @@ -178,7 +178,7 @@ public class JpaBaseEventDaoTest extends AbstractJpaDaoTest { private Event getEvent(UUID eventId, UUID tenantId, UUID entityId) { Event event = new Event(); event.setId(new EventId(eventId)); - event.setTenantId(new TenantId(tenantId)); + event.setTenantId(TenantId.fromUUID(tenantId)); EntityId deviceId = new DeviceId(entityId); event.setEntityId(deviceId); event.setUid(event.getId().getId().toString()); diff --git a/dao/src/test/java/org/thingsboard/server/dao/sql/tenant/JpaTenantDaoTest.java b/dao/src/test/java/org/thingsboard/server/dao/sql/tenant/JpaTenantDaoTest.java index 3b31be7a04..b965bd2a0c 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/sql/tenant/JpaTenantDaoTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/sql/tenant/JpaTenantDaoTest.java @@ -69,7 +69,7 @@ public class JpaTenantDaoTest extends AbstractJpaDaoTest { private void createTenant(String region, String title, int index) { Tenant tenant = new Tenant(); - tenant.setId(new TenantId(Uuids.timeBased())); + tenant.setId(TenantId.fromUUID(Uuids.timeBased())); tenant.setRegion(region); tenant.setTitle(title + "_" + index); tenantDao.save(AbstractServiceTest.SYSTEM_TENANT_ID, tenant); diff --git a/dao/src/test/java/org/thingsboard/server/dao/sql/user/JpaUserDaoTest.java b/dao/src/test/java/org/thingsboard/server/dao/sql/user/JpaUserDaoTest.java index b22dd08381..213f9c1d6b 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/sql/user/JpaUserDaoTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/sql/user/JpaUserDaoTest.java @@ -111,7 +111,7 @@ public class JpaUserDaoTest extends AbstractJpaDaoTest { public void testSave() throws IOException { User user = new User(); user.setId(new UserId(UUID.fromString("cd481534-27cc-11e7-93ae-92361f002671"))); - user.setTenantId(new TenantId(UUID.fromString("1edcb2c6-27cb-11e7-93ae-92361f002671"))); + user.setTenantId(TenantId.fromUUID(UUID.fromString("1edcb2c6-27cb-11e7-93ae-92361f002671"))); user.setCustomerId(new CustomerId(UUID.fromString("51477cb4-27cb-11e7-93ae-92361f002671"))); user.setEmail("user@thingsboard.org"); user.setFirstName("Jackson"); @@ -140,7 +140,7 @@ public class JpaUserDaoTest extends AbstractJpaDaoTest { User user = new User(); UUID id = Uuids.timeBased(); user.setId(new UserId(id)); - user.setTenantId(new TenantId(tenantId)); + user.setTenantId(TenantId.fromUUID(tenantId)); user.setCustomerId(new CustomerId(customerId)); if (customerId == NULL_UUID) { user.setAuthority(Authority.TENANT_ADMIN); diff --git a/dao/src/test/java/org/thingsboard/server/dao/sql/widget/JpaWidgetsBundleDaoTest.java b/dao/src/test/java/org/thingsboard/server/dao/sql/widget/JpaWidgetsBundleDaoTest.java index 11e2a47af0..54a97ea088 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/sql/widget/JpaWidgetsBundleDaoTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/sql/widget/JpaWidgetsBundleDaoTest.java @@ -149,7 +149,7 @@ public class JpaWidgetsBundleDaoTest extends AbstractJpaDaoTest { widgetsBundle.setAlias(prefix + i); widgetsBundle.setTitle(prefix + i); widgetsBundle.setId(new WidgetsBundleId(Uuids.timeBased())); - widgetsBundle.setTenantId(new TenantId(tenantId)); + widgetsBundle.setTenantId(TenantId.fromUUID(tenantId)); widgetsBundleDao.save(AbstractServiceTest.SYSTEM_TENANT_ID, widgetsBundle); } } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCreateRelationNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCreateRelationNode.java index 28eafabfce..05b3bdc1d0 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCreateRelationNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCreateRelationNode.java @@ -208,7 +208,7 @@ public class TbCreateRelationNode extends TbAbstractRelationActionNode processTenant(TbContext ctx, EntityContainer entityContainer, SearchDirectionIds sdId, String relationType) { - return Futures.transformAsync(ctx.getTenantService().findTenantByIdAsync(ctx.getTenantId(), new TenantId(entityContainer.getEntityId().getId())), tenant -> { + return Futures.transformAsync(ctx.getTenantService().findTenantByIdAsync(ctx.getTenantId(), TenantId.fromUUID(entityContainer.getEntityId().getId())), tenant -> { if (tenant != null) { return processSave(ctx, sdId, relationType); } else { diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbAlarmNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbAlarmNodeTest.java index 0b800eb22c..e2de0bb55f 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbAlarmNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbAlarmNodeTest.java @@ -98,7 +98,7 @@ public class TbAlarmNodeTest { private EntityId originator = new DeviceId(Uuids.timeBased()); private EntityId alarmOriginator = new AlarmId(Uuids.timeBased()); - private TenantId tenantId = new TenantId(Uuids.timeBased()); + private TenantId tenantId = TenantId.fromUUID(Uuids.timeBased()); private TbMsgMetaData metaData = new TbMsgMetaData(); private String rawJson = "{\"name\": \"Vit\", \"passed\": 5}"; diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/AbstractAttributeNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/AbstractAttributeNodeTest.java index a0f2879851..b8265e2a2e 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/AbstractAttributeNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/AbstractAttributeNodeTest.java @@ -68,7 +68,7 @@ import static org.thingsboard.server.common.data.DataConstants.SERVER_SCOPE; @RunWith(MockitoJUnitRunner.class) public abstract class AbstractAttributeNodeTest { final CustomerId customerId = new CustomerId(Uuids.timeBased()); - final TenantId tenantId = new TenantId(Uuids.timeBased()); + final TenantId tenantId = TenantId.fromUUID(Uuids.timeBased()); final RuleChainId ruleChainId = new RuleChainId(Uuids.timeBased()); final RuleNodeId ruleNodeId = new RuleNodeId(Uuids.timeBased()); final String keyAttrConf = "${word}"; diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/profile/TbDeviceProfileNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/profile/TbDeviceProfileNodeTest.java index b2c79102c4..0f88f9baac 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/profile/TbDeviceProfileNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/profile/TbDeviceProfileNodeTest.java @@ -99,7 +99,7 @@ public class TbDeviceProfileNodeTest { @Mock private AttributesService attributesService; - private final TenantId tenantId = new TenantId(UUID.randomUUID()); + private final TenantId tenantId = TenantId.fromUUID(UUID.randomUUID()); private final DeviceId deviceId = new DeviceId(UUID.randomUUID()); private final CustomerId customerId = new CustomerId(UUID.randomUUID()); private final DeviceProfileId deviceProfileId = new DeviceProfileId(UUID.randomUUID()); From 8611349e4b8c08add2206777475d4e2808088891 Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Mon, 10 Jan 2022 15:03:15 +0200 Subject: [PATCH 358/432] TenantId static initializer --- .../org/thingsboard/server/common/data/id/TenantId.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/id/TenantId.java b/common/data/src/main/java/org/thingsboard/server/common/data/id/TenantId.java index 665edc0ca9..77a3480f0a 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/id/TenantId.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/id/TenantId.java @@ -28,10 +28,14 @@ import java.util.UUID; public final class TenantId extends UUIDBased implements EntityId { @JsonIgnore - public static final TenantId SYS_TENANT_ID = TenantId.fromUUID(EntityId.NULL_UUID); + public static final TenantId SYS_TENANT_ID = new TenantId(EntityId.NULL_UUID); static final ConcurrentReferenceHashMap tenants = new ConcurrentReferenceHashMap<>(16, ReferenceType.SOFT); + static { + tenants.put(SYS_TENANT_ID.getId(), SYS_TENANT_ID); + } + private static final long serialVersionUID = 1L; @JsonCreator From fa1cd21473e5fe6e2c21758b95846ae39685ea18 Mon Sep 17 00:00:00 2001 From: ArtemDzhereleiko Date: Mon, 10 Jan 2022 15:21:44 +0200 Subject: [PATCH 359/432] UI: Fixed cancel event on color picker --- .../shared/components/dialog/color-picker-dialog.component.ts | 2 +- .../src/app/shared/components/json-form/json-form.component.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ui-ngx/src/app/shared/components/dialog/color-picker-dialog.component.ts b/ui-ngx/src/app/shared/components/dialog/color-picker-dialog.component.ts index 2374749cbc..499f857df8 100644 --- a/ui-ngx/src/app/shared/components/dialog/color-picker-dialog.component.ts +++ b/ui-ngx/src/app/shared/components/dialog/color-picker-dialog.component.ts @@ -67,7 +67,7 @@ export class ColorPickerDialogComponent extends DialogComponent void) { this.dialogs.colorPicker(tinycolor(val).toRgbString()).subscribe((color) => { - if (colorSelectedFn) { + if (color && colorSelectedFn) { colorSelectedFn(tinycolor(color).toRgb()); } }); From 2e9d7768450c8da689e221cd298364e1f0d5f5cf Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Mon, 10 Jan 2022 17:16:30 +0200 Subject: [PATCH 360/432] TenantId static initializer replaced with a static variable order --- .../org/thingsboard/server/common/data/id/TenantId.java | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/id/TenantId.java b/common/data/src/main/java/org/thingsboard/server/common/data/id/TenantId.java index 77a3480f0a..1d62d8e3f2 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/id/TenantId.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/id/TenantId.java @@ -28,13 +28,10 @@ import java.util.UUID; public final class TenantId extends UUIDBased implements EntityId { @JsonIgnore - public static final TenantId SYS_TENANT_ID = new TenantId(EntityId.NULL_UUID); - static final ConcurrentReferenceHashMap tenants = new ConcurrentReferenceHashMap<>(16, ReferenceType.SOFT); - static { - tenants.put(SYS_TENANT_ID.getId(), SYS_TENANT_ID); - } + @JsonIgnore + public static final TenantId SYS_TENANT_ID = TenantId.fromUUID(EntityId.NULL_UUID); private static final long serialVersionUID = 1L; From 0ef9d5753cd271fd7c8729567b5a2765943538d1 Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Mon, 10 Jan 2022 17:36:57 +0200 Subject: [PATCH 361/432] MqttTransportHandler refactored to not reference on InetSocketAddress instances to free some heap space. IPv4 are stored and logged as int. --- .../transport/mqtt/MqttTransportHandler.java | 25 +++++++++++++------ .../mqtt/session/DeviceSessionCtx.java | 2 +- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportHandler.java b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportHandler.java index bf474cc266..fe39721f27 100644 --- a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportHandler.java +++ b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportHandler.java @@ -76,6 +76,7 @@ import org.thingsboard.server.transport.mqtt.session.MqttTopicMatcher; import javax.net.ssl.SSLPeerUnverifiedException; import java.io.IOException; import java.net.InetSocketAddress; +import java.nio.ByteBuffer; import java.security.cert.Certificate; import java.security.cert.X509Certificate; import java.util.ArrayList; @@ -111,7 +112,6 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement private static final Pattern FW_REQUEST_PATTERN = Pattern.compile(MqttTopics.DEVICE_FIRMWARE_REQUEST_TOPIC_PATTERN); private static final Pattern SW_REQUEST_PATTERN = Pattern.compile(MqttTopics.DEVICE_SOFTWARE_REQUEST_TOPIC_PATTERN); - private static final String PAYLOAD_TOO_LARGE = "PAYLOAD_TOO_LARGE"; private static final MqttQoS MAX_SUPPORTED_QOS_LVL = AT_LEAST_ONCE; @@ -124,7 +124,8 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement private final ConcurrentMap mqttQoSMap; final DeviceSessionCtx deviceSessionCtx; - volatile InetSocketAddress address; + volatile int ip = 0; + volatile int port = 0; volatile GatewaySessionHandler gatewaySessionHandler; private final ConcurrentHashMap otaPackSessions; @@ -183,9 +184,14 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement } void processMqttMsg(ChannelHandlerContext ctx, MqttMessage msg) { - address = getAddress(ctx); + if (port == 0) { + InetSocketAddress address = getAddress(ctx); + ip = getIpv4(address); //ipv6 will not appear in logs + port = address.getPort(); + } + if (msg.fixedHeader() == null) { - log.info("[{}:{}] Invalid message received", address.getHostName(), address.getPort()); + log.info("[{}:{}] Invalid message received", ip, port); ctx.close(); return; } @@ -199,6 +205,11 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement } } + int getIpv4(InetSocketAddress address) { + byte[] ipBytes = address.getAddress().getAddress(); + return ipBytes.length == 4 ? ByteBuffer.wrap(ipBytes).getInt() : -1; + } + InetSocketAddress getAddress(ChannelHandlerContext ctx) { return (InetSocketAddress) ctx.channel().remoteAddress(); } @@ -791,7 +802,7 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement @Override public void onError(Throwable e) { - log.trace("[{}] Failed to process credentials: {}", address, userName, e); + log.trace("[{}] Failed to process credentials: {}", ip, userName, e); ctx.writeAndFlush(createMqttConnAckMsg(MqttConnectReturnCode.CONNECTION_REFUSED_SERVER_UNAVAILABLE, connectMessage)); ctx.close(); } @@ -814,14 +825,14 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement @Override public void onError(Throwable e) { - log.trace("[{}] Failed to process credentials: {}", address, sha3Hash, e); + log.trace("[{}] Failed to process credentials: {}", ip, sha3Hash, e); ctx.writeAndFlush(createMqttConnAckMsg(MqttConnectReturnCode.CONNECTION_REFUSED_SERVER_UNAVAILABLE, connectMessage)); ctx.close(); } }); } catch (Exception e) { ctx.writeAndFlush(createMqttConnAckMsg(CONNECTION_REFUSED_NOT_AUTHORIZED, connectMessage)); - log.trace("[{}] X509 auth failure: {}", sessionId, address, e); + log.trace("[{}] X509 auth failure: {}", sessionId, ip, e); ctx.close(); } } diff --git a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/DeviceSessionCtx.java b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/DeviceSessionCtx.java index 9f0c89714a..76e2911793 100644 --- a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/DeviceSessionCtx.java +++ b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/DeviceSessionCtx.java @@ -238,7 +238,7 @@ public class DeviceSessionCtx extends MqttDeviceAwareSessionContext { public void release() { if (!msgQueue.isEmpty()) { - log.warn("doDisconnect for device {} but unprocessed messages {} left in the msg queue", getDeviceId(), msgQueue.size()); + log.warn("doDisconnect for device {} but unprocessed messages {} left in the msg queue. cleared", getDeviceId(), getMsgQueueSize()); msgQueue.forEach(ReferenceCountUtil::safeRelease); msgQueue.clear(); } From ef53df75128a0502c5727d4229acd37cd79c1aaa Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Mon, 10 Jan 2022 18:41:53 +0200 Subject: [PATCH 362/432] MqttTransportHandler fixed test --- .../server/transport/mqtt/MqttTransportHandlerTest.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/common/transport/mqtt/src/test/java/org/thingsboard/server/transport/mqtt/MqttTransportHandlerTest.java b/common/transport/mqtt/src/test/java/org/thingsboard/server/transport/mqtt/MqttTransportHandlerTest.java index a9903fe867..7701a82cbe 100644 --- a/common/transport/mqtt/src/test/java/org/thingsboard/server/transport/mqtt/MqttTransportHandlerTest.java +++ b/common/transport/mqtt/src/test/java/org/thingsboard/server/transport/mqtt/MqttTransportHandlerTest.java @@ -23,7 +23,6 @@ import io.netty.handler.codec.mqtt.MqttConnectMessage; import io.netty.handler.codec.mqtt.MqttConnectPayload; import io.netty.handler.codec.mqtt.MqttConnectVariableHeader; import io.netty.handler.codec.mqtt.MqttFixedHeader; -import io.netty.handler.codec.mqtt.MqttMessage; import io.netty.handler.codec.mqtt.MqttMessageType; import io.netty.handler.codec.mqtt.MqttPublishMessage; import io.netty.handler.codec.mqtt.MqttPublishVariableHeader; @@ -118,7 +117,8 @@ public class MqttTransportHandlerTest { handler.processMqttMsg(ctx, msg); - assertThat(handler.address, is(IP_ADDR)); + assertThat(handler.ip, is(handler.getIpv4(IP_ADDR))); + assertThat(handler.port, is(IP_ADDR.getPort())); assertThat(handler.deviceSessionCtx.getChannel(), is(ctx)); verify(handler, never()).doDisconnect(); verify(handler, times(1)).processConnect(ctx, msg); @@ -154,7 +154,7 @@ public class MqttTransportHandlerTest { messages.forEach((msg) -> handler.processMqttMsg(ctx, msg)); - assertThat(handler.address, is(IP_ADDR)); + assertThat(handler.ip, is(handler.getIpv4(IP_ADDR))); assertThat(handler.deviceSessionCtx.getChannel(), is(ctx)); assertThat(handler.deviceSessionCtx.isConnected(), is(false)); assertThat(handler.deviceSessionCtx.getMsgQueueSize(), is(MSG_QUEUE_LIMIT)); From c4d180eecc3f147bbf35735074b0ce957b31d8f3 Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Mon, 10 Jan 2022 19:25:56 +0200 Subject: [PATCH 363/432] DeviceActorMessageProcessor(AbstractContextAwareMsgProcessor): ObjectMapper live instance count reduced with a static ObjectMapper --- .../actors/shared/AbstractContextAwareMsgProcessor.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/actors/shared/AbstractContextAwareMsgProcessor.java b/application/src/main/java/org/thingsboard/server/actors/shared/AbstractContextAwareMsgProcessor.java index a5de546cb6..0a89cabe5d 100644 --- a/application/src/main/java/org/thingsboard/server/actors/shared/AbstractContextAwareMsgProcessor.java +++ b/application/src/main/java/org/thingsboard/server/actors/shared/AbstractContextAwareMsgProcessor.java @@ -22,13 +22,13 @@ import org.thingsboard.server.actors.TbActorCtx; import org.thingsboard.server.common.msg.TbActorMsg; import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; @Slf4j public abstract class AbstractContextAwareMsgProcessor { + protected final static ObjectMapper mapper = new ObjectMapper(); + protected final ActorSystemContext systemContext; - protected final ObjectMapper mapper = new ObjectMapper(); protected AbstractContextAwareMsgProcessor(ActorSystemContext systemContext) { super(); From f5c09d221de6ce6f307edc59e3ee0db39a382d3e Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Mon, 10 Jan 2022 23:47:50 +0200 Subject: [PATCH 364/432] TbMsgMetaData refactored constructor and copy method --- .../server/common/msg/TbMsgMetaData.java | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsgMetaData.java b/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsgMetaData.java index 1fa6f0d4f4..8f23a917a2 100644 --- a/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsgMetaData.java +++ b/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsgMetaData.java @@ -15,9 +15,7 @@ */ package org.thingsboard.server.common.msg; -import lombok.AllArgsConstructor; import lombok.Data; -import lombok.NoArgsConstructor; import java.io.Serializable; import java.util.Collections; @@ -29,15 +27,18 @@ import java.util.concurrent.ConcurrentHashMap; * Created by ashvayka on 13.01.18. */ @Data -@NoArgsConstructor public final class TbMsgMetaData implements Serializable { public static final TbMsgMetaData EMPTY = new TbMsgMetaData(Collections.emptyMap()); - private final Map data = new ConcurrentHashMap<>(); + private final Map data; + + public TbMsgMetaData() { + this.data = new ConcurrentHashMap<>(); + } public TbMsgMetaData(Map data) { - data.forEach((key, val) -> putValue(key, val)); + this.data = new ConcurrentHashMap<>(data); } public String getValue(String key) { @@ -55,6 +56,6 @@ public final class TbMsgMetaData implements Serializable { } public TbMsgMetaData copy() { - return new TbMsgMetaData(new ConcurrentHashMap<>(data)); + return new TbMsgMetaData(data); } } From a11146b44592d13ef636e397a24250ebe4e910cb Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Mon, 10 Jan 2022 23:55:58 +0200 Subject: [PATCH 365/432] immutable TbMsgMetaData.EMPTY --- .../org/thingsboard/server/common/msg/TbMsgMetaData.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsgMetaData.java b/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsgMetaData.java index 8f23a917a2..2376a7a35f 100644 --- a/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsgMetaData.java +++ b/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsgMetaData.java @@ -29,7 +29,7 @@ import java.util.concurrent.ConcurrentHashMap; @Data public final class TbMsgMetaData implements Serializable { - public static final TbMsgMetaData EMPTY = new TbMsgMetaData(Collections.emptyMap()); + public static final TbMsgMetaData EMPTY = new TbMsgMetaData(0); private final Map data; @@ -41,6 +41,13 @@ public final class TbMsgMetaData implements Serializable { this.data = new ConcurrentHashMap<>(data); } + /** + * Internal constructor to create immutable TbMsgMetaData.EMPTY + * */ + private TbMsgMetaData(int ignored) { + this.data = Collections.emptyMap(); + } + public String getValue(String key) { return data.get(key); } From d46575aeafddda85cf37b4de9b36103e660d5607 Mon Sep 17 00:00:00 2001 From: Nikitozin Date: Tue, 11 Jan 2022 11:49:28 +0200 Subject: [PATCH 366/432] [WIP][3.3.3] Add statement for support double type. --- .../engine/action/TbSaveToCustomCassandraTableNode.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbSaveToCustomCassandraTableNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbSaveToCustomCassandraTableNode.java index a56cb644be..bd3371edae 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbSaveToCustomCassandraTableNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbSaveToCustomCassandraTableNode.java @@ -182,7 +182,11 @@ public class TbSaveToCustomCassandraTableNode implements TbNode { if (dataAsObject.get(key).isJsonPrimitive()) { JsonPrimitive primitive = dataAsObject.get(key).getAsJsonPrimitive(); if (primitive.isNumber()) { - stmtBuilder.setLong(i.get(), dataAsObject.get(key).getAsLong()); + if (dataAsObject.get(key).getAsString().contains(".")) { + stmtBuilder.setDouble(i.get(), dataAsObject.get(key).getAsDouble()); + } else { + stmtBuilder.setLong(i.get(), dataAsObject.get(key).getAsLong()); + } } else if (primitive.isBoolean()) { stmtBuilder.setBoolean(i.get(), dataAsObject.get(key).getAsBoolean()); } else if (primitive.isString()) { From b0a79e9fc3236dffd2a763274cb7c9d15cc797fa Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Tue, 11 Jan 2022 12:23:48 +0200 Subject: [PATCH 367/432] static transport immutable proto SESSION_EVENT_MSG_OPEN, SESSION_EVENT_MSG_CLOSED, SESSION_CLOSE_NOTIFICATION_PROTO, SUBSCRIBE_TO_ATTRIBUTE_UPDATES_ASYNC_MSG, SUBSCRIBE_TO_RPC_ASYNC_MSG --- .../session/DefaultLwM2MSessionManager.java | 14 +++++++---- .../transport/mqtt/MqttTransportHandler.java | 7 +++--- .../mqtt/session/GatewaySessionHandler.java | 15 ++++++------ .../service/DefaultTransportService.java | 24 ++++++++++--------- 4 files changed, 34 insertions(+), 26 deletions(-) diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/session/DefaultLwM2MSessionManager.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/session/DefaultLwM2MSessionManager.java index ee6e4a779b..a9198f9fcd 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/session/DefaultLwM2MSessionManager.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/session/DefaultLwM2MSessionManager.java @@ -19,7 +19,6 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.thingsboard.server.common.transport.TransportService; -import org.thingsboard.server.common.transport.service.DefaultTransportService; import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; import org.thingsboard.server.transport.lwm2m.server.LwM2mSessionMsgListener; @@ -27,6 +26,11 @@ import org.thingsboard.server.transport.lwm2m.server.attributes.LwM2MAttributesS import org.thingsboard.server.transport.lwm2m.server.rpc.LwM2MRpcRequestHandler; import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler; +import static org.thingsboard.server.common.transport.service.DefaultTransportService.SESSION_EVENT_MSG_CLOSED; +import static org.thingsboard.server.common.transport.service.DefaultTransportService.SESSION_EVENT_MSG_OPEN; +import static org.thingsboard.server.common.transport.service.DefaultTransportService.SUBSCRIBE_TO_ATTRIBUTE_UPDATES_ASYNC_MSG; +import static org.thingsboard.server.common.transport.service.DefaultTransportService.SUBSCRIBE_TO_RPC_ASYNC_MSG; + @Slf4j @Service @TbLwM2mTransportComponent @@ -52,16 +56,16 @@ public class DefaultLwM2MSessionManager implements LwM2MSessionManager { transportService.registerAsyncSession(sessionInfo, new LwM2mSessionMsgListener(uplinkHandler, attributesService, rpcHandler, sessionInfo, transportService)); TransportProtos.TransportToDeviceActorMsg msg = TransportProtos.TransportToDeviceActorMsg.newBuilder() .setSessionInfo(sessionInfo) - .setSessionEvent(DefaultTransportService.getSessionEventMsg(TransportProtos.SessionEvent.OPEN)) - .setSubscribeToAttributes(TransportProtos.SubscribeToAttributeUpdatesMsg.newBuilder().setSessionType(TransportProtos.SessionType.ASYNC).build()) - .setSubscribeToRPC(TransportProtos.SubscribeToRPCMsg.newBuilder().setSessionType(TransportProtos.SessionType.ASYNC).build()) + .setSessionEvent(SESSION_EVENT_MSG_OPEN) + .setSubscribeToAttributes(SUBSCRIBE_TO_ATTRIBUTE_UPDATES_ASYNC_MSG) + .setSubscribeToRPC(SUBSCRIBE_TO_RPC_ASYNC_MSG) .build(); transportService.process(msg, null); } @Override public void deregister(TransportProtos.SessionInfoProto sessionInfo) { - transportService.process(sessionInfo, DefaultTransportService.getSessionEventMsg(TransportProtos.SessionEvent.CLOSED), null); + transportService.process(sessionInfo, SESSION_EVENT_MSG_CLOSED, null); transportService.deregisterSession(sessionInfo); } } diff --git a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportHandler.java b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportHandler.java index fe39721f27..c99b4e1a45 100644 --- a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportHandler.java +++ b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportHandler.java @@ -65,7 +65,6 @@ import org.thingsboard.server.common.transport.service.SessionMetaData; import org.thingsboard.server.common.transport.util.SslUtil; import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.gen.transport.TransportProtos.ProvisionDeviceResponseMsg; -import org.thingsboard.server.gen.transport.TransportProtos.SessionEvent; import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceX509CertRequestMsg; import org.thingsboard.server.queue.scheduler.SchedulerComponent; import org.thingsboard.server.transport.mqtt.adaptors.MqttTransportAdaptor; @@ -102,6 +101,8 @@ import static io.netty.handler.codec.mqtt.MqttMessageType.UNSUBACK; import static io.netty.handler.codec.mqtt.MqttQoS.AT_LEAST_ONCE; import static io.netty.handler.codec.mqtt.MqttQoS.AT_MOST_ONCE; import static io.netty.handler.codec.mqtt.MqttQoS.FAILURE; +import static org.thingsboard.server.common.transport.service.DefaultTransportService.SESSION_EVENT_MSG_CLOSED; +import static org.thingsboard.server.common.transport.service.DefaultTransportService.SESSION_EVENT_MSG_OPEN; /** * @author Andrew Shvayka @@ -929,7 +930,7 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement public void doDisconnect() { if (deviceSessionCtx.isConnected()) { log.debug("[{}] Client disconnected!", sessionId); - transportService.process(deviceSessionCtx.getSessionInfo(), DefaultTransportService.getSessionEventMsg(SessionEvent.CLOSED), null); + transportService.process(deviceSessionCtx.getSessionInfo(), SESSION_EVENT_MSG_CLOSED, null); transportService.deregisterSession(deviceSessionCtx.getSessionInfo()); if (gatewaySessionHandler != null) { gatewaySessionHandler.onGatewayDisconnect(); @@ -948,7 +949,7 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement deviceSessionCtx.setDeviceInfo(msg.getDeviceInfo()); deviceSessionCtx.setDeviceProfile(msg.getDeviceProfile()); deviceSessionCtx.setSessionInfo(SessionInfoCreator.create(msg, context, sessionId)); - transportService.process(deviceSessionCtx.getSessionInfo(), DefaultTransportService.getSessionEventMsg(SessionEvent.OPEN), new TransportServiceCallback() { + transportService.process(deviceSessionCtx.getSessionInfo(), SESSION_EVENT_MSG_OPEN, new TransportServiceCallback() { @Override public void onSuccess(Void msg) { SessionMetaData sessionMetaData = transportService.registerAsyncSession(deviceSessionCtx.getSessionInfo(), MqttTransportHandler.this); diff --git a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/GatewaySessionHandler.java b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/GatewaySessionHandler.java index 7b45b5f9d9..cb984327da 100644 --- a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/GatewaySessionHandler.java +++ b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/GatewaySessionHandler.java @@ -44,7 +44,6 @@ import org.thingsboard.server.common.transport.adaptor.JsonConverter; import org.thingsboard.server.common.transport.adaptor.ProtoConverter; import org.thingsboard.server.common.transport.auth.GetOrCreateDeviceFromGatewayResponse; import org.thingsboard.server.common.transport.auth.TransportDeviceInfo; -import org.thingsboard.server.common.transport.service.DefaultTransportService; import org.thingsboard.server.gen.transport.TransportApiProtos; import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.gen.transport.TransportProtos.GetOrCreateDeviceFromGatewayRequestMsg; @@ -68,6 +67,10 @@ import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import static org.springframework.util.ConcurrentReferenceHashMap.ReferenceType; +import static org.thingsboard.server.common.transport.service.DefaultTransportService.SESSION_EVENT_MSG_CLOSED; +import static org.thingsboard.server.common.transport.service.DefaultTransportService.SESSION_EVENT_MSG_OPEN; +import static org.thingsboard.server.common.transport.service.DefaultTransportService.SUBSCRIBE_TO_ATTRIBUTE_UPDATES_ASYNC_MSG; +import static org.thingsboard.server.common.transport.service.DefaultTransportService.SUBSCRIBE_TO_RPC_ASYNC_MSG; /** * Created by ashvayka on 19.01.17. @@ -267,11 +270,9 @@ public class GatewaySessionHandler { transportService.registerAsyncSession(deviceSessionInfo, deviceSessionCtx); transportService.process(TransportProtos.TransportToDeviceActorMsg.newBuilder() .setSessionInfo(deviceSessionInfo) - .setSessionEvent(DefaultTransportService.getSessionEventMsg(TransportProtos.SessionEvent.OPEN)) - .setSubscribeToAttributes(TransportProtos.SubscribeToAttributeUpdatesMsg.newBuilder() - .setSessionType(TransportProtos.SessionType.ASYNC).build()) - .setSubscribeToRPC(TransportProtos.SubscribeToRPCMsg.newBuilder() - .setSessionType(TransportProtos.SessionType.ASYNC).build()) + .setSessionEvent(SESSION_EVENT_MSG_OPEN) + .setSubscribeToAttributes(SUBSCRIBE_TO_ATTRIBUTE_UPDATES_ASYNC_MSG) + .setSubscribeToRPC(SUBSCRIBE_TO_RPC_ASYNC_MSG) .build(), null); } futureToSet.set(devices.get(deviceName)); @@ -720,7 +721,7 @@ public class GatewaySessionHandler { private void deregisterSession(String deviceName, GatewayDeviceSessionCtx deviceSessionCtx) { transportService.deregisterSession(deviceSessionCtx.getSessionInfo()); - transportService.process(deviceSessionCtx.getSessionInfo(), DefaultTransportService.getSessionEventMsg(TransportProtos.SessionEvent.CLOSED), null); + transportService.process(deviceSessionCtx.getSessionInfo(), SESSION_EVENT_MSG_CLOSED, null); log.debug("[{}] Removed device [{}] from the gateway session", sessionId, deviceName); } diff --git a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java index 57d1da63b4..98ffcd721e 100644 --- a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java +++ b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java @@ -21,7 +21,6 @@ import com.google.common.util.concurrent.MoreExecutors; import com.google.gson.Gson; import com.google.gson.JsonObject; import com.google.protobuf.ByteString; -import lombok.Getter; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.ApplicationEventPublisher; @@ -124,6 +123,15 @@ import java.util.stream.Collectors; public class DefaultTransportService implements TransportService { public static final String OVERWRITE_ACTIVITY_TIME = "overwriteActivityTime"; + public static final String SESSION_EXPIRED_MESSAGE = "Session has expired due to last activity time!"; + public static final TransportProtos.SessionEventMsg SESSION_EVENT_MSG_OPEN = getSessionEventMsg(TransportProtos.SessionEvent.OPEN); + public static final TransportProtos.SessionEventMsg SESSION_EVENT_MSG_CLOSED = getSessionEventMsg(TransportProtos.SessionEvent.CLOSED); + public static final TransportProtos.SessionCloseNotificationProto SESSION_CLOSE_NOTIFICATION_PROTO = TransportProtos.SessionCloseNotificationProto.newBuilder() + .setMessage(SESSION_EXPIRED_MESSAGE).build(); + public static final TransportProtos.SubscribeToAttributeUpdatesMsg SUBSCRIBE_TO_ATTRIBUTE_UPDATES_ASYNC_MSG = TransportProtos.SubscribeToAttributeUpdatesMsg.newBuilder() + .setSessionType(TransportProtos.SessionType.ASYNC).build(); + public static final TransportProtos.SubscribeToRPCMsg SUBSCRIBE_TO_RPC_ASYNC_MSG = TransportProtos.SubscribeToRPCMsg.newBuilder() + .setSessionType(TransportProtos.SessionType.ASYNC).build(); private final AtomicInteger atomicTs = new AtomicInteger(0); @@ -267,9 +275,7 @@ public class DefaultTransportService implements TransportService { @Override public SessionMetaData registerAsyncSession(TransportProtos.SessionInfoProto sessionInfo, SessionMsgListener listener) { - SessionMetaData newValue = new SessionMetaData(sessionInfo, TransportProtos.SessionType.ASYNC, listener); - SessionMetaData oldValue = sessions.putIfAbsent(toSessionId(sessionInfo), newValue); - return oldValue != null ? oldValue : newValue; + return sessions.computeIfAbsent(toSessionId(sessionInfo), (x) -> new SessionMetaData(sessionInfo, TransportProtos.SessionType.ASYNC, listener)); } @Override @@ -719,12 +725,8 @@ public class DefaultTransportService implements TransportService { } sessions.remove(uuid); sessionsToRemove.add(uuid); - process(sessionInfo, getSessionEventMsg(TransportProtos.SessionEvent.CLOSED), null); - TransportProtos.SessionCloseNotificationProto sessionCloseNotificationProto = TransportProtos.SessionCloseNotificationProto - .newBuilder() - .setMessage("Session has expired due to last activity time!") - .build(); - sessionMD.getListener().onRemoteSessionCloseCommand(uuid, sessionCloseNotificationProto); + process(sessionInfo, SESSION_EVENT_MSG_CLOSED, null); + sessionMD.getListener().onRemoteSessionCloseCommand(uuid, SESSION_CLOSE_NOTIFICATION_PROTO); } } else { if (lastActivityTime > sessionAD.getLastReportedActivityTime()) { @@ -1018,7 +1020,7 @@ public class DefaultTransportService implements TransportService { return new DeviceId(new UUID(sessionInfo.getDeviceIdMSB(), sessionInfo.getDeviceIdLSB())); } - public static TransportProtos.SessionEventMsg getSessionEventMsg(TransportProtos.SessionEvent event) { + private static TransportProtos.SessionEventMsg getSessionEventMsg(TransportProtos.SessionEvent event) { return TransportProtos.SessionEventMsg.newBuilder() .setSessionType(TransportProtos.SessionType.ASYNC) .setEvent(event).build(); From 3c7ec8b7d3de98e20753aa4d31f5e3ba913b3c09 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Tue, 11 Jan 2022 12:45:34 +0200 Subject: [PATCH 368/432] lwm2m tests refactoring by comments --- .../thingsboard/server/controller/TbTestWebSocketClient.java | 2 +- .../server/transport/lwm2m/AbstractLwM2MIntegrationTest.java | 1 - .../server/transport/lwm2m/ota/sql/OtaLwM2MIntegrationTest.java | 2 -- 3 files changed, 1 insertion(+), 4 deletions(-) diff --git a/application/src/test/java/org/thingsboard/server/controller/TbTestWebSocketClient.java b/application/src/test/java/org/thingsboard/server/controller/TbTestWebSocketClient.java index 2bb68737ac..ff6b004405 100644 --- a/application/src/test/java/org/thingsboard/server/controller/TbTestWebSocketClient.java +++ b/application/src/test/java/org/thingsboard/server/controller/TbTestWebSocketClient.java @@ -74,7 +74,7 @@ public class TbTestWebSocketClient extends WebSocketClient { } public String waitForUpdate() { - return waitForUpdate(TimeUnit.SECONDS.toMillis(8)); + return waitForUpdate(TimeUnit.SECONDS.toMillis(3)); } public String waitForUpdate(long ms) { diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/AbstractLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/AbstractLwM2MIntegrationTest.java index 09495402f3..4fc9108862 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/AbstractLwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/AbstractLwM2MIntegrationTest.java @@ -16,7 +16,6 @@ package org.thingsboard.server.transport.lwm2m; import com.fasterxml.jackson.core.type.TypeReference; -import lombok.extern.slf4j.Slf4j; import org.apache.commons.io.IOUtils; import org.eclipse.californium.core.network.config.NetworkConfig; import org.eclipse.leshan.client.object.Security; diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/ota/sql/OtaLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/ota/sql/OtaLwM2MIntegrationTest.java index e3c538c928..3b152ec728 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/ota/sql/OtaLwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/ota/sql/OtaLwM2MIntegrationTest.java @@ -200,8 +200,6 @@ public class OtaLwM2MIntegrationTest extends AbstractOtaLwM2MIntegrationTest { * */ @Test public void testSoftwareUpdateByObject9() throws Exception { -// String endpoint = "Ota9_Device"; -// setEndpoint(endpoint); createDeviceProfile(OTA_TRANSPORT_CONFIGURATION); NoSecClientCredential credentials = createNoSecClientCredentials(this.CLIENT_ENDPOINT_OTA9); final Device device = createDevice(credentials); From 217a84f1f2ea3bbed90ba0e2d624ed4e4cd94665 Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Tue, 11 Jan 2022 12:56:02 +0200 Subject: [PATCH 369/432] request added to the log on "Pending request map is full" in DefaultTbQueueRequestTemplate.java --- .../server/queue/common/DefaultTbQueueRequestTemplate.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/common/DefaultTbQueueRequestTemplate.java b/common/queue/src/main/java/org/thingsboard/server/queue/common/DefaultTbQueueRequestTemplate.java index 7463c11df5..58890fb2a3 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/common/DefaultTbQueueRequestTemplate.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/common/DefaultTbQueueRequestTemplate.java @@ -210,7 +210,7 @@ public class DefaultTbQueueRequestTemplate send(Request request, long requestTimeoutNs) { if (pendingRequests.mappingCount() >= maxPendingRequests) { - log.warn("Pending request map is full [{}]! Consider to increase maxPendingRequests or increase processing performance", maxPendingRequests); + log.warn("Pending request map is full [{}]! Consider to increase maxPendingRequests or increase processing performance. Request is {}", maxPendingRequests, request); return Futures.immediateFailedFuture(new RuntimeException("Pending request map is full!")); } UUID requestId = UUID.randomUUID(); From 6479160932d8a6f78e9e556a5349ef1c8946e8e9 Mon Sep 17 00:00:00 2001 From: Nikitozin Date: Tue, 11 Jan 2022 13:44:47 +0200 Subject: [PATCH 370/432] [WIP][3.3.3] Refactor variables. --- .../action/TbSaveToCustomCassandraTableNode.java | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbSaveToCustomCassandraTableNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbSaveToCustomCassandraTableNode.java index bd3371edae..66291f5245 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbSaveToCustomCassandraTableNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbSaveToCustomCassandraTableNode.java @@ -179,18 +179,19 @@ public class TbSaveToCustomCassandraTableNode implements TbNode { if (key.equals(ENTITY_ID)) { stmtBuilder.setUuid(i.get(), msg.getOriginator().getId()); } else if (dataAsObject.has(key)) { - if (dataAsObject.get(key).isJsonPrimitive()) { - JsonPrimitive primitive = dataAsObject.get(key).getAsJsonPrimitive(); + JsonElement dataKeyElement = dataAsObject.get(key); + if (dataKeyElement.isJsonPrimitive()) { + JsonPrimitive primitive = dataKeyElement.getAsJsonPrimitive(); if (primitive.isNumber()) { - if (dataAsObject.get(key).getAsString().contains(".")) { - stmtBuilder.setDouble(i.get(), dataAsObject.get(key).getAsDouble()); + if (primitive.getAsString().contains(".")) { + stmtBuilder.setDouble(i.get(), primitive.getAsDouble()); } else { - stmtBuilder.setLong(i.get(), dataAsObject.get(key).getAsLong()); + stmtBuilder.setLong(i.get(), primitive.getAsLong()); } } else if (primitive.isBoolean()) { - stmtBuilder.setBoolean(i.get(), dataAsObject.get(key).getAsBoolean()); + stmtBuilder.setBoolean(i.get(), primitive.getAsBoolean()); } else if (primitive.isString()) { - stmtBuilder.setString(i.get(), dataAsObject.get(key).getAsString()); + stmtBuilder.setString(i.get(), primitive.getAsString()); } else { stmtBuilder.setToNull(i.get()); } From 667045384649ac02f86e73418cf3daf07259c323 Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Tue, 11 Jan 2022 14:59:49 +0200 Subject: [PATCH 371/432] UI: Added persistent page link for entities pages --- .../components/alarm/alarm-table-config.ts | 1 + .../audit-log/audit-log-table-config.ts | 4 +- .../audit-log/audit-log-table.component.ts | 8 +- .../entity/entities-table.component.ts | 96 ++++++++++++++----- .../components/event/event-table-config.ts | 1 + .../entity/entities-table-config.models.ts | 1 + .../entity/entity-table-component.models.ts | 1 + .../audit-log/audit-log-routing.module.ts | 3 +- 8 files changed, 88 insertions(+), 27 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/alarm/alarm-table-config.ts b/ui-ngx/src/app/modules/home/components/alarm/alarm-table-config.ts index 2bff69a53e..6c4e0a22e0 100644 --- a/ui-ngx/src/app/modules/home/components/alarm/alarm-table-config.ts +++ b/ui-ngx/src/app/modules/home/components/alarm/alarm-table-config.ts @@ -60,6 +60,7 @@ export class AlarmTableConfig extends EntityTableConfig this.loadDataOnInit = false; this.tableTitle = ''; this.useTimePageLink = true; + this.persistentPageLinkMode = false; this.defaultTimewindowInterval = historyInterval(DAY * 30); this.detailsPanelEnabled = false; this.selectionEnabled = false; diff --git a/ui-ngx/src/app/modules/home/components/audit-log/audit-log-table-config.ts b/ui-ngx/src/app/modules/home/components/audit-log/audit-log-table-config.ts index f5c928f275..a61d0c54ab 100644 --- a/ui-ngx/src/app/modules/home/components/audit-log/audit-log-table-config.ts +++ b/ui-ngx/src/app/modules/home/components/audit-log/audit-log-table-config.ts @@ -52,11 +52,13 @@ export class AuditLogTableConfig extends EntityTableConfig) { + private store: Store, + private route: ActivatedRoute) { } ngOnInit() { @@ -117,6 +119,7 @@ export class AuditLogTableComponent implements OnInit { } updateOnInit = true; } + const persistentPageLinkMode = !!this.route.snapshot.data.isPage; this.auditLogTableConfig = new AuditLogTableConfig( this.auditLogService, this.translate, @@ -126,7 +129,8 @@ export class AuditLogTableComponent implements OnInit { this.entityIdValue, this.userIdValue, this.customerIdValue, - updateOnInit + updateOnInit, + persistentPageLinkMode ); } diff --git a/ui-ngx/src/app/modules/home/components/entity/entities-table.component.ts b/ui-ngx/src/app/modules/home/components/entity/entities-table.component.ts index 33f1b2afe4..8fd2f8a976 100644 --- a/ui-ngx/src/app/modules/home/components/entity/entities-table.component.ts +++ b/ui-ngx/src/app/modules/home/components/entity/entities-table.component.ts @@ -41,9 +41,10 @@ import { Direction, SortOrder } from '@shared/models/page/sort-order'; import { forkJoin, fromEvent, merge, Observable, of, Subscription } from 'rxjs'; import { TranslateService } from '@ngx-translate/core'; import { BaseData, HasId } from '@shared/models/base-data'; -import { ActivatedRoute } from '@angular/router'; +import { ActivatedRoute, QueryParamsHandling, Router } from '@angular/router'; import { - CellActionDescriptor, CellActionDescriptorType, + CellActionDescriptor, + CellActionDescriptorType, EntityActionTableColumn, EntityColumn, EntityTableColumn, @@ -55,14 +56,10 @@ import { EntityTypeTranslation } from '@shared/models/entity-type.models'; import { DialogService } from '@core/services/dialog.service'; import { AddEntityDialogComponent } from './add-entity-dialog.component'; import { AddEntityDialogData, EntityAction } from '@home/models/entity/entity-component.models'; -import { - calculateIntervalStartEndTime, - HistoryWindowType, - Timewindow -} from '@shared/models/time/time.models'; +import { calculateIntervalStartEndTime, HistoryWindowType, Timewindow } from '@shared/models/time/time.models'; import { DomSanitizer, SafeHtml } from '@angular/platform-browser'; import { TbAnchorComponent } from '@shared/components/tb-anchor.component'; -import { isDefined, isUndefined } from '@core/utils'; +import { isDefined, isEmptyStr, isUndefined } from '@core/utils'; import { HasUUID } from '@shared/models/id/has-uuid'; import { IEntitiesTableComponent } from '@home/models/entity/entity-table-component.models'; @@ -101,6 +98,7 @@ export class EntitiesTableComponent extends PageComponent implements IEntitiesTa displayPagination = true; pageSizeOptions; pageLink: PageLink; + persistentPageLinkMode = true; textSearchMode = false; timewindow: Timewindow; dataSource: EntitiesDataSource>; @@ -117,7 +115,6 @@ export class EntitiesTableComponent extends PageComponent implements IEntitiesTa @ViewChild(MatPaginator) paginator: MatPaginator; @ViewChild(MatSort) sort: MatSort; - private sortSubscription: Subscription; private updateDataSubscription: Subscription; private viewInited = false; @@ -128,6 +125,7 @@ export class EntitiesTableComponent extends PageComponent implements IEntitiesTa private dialogService: DialogService, private domSanitizer: DomSanitizer, private cd: ChangeDetectorRef, + private router: Router, private componentFactoryResolver: ComponentFactoryResolver) { super(store); } @@ -196,16 +194,19 @@ export class EntitiesTableComponent extends PageComponent implements IEntitiesTa this.columnsUpdated(); + const routerQueryParams = this.route.snapshot.queryParams; + let sortOrder: SortOrder = null; - if (this.entitiesTableConfig.defaultSortOrder) { + if (this.entitiesTableConfig.defaultSortOrder || routerQueryParams.hasOwnProperty('direction') || routerQueryParams.hasOwnProperty('property')) { sortOrder = { - property: this.entitiesTableConfig.defaultSortOrder.property, - direction: this.entitiesTableConfig.defaultSortOrder.direction + property: routerQueryParams?.property || this.entitiesTableConfig.defaultSortOrder.property, + direction: routerQueryParams?.direction || this.entitiesTableConfig.defaultSortOrder.direction }; } this.displayPagination = this.entitiesTableConfig.displayPagination; this.defaultPageSize = this.entitiesTableConfig.defaultPageSize; + this.persistentPageLinkMode = this.entitiesTableConfig.persistentPageLinkMode; this.pageSizeOptions = [this.defaultPageSize, this.defaultPageSize * 2, this.defaultPageSize * 3]; if (this.entitiesTableConfig.useTimePageLink) { @@ -217,6 +218,16 @@ export class EntitiesTableComponent extends PageComponent implements IEntitiesTa this.pageLink = new PageLink(10, 0, null, sortOrder); } this.pageLink.pageSize = this.displayPagination ? this.defaultPageSize : MAX_SAFE_PAGE_SIZE; + if (routerQueryParams.hasOwnProperty('page')) { + this.pageLink.page = routerQueryParams.page; + } + if (routerQueryParams.hasOwnProperty('pageSize')) { + this.pageLink.pageSize = routerQueryParams.pageSize; + } + if (routerQueryParams.hasOwnProperty('textSearch') && !isEmptyStr(routerQueryParams.textSearch)) { + this.textSearchMode = true; + this.pageLink.textSearch = decodeURI(routerQueryParams.textSearch); + } this.dataSource = this.entitiesTableConfig.dataSource(this.dataLoaded.bind(this)); if (this.entitiesTableConfig.onLoadAction) { this.entitiesTableConfig.onLoadAction(this.route); @@ -238,9 +249,14 @@ export class EntitiesTableComponent extends PageComponent implements IEntitiesTa debounceTime(150), distinctUntilChanged(), tap(() => { + const queryParams: any = { + textSearch: encodeURI(this.pageLink.textSearch) || null + }; if (this.displayPagination) { this.paginator.pageIndex = 0; + queryParams.page = null; } + this.updatedRouterQueryParams(queryParams); this.updateData(); }) ) @@ -251,23 +267,42 @@ export class EntitiesTableComponent extends PageComponent implements IEntitiesTa } private updatePaginationSubscriptions() { - if (this.sortSubscription) { - this.sortSubscription.unsubscribe(); - this.sortSubscription = null; - } if (this.updateDataSubscription) { this.updateDataSubscription.unsubscribe(); this.updateDataSubscription = null; } + let paginatorSubscription$: Observable; + const sortSubscription$: Observable = this.sort.sortChange.asObservable().pipe( + map((data) => { + const direction = data.direction.toUpperCase(); + const queryParams: any = { + direction: this.entitiesTableConfig?.defaultSortOrder?.direction === direction ? null : direction, + property: this.entitiesTableConfig?.defaultSortOrder?.property === data.active ? null : data.active + }; + if (this.displayPagination) { + queryParams.page = null; + this.paginator.pageIndex = 0; + } + return queryParams; + }) + ); if (this.displayPagination) { - this.sortSubscription = this.sort.sortChange.subscribe(() => this.paginator.pageIndex = 0); + paginatorSubscription$ = this.paginator.page.asObservable().pipe( + map((data) => { + return { + page: data.pageIndex === 0 ? null : data.pageIndex, + pageSize: data.pageSize === this.defaultPageSize ? null : data.pageSize + }; + }) + ); } - this.updateDataSubscription = ((this.displayPagination ? merge(this.sort.sortChange, this.paginator.page) - : this.sort.sortChange) as Observable) - .pipe( - tap(() => this.updateData()) - ) - .subscribe(); + this.updateDataSubscription = ((this.displayPagination ? merge(sortSubscription$, paginatorSubscription$) + : sortSubscription$) as Observable).pipe( + tap((queryParams) => { + this.updatedRouterQueryParams(queryParams); + this.updateData(); + }) + ).subscribe(); } addEnabled() { @@ -451,9 +486,14 @@ export class EntitiesTableComponent extends PageComponent implements IEntitiesTa exitFilterMode() { this.textSearchMode = false; this.pageLink.textSearch = null; + const queryParams: any = { + textSearch: null + }; if (this.displayPagination) { this.paginator.pageIndex = 0; + queryParams.page = null; } + this.updatedRouterQueryParams(queryParams); this.updateData(); } @@ -468,6 +508,7 @@ export class EntitiesTableComponent extends PageComponent implements IEntitiesTa const sortable = this.sort.sortables.get(this.entitiesTableConfig.defaultSortOrder.property); this.sort.active = sortable.id; this.sort.direction = this.entitiesTableConfig.defaultSortOrder.direction === Direction.ASC ? 'asc' : 'desc'; + this.updatedRouterQueryParams({}, 'preserve'); if (update) { this.updateData(); } @@ -587,4 +628,13 @@ export class EntitiesTableComponent extends PageComponent implements IEntitiesTa return entity.id.id; } + protected updatedRouterQueryParams(queryParams: object, queryParamsHandling: QueryParamsHandling = 'merge') { + if (this.persistentPageLinkMode) { + this.router.navigate([], { + relativeTo: this.route, + queryParams, + queryParamsHandling + }); + } + } } diff --git a/ui-ngx/src/app/modules/home/components/event/event-table-config.ts b/ui-ngx/src/app/modules/home/components/event/event-table-config.ts index d407cf262b..d6eedb7ff6 100644 --- a/ui-ngx/src/app/modules/home/components/event/event-table-config.ts +++ b/ui-ngx/src/app/modules/home/components/event/event-table-config.ts @@ -92,6 +92,7 @@ export class EventTableConfig extends EntityTableConfig { this.searchEnabled = false; this.addEnabled = false; this.entitiesDeleteEnabled = false; + this.persistentPageLinkMode = false; this.headerComponent = EventTableHeaderComponent; diff --git a/ui-ngx/src/app/modules/home/models/entity/entities-table-config.models.ts b/ui-ngx/src/app/modules/home/models/entity/entities-table-config.models.ts index 93e68e40b7..d6ddf40735 100644 --- a/ui-ngx/src/app/modules/home/models/entity/entities-table-config.models.ts +++ b/ui-ngx/src/app/modules/home/models/entity/entities-table-config.models.ts @@ -160,6 +160,7 @@ export class EntityTableConfig, P extends PageLink = P addDialogStyle = {}; defaultSortOrder: SortOrder = {property: 'createdTime', direction: Direction.DESC}; displayPagination = true; + persistentPageLinkMode = true; defaultPageSize = 10; columns: Array> = []; cellActionDescriptors: Array> = []; diff --git a/ui-ngx/src/app/modules/home/models/entity/entity-table-component.models.ts b/ui-ngx/src/app/modules/home/models/entity/entity-table-component.models.ts index 20b1d15b32..4cf41f0fed 100644 --- a/ui-ngx/src/app/modules/home/models/entity/entity-table-component.models.ts +++ b/ui-ngx/src/app/modules/home/models/entity/entity-table-component.models.ts @@ -50,6 +50,7 @@ export interface IEntitiesTableComponent { displayPagination: boolean; pageSizeOptions: number[]; pageLink: PageLink; + persistentPageLinkMode: boolean; textSearchMode: boolean; timewindow: Timewindow; dataSource: EntitiesDataSource>; diff --git a/ui-ngx/src/app/modules/home/pages/audit-log/audit-log-routing.module.ts b/ui-ngx/src/app/modules/home/pages/audit-log/audit-log-routing.module.ts index 89d304e8f1..b471f3b540 100644 --- a/ui-ngx/src/app/modules/home/pages/audit-log/audit-log-routing.module.ts +++ b/ui-ngx/src/app/modules/home/pages/audit-log/audit-log-routing.module.ts @@ -29,7 +29,8 @@ const routes: Routes = [ breadcrumb: { label: 'audit-log.audit-logs', icon: 'track_changes' - } + }, + isPage: true } } ]; From 76a8f32c211a2778db98a41dc662a7610cbb5fe5 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Tue, 11 Jan 2022 15:51:51 +0200 Subject: [PATCH 372/432] Fix markdown component styles --- ui-ngx/src/styles.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui-ngx/src/styles.scss b/ui-ngx/src/styles.scss index edf7e0e2bb..e34af4a5ab 100644 --- a/ui-ngx/src/styles.scss +++ b/ui-ngx/src/styles.scss @@ -566,7 +566,7 @@ mat-label { } } - table { + & > table { margin-left: 32px; width: calc(100% - 64px); border: 1px solid rgba(42,125,236,.2); From 9de9e6147fa5ef6db5d644b3cffd36bd6422a718 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Tue, 11 Jan 2022 17:46:06 +0200 Subject: [PATCH 373/432] lwm2m fix bug update profile if security mode == null --- .../3.3.2/schema_update_lwm2m_bootstrap.sql | 51 ++++++++++++------- .../install/SqlDatabaseUpgradeService.java | 2 + 2 files changed, 34 insertions(+), 19 deletions(-) diff --git a/application/src/main/data/upgrade/3.3.2/schema_update_lwm2m_bootstrap.sql b/application/src/main/data/upgrade/3.3.2/schema_update_lwm2m_bootstrap.sql index a182bc8117..8daa1b1e1e 100644 --- a/application/src/main/data/upgrade/3.3.2/schema_update_lwm2m_bootstrap.sql +++ b/application/src/main/data/upgrade/3.3.2/schema_update_lwm2m_bootstrap.sql @@ -14,6 +14,7 @@ -- limitations under the License. -- + CREATE OR REPLACE PROCEDURE update_profile_bootstrap() LANGUAGE plpgsql AS $$ @@ -25,9 +26,11 @@ BEGIN profile_data, '{transportConfiguration}', get_bootstrap( - profile_data::jsonb #> '{transportConfiguration}', - subquery.publickey_bs, - subquery.publickey_lw), + profile_data::jsonb #> '{transportConfiguration}', + subquery.publickey_bs, + subquery.publickey_lw, + profile_data::json #>> '{transportConfiguration, bootstrap, bootstrapServer, securityMode}', + profile_data::json #>> '{transportConfiguration, bootstrap, lwm2mServer, securityMode}'), true) FROM ( SELECT id, @@ -48,7 +51,8 @@ END; $$; CREATE OR REPLACE FUNCTION get_bootstrap(transport_configuration_in jsonb, publickey_bs text, - publickey_lw text) RETURNS jsonb AS + publickey_lw text, security_mode_bs text, + security_mode_lw text) RETURNS jsonb AS $$ DECLARE @@ -56,10 +60,19 @@ DECLARE bootstrap_in jsonb; BEGIN + + IF security_mode_lw IS NULL THEN + security_mode_lw := 'NO_SEC'; + END IF; + + IF security_mode_bs IS NULL THEN + security_mode_bs := 'NO_SEC'; + END IF; + bootstrap_in := transport_configuration_in::jsonb #> '{bootstrap}'; bootstrap_new := json_build_array( json_build_object('shortServerId', bootstrap_in::json #> '{bootstrapServer}' -> 'serverId', - 'securityMode', bootstrap_in::json #> '{bootstrapServer}' ->> 'securityMode', + 'securityMode', security_mode_bs, 'binding', bootstrap_in::json #> '{servers}' ->> 'binding', 'lifetime', bootstrap_in::json #> '{servers}' -> 'lifetime', 'notifIfDisabled', bootstrap_in::json #> '{servers}' -> 'notifIfDisabled', @@ -73,7 +86,7 @@ BEGIN bootstrap_in::json #> '{bootstrapServer}' -> 'bootstrapServerAccountTimeout' ), json_build_object('shortServerId', bootstrap_in::json #> '{lwm2mServer}' -> 'serverId', - 'securityMode', bootstrap_in::json #> '{lwm2mServer}' ->> 'securityMode', + 'securityMode', security_mode_lw, 'binding', bootstrap_in::json #> '{servers}' ->> 'binding', 'lifetime', bootstrap_in::json #> '{servers}' -> 'lifetime', 'notifIfDisabled', bootstrap_in::json #> '{servers}' -> 'notifIfDisabled', @@ -93,7 +106,7 @@ BEGIN bootstrap_new, true) || '{"bootstrapServerUpdateEnable": true}'; -END ; +END; $$ LANGUAGE plpgsql; CREATE OR REPLACE PROCEDURE update_device_credentials_to_base64_and_bootstrap() @@ -102,9 +115,9 @@ $$ BEGIN -UPDATE device_credentials -SET credentials_value = get_device_and_bootstrap(credentials_value::text) -WHERE credentials_type = 'LWM2M_CREDENTIALS'; + UPDATE device_credentials + SET credentials_value = get_device_and_bootstrap(credentials_value::text) + WHERE credentials_type = 'LWM2M_CREDENTIALS'; END; $$; @@ -112,7 +125,7 @@ CREATE OR REPLACE FUNCTION get_device_and_bootstrap(IN credentials_value text, O LANGUAGE plpgsql AS $$ DECLARE -client_secret_key text; + client_secret_key text; client_public_key_or_id text; client_key_value_object jsonb; client_bootstrap_server_value_object jsonb; @@ -130,7 +143,7 @@ BEGIN 'key', client_public_key_or_id); credentials_value_new := credentials_value_new::jsonb || json_build_object('client', client_key_value_object)::jsonb; -END IF; + END IF; IF credentials_value::jsonb #> '{client}' ->> 'securityConfigClientMode' = 'X509' AND NULLIF((credentials_value::jsonb #> '{client}' ->> 'cert' ~ '^[0-9a-fA-F]+$')::text, 'false') = 'true' THEN client_public_key_or_id := @@ -141,8 +154,8 @@ END IF; 'cert', client_public_key_or_id); credentials_value_new := credentials_value_new::jsonb || json_build_object('client', client_key_value_object)::jsonb; -END IF; - + END IF; + IF credentials_value::jsonb #> '{bootstrap,lwm2mServer}' ->> 'securityMode' = 'RPK' OR credentials_value::jsonb #> '{bootstrap,lwm2mServer}' ->> 'securityMode' = 'X509' THEN IF NULLIF((credentials_value::jsonb #> '{bootstrap,lwm2mServer}' ->> 'clientSecretKey' ~ '^[0-9a-fA-F]+$')::text, @@ -165,9 +178,9 @@ END IF; client_bootstrap_object := credentials_value_new::jsonb #> '{bootstrap}' || client_bootstrap_server_object::jsonb; credentials_value_new := jsonb_set(credentials_value_new::jsonb, '{bootstrap}', client_bootstrap_object::jsonb, false)::jsonb; -END IF; -END IF; - + END IF; + END IF; + IF credentials_value::jsonb #> '{bootstrap,bootstrapServer}' ->> 'securityMode' = 'RPK' OR credentials_value::jsonb #> '{bootstrap,bootstrapServer}' ->> 'securityMode' = 'X509' THEN IF NULLIF( @@ -193,8 +206,8 @@ END IF; client_bootstrap_object := credentials_value_new::jsonb #> '{bootstrap}' || client_bootstrap_server_object::jsonb; credentials_value_new := jsonb_set(credentials_value_new::jsonb, '{bootstrap}', client_bootstrap_object::jsonb, false)::jsonb; -END IF; -END IF; + END IF; + END IF; END; $$; \ No newline at end of file diff --git a/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java b/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java index eef29026ba..c98e46d86e 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java @@ -476,6 +476,8 @@ public class SqlDatabaseUpgradeService implements DatabaseEntitiesUpgradeService schemaUpdateFile = Paths.get(installScripts.getDataDir(), "upgrade", "3.3.2", SCHEMA_UPDATE_SQL); loadSql(schemaUpdateFile, conn); log.info("Updating server`s public key from HexDec to Base64 in profile for LWM2M..."); + schemaUpdateFile = Paths.get(installScripts.getDataDir(), "upgrade", "3.3.2", "schema_update_lwm2m_bootstrap.sql"); + loadSql(schemaUpdateFile, conn); conn.createStatement().execute("call update_profile_bootstrap();"); log.info("Server`s public key from HexDec to Base64 in profile for LWM2M updated."); log.info("Updating client`s public key and secret key from HexDec to Base64 for LWM2M..."); From b49c32e7b15117df4842386eebb02b6e0bedffd2 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Tue, 11 Jan 2022 18:19:36 +0200 Subject: [PATCH 374/432] lwm2m frefactoring by comments2 --- .../lwm2m/AbstractLwM2MIntegrationTest.java | 4 +- .../transport/lwm2m/Lwm2mTestHelper.java | 42 +++++----- .../lwm2m/client/LwM2MTestClient.java | 25 ++---- .../client/LwM2mBinaryAppDataContainer.java | 11 +-- .../transport/lwm2m/client/LwM2mLocation.java | 4 - .../ota/AbstractOtaLwM2MIntegrationTest.java | 4 +- .../ota/sql/OtaLwM2MIntegrationTest.java | 2 +- .../rpc/AbstractRpcLwM2MIntegrationTest.java | 54 ++++++------- .../sql/RpcLwm2mIntegrationCreateTest.java | 30 ++++---- .../sql/RpcLwm2mIntegrationDeleteTest.java | 13 ++-- .../sql/RpcLwm2mIntegrationDiscoverTest.java | 8 +- .../sql/RpcLwm2mIntegrationExecuteTest.java | 30 ++++---- .../sql/RpcLwm2mIntegrationObserveTest.java | 26 +++---- .../rpc/sql/RpcLwm2mIntegrationReadTest.java | 68 ++++++++-------- ...pcLwm2mIntegrationWriteAttributesTest.java | 11 +-- .../rpc/sql/RpcLwm2mIntegrationWriteTest.java | 77 +++++++++---------- .../AbstractSecurityLwM2MIntegrationTest.java | 4 +- 17 files changed, 190 insertions(+), 223 deletions(-) diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/AbstractLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/AbstractLwM2MIntegrationTest.java index 4fc9108862..402e95b9ca 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/AbstractLwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/AbstractLwM2MIntegrationTest.java @@ -69,7 +69,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. @DaoSqlTest public abstract class AbstractLwM2MIntegrationTest extends AbstractWebsocketTest { - protected String transportConfiguration = "{\n" + + protected final String TRANSPORT_CONFIGURATION = "{\n" + " \"type\": \"LWM2M\",\n" + " \"observeAttr\": {\n" + " \"keyName\": {\n" + @@ -176,7 +176,7 @@ public abstract class AbstractLwM2MIntegrationTest extends AbstractWebsocketTest LwM2MClientCredential credentials, NetworkConfig coapConfig, String endpoint) throws Exception { - createDeviceProfile(transportConfiguration); + createDeviceProfile(TRANSPORT_CONFIGURATION); Device device = createDevice(credentials); SingleEntityFilter sef = new SingleEntityFilter(); diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/Lwm2mTestHelper.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/Lwm2mTestHelper.java index 8dd44d25ae..19bde32467 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/Lwm2mTestHelper.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/Lwm2mTestHelper.java @@ -43,26 +43,26 @@ public class Lwm2mTestHelper { public static final int TEMPERATURE_SENSOR = 3303; // Ids in Client - public static final int objectId_0 = 0; - public static final int objectInstanceId_0 = 0; - public static final int objectInstanceId_1 = 1; - public static final int objectInstanceId_2 = 2; - public static final int objectInstanceId_12 = 12; - public static final int resourceId_0 = 0; - public static final int resourceId_1 = 1; - public static final int resourceId_2 = 2; - public static final int resourceId_3 = 3; - public static final int resourceId_4 = 4; - public static final int resourceId_7 = 7; - public static final int resourceId_8 = 8; - public static final int resourceId_9 = 9; - public static final int resourceId_11 = 11; - public static final int resourceId_14 = 14; - public static final int resourceId_15= 15; - public static final int resourceInstanceId_2 = 2; + public static final int OBJECT_ID_0 = 0; + public static final int OBJECT_INSTANCE_ID_0 = 0; + public static final int OBJECT_INSTANCE_ID_1 = 1; + public static final int OBJECT_INSTANCE_ID_2 = 2; + public static final int OBJECT_INSTANCE_ID_12 = 12; + public static final int RESOURCE_ID_0 = 0; + public static final int RESOURCE_ID_1 = 1; + public static final int RESOURCE_ID_2 = 2; + public static final int RESOURCE_ID_3 = 3; + public static final int RESOURCE_ID_4 = 4; + public static final int RESOURCE_ID_7 = 7; + public static final int RESOURCE_ID_8 = 8; + public static final int RESOURCE_ID_9 = 9; + public static final int RESOURCE_ID_11 = 11; + public static final int RESOURCE_ID_14 = 14; + public static final int RESOURCE_ID_15 = 15; + public static final int RESOURCE_INSTANCE_ID_2 = 2; - public static final String resourceIdName_3_9 = "batteryLevel"; - public static final String resourceIdName_3_14 = "UtfOffset"; - public static final String resourceIdName_19_0_0 = "dataRead"; - public static final String resourceIdName_19_1_0 = "dataWrite"; + public static final String RESOURCE_ID_NAME_3_9 = "batteryLevel"; + public static final String RESOURCE_ID_NAME_3_14 = "UtfOffset"; + public static final String RESOURCE_ID_NAME_19_0_0 = "dataRead"; + public static final String RESOURCE_ID_NAME_19_1_0 = "dataWrite"; } diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2MTestClient.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2MTestClient.java index 1c62b2b79d..af12168802 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2MTestClient.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2MTestClient.java @@ -62,9 +62,9 @@ import static org.eclipse.leshan.core.LwM2mId.SERVER; import static org.eclipse.leshan.core.LwM2mId.SOFTWARE_MANAGEMENT; import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.BINARY_APP_DATA_CONTAINER; import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.TEMPERATURE_SENSOR; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.objectInstanceId_0; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.objectInstanceId_1; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.objectInstanceId_12; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.OBJECT_INSTANCE_ID_0; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.OBJECT_INSTANCE_ID_1; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.OBJECT_INSTANCE_ID_12; import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resources; @@ -99,12 +99,12 @@ public class LwM2MTestClient { initializer.setInstancesForObject(FIRMWARE, fwLwM2MDevice = new FwLwM2MDevice()); initializer.setInstancesForObject(SOFTWARE_MANAGEMENT, swLwM2MDevice = new SwLwM2MDevice()); initializer.setClassForObject(ACCESS_CONTROL, DummyInstanceEnabler.class); - initializer.setInstancesForObject(BINARY_APP_DATA_CONTAINER, lwM2MBinaryAppDataContainer = new LwM2mBinaryAppDataContainer(executor, objectInstanceId_0), - new LwM2mBinaryAppDataContainer(executor, objectInstanceId_1)); + initializer.setInstancesForObject(BINARY_APP_DATA_CONTAINER, lwM2MBinaryAppDataContainer = new LwM2mBinaryAppDataContainer(executor, OBJECT_INSTANCE_ID_0), + new LwM2mBinaryAppDataContainer(executor, OBJECT_INSTANCE_ID_1)); locationParams = new LwM2MLocationParams(); locationParams.getPos(); - initializer.setInstancesForObject(LOCATION, new LwM2mLocation(locationParams.getLatitude(), locationParams.getLongitude(), locationParams.getScaleFactor(), executor, objectInstanceId_0)); - initializer.setInstancesForObject(TEMPERATURE_SENSOR, lwM2MTemperatureSensor = new LwM2mTemperatureSensor(executor, objectInstanceId_0), new LwM2mTemperatureSensor(executor, objectInstanceId_12)); + initializer.setInstancesForObject(LOCATION, new LwM2mLocation(locationParams.getLatitude(), locationParams.getLongitude(), locationParams.getScaleFactor(), executor, OBJECT_INSTANCE_ID_0)); + initializer.setInstancesForObject(TEMPERATURE_SENSOR, lwM2MTemperatureSensor = new LwM2mTemperatureSensor(executor, OBJECT_INSTANCE_ID_0), new LwM2mTemperatureSensor(executor, OBJECT_INSTANCE_ID_12)); DtlsConnectorConfig.Builder dtlsConfig = new DtlsConnectorConfig.Builder(); dtlsConfig.setRecommendedCipherSuitesOnly(true); @@ -130,16 +130,6 @@ public class LwM2MTestClient { ObservationStore store) { CoapEndpoint.Builder builder = new CoapEndpoint.Builder(); DtlsConnectorConfig.Builder dtlsConfigBuilder = new DtlsConnectorConfig.Builder(dtlsConfig); - - // tricks to be able to change psk information on the fly -// AdvancedPskStore pskStore = dtlsConfig.getAdvancedPskStore(); -// if (pskStore != null) { -// PskPublicInformation identity = pskStore.getIdentity(null, null); -// SecretKey key = pskStore -// .requestPskSecretResult(ConnectionId.EMPTY, null, identity, null, null, null).getSecret(); -// singlePSKStore = new SinglePSKStore(identity, key); -// dtlsConfigBuilder.setAdvancedPskStore(singlePSKStore); -// } builder.setConnector(new DTLSConnector(dtlsConfigBuilder.build())); builder.setNetworkConfig(coapConfig); return builder.build(); @@ -283,5 +273,4 @@ public class LwM2MTestClient { client.start(); } } - } diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2mBinaryAppDataContainer.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2mBinaryAppDataContainer.java index b7ac889649..7da7599119 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2mBinaryAppDataContainer.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2mBinaryAppDataContainer.java @@ -66,8 +66,7 @@ public class LwM2mBinaryAppDataContainer extends BaseInstanceEnabler implements * "value":4 * }, */ -// private String data = "InNlcnZpY2VJZCI6Ik1ldGVyIiwNCiJzZXJ2aWNlRGF0YSI6ew0KImN1cnJlbnRSZWFkaW5nIjoiNDYuMyIsDQoic2lnbmFsU3RyZW5ndGgiOjE2LA0KImRhaWx5QWN0aXZpdHlUaW1lIjo1NzA2DQo="; -// private byte[] data; + Map data; private Integer priority = 0; private Time timestamp; @@ -83,7 +82,6 @@ public class LwM2mBinaryAppDataContainer extends BaseInstanceEnabler implements try { if (id != null) this.setId(id); executorService.scheduleWithFixedDelay(() -> -// fireResourcesChange(0, 2), 5000, 5000, TimeUnit.MILLISECONDS); fireResourcesChange(0, 2), 1800000, 1800000, TimeUnit.MILLISECONDS); // 30 MIN } catch (Throwable e) { log.error("[{}]Throwable", e.toString()); @@ -93,15 +91,11 @@ public class LwM2mBinaryAppDataContainer extends BaseInstanceEnabler implements @Override public ReadResponse read(ServerIdentity identity, int resourceId) { -// log.warn("Read on Location resource /[{}]/[{}]/[{}]", getModel().id, getId(), resourceId); try { switch (resourceId) { case 0: -// log.warn("Read on Location resource /[{}]/[{}]/[{}]", getModel().id, getId(), resourceId); ReadResponse response = ReadResponse.success(resourceId, getData(), ResourceModel.Type.OPAQUE); -// log.warn("Response [{}]", response); return response; - case 1: return ReadResponse.success(resourceId, getPriority()); case 2: @@ -168,7 +162,6 @@ public class LwM2mBinaryAppDataContainer extends BaseInstanceEnabler implements } private String getDataFormat() { -// return this.dataFormat == null ? "base64" : this.dataFormat; return this.dataFormat == null ? "OPAQUE" : this.dataFormat; } @@ -188,7 +181,6 @@ public class LwM2mBinaryAppDataContainer extends BaseInstanceEnabler implements return this.timestamp != null ? this.timestamp : new Time(new Date().getTime()); } -// fireResourcesChange(resourceId); private boolean setData(LwM2mResource value, boolean replace) { try { if (value instanceof LwM2mMultipleResource) { @@ -208,7 +200,6 @@ public class LwM2mBinaryAppDataContainer extends BaseInstanceEnabler implements } private Map getData() { -// this.data.put(23, new byte[]{0,0, 2,3}); return data; } diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2mLocation.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2mLocation.java index 079cd9fdac..b4dd8531f2 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2mLocation.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2mLocation.java @@ -101,19 +101,15 @@ public class LwM2mLocation extends BaseInstanceEnabler implements Destroyable { switch (nextMove.charAt(0)) { case 'w': moveLatitude(1.0f); -// log.info("Move to North [{}]/[{}]", getLatitude(), getLongitude()); break; case 'a': moveLongitude(-1.0f); -// log.info("Move to East [{}]/[{}]", getLatitude(), getLongitude()); break; case 's': moveLatitude(-1.0f); -// log.info("Move to South [{}]/[{}]", getLatitude(), getLongitude()); break; case 'd': moveLongitude(1.0f); -// log.info("Move to West [{}]/[{}]", getLatitude(), getLongitude()); break; } } diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/ota/AbstractOtaLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/ota/AbstractOtaLwM2MIntegrationTest.java index 6cf35aeb94..a4e5e92db4 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/ota/AbstractOtaLwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/ota/AbstractOtaLwM2MIntegrationTest.java @@ -29,13 +29,13 @@ import static org.thingsboard.server.common.data.ota.OtaPackageType.SOFTWARE; @DaoSqlTest public abstract class AbstractOtaLwM2MIntegrationTest extends AbstractLwM2MIntegrationTest { - private final String[] resources = new String[]{"3.xml", "5.xml", "9.xml"}; + private final String[] RESOURCES_OTA = new String[]{"3.xml", "5.xml", "9.xml"}; protected static final String CLIENT_ENDPOINT_WITHOUT_FW_INFO = "WithoutFirmwareInfoDevice"; protected static final String CLIENT_ENDPOINT_OTA5 = "Ota5_Device"; protected static final String CLIENT_ENDPOINT_OTA9 = "Ota9_Device"; public AbstractOtaLwM2MIntegrationTest() { - setResources(this.resources); + setResources(this.RESOURCES_OTA); } protected OtaPackageInfo createFirmware() throws Exception { diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/ota/sql/OtaLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/ota/sql/OtaLwM2MIntegrationTest.java index 3b152ec728..38db441e5d 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/ota/sql/OtaLwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/ota/sql/OtaLwM2MIntegrationTest.java @@ -138,7 +138,7 @@ public class OtaLwM2MIntegrationTest extends AbstractOtaLwM2MIntegrationTest { @Test public void testFirmwareUpdateWithClientWithoutFirmwareOtaInfoFromProfile() throws Exception { - createDeviceProfile(transportConfiguration); + createDeviceProfile(TRANSPORT_CONFIGURATION); NoSecClientCredential credentials = createNoSecClientCredentials(this.CLIENT_ENDPOINT_WITHOUT_FW_INFO); final Device device = createDevice(credentials); createNewClient(SECURITY, COAP_CONFIG, false, this.CLIENT_ENDPOINT_WITHOUT_FW_INFO); diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/AbstractRpcLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/AbstractRpcLwM2MIntegrationTest.java index 4303c5e6eb..fba8109dbf 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/AbstractRpcLwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/AbstractRpcLwM2MIntegrationTest.java @@ -34,16 +34,16 @@ import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.BINARY_APP_ import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.COAP_CONFIG; import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SECURITY; import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.TEMPERATURE_SENSOR; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.objectId_0; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.objectInstanceId_0; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.objectInstanceId_1; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceIdName_19_0_0; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceIdName_19_1_0; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceIdName_3_14; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceIdName_3_9; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_0; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_14; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_9; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.OBJECT_ID_0; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.OBJECT_INSTANCE_ID_0; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.OBJECT_INSTANCE_ID_1; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.RESOURCE_ID_NAME_19_0_0; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.RESOURCE_ID_NAME_19_1_0; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.RESOURCE_ID_NAME_3_14; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.RESOURCE_ID_NAME_3_9; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.RESOURCE_ID_0; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.RESOURCE_ID_14; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.RESOURCE_ID_9; import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resources; @DaoSqlTest @@ -60,13 +60,13 @@ public abstract class AbstractRpcLwM2MIntegrationTest extends AbstractLwM2MInteg protected String objectInstanceIdVer_1; protected String objectIdVer_0; protected String objectIdVer_2; - private static final Predicate predicate_3 = path -> (!((String) path).contains("/" + TEMPERATURE_SENSOR) && ((String) path).contains("/" + DEVICE)); + private static final Predicate PREDICATE_3 = path -> (!((String) path).contains("/" + TEMPERATURE_SENSOR) && ((String) path).contains("/" + DEVICE)); protected String objectIdVer_3; protected String objectInstanceIdVer_3; protected String objectInstanceIdVer_5; protected String objectInstanceIdVer_9; protected String objectIdVer_19; - protected String objectIdVer_50 = "/50"; + protected final String OBJECT_ID_VER_50 = "/50"; protected String objectIdVer_3303; protected static AtomicInteger endpointSequence = new AtomicInteger(); protected static String DEVICE_ENDPOINT_RPC_PREF = "deviceEndpointRpc"; @@ -100,19 +100,19 @@ public abstract class AbstractRpcLwM2MIntegrationTest extends AbstractLwM2MInteg }); } }); - String ver_Id_0 = client.getClient().getObjectTree().getModel().getObjectModel(objectId_0).version; + String ver_Id_0 = client.getClient().getObjectTree().getModel().getObjectModel(OBJECT_ID_0).version; if ("1.0".equals(ver_Id_0)) { - objectIdVer_0 = "/" + objectId_0; + objectIdVer_0 = "/" + OBJECT_ID_0; } else { - objectIdVer_0 = "/" + objectId_0 + "_" + ver_Id_0; + objectIdVer_0 = "/" + OBJECT_ID_0 + "_" + ver_Id_0; } objectIdVer_2 = (String) expectedObjectIdVers.stream().filter(path -> ((String) path).contains("/" + ACCESS_CONTROL)).findFirst().get(); - objectIdVer_3 = (String) expectedObjects.stream().filter(predicate_3).findFirst().get(); + objectIdVer_3 = (String) expectedObjects.stream().filter(PREDICATE_3).findFirst().get(); objectIdVer_19 = (String) expectedObjectIdVers.stream().filter(path -> ((String) path).contains("/" + BINARY_APP_DATA_CONTAINER)).findFirst().get(); objectIdVer_3303 = (String) expectedObjectIdVers.stream().filter(path -> ((String) path).contains("/" + TEMPERATURE_SENSOR)).findFirst().get(); objectInstanceIdVer_1 = (String) expectedObjectIdVerInstances.stream().filter(path -> (!((String) path).contains("/" + BINARY_APP_DATA_CONTAINER) && ((String) path).contains("/" + SERVER))).findFirst().get(); - objectInstanceIdVer_3 = (String) expectedObjectIdVerInstances.stream().filter(predicate_3).findFirst().get(); + objectInstanceIdVer_3 = (String) expectedObjectIdVerInstances.stream().filter(PREDICATE_3).findFirst().get(); objectInstanceIdVer_5 = (String) expectedObjectIdVerInstances.stream().filter(path -> ((String) path).contains("/" + FIRMWARE)).findFirst().get(); objectInstanceIdVer_9 = (String) expectedObjectIdVerInstances.stream().filter(path -> ((String) path).contains("/" + SOFTWARE_MANAGEMENT)).findFirst().get(); @@ -120,22 +120,22 @@ public abstract class AbstractRpcLwM2MIntegrationTest extends AbstractLwM2MInteg " \"type\": \"LWM2M\",\n" + " \"observeAttr\": {\n" + " \"keyName\": {\n" + - " \"" + objectIdVer_3 + "/" + objectInstanceId_0 + "/" + resourceId_9 + "\": \"" + resourceIdName_3_9 + "\",\n" + - " \"" + objectIdVer_3 + "/" + objectInstanceId_0 + "/" + resourceId_14 + "\": \"" + resourceIdName_3_14 + "\",\n" + - " \"" + objectIdVer_19 + "/" + objectInstanceId_0 + "/" + resourceId_0 + "\": \"" + resourceIdName_19_0_0 + "\",\n" + - " \"" + objectIdVer_19 + "/" + objectInstanceId_1 + "/" + resourceId_0 + "\": \"" + resourceIdName_19_1_0 + "\"\n" + + " \"" + objectIdVer_3 + "/" + OBJECT_INSTANCE_ID_0 + "/" + RESOURCE_ID_9 + "\": \"" + RESOURCE_ID_NAME_3_9 + "\",\n" + + " \"" + objectIdVer_3 + "/" + OBJECT_INSTANCE_ID_0 + "/" + RESOURCE_ID_14 + "\": \"" + RESOURCE_ID_NAME_3_14 + "\",\n" + + " \"" + objectIdVer_19 + "/" + OBJECT_INSTANCE_ID_0 + "/" + RESOURCE_ID_0 + "\": \"" + RESOURCE_ID_NAME_19_0_0 + "\",\n" + + " \"" + objectIdVer_19 + "/" + OBJECT_INSTANCE_ID_1 + "/" + RESOURCE_ID_0 + "\": \"" + RESOURCE_ID_NAME_19_1_0 + "\"\n" + " },\n" + " \"observe\": [\n" + - " \"" + objectIdVer_3 + "/" + objectInstanceId_0 + "/" + resourceId_9 + "\",\n" + - " \"" + objectIdVer_19 + "/" + objectInstanceId_0 + "/" + resourceId_0 + "\"\n" + + " \"" + objectIdVer_3 + "/" + OBJECT_INSTANCE_ID_0 + "/" + RESOURCE_ID_9 + "\",\n" + + " \"" + objectIdVer_19 + "/" + OBJECT_INSTANCE_ID_0 + "/" + RESOURCE_ID_0 + "\"\n" + " ],\n" + " \"attribute\": [\n" + " ],\n" + " \"telemetry\": [\n" + - " \"" + objectIdVer_3 + "/" + objectInstanceId_0 + "/" + resourceId_9 + "\",\n" + - " \"" + objectIdVer_3 + "/" + objectInstanceId_0 + "/" + resourceId_14 + "\",\n" + - " \"" + objectIdVer_19 + "/" + objectInstanceId_0 + "/" + resourceId_0 + "\",\n" + - " \"" + objectIdVer_19 + "/" + objectInstanceId_1 + "/" + resourceId_0 + "\"\n" + + " \"" + objectIdVer_3 + "/" + OBJECT_INSTANCE_ID_0 + "/" + RESOURCE_ID_9 + "\",\n" + + " \"" + objectIdVer_3 + "/" + OBJECT_INSTANCE_ID_0 + "/" + RESOURCE_ID_14 + "\",\n" + + " \"" + objectIdVer_19 + "/" + OBJECT_INSTANCE_ID_0 + "/" + RESOURCE_ID_0 + "\",\n" + + " \"" + objectIdVer_19 + "/" + OBJECT_INSTANCE_ID_1 + "/" + RESOURCE_ID_0 + "\"\n" + " ],\n" + " \"attributeLwm2m\": {}\n" + " },\n" + diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationCreateTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationCreateTest.java index 4ab0d68794..40d26bfc17 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationCreateTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationCreateTest.java @@ -25,10 +25,10 @@ import org.thingsboard.server.transport.lwm2m.rpc.AbstractRpcLwM2MIntegrationTes import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.objectInstanceId_0; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.objectInstanceId_1; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.objectInstanceId_12; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_0; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.OBJECT_INSTANCE_ID_0; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.OBJECT_INSTANCE_ID_1; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.OBJECT_INSTANCE_ID_12; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.RESOURCE_ID_0; public class RpcLwm2mIntegrationCreateTest extends AbstractRpcLwM2MIntegrationTest { @@ -43,8 +43,8 @@ public class RpcLwm2mIntegrationCreateTest extends AbstractRpcLwM2MIntegrationTe */ @Test public void testCreateObjectInstanceWithInstanceIdByIdKey_Result_CREATED() throws Exception { - String expectedPath = objectIdVer_19 + "/" + objectInstanceId_12; - String expectedValue = "{\"" + resourceId_0 + "\":{\"0\":\"00AC\"}, \"1\":1}"; + String expectedPath = objectIdVer_19 + "/" + OBJECT_INSTANCE_ID_12; + String expectedValue = "{\"" + RESOURCE_ID_0 + "\":{\"0\":\"00AC\"}, \"1\":1}"; String actualResult = sendRPCreateById(expectedPath, expectedValue); ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); assertEquals(ResponseCode.CREATED.getName(), rpcActualResult.get("result").asText()); @@ -60,12 +60,12 @@ public class RpcLwm2mIntegrationCreateTest extends AbstractRpcLwM2MIntegrationTe */ @Test public void testCreateObjectInstanceWithInstanceIdAlreadyExistsById_Result_BAD_REQUEST() throws Exception { - String expectedPath = objectIdVer_19 + "/" + objectInstanceId_0; - String expectedValue = "{\"" + resourceId_0 + "\":{\"0\":\"00AC\"}, \"1\":1}"; + String expectedPath = objectIdVer_19 + "/" + OBJECT_INSTANCE_ID_0; + String expectedValue = "{\"" + RESOURCE_ID_0 + "\":{\"0\":\"00AC\"}, \"1\":1}"; String actualResult = sendRPCreateById(expectedPath, expectedValue); ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); assertEquals(ResponseCode.BAD_REQUEST.getName(), rpcActualResult.get("result").asText()); - String expected = "instance " + objectInstanceId_0 + " already exists"; + String expected = "instance " + OBJECT_INSTANCE_ID_0 + " already exists"; String actual = rpcActualResult.get("error").asText(); assertTrue(actual.equals(expected)); } @@ -77,8 +77,8 @@ public class RpcLwm2mIntegrationCreateTest extends AbstractRpcLwM2MIntegrationTe */ @Test public void testCreateObjectInstanceWithInstanceIdMandatorySingleObjectById_Result_BAD_REQUEST() throws Exception { - String expectedPath = objectIdVer_3 + "/" + objectInstanceId_1; - String expectedValue = "{\"" + resourceId_0 + "\":{\"0\":\"00AC\"}}"; + String expectedPath = objectIdVer_3 + "/" + OBJECT_INSTANCE_ID_1; + String expectedValue = "{\"" + RESOURCE_ID_0 + "\":{\"0\":\"00AC\"}}"; String actualResult = sendRPCreateById(expectedPath, expectedValue); ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); assertEquals(ResponseCode.BAD_REQUEST.getName(), rpcActualResult.get("result").asText()); @@ -94,8 +94,8 @@ public class RpcLwm2mIntegrationCreateTest extends AbstractRpcLwM2MIntegrationTe */ @Test public void testCreateObjectInstanceWithInstanceIdSecurityObjectById_Result_BAD_REQUEST() throws Exception { - String expectedPath = objectIdVer_0 + "/" + objectInstanceId_1; - String expectedValue = "{\"" + resourceId_0 + "\":{\"2\":4}}"; + String expectedPath = objectIdVer_0 + "/" + OBJECT_INSTANCE_ID_1; + String expectedValue = "{\"" + RESOURCE_ID_0 + "\":{\"2\":4}}"; String actualResult = sendRPCreateById(expectedPath, expectedValue); ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); assertEquals(ResponseCode.BAD_REQUEST.getName(), rpcActualResult.get("result").asText()); @@ -113,8 +113,8 @@ public class RpcLwm2mIntegrationCreateTest extends AbstractRpcLwM2MIntegrationTe */ @Test public void testCreateObjectInstanceWithInstanceIdAbsentObjectById_Result_BAD_REQUEST() throws Exception { - String expectedPath = objectIdVer_50+ "/" + objectInstanceId_1; - String expectedValue = "{\"" + resourceId_0 + "\":{\"0\":\"00AC\"}}"; + String expectedPath = OBJECT_ID_VER_50 + "/" + OBJECT_INSTANCE_ID_1; + String expectedValue = "{\"" + RESOURCE_ID_0 + "\":{\"0\":\"00AC\"}}"; String actualResult = sendRPCreateById(expectedPath, expectedValue); ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); assertEquals(ResponseCode.BAD_REQUEST.getName(), rpcActualResult.get("result").asText()); diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationDeleteTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationDeleteTest.java index ebc0f6d783..099477d216 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationDeleteTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationDeleteTest.java @@ -24,10 +24,9 @@ import org.thingsboard.server.transport.lwm2m.rpc.AbstractRpcLwM2MIntegrationTes import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.objectInstanceId_0; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.objectInstanceId_12; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_7; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_9; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.OBJECT_INSTANCE_ID_0; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.OBJECT_INSTANCE_ID_12; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.RESOURCE_ID_7; public class RpcLwm2mIntegrationDeleteTest extends AbstractRpcLwM2MIntegrationTest { @@ -39,7 +38,7 @@ public class RpcLwm2mIntegrationDeleteTest extends AbstractRpcLwM2MIntegrationTe */ @Test public void testDeleteObjectInstanceIsSuchByIdKey_Result_DELETED() throws Exception { - String expectedPath = objectIdVer_3303 + "/" + objectInstanceId_12; + String expectedPath = objectIdVer_3303 + "/" + OBJECT_INSTANCE_ID_12; String actualResult = sendRPCDeleteById(expectedPath); ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); assertEquals(ResponseCode.DELETED.getName(), rpcActualResult.get("result").asText()); @@ -52,7 +51,7 @@ public class RpcLwm2mIntegrationDeleteTest extends AbstractRpcLwM2MIntegrationTe */ @Test public void testDeleteObjectInstanceIsNotSuchByIdKey_Result_NOT_FOUND() throws Exception { - String expectedPath = objectIdVer_19 + "/" + objectInstanceId_12; + String expectedPath = objectIdVer_19 + "/" + OBJECT_INSTANCE_ID_12; String actualResult = sendRPCDeleteById(expectedPath); ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); assertEquals(ResponseCode.NOT_FOUND.getName(), rpcActualResult.get("result").asText()); @@ -82,7 +81,7 @@ public class RpcLwm2mIntegrationDeleteTest extends AbstractRpcLwM2MIntegrationTe */ @Test public void testDeleteResourceByIdKey_Result_METHOD_NOT_ALLOWED() throws Exception { - String expectedPath = objectIdVer_3 + "/" + objectInstanceId_0 + resourceId_7; + String expectedPath = objectIdVer_3 + "/" + OBJECT_INSTANCE_ID_0 + RESOURCE_ID_7; String actualResult = sendRPCDeleteById(expectedPath); ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); assertEquals(ResponseCode.METHOD_NOT_ALLOWED.getName(), rpcActualResult.get("result").asText()); diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationDiscoverTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationDiscoverTest.java index b8ca7be61f..ede501c4a2 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationDiscoverTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationDiscoverTest.java @@ -31,8 +31,8 @@ import java.util.stream.Collectors; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.objectInstanceId_0; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_2; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.OBJECT_INSTANCE_ID_0; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.RESOURCE_ID_2; public class RpcLwm2mIntegrationDiscoverTest extends AbstractRpcLwM2MIntegrationTest { @@ -141,7 +141,7 @@ public class RpcLwm2mIntegrationDiscoverTest extends AbstractRpcLwM2MIntegration */ @Test public void testDiscoverObjectInstanceAbsentInObject_Return_NOT_FOUND() throws Exception { - String expected = objectIdVer_2 + "/" + objectInstanceId_0; + String expected = objectIdVer_2 + "/" + OBJECT_INSTANCE_ID_0; String actualResult = sendDiscover(expected); ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); assertEquals(ResponseCode.NOT_FOUND.getName(), rpcActualResult.get("result").asText()); @@ -152,7 +152,7 @@ public class RpcLwm2mIntegrationDiscoverTest extends AbstractRpcLwM2MIntegration */ @Test public void testDiscoverResourceAbsentInObject_Return_NOT_FOUND() throws Exception { - String expected = objectIdVer_2 + "/" + objectInstanceId_0 + "/" + resourceId_2; + String expected = objectIdVer_2 + "/" + OBJECT_INSTANCE_ID_0 + "/" + RESOURCE_ID_2; String actualResult = sendDiscover(expected); ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); assertEquals(ResponseCode.NOT_FOUND.getName(), rpcActualResult.get("result").asText()); diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationExecuteTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationExecuteTest.java index 73ea0fb74c..4d13cbd386 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationExecuteTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationExecuteTest.java @@ -25,12 +25,12 @@ import org.thingsboard.server.transport.lwm2m.rpc.AbstractRpcLwM2MIntegrationTes import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.objectInstanceId_0; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_2; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_3; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_4; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_8; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_9; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.OBJECT_INSTANCE_ID_0; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.RESOURCE_ID_2; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.RESOURCE_ID_3; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.RESOURCE_ID_4; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.RESOURCE_ID_8; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.RESOURCE_ID_9; public class RpcLwm2mIntegrationExecuteTest extends AbstractRpcLwM2MIntegrationTest { @@ -43,7 +43,7 @@ public class RpcLwm2mIntegrationExecuteTest extends AbstractRpcLwM2MIntegrationT */ @Test public void testExecuteUpdateFWById_Result_CHANGED() throws Exception { - String expectedPath = objectInstanceIdVer_5 + "/" + resourceId_2; + String expectedPath = objectInstanceIdVer_5 + "/" + RESOURCE_ID_2; String actualResult = sendRPCExecuteById(expectedPath); ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); assertEquals(ResponseCode.CHANGED.getName(), rpcActualResult.get("result").asText()); @@ -56,7 +56,7 @@ public class RpcLwm2mIntegrationExecuteTest extends AbstractRpcLwM2MIntegrationT */ @Test public void testExecuteUpdateSWById_Result_CHANGED() throws Exception { - String expectedPath = objectInstanceIdVer_9 + "/" + resourceId_4; + String expectedPath = objectInstanceIdVer_9 + "/" + RESOURCE_ID_4; String actualResult = sendRPCExecuteById(expectedPath); ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); assertEquals(ResponseCode.CHANGED.getName(), rpcActualResult.get("result").asText()); @@ -69,7 +69,7 @@ public class RpcLwm2mIntegrationExecuteTest extends AbstractRpcLwM2MIntegrationT */ @Test public void testExecuteRebootById_Result_CHANGED() throws Exception { - String expectedPath = objectInstanceIdVer_3 + "/" + resourceId_4; + String expectedPath = objectInstanceIdVer_3 + "/" + RESOURCE_ID_4; String actualResult = sendRPCExecuteById(expectedPath); ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); assertEquals(ResponseCode.CHANGED.getName(), rpcActualResult.get("result").asText()); @@ -82,7 +82,7 @@ public class RpcLwm2mIntegrationExecuteTest extends AbstractRpcLwM2MIntegrationT */ @Test public void testExecuteRegistrationUpdateTriggerById_Result_CHANGED() throws Exception { - String expectedPath = objectInstanceIdVer_1 + "/" + resourceId_8; + String expectedPath = objectInstanceIdVer_1 + "/" + RESOURCE_ID_8; String actualResult = sendRPCExecuteById(expectedPath); ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); assertEquals(ResponseCode.CHANGED.getName(), rpcActualResult.get("result").asText()); @@ -96,7 +96,7 @@ public class RpcLwm2mIntegrationExecuteTest extends AbstractRpcLwM2MIntegrationT */ @Test public void testExecuteResourceWithParametersById_Result_CHANGED() throws Exception { - String expectedPath = objectInstanceIdVer_3 + "/" + resourceId_4; + String expectedPath = objectInstanceIdVer_3 + "/" + RESOURCE_ID_4; Object expectedValue = 60; String actualResult = sendRPCExecuteWithValueById(expectedPath, expectedValue); ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); @@ -110,7 +110,7 @@ public class RpcLwm2mIntegrationExecuteTest extends AbstractRpcLwM2MIntegrationT */ @Test public void testExecuteBootstrapRequestTriggerById_Result_BAD_REQUEST_Error_NoBootstrapServerConfigured() throws Exception { - String expectedPath = objectInstanceIdVer_1 + "/" + resourceId_9; + String expectedPath = objectInstanceIdVer_1 + "/" + RESOURCE_ID_9; String actualResult = sendRPCExecuteById(expectedPath); ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); assertEquals(ResponseCode.BAD_REQUEST.getName(), rpcActualResult.get("result").asText()); @@ -126,7 +126,7 @@ public class RpcLwm2mIntegrationExecuteTest extends AbstractRpcLwM2MIntegrationT */ @Test public void testExecuteResourceWithOperationNotExecuteById_Result_METHOD_NOT_ALLOWED() throws Exception { - String expectedPath = objectInstanceIdVer_5 + "/" + resourceId_3; + String expectedPath = objectInstanceIdVer_5 + "/" + RESOURCE_ID_3; String actualResult = sendRPCExecuteById(expectedPath); ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); assertEquals(ResponseCode.BAD_REQUEST.getName(), rpcActualResult.get("result").asText()); @@ -143,7 +143,7 @@ public class RpcLwm2mIntegrationExecuteTest extends AbstractRpcLwM2MIntegrationT */ @Test public void testExecuteNonExistingResourceOnNonExistingObjectById_Result_BAD_REQUEST() throws Exception { - String expectedPath = objectIdVer_50 + "/" + objectInstanceId_0 + "/" + resourceId_3; + String expectedPath = OBJECT_ID_VER_50 + "/" + OBJECT_INSTANCE_ID_0 + "/" + RESOURCE_ID_3; String actualResult = sendRPCExecuteById(expectedPath); ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); assertEquals(ResponseCode.BAD_REQUEST.getName(), rpcActualResult.get("result").asText()); @@ -161,7 +161,7 @@ public class RpcLwm2mIntegrationExecuteTest extends AbstractRpcLwM2MIntegrationT */ @Test public void testExecuteSecurityObjectById_Result_NOT_FOUND() throws Exception { - String expectedPath = objectIdVer_0 + "/" + objectInstanceId_0 + "/" + resourceId_3; + String expectedPath = objectIdVer_0 + "/" + OBJECT_INSTANCE_ID_0 + "/" + RESOURCE_ID_3; String actualResult = sendRPCExecuteById(expectedPath); ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); assertEquals(ResponseCode.BAD_REQUEST.getName(), rpcActualResult.get("result").asText()); diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationObserveTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationObserveTest.java index 848a9563ed..f6b53c8c07 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationObserveTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationObserveTest.java @@ -27,10 +27,10 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.BINARY_APP_DATA_CONTAINER; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.objectInstanceId_0; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_0; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_3; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_9; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.OBJECT_INSTANCE_ID_0; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.RESOURCE_ID_0; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.RESOURCE_ID_3; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.RESOURCE_ID_9; public class RpcLwm2mIntegrationObserveTest extends AbstractRpcLwM2MIntegrationTest { @@ -55,7 +55,7 @@ public class RpcLwm2mIntegrationObserveTest extends AbstractRpcLwM2MIntegrationT */ @Test public void testObserveSingleResource_Result_CONTENT_Value_SingleResource() throws Exception { - String expectedIdVer = objectInstanceIdVer_3 + "/" + resourceId_9; + String expectedIdVer = objectInstanceIdVer_3 + "/" + RESOURCE_ID_9; String actualResult = sendObserve("Observe", expectedIdVer); ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); assertEquals(ResponseCode.CONTENT.getName(), rpcActualResult.get("result").asText()); @@ -87,7 +87,7 @@ public class RpcLwm2mIntegrationObserveTest extends AbstractRpcLwM2MIntegrationT @Test public void testObserveNoImplementedInstanceOnDevice_Result_NotFound() throws Exception { String objectInstanceIdVer = (String) expectedObjectIdVers.stream().filter(path -> ((String)path).contains("/" + ACCESS_CONTROL)).findFirst().get(); - String expected = objectInstanceIdVer + "/" + objectInstanceId_0; + String expected = objectInstanceIdVer + "/" + OBJECT_INSTANCE_ID_0; String actualResult = sendObserve("Observe", expected); ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); assertEquals(ResponseCode.NOT_FOUND.getName(), rpcActualResult.get("result").asText()); @@ -101,7 +101,7 @@ public class RpcLwm2mIntegrationObserveTest extends AbstractRpcLwM2MIntegrationT @Test public void testObserveNoImplementedResourceOnDeviceValueNull_Result_BadRequest() throws Exception { String objectIdVer = (String) expectedObjectIdVers.stream().filter(path -> ((String)path).contains("/" + BINARY_APP_DATA_CONTAINER)).findFirst().get(); - String expected = objectIdVer + "/" + objectInstanceId_0 + "/" + resourceId_0; + String expected = objectIdVer + "/" + OBJECT_INSTANCE_ID_0 + "/" + RESOURCE_ID_0; String actualResult = sendObserve("Observe", expected); ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); String expectedValue = "values MUST NOT be null"; @@ -116,7 +116,7 @@ public class RpcLwm2mIntegrationObserveTest extends AbstractRpcLwM2MIntegrationT */ @Test public void testObserveRSourceNotRead_Result_METHOD_NOT_ALLOWED() throws Exception { - String expectedId = objectInstanceIdVer_5 + "/" + resourceId_0; + String expectedId = objectInstanceIdVer_5 + "/" + RESOURCE_ID_0; sendObserve("Observe", expectedId); String actualResult = sendObserve("Observe", expectedId); ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); @@ -130,7 +130,7 @@ public class RpcLwm2mIntegrationObserveTest extends AbstractRpcLwM2MIntegrationT */ @Test public void testObserveRepeatedRequestObserveOnDevice_Result_BAD_REQUEST_ErrorMsg_AlreadyRegistered() throws Exception { - String expectedId = objectInstanceIdVer_3 + "/" + resourceId_0; + String expectedId = objectInstanceIdVer_3 + "/" + RESOURCE_ID_0; sendObserve("Observe", expectedId); String actualResult = sendObserve("Observe", expectedId); ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); @@ -146,8 +146,8 @@ public class RpcLwm2mIntegrationObserveTest extends AbstractRpcLwM2MIntegrationT @Test public void testObserveReadAll_Result_CONTENT_Value_Contains_Paths_Count_ObserveAll() throws Exception { sendObserve("ObserveCancelAll", null); - String expectedId_0 = objectInstanceIdVer_3 + "/" + resourceId_0; - String expectedId_9 = objectInstanceIdVer_3 + "/" + resourceId_9; + String expectedId_0 = objectInstanceIdVer_3 + "/" + RESOURCE_ID_0; + String expectedId_9 = objectInstanceIdVer_3 + "/" + RESOURCE_ID_9; sendObserve("Observe", expectedId_0); sendObserve("Observe", expectedId_9); String actualResult = sendObserve("ObserveReadAll", null); @@ -167,8 +167,8 @@ public class RpcLwm2mIntegrationObserveTest extends AbstractRpcLwM2MIntegrationT @Test public void testObserveCancelOneResource_Result_CONTENT_Value_Count_1() throws Exception { sendObserve("ObserveCancelAll", null); - String expectedId_0 = objectInstanceIdVer_3 + "/" + resourceId_0; - String expectedId_3 = objectInstanceIdVer_5 + "/" + resourceId_3; + String expectedId_0 = objectInstanceIdVer_3 + "/" + RESOURCE_ID_0; + String expectedId_3 = objectInstanceIdVer_5 + "/" + RESOURCE_ID_3; sendObserve("Observe", expectedId_0); sendObserve("Observe", expectedId_3); String actualResult = sendObserve("ObserveCancel", expectedId_0); diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationReadTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationReadTest.java index 9116659bc3..aece59d119 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationReadTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationReadTest.java @@ -27,18 +27,18 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.BINARY_APP_DATA_CONTAINER; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.objectInstanceId_0; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.objectInstanceId_1; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceIdName_19_0_0; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceIdName_19_1_0; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceIdName_3_14; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceIdName_3_9; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_0; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_1; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_11; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_14; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_2; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_9; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.OBJECT_INSTANCE_ID_0; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.OBJECT_INSTANCE_ID_1; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.RESOURCE_ID_NAME_19_0_0; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.RESOURCE_ID_NAME_19_1_0; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.RESOURCE_ID_NAME_3_14; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.RESOURCE_ID_NAME_3_9; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.RESOURCE_ID_0; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.RESOURCE_ID_1; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.RESOURCE_ID_11; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.RESOURCE_ID_14; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.RESOURCE_ID_2; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.RESOURCE_ID_9; public class RpcLwm2mIntegrationReadTest extends AbstractRpcLwM2MIntegrationTest { @@ -96,11 +96,11 @@ public class RpcLwm2mIntegrationReadTest extends AbstractRpcLwM2MIntegrationTest */ @Test public void testReadMultipleResourceById_Result_CONTENT_Value_IsLwM2mMultipleResource() throws Exception { - String expectedIdVer = objectInstanceIdVer_3 +"/" + resourceId_11 ; + String expectedIdVer = objectInstanceIdVer_3 +"/" + RESOURCE_ID_11; String actualResult = sendRPCById(expectedIdVer); ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); assertEquals(ResponseCode.CONTENT.getName(), rpcActualResult.get("result").asText()); - String expected = "LwM2mMultipleResource [id=" + resourceId_11 + ", values={"; + String expected = "LwM2mMultipleResource [id=" + RESOURCE_ID_11 + ", values={"; assertTrue(rpcActualResult.get("value").asText().contains(expected)); } @@ -109,11 +109,11 @@ public class RpcLwm2mIntegrationReadTest extends AbstractRpcLwM2MIntegrationTest */ @Test public void testReadSingleResourceById_Result_CONTENT_Value_IsLwM2mSingleResource() throws Exception { - String expectedIdVer = objectInstanceIdVer_3 +"/" + resourceId_14 ; + String expectedIdVer = objectInstanceIdVer_3 +"/" + RESOURCE_ID_14; String actualResult = sendRPCById(expectedIdVer); ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); assertEquals(ResponseCode.CONTENT.getName(), rpcActualResult.get("result").asText()); - String expected = "LwM2mSingleResource [id=" + resourceId_14 + ", value="; + String expected = "LwM2mSingleResource [id=" + RESOURCE_ID_14 + ", value="; assertTrue(rpcActualResult.get("value").asText().contains(expected)); } @@ -122,11 +122,11 @@ public class RpcLwm2mIntegrationReadTest extends AbstractRpcLwM2MIntegrationTest */ @Test public void testReadSingleResourceByKey_Result_CONTENT_Value_IsLwM2mSingleResource() throws Exception { - String expectedKey = resourceIdName_3_14 ; + String expectedKey = RESOURCE_ID_NAME_3_14; String actualResult = sendRPCByKey(expectedKey); ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); assertEquals(ResponseCode.CONTENT.getName(), rpcActualResult.get("result").asText()); - String expected = "LwM2mSingleResource [id=" + resourceId_14 + ", value="; + String expected = "LwM2mSingleResource [id=" + RESOURCE_ID_14 + ", value="; assertTrue(rpcActualResult.get("value").asText().contains(expected)); } @@ -137,16 +137,16 @@ public class RpcLwm2mIntegrationReadTest extends AbstractRpcLwM2MIntegrationTest public void testReadCompositeSingleResourceByIds_Result_CONTENT_Value_IsObjectIsLwM2mSingleResourceIsLwM2mMultipleResource() throws Exception { String expectedIdVer_1 = (String) expectedObjectIdVers.stream().filter(path -> (!((String)path).contains("/" + BINARY_APP_DATA_CONTAINER) && ((String)path).contains("/" + SERVER))).findFirst().get(); String objectId_1 = pathIdVerToObjectId(expectedIdVer_1); - String expectedIdVer3_0_1 = objectInstanceIdVer_3 + "/" + resourceId_1; - String expectedIdVer3_0_11 = objectInstanceIdVer_3 + "/" + resourceId_11; + String expectedIdVer3_0_1 = objectInstanceIdVer_3 + "/" + RESOURCE_ID_1; + String expectedIdVer3_0_11 = objectInstanceIdVer_3 + "/" + RESOURCE_ID_11; String objectInstanceId_3 = pathIdVerToObjectId(objectInstanceIdVer_3); String expectedIds = "[\"" + expectedIdVer_1 + "\", \"" + expectedIdVer3_0_1 + "\", \"" + expectedIdVer3_0_11 + "\"]"; String actualResult = sendCompositeRPCByIds(expectedIds); ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); assertEquals(ResponseCode.CONTENT.getName(), rpcActualResult.get("result").asText()); String expected1 = objectId_1 + "=LwM2mObject [id=" + new LwM2mPath(objectId_1).getObjectId() + ", instances={"; - String expected3_0_1 = objectInstanceId_3 + "/" + resourceId_1 + "=LwM2mSingleResource [id=" + resourceId_1 + ", value="; - String expected3_0_11 = objectInstanceId_3 + "/" + resourceId_11 + "=LwM2mMultipleResource [id=" + resourceId_11 + ", values={"; + String expected3_0_1 = objectInstanceId_3 + "/" + RESOURCE_ID_1 + "=LwM2mSingleResource [id=" + RESOURCE_ID_1 + ", value="; + String expected3_0_11 = objectInstanceId_3 + "/" + RESOURCE_ID_11 + "=LwM2mMultipleResource [id=" + RESOURCE_ID_11 + ", values={"; String actualValues = rpcActualResult.get("value").asText(); assertTrue(actualValues.contains(expected1)); assertTrue(actualValues.contains(expected3_0_1)); @@ -159,8 +159,8 @@ public class RpcLwm2mIntegrationReadTest extends AbstractRpcLwM2MIntegrationTest @Test public void testReadCompositeSingleResourceByIds_Result_CONTENT_Value_IsObjectInstanceIsLwM2mSingleResource() throws Exception { String expectedIdVer3_0 = objectInstanceIdVer_3; - String expectedIdVer1_0_1 = objectInstanceIdVer_1 + "/" + resourceId_1; - String expectedIdVer1_0_2 = objectInstanceIdVer_1 + "/" + resourceId_2; + String expectedIdVer1_0_1 = objectInstanceIdVer_1 + "/" + RESOURCE_ID_1; + String expectedIdVer1_0_2 = objectInstanceIdVer_1 + "/" + RESOURCE_ID_2; String expectedIds = "[\"" + expectedIdVer1_0_1 + "\", \"" + expectedIdVer1_0_2 + "\", \"" + expectedIdVer3_0 + "\"]"; String actualResult = sendCompositeRPCByIds(expectedIds); ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); @@ -169,8 +169,8 @@ public class RpcLwm2mIntegrationReadTest extends AbstractRpcLwM2MIntegrationTest LwM2mPath path = new LwM2mPath(objectInstanceId_3); String expected3_0 = objectInstanceId_3 + "=LwM2mObjectInstance [id=" + path.getObjectInstanceId() + ", resources={"; String objectInstanceId_1 = pathIdVerToObjectId(objectInstanceIdVer_1); - String expected1_0_1 = objectInstanceId_1 + "/" + resourceId_1 + "=LwM2mSingleResource [id=" + resourceId_1 + ", value="; - String expected1_0_2 = objectInstanceId_1 + "/" + resourceId_2 + "=null"; + String expected1_0_1 = objectInstanceId_1 + "/" + RESOURCE_ID_1 + "=LwM2mSingleResource [id=" + RESOURCE_ID_1 + ", value="; + String expected1_0_2 = objectInstanceId_1 + "/" + RESOURCE_ID_2 + "=null"; String actualValues = rpcActualResult.get("value").asText(); assertTrue(actualValues.contains(expected3_0)); assertTrue(actualValues.contains(expected1_0_1)); @@ -182,20 +182,20 @@ public class RpcLwm2mIntegrationReadTest extends AbstractRpcLwM2MIntegrationTest */ @Test public void testReadCompositeSingleResourceByKeys_Result_CONTENT_Value_3_0_IsLwM2mSingleResource_19_0_0_AND_19_0_1_Null() throws Exception { - String expectedKey3_0_9 = resourceIdName_3_9; - String expectedKey3_0_14 = resourceIdName_3_14; - String expectedKey19_0_0 = resourceIdName_19_0_0; - String expectedKey19_1_0 = resourceIdName_19_1_0; + String expectedKey3_0_9 = RESOURCE_ID_NAME_3_9; + String expectedKey3_0_14 = RESOURCE_ID_NAME_3_14; + String expectedKey19_0_0 = RESOURCE_ID_NAME_19_0_0; + String expectedKey19_1_0 = RESOURCE_ID_NAME_19_1_0; String expectedKeys = "[\"" + expectedKey3_0_9 + "\", \"" + expectedKey3_0_14 + "\", \"" + expectedKey19_0_0 + "\", \"" + expectedKey19_1_0 + "\"]"; String actualResult = sendCompositeRPCByKeys(expectedKeys); ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); assertEquals(ResponseCode.CONTENT.getName(), rpcActualResult.get("result").asText()); String objectInstanceId_3 = pathIdVerToObjectId(objectInstanceIdVer_3); String objectId_19 = pathIdVerToObjectId(objectIdVer_19); - String expected3_0_9 = objectInstanceId_3 + "/" + resourceId_9 + "=LwM2mSingleResource [id=" + resourceId_9 + ", value="; - String expected3_0_14 = objectInstanceId_3 + "/" + resourceId_14 + "=LwM2mSingleResource [id=" + resourceId_14 + ", value="; - String expected19_0_0 = objectId_19 + "/" + objectInstanceId_0 + "/" + resourceId_0 + "=null"; - String expected19_1_0 = objectId_19 + "/" + objectInstanceId_1 + "/" + resourceId_0 + "=null"; + String expected3_0_9 = objectInstanceId_3 + "/" + RESOURCE_ID_9 + "=LwM2mSingleResource [id=" + RESOURCE_ID_9 + ", value="; + String expected3_0_14 = objectInstanceId_3 + "/" + RESOURCE_ID_14 + "=LwM2mSingleResource [id=" + RESOURCE_ID_14 + ", value="; + String expected19_0_0 = objectId_19 + "/" + OBJECT_INSTANCE_ID_0 + "/" + RESOURCE_ID_0 + "=null"; + String expected19_1_0 = objectId_19 + "/" + OBJECT_INSTANCE_ID_1 + "/" + RESOURCE_ID_0 + "=null"; String actualValues = rpcActualResult.get("value").asText(); assertTrue(actualValues.contains(expected3_0_9)); assertTrue(actualValues.contains(expected3_0_14)); diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationWriteAttributesTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationWriteAttributesTest.java index ea23ab48b9..531fa33dc9 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationWriteAttributesTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationWriteAttributesTest.java @@ -17,7 +17,6 @@ package org.thingsboard.server.transport.lwm2m.rpc.sql; import com.fasterxml.jackson.databind.node.ObjectNode; import org.eclipse.leshan.core.ResponseCode; -import org.eclipse.leshan.core.node.LwM2mPath; import org.junit.Test; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.transport.lwm2m.rpc.AbstractRpcLwM2MIntegrationTest; @@ -25,13 +24,7 @@ import org.thingsboard.server.transport.lwm2m.rpc.AbstractRpcLwM2MIntegrationTes import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.objectInstanceId_0; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_14; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_2; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_3; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_4; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_8; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_9; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.RESOURCE_ID_14; public class RpcLwm2mIntegrationWriteAttributesTest extends AbstractRpcLwM2MIntegrationTest { @@ -45,7 +38,7 @@ public class RpcLwm2mIntegrationWriteAttributesTest extends AbstractRpcLwM2MInte */ @Test public void testWriteAttributesResourceWithParametersById_Result_INTERNAL_SERVER_ERROR() throws Exception { - String expectedPath = objectInstanceIdVer_3 + "/" + resourceId_14; + String expectedPath = objectInstanceIdVer_3 + "/" + RESOURCE_ID_14; String expectedValue = "{\"pmax\":100, \"pmin\":10}"; String actualResult = sendRPCExecuteWithValueById(expectedPath, expectedValue); ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationWriteTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationWriteTest.java index 1a92831a36..f5f06631b9 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationWriteTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationWriteTest.java @@ -25,16 +25,15 @@ import org.thingsboard.server.transport.lwm2m.rpc.AbstractRpcLwM2MIntegrationTes import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.BINARY_APP_DATA_CONTAINER; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.objectInstanceId_0; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.objectInstanceId_1; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.objectInstanceId_2; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceIdName_3_14; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_0; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_14; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_15; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_9; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceInstanceId_2; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.OBJECT_INSTANCE_ID_0; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.OBJECT_INSTANCE_ID_1; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.OBJECT_INSTANCE_ID_2; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.RESOURCE_ID_NAME_3_14; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.RESOURCE_ID_0; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.RESOURCE_ID_14; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.RESOURCE_ID_15; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.RESOURCE_ID_9; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.RESOURCE_INSTANCE_ID_2; public class RpcLwm2mIntegrationWriteTest extends AbstractRpcLwM2MIntegrationTest { @@ -46,7 +45,7 @@ public class RpcLwm2mIntegrationWriteTest extends AbstractRpcLwM2MIntegrationTes */ @Test public void testWriteReplaceValueSingleResourceById_Result_CHANGED() throws Exception { - String expectedPath = objectInstanceIdVer_3 + "/" + resourceId_14; + String expectedPath = objectInstanceIdVer_3 + "/" + RESOURCE_ID_14; String expectedValue = "+12"; String actualResult = sendRPCWriteStringById("WriteReplace", expectedPath, expectedValue); ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); @@ -54,7 +53,7 @@ public class RpcLwm2mIntegrationWriteTest extends AbstractRpcLwM2MIntegrationTes actualResult = sendRPCReadById(expectedPath); rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); String actualValues = rpcActualResult.get("value").asText(); - String expected = "LwM2mSingleResource [id=" + resourceId_14 + ", value=" + expectedValue + ", type=STRING]"; + String expected = "LwM2mSingleResource [id=" + RESOURCE_ID_14 + ", value=" + expectedValue + ", type=STRING]"; assertTrue(actualValues.contains(expected)); } @@ -65,7 +64,7 @@ public class RpcLwm2mIntegrationWriteTest extends AbstractRpcLwM2MIntegrationTes */ @Test public void testWriteReplaceValueSingleResourceByKey_Result_CHANGED() throws Exception { - String expectedKey = resourceIdName_3_14; + String expectedKey = RESOURCE_ID_NAME_3_14; String expectedValue = "+09"; String actualResult = sendRPCWriteByKey("WriteReplace", expectedKey, expectedValue); ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); @@ -73,7 +72,7 @@ public class RpcLwm2mIntegrationWriteTest extends AbstractRpcLwM2MIntegrationTes actualResult = sendRPCReadByKey(expectedKey); rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); String actualValues = rpcActualResult.get("value").asText(); - String expected = "LwM2mSingleResource [id=" + resourceId_14 + ", value=" + expectedValue + ", type=STRING]"; + String expected = "LwM2mSingleResource [id=" + RESOURCE_ID_14 + ", value=" + expectedValue + ", type=STRING]"; assertTrue(actualValues.contains(expected)); } @@ -85,7 +84,7 @@ public class RpcLwm2mIntegrationWriteTest extends AbstractRpcLwM2MIntegrationTes */ @Test public void testWriteReplaceValueMultipleResource_Result_CHANGED_Value_Multi_Instance_Resource_must_in_Json_format() throws Exception { - String expectedPath = objectIdVer_19 + "/" + objectInstanceId_0 + "/" + resourceId_0; + String expectedPath = objectIdVer_19 + "/" + OBJECT_INSTANCE_ID_0 + "/" + RESOURCE_ID_0; int resourceInstanceId0 = 0; int resourceInstanceId15 = 15; String expectedValue0 = "0000ad45675600"; @@ -115,7 +114,7 @@ public class RpcLwm2mIntegrationWriteTest extends AbstractRpcLwM2MIntegrationTes */ @Test public void testWriteReplaceValueSingleResourceR_ById_Result_CHANGED() throws Exception { - String expectedPath = objectInstanceIdVer_3 + "/" + resourceId_9; + String expectedPath = objectInstanceIdVer_3 + "/" + RESOURCE_ID_9; Integer expectedValue = 90; String actualResult = sendRPCWriteObjectById("WriteReplace", expectedPath, expectedValue); ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); @@ -132,21 +131,21 @@ public class RpcLwm2mIntegrationWriteTest extends AbstractRpcLwM2MIntegrationTes String expectedPath = objectInstanceIdVer_3; String expectedValue14 = "+5"; String expectedValue15 = "Kiyv/Europe"; - String expectedValue = "{\"" + resourceId_14 + "\":\"" + expectedValue14 + "\",\"" + resourceId_15 + "\":\"" + expectedValue15 + "\"}"; + String expectedValue = "{\"" + RESOURCE_ID_14 + "\":\"" + expectedValue14 + "\",\"" + RESOURCE_ID_15 + "\":\"" + expectedValue15 + "\"}"; String actualResult = sendRPCWriteObjectById("WriteUpdate", expectedPath, expectedValue); ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); assertEquals(ResponseCode.CHANGED.getName(), rpcActualResult.get("result").asText()); - String expectedPath14 = objectInstanceIdVer_3 + "/" + resourceId_14; - String expectedPath15 = objectInstanceIdVer_3 + "/" + resourceId_15; + String expectedPath14 = objectInstanceIdVer_3 + "/" + RESOURCE_ID_14; + String expectedPath15 = objectInstanceIdVer_3 + "/" + RESOURCE_ID_15; actualResult = sendRPCReadById(expectedPath14); rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); String actualValues = rpcActualResult.get("value").asText(); - String expected = "LwM2mSingleResource [id=" + resourceId_14 + ", value=" + expectedValue14 + ", type=STRING]"; + String expected = "LwM2mSingleResource [id=" + RESOURCE_ID_14 + ", value=" + expectedValue14 + ", type=STRING]"; assertTrue(actualValues.contains(expected)); actualResult = sendRPCReadById(expectedPath15); rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); actualValues = rpcActualResult.get("value").asText(); - expected = "LwM2mSingleResource [id=" + resourceId_15 + ", value=" + expectedValue15 + ", type=STRING]"; + expected = "LwM2mSingleResource [id=" + RESOURCE_ID_15 + ", value=" + expectedValue15 + ", type=STRING]"; assertTrue(actualValues.contains(expected)); } @@ -157,17 +156,17 @@ public class RpcLwm2mIntegrationWriteTest extends AbstractRpcLwM2MIntegrationTes */ @Test public void testWriteUpdateValueMultipleResourceById_Result_CHANGED() throws Exception { - String expectedPath = objectIdVer_19 + "/" + objectInstanceId_0; + String expectedPath = objectIdVer_19 + "/" + OBJECT_INSTANCE_ID_0; int resourceInstanceId0 = 0; int resourceInstanceId25 = 25; String expectedValue0 = "00ad45675600"; String expectedValue25 = "25ad45675600cdef"; - String expectedValue = "{\"" + resourceId_0 + "\":{\"" + resourceInstanceId0 + "\":\"" + expectedValue0 + "\", \"" + resourceInstanceId25 + "\":\"" + expectedValue25 + "\"}}"; + String expectedValue = "{\"" + RESOURCE_ID_0 + "\":{\"" + resourceInstanceId0 + "\":\"" + expectedValue0 + "\", \"" + resourceInstanceId25 + "\":\"" + expectedValue25 + "\"}}"; String actualResult = sendRPCWriteObjectById("WriteUpdate", expectedPath, expectedValue); ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); assertEquals(ResponseCode.CHANGED.getName(), rpcActualResult.get("result").asText()); - String expectedPath0 = expectedPath + "/" + resourceId_0 + "/" + resourceInstanceId0; - String expectedPath25 =expectedPath + "/" + resourceId_0 + "/" + resourceInstanceId25; + String expectedPath0 = expectedPath + "/" + RESOURCE_ID_0 + "/" + resourceInstanceId0; + String expectedPath25 =expectedPath + "/" + RESOURCE_ID_0 + "/" + resourceInstanceId25; actualResult = sendRPCReadById(expectedPath0); rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); String actualValues = rpcActualResult.get("value").asText(); @@ -188,11 +187,11 @@ public class RpcLwm2mIntegrationWriteTest extends AbstractRpcLwM2MIntegrationTes @Test public void testWriteCompositeValueSingleResourceResourceInstanceByIdKey_Result_CHANGED() throws Exception { int resourceInstanceId2 = 2; - String expectedPath19_1_0_2 = objectIdVer_19 + "/" + objectInstanceId_1 + "/" + resourceId_0 + "/" + resourceInstanceId2; + String expectedPath19_1_0_2 = objectIdVer_19 + "/" + OBJECT_INSTANCE_ID_1 + "/" + RESOURCE_ID_0 + "/" + resourceInstanceId2; String expectedValue19_1_0_2 = "00001234"; - String expectedKey3_0_14 = resourceIdName_3_14; + String expectedKey3_0_14 = RESOURCE_ID_NAME_3_14; String expectedValue3_0_14 = "+04"; - String expectedPath3_0_15 = objectInstanceIdVer_3 + "/" + resourceId_15; + String expectedPath3_0_15 = objectInstanceIdVer_3 + "/" + RESOURCE_ID_15; String expectedValue3_0_15 = "Kiyv/Europe"; String nodes = "{\"" + expectedPath19_1_0_2 + "\":\"" + expectedValue19_1_0_2 + "\", \"" + expectedKey3_0_14 + "\":\"" + expectedValue3_0_14 + "\", \"" + expectedPath3_0_15 + "\":\"" + expectedValue3_0_15 + "\"}"; @@ -207,12 +206,12 @@ public class RpcLwm2mIntegrationWriteTest extends AbstractRpcLwM2MIntegrationTes actualResult = sendRPCReadByKey(expectedKey3_0_14); rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); actualValues = rpcActualResult.get("value").asText(); - expected = "LwM2mSingleResource [id=" + resourceId_14 + ", value=" + expectedValue3_0_14 + ", type=STRING]"; + expected = "LwM2mSingleResource [id=" + RESOURCE_ID_14 + ", value=" + expectedValue3_0_14 + ", type=STRING]"; assertTrue(actualValues.contains(expected)); actualResult = sendRPCReadById(expectedPath3_0_15); rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); actualValues = rpcActualResult.get("value").asText(); - expected = "LwM2mSingleResource [id=" + resourceId_15 + ", value=" + expectedValue3_0_15 + ", type=STRING]"; + expected = "LwM2mSingleResource [id=" + RESOURCE_ID_15 + ", value=" + expectedValue3_0_15 + ", type=STRING]"; assertTrue(actualValues.contains(expected)); } @@ -246,11 +245,11 @@ public class RpcLwm2mIntegrationWriteTest extends AbstractRpcLwM2MIntegrationTes */ @Test public void testWriteCompositeCreateResourceInstanceUpdateSingleResourceByIdKey_Result_CHANGED() throws Exception { - String expectedPath19_1_0_2 = objectIdVer_19 + "/" + objectInstanceId_1 + "/" + resourceId_0 + "/" + resourceInstanceId_2; + String expectedPath19_1_0_2 = objectIdVer_19 + "/" + OBJECT_INSTANCE_ID_1 + "/" + RESOURCE_ID_0 + "/" + RESOURCE_INSTANCE_ID_2; String expectedValue19_1_0_2 = "00001234"; - String expectedKey3_0_14 = resourceIdName_3_14; + String expectedKey3_0_14 = RESOURCE_ID_NAME_3_14; String expectedValue3_0_14 = "+04"; - String expectedPath3_0_15 = objectInstanceIdVer_3 + "/" + resourceId_15; + String expectedPath3_0_15 = objectInstanceIdVer_3 + "/" + RESOURCE_ID_15; String expectedValue3_0_15 = "Kiyv/Europe"; String nodes = "{\"" + expectedPath19_1_0_2 + "\":\"" + expectedValue19_1_0_2 + "\", \"" + expectedKey3_0_14 + "\":\"" + expectedValue3_0_14 + "\", \"" + expectedPath3_0_15 + "\":\"" + expectedValue3_0_15 + "\"}"; @@ -260,17 +259,17 @@ public class RpcLwm2mIntegrationWriteTest extends AbstractRpcLwM2MIntegrationTes actualResult = sendRPCReadById(expectedPath19_1_0_2); rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); String actualValues = rpcActualResult.get("value").asText(); - String expected = "LwM2mResourceInstance [id=" + resourceInstanceId_2 + ", value=" + expectedValue19_1_0_2.length()/2 + "Bytes, type=OPAQUE]"; + String expected = "LwM2mResourceInstance [id=" + RESOURCE_INSTANCE_ID_2 + ", value=" + expectedValue19_1_0_2.length()/2 + "Bytes, type=OPAQUE]"; assertTrue(actualValues.contains(expected)); actualResult = sendRPCReadByKey(expectedKey3_0_14); rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); actualValues = rpcActualResult.get("value").asText(); - expected = "LwM2mSingleResource [id=" + resourceId_14 + ", value=" + expectedValue3_0_14 + ", type=STRING]"; + expected = "LwM2mSingleResource [id=" + RESOURCE_ID_14 + ", value=" + expectedValue3_0_14 + ", type=STRING]"; assertTrue(actualValues.contains(expected)); actualResult = sendRPCReadById(expectedPath3_0_15); rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); actualValues = rpcActualResult.get("value").asText(); - expected = "LwM2mSingleResource [id=" + resourceId_15 + ", value=" + expectedValue3_0_15 + ", type=STRING]"; + expected = "LwM2mSingleResource [id=" + RESOURCE_ID_15 + ", value=" + expectedValue3_0_15 + ", type=STRING]"; assertTrue(actualValues.contains(expected)); } @@ -285,11 +284,11 @@ public class RpcLwm2mIntegrationWriteTest extends AbstractRpcLwM2MIntegrationTes */ @Test public void testWriteCompositeCreateObjectInstanceUpdateSingleResourceByIdKey_Result_BAD_REQUEST() throws Exception { - String expectedPath19_1_2_2 = objectIdVer_19 + "/" + objectInstanceId_2 + "/" + resourceId_0 + "/" + resourceInstanceId_2; + String expectedPath19_1_2_2 = objectIdVer_19 + "/" + OBJECT_INSTANCE_ID_2 + "/" + RESOURCE_ID_0 + "/" + RESOURCE_INSTANCE_ID_2; String expectedValue19_1_0_2 = "00001234"; - String expectedKey3_0_14 = resourceIdName_3_14; + String expectedKey3_0_14 = RESOURCE_ID_NAME_3_14; String expectedValue3_0_14 = "+04"; - String expectedPath3_0_15 = objectInstanceIdVer_3 + "/" + resourceId_15; + String expectedPath3_0_15 = objectInstanceIdVer_3 + "/" + RESOURCE_ID_15; String expectedValue3_0_15 = "Kiyv/Europe"; String nodes = "{\"" + expectedPath19_1_2_2 + "\":\"" + expectedValue19_1_0_2 + "\", \"" + expectedKey3_0_14 + "\":\"" + expectedValue3_0_14 + "\", \"" + expectedPath3_0_15 + "\":\"" + expectedValue3_0_15 + "\"}"; diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/AbstractSecurityLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/AbstractSecurityLwM2MIntegrationTest.java index c9d2b556af..9108366395 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/AbstractSecurityLwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/AbstractSecurityLwM2MIntegrationTest.java @@ -62,7 +62,7 @@ protected final X509Certificate serverX509Cert; protected final X509Certificate clientX509CertTrustNo; // client certificate signed by intermediate, rootCA with a good CN ("host name") protected final PrivateKey clientPrivateKeyFromCertTrustNo; // client private key used for X509 and RPK protected final PublicKey clientPublicKeyFromCertTrustNo; // client public key used for RPK - private final String[] resources = new String[]{"1.xml", "2.xml", "3.xml", "5.xml", "9.xml"}; + private final String[] RESOURCES_SECURITY = new String[]{"1.xml", "2.xml", "3.xml", "5.xml", "9.xml"}; private final LwM2MBootstrapClientCredentials defaultBootstrapCredentials; @@ -71,7 +71,7 @@ protected final X509Certificate serverX509Cert; public AbstractSecurityLwM2MIntegrationTest() { // create client credentials - setResources(this.resources); + setResources(this.RESOURCES_SECURITY); try { // Get certificates from key store char[] clientKeyStorePwd = CLIENT_STORE_PWD.toCharArray(); From 1b488781d5690093e968fec4f6c6adb5f852af00 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Tue, 11 Jan 2022 19:07:33 +0200 Subject: [PATCH 375/432] lwm2m for profile bootstrap need input: X509 certificate (instead of X509 public key) --- .../server/service/lwm2m/LwM2MServiceImpl.java | 18 ++++++++++++++++++ .../bootstrap/LwM2MServerSecurityConfig.java | 14 ++++++++++---- .../dao/device/DeviceProfileServiceImpl.java | 6 +++--- 3 files changed, 31 insertions(+), 7 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MServiceImpl.java b/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MServiceImpl.java index b5ec5cc654..7d0c623f96 100644 --- a/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MServiceImpl.java +++ b/application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MServiceImpl.java @@ -63,6 +63,12 @@ public class LwM2MServiceImpl implements LwM2MService { } else { bsServ.setServerPublicKey(Base64.encodeBase64String(publicKeyBase64)); } + byte[] certificateBase64 = getCertificate(bsServerConfig); + if (certificateBase64 == null) { + bsServ.setServerCertificate(""); + } else { + bsServ.setServerCertificate(Base64.encodeBase64String(certificateBase64)); + } return bsServ; } @@ -77,5 +83,17 @@ public class LwM2MServiceImpl implements LwM2MService { } return null; } + + private byte[] getCertificate(LwM2MSecureServerConfig config) { + try { + SslCredentials sslCredentials = config.getSslCredentials(); + if (sslCredentials != null) { + return sslCredentials.getCertificateChain()[0].getEncoded(); + } + } catch (Exception e) { + log.trace("Failed to fetch certificate from key store!", e); + } + return null; + } } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/LwM2MServerSecurityConfig.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/LwM2MServerSecurityConfig.java index 12dd9c5a64..11bf049621 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/LwM2MServerSecurityConfig.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/bootstrap/LwM2MServerSecurityConfig.java @@ -42,17 +42,23 @@ public class LwM2MServerSecurityConfig { @ApiModelProperty(position = 8, value = "Server Public Key for 'Security' mode (DTLS): RPK or X509. Format: base64 encoded", example = "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEAZ0pSaGKHk/GrDaUDnQZpeEdGwX7m3Ws+U/kiVat\n" + "+44sgk3c8g0LotfMpLlZJPhPwJ6ipXV+O1r7IZUjBs3LNA==", readOnly = true) protected String serverPublicKey; - @ApiModelProperty(position = 9, value = "Bootstrap Server Account Timeout (If the value is set to 0, or if this resource is not instantiated, the Bootstrap-Server Account lifetime is infinite.)", example = "0", readOnly = true) + @ApiModelProperty(position = 9, value = "Server Public Key for 'Security' mode (DTLS): X509. Format: base64 encoded", example = "MMIICODCCAd6gAwIBAgIUI88U1zowOdrxDK/dOV+36gJxI2MwCgYIKoZIzj0EAwIwejELMAkGA1UEBhMCVUs\n" + + "xEjAQBgNVBAgTCUt5aXYgY2l0eTENMAsGA1UEBxMES3lpdjEUMBIGA1UEChMLVGhpbmdzYm9hcmQxFzAVBgNVBAsMDkRFVkVMT1BFUl9URVNUMRkwFwYDVQQDDBBpbnRlcm1lZGlhdGVfY2EwMB4XDTIyMDEwOTEzMDMwMFoXDTI3MDEwODEzMDMwMFowFDESMBAGA1UEAxM\n" + + "JbG9jYWxob3N0MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEUO3vBo/JTv0eooY7XHiKAIVDoWKFqtrU7C6q8AIKqpLcqhCdW+haFeBOH3PjY6EwaWkY04Bir4oanU0s7tz2uKOBpzCBpDAOBgNVHQ8BAf8EBAMCBaAwEwYDVR0lBAwwCgYIKwYBBQUHAwEwDAYDVR0TAQH/\n" + + "BAIwADAdBgNVHQ4EFgQUEjc3Q4a0TxzP/3x3EV4fHxYUg0YwHwYDVR0jBBgwFoAUuSquGycMU6Q0SYNcbtSkSD3TfH0wLwYDVR0RBCgwJoIVbG9jYWxob3N0LmxvY2FsZG9tYWlugglsb2NhbGhvc3SCAiAtMAoGCCqGSM49BAMCA0gAMEUCIQD7dbZObyUaoDiNbX+9fUNp\n" + + "AWrD7N7XuJUwZ9FcN75R3gIgb2RNjDkHoyUyF1YajwkBk+7XmIXNClmizNJigj908mw=", readOnly = true) + protected String serverCertificate; + @ApiModelProperty(position = 10, value = "Bootstrap Server Account Timeout (If the value is set to 0, or if this resource is not instantiated, the Bootstrap-Server Account lifetime is infinite.)", example = "0", readOnly = true) Integer bootstrapServerAccountTimeout = 0; /** Config -> ObjectId = 1 'LwM2M Server' */ - @ApiModelProperty(position = 10, value = "Specify the lifetime of the registration in seconds.", example = "300", readOnly = true) + @ApiModelProperty(position = 11, value = "Specify the lifetime of the registration in seconds.", example = "300", readOnly = true) private Integer lifetime = 300; - @ApiModelProperty(position = 11, value = "The default value the LwM2M Client should use for the Minimum Period of an Observation in the absence of this parameter being included in an Observation. " + + @ApiModelProperty(position = 12, value = "The default value the LwM2M Client should use for the Minimum Period of an Observation in the absence of this parameter being included in an Observation. " + "If this Resource doesn’t exist, the default value is 0.", example = "1", readOnly = true) private Integer defaultMinPeriod = 1; /** ResourceID=6 'Notification Storing When Disabled or Offline' */ - @ApiModelProperty(position = 12, value = "If true, the LwM2M Client stores “Notify” operations to the LwM2M Server while the LwM2M Server account is disabled or the LwM2M Client is offline. After the LwM2M Server account is enabled or the LwM2M Client is online, the LwM2M Client reports the stored “Notify” operations to the Server. " + + @ApiModelProperty(position = 13, value = "If true, the LwM2M Client stores “Notify” operations to the LwM2M Server while the LwM2M Server account is disabled or the LwM2M Client is offline. After the LwM2M Server account is enabled or the LwM2M Client is online, the LwM2M Client reports the stored “Notify” operations to the Server. " + "If false, the LwM2M Client discards all the “Notify” operations or temporarily disables the Observe function while the LwM2M Server is disabled or the LwM2M Client is offline. " + "The default value is true.", example = "true", readOnly = true) private boolean notifIfDisabled = true; diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java index 18a8a1ecde..b685fc7aa8 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java @@ -765,15 +765,15 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D X509LwM2MBootstrapServerCredential x509ServerCredentials = (X509LwM2MBootstrapServerCredential) bootstrapServerConfig; server = x509ServerCredentials.isBootstrapServerIs() ? "Bootstrap Server" : "LwM2M Server"; if (StringUtils.isEmpty(x509ServerCredentials.getServerPublicKey())) { - throw new DeviceCredentialsValidationException(server + " X509 public key must be specified!"); + throw new DeviceCredentialsValidationException(server + " X509 certificate must be specified!"); } try { String certServer = EncryptionUtil.certTrimNewLines(x509ServerCredentials.getServerPublicKey()); x509ServerCredentials.setServerPublicKey(certServer); - SecurityUtil.publicKey.decode(x509ServerCredentials.getDecodedCServerPublicKey()); + SecurityUtil.certificate.decode(x509ServerCredentials.getDecodedCServerPublicKey()); } catch (Exception e) { - throw new DeviceCredentialsValidationException(server + " X509 public key must be in standard [RFC7250] and then encoded to Base64 format!"); + throw new DeviceCredentialsValidationException(server + " X509 certificate must be in DER-encoded X509v3 format and support only EC algorithm and then encoded to Base64 format!"); } break; } From 753371cc2e3d9224bfc6b2d9f78b7ce294627db0 Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Wed, 12 Jan 2022 10:48:58 +0200 Subject: [PATCH 376/432] dao: existsById, existsByIdAsync added --- .../java/org/thingsboard/server/dao/Dao.java | 4 ++++ .../server/dao/sql/JpaAbstractDao.java | 12 ++++++++++++ .../dao/sql/tenant/JpaTenantDaoTest.java | 18 +++++++++++++++++- 3 files changed, 33 insertions(+), 1 deletion(-) diff --git a/dao/src/main/java/org/thingsboard/server/dao/Dao.java b/dao/src/main/java/org/thingsboard/server/dao/Dao.java index a5d4dfd9d1..830dc2855a 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/Dao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/Dao.java @@ -30,6 +30,10 @@ public interface Dao { ListenableFuture findByIdAsync(TenantId tenantId, UUID id); + boolean existsById(TenantId tenantId, UUID id); + + ListenableFuture existsByIdAsync(TenantId tenantId, UUID id); + T save(TenantId tenantId, T t); boolean removeById(TenantId tenantId, UUID id); diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/JpaAbstractDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/JpaAbstractDao.java index 18852cbf11..80629a2f4e 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/JpaAbstractDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/JpaAbstractDao.java @@ -80,6 +80,18 @@ public abstract class JpaAbstractDao, D> return service.submit(() -> DaoUtil.getData(getCrudRepository().findById(key))); } + @Override + public boolean existsById(TenantId tenantId, UUID key) { + log.debug("Exists by key {}", key); + return getCrudRepository().existsById(key); + } + + @Override + public ListenableFuture existsByIdAsync(TenantId tenantId, UUID key) { + log.debug("Exists by key async {}", key); + return service.submit(() -> getCrudRepository().existsById(key)); + } + @Override @Transactional public boolean removeById(TenantId tenantId, UUID id) { diff --git a/dao/src/test/java/org/thingsboard/server/dao/sql/tenant/JpaTenantDaoTest.java b/dao/src/test/java/org/thingsboard/server/dao/sql/tenant/JpaTenantDaoTest.java index 3b31be7a04..8ee7296153 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/sql/tenant/JpaTenantDaoTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/sql/tenant/JpaTenantDaoTest.java @@ -27,8 +27,9 @@ import org.thingsboard.server.dao.AbstractJpaDaoTest; import org.thingsboard.server.dao.service.AbstractServiceTest; import org.thingsboard.server.dao.tenant.TenantDao; -import java.util.List; +import java.util.UUID; +import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assert.assertEquals; /** @@ -75,4 +76,19 @@ public class JpaTenantDaoTest extends AbstractJpaDaoTest { tenantDao.save(AbstractServiceTest.SYSTEM_TENANT_ID, tenant); } + @Test + @DatabaseSetup("classpath:dbunit/empty_dataset.xml") + public void testIsExistsTenantById() { + final UUID uuid = Uuids.timeBased(); + final TenantId tenantId = new TenantId(uuid); + assertThat(tenantDao.existsById(tenantId, uuid)).as("Is tenant exists before save").isFalse(); + + final Tenant tenant = new Tenant(); + tenant.setId(tenantId); + tenant.setTitle("Tenant " + uuid); + tenantDao.save(AbstractServiceTest.SYSTEM_TENANT_ID, tenant); + + assertThat(tenantDao.existsById(tenantId, uuid)).as("Is tenant exists after save").isTrue(); + } + } From e4579d21d788db8a0784a7dd9bf68383683cd216 Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Wed, 12 Jan 2022 11:01:29 +0200 Subject: [PATCH 377/432] UI: Added persistent page link models and subscribe to router query params --- .../entity/entities-table.component.ts | 53 ++++++++++++------- .../src/app/shared/models/page/page-link.ts | 6 +++ 2 files changed, 39 insertions(+), 20 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/entity/entities-table.component.ts b/ui-ngx/src/app/modules/home/components/entity/entities-table.component.ts index 8fd2f8a976..11b0ea0488 100644 --- a/ui-ngx/src/app/modules/home/components/entity/entities-table.component.ts +++ b/ui-ngx/src/app/modules/home/components/entity/entities-table.component.ts @@ -31,12 +31,12 @@ import { import { PageComponent } from '@shared/components/page.component'; import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; -import { MAX_SAFE_PAGE_SIZE, PageLink, TimePageLink } from '@shared/models/page/page-link'; +import { MAX_SAFE_PAGE_SIZE, PageLink, PageQueryParam, TimePageLink } from '@shared/models/page/page-link'; import { MatDialog } from '@angular/material/dialog'; import { MatPaginator } from '@angular/material/paginator'; -import { MatSort } from '@angular/material/sort'; +import { MatSort, SortDirection } from '@angular/material/sort'; import { EntitiesDataSource } from '@home/models/datasource/entity-datasource'; -import { catchError, debounceTime, distinctUntilChanged, map, tap } from 'rxjs/operators'; +import { catchError, debounceTime, distinctUntilChanged, map, skip, tap } from 'rxjs/operators'; import { Direction, SortOrder } from '@shared/models/page/sort-order'; import { forkJoin, fromEvent, merge, Observable, of, Subscription } from 'rxjs'; import { TranslateService } from '@ngx-translate/core'; @@ -194,7 +194,7 @@ export class EntitiesTableComponent extends PageComponent implements IEntitiesTa this.columnsUpdated(); - const routerQueryParams = this.route.snapshot.queryParams; + const routerQueryParams: PageQueryParam = this.route.snapshot.queryParams; let sortOrder: SortOrder = null; if (this.entitiesTableConfig.defaultSortOrder || routerQueryParams.hasOwnProperty('direction') || routerQueryParams.hasOwnProperty('property')) { @@ -219,10 +219,10 @@ export class EntitiesTableComponent extends PageComponent implements IEntitiesTa } this.pageLink.pageSize = this.displayPagination ? this.defaultPageSize : MAX_SAFE_PAGE_SIZE; if (routerQueryParams.hasOwnProperty('page')) { - this.pageLink.page = routerQueryParams.page; + this.pageLink.page = Number(routerQueryParams.page); } if (routerQueryParams.hasOwnProperty('pageSize')) { - this.pageLink.pageSize = routerQueryParams.pageSize; + this.pageLink.pageSize = Number(routerQueryParams.pageSize); } if (routerQueryParams.hasOwnProperty('textSearch') && !isEmptyStr(routerQueryParams.textSearch)) { this.textSearchMode = true; @@ -249,19 +249,33 @@ export class EntitiesTableComponent extends PageComponent implements IEntitiesTa debounceTime(150), distinctUntilChanged(), tap(() => { - const queryParams: any = { + const queryParams: PageQueryParam = { textSearch: encodeURI(this.pageLink.textSearch) || null }; if (this.displayPagination) { this.paginator.pageIndex = 0; queryParams.page = null; } - this.updatedRouterQueryParams(queryParams); - this.updateData(); + this.updatedRouterParamsAndData(queryParams); }) ) .subscribe(); + this.route.queryParams.pipe(skip(1)).subscribe((params: PageQueryParam) => { + this.paginator.pageIndex = Number(params.page) || 0; + this.paginator.pageSize = Number(params.pageSize) || this.defaultPageSize; + this.sort.active = params.property || this.entitiesTableConfig.defaultSortOrder.property; + this.sort.direction = (params.direction || this.entitiesTableConfig.defaultSortOrder.direction).toLowerCase() as SortDirection; + if (params.hasOwnProperty('textSearch') && !isEmptyStr(params.textSearch)) { + this.textSearchMode = true; + this.pageLink.textSearch = decodeURI(params.textSearch); + } else { + this.textSearchMode = false; + this.pageLink.textSearch = null; + } + this.updateData(); + }); + this.updatePaginationSubscriptions(); this.viewInited = true; } @@ -275,8 +289,8 @@ export class EntitiesTableComponent extends PageComponent implements IEntitiesTa const sortSubscription$: Observable = this.sort.sortChange.asObservable().pipe( map((data) => { const direction = data.direction.toUpperCase(); - const queryParams: any = { - direction: this.entitiesTableConfig?.defaultSortOrder?.direction === direction ? null : direction, + const queryParams: PageQueryParam = { + direction: (this.entitiesTableConfig?.defaultSortOrder?.direction === direction ? null : direction) as Direction, property: this.entitiesTableConfig?.defaultSortOrder?.property === data.active ? null : data.active }; if (this.displayPagination) { @@ -297,10 +311,9 @@ export class EntitiesTableComponent extends PageComponent implements IEntitiesTa ); } this.updateDataSubscription = ((this.displayPagination ? merge(sortSubscription$, paginatorSubscription$) - : sortSubscription$) as Observable).pipe( + : sortSubscription$) as Observable).pipe( tap((queryParams) => { - this.updatedRouterQueryParams(queryParams); - this.updateData(); + this.updatedRouterParamsAndData(queryParams); }) ).subscribe(); } @@ -486,15 +499,14 @@ export class EntitiesTableComponent extends PageComponent implements IEntitiesTa exitFilterMode() { this.textSearchMode = false; this.pageLink.textSearch = null; - const queryParams: any = { + const queryParams: PageQueryParam = { textSearch: null }; if (this.displayPagination) { this.paginator.pageIndex = 0; queryParams.page = null; } - this.updatedRouterQueryParams(queryParams); - this.updateData(); + this.updatedRouterParamsAndData(queryParams); } resetSortAndFilter(update: boolean = true, preserveTimewindow: boolean = false) { @@ -508,9 +520,8 @@ export class EntitiesTableComponent extends PageComponent implements IEntitiesTa const sortable = this.sort.sortables.get(this.entitiesTableConfig.defaultSortOrder.property); this.sort.active = sortable.id; this.sort.direction = this.entitiesTableConfig.defaultSortOrder.direction === Direction.ASC ? 'asc' : 'desc'; - this.updatedRouterQueryParams({}, 'preserve'); if (update) { - this.updateData(); + this.updatedRouterParamsAndData({}, 'preserve'); } } @@ -628,13 +639,15 @@ export class EntitiesTableComponent extends PageComponent implements IEntitiesTa return entity.id.id; } - protected updatedRouterQueryParams(queryParams: object, queryParamsHandling: QueryParamsHandling = 'merge') { + protected updatedRouterParamsAndData(queryParams: object, queryParamsHandling: QueryParamsHandling = 'merge') { if (this.persistentPageLinkMode) { this.router.navigate([], { relativeTo: this.route, queryParams, queryParamsHandling }); + } else { + this.updateData(); } } } diff --git a/ui-ngx/src/app/shared/models/page/page-link.ts b/ui-ngx/src/app/shared/models/page/page-link.ts index 92fe4634f5..2528b6ce99 100644 --- a/ui-ngx/src/app/shared/models/page/page-link.ts +++ b/ui-ngx/src/app/shared/models/page/page-link.ts @@ -23,6 +23,12 @@ export const MAX_SAFE_PAGE_SIZE = 2147483647; export type PageLinkSearchFunction = (entity: T, textSearch: string, searchProperty?: string) => boolean; +export interface PageQueryParam extends Partial{ + textSearch?: string; + pageSize?: number; + page?: number; +} + export function defaultPageLinkSearchFunction(searchProperty?: string): PageLinkSearchFunction { return (entity, textSearch) => defaultPageLinkSearch(entity, textSearch, searchProperty); } From b458dddc56c2db52615e5f2ebc1421da9a7d4074 Mon Sep 17 00:00:00 2001 From: Andrew Shvayka Date: Wed, 12 Jan 2022 11:20:18 +0200 Subject: [PATCH 378/432] Restore alarm relations update script. Add Bootstrap upgrade script --- .../install/SqlDatabaseUpgradeService.java | 30 +++++++++++++++---- 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java b/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java index eef29026ba..4a6d64caea 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java @@ -475,12 +475,30 @@ public class SqlDatabaseUpgradeService implements DatabaseEntitiesUpgradeService log.info("Updating schema ..."); schemaUpdateFile = Paths.get(installScripts.getDataDir(), "upgrade", "3.3.2", SCHEMA_UPDATE_SQL); loadSql(schemaUpdateFile, conn); - log.info("Updating server`s public key from HexDec to Base64 in profile for LWM2M..."); - conn.createStatement().execute("call update_profile_bootstrap();"); - log.info("Server`s public key from HexDec to Base64 in profile for LWM2M updated."); - log.info("Updating client`s public key and secret key from HexDec to Base64 for LWM2M..."); - conn.createStatement().execute("call update_device_credentials_to_base64_and_bootstrap();"); - log.info("Client`s public key and secret key from HexDec to Base64 for LWM2M updated."); + try { + conn.createStatement().execute("insert into entity_alarm(tenant_id, entity_id, created_time, type, customer_id, alarm_id)" + + " select tenant_id, originator_id, created_time, type, customer_id, id from alarm;"); + conn.createStatement().execute("insert into entity_alarm(tenant_id, entity_id, created_time, type, customer_id, alarm_id)" + + " select a.tenant_id, r.from_id, created_time, type, customer_id, id" + + " from alarm a inner join relation r on r.relation_type_group = 'ALARM' and r.relation_type = 'ANY' and a.id = r.to_id ON CONFLICT DO NOTHING;"); + conn.createStatement().execute("delete from relation r where r.relation_type_group = 'ALARM';"); + } catch (Exception e) { + log.error("Failed to update alarm relations!!!", e); + } + + log.info("Updating lwm2m device profiles ..."); + try { + schemaUpdateFile = Paths.get(installScripts.getDataDir(), "upgrade", "3.3.2", "schema_update_lwm2m_bootstrap.sql"); + loadSql(schemaUpdateFile, conn); + log.info("Updating server`s public key from HexDec to Base64 in profile for LWM2M..."); + conn.createStatement().execute("call update_profile_bootstrap();"); + log.info("Server`s public key from HexDec to Base64 in profile for LWM2M updated."); + log.info("Updating client`s public key and secret key from HexDec to Base64 for LWM2M..."); + conn.createStatement().execute("call update_device_credentials_to_base64_and_bootstrap();"); + log.info("Client`s public key and secret key from HexDec to Base64 for LWM2M updated."); + } catch (Exception e) { + log.error("Failed to update lwm2m profiles!!!", e); + } log.info("Updating schema settings..."); conn.createStatement().execute("UPDATE tb_schema_settings SET schema_version = 3003003;"); log.info("Schema updated."); From 08997d682c0c69392cd268be8633408d6a2b325f Mon Sep 17 00:00:00 2001 From: Viacheslav Klimov Date: Wed, 12 Jan 2022 12:23:43 +0200 Subject: [PATCH 379/432] Don't allow sysadmin to delete himself --- .../org/thingsboard/server/controller/UserController.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/application/src/main/java/org/thingsboard/server/controller/UserController.java b/application/src/main/java/org/thingsboard/server/controller/UserController.java index e83bc8970c..c7369fa5b9 100644 --- a/application/src/main/java/org/thingsboard/server/controller/UserController.java +++ b/application/src/main/java/org/thingsboard/server/controller/UserController.java @@ -302,6 +302,10 @@ public class UserController extends BaseController { UserId userId = new UserId(toUUID(strUserId)); User user = checkUserId(userId, Operation.DELETE); + if (user.getAuthority() == Authority.SYS_ADMIN && getCurrentUser().getId().equals(userId)) { + throw new ThingsboardException("Sysadmin is not allowed to delete himself", ThingsboardErrorCode.PERMISSION_DENIED); + } + List relatedEdgeIds = findRelatedEdgeIds(getTenantId(), userId); userService.deleteUser(getCurrentUser().getTenantId(), userId); From b84ab58d7b41f307d8d8a4cd99f160c5a73dc330 Mon Sep 17 00:00:00 2001 From: Sergey Tarnavskiy Date: Wed, 12 Jan 2022 12:56:02 +0200 Subject: [PATCH 380/432] LwM2M transport. Added serverCertificate value for X509-securityMode in Bootstrap-config. --- .../device/lwm2m/lwm2m-device-config-server.component.ts | 3 +++ .../profile/device/lwm2m/lwm2m-profile-config.models.ts | 1 + 2 files changed, 4 insertions(+) diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-config-server.component.ts b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-config-server.component.ts index fa6d31153c..de75ea416b 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-config-server.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-config-server.component.ts @@ -112,6 +112,9 @@ export class Lwm2mDeviceConfigServerComponent implements OnInit, ControlValueAcc this.changeSecurityHostPortFields(serverSecurityConfig); } this.serverFormGroup.patchValue(serverSecurityConfig, {emitEvent: false}); + if (this.currentSecurityMode === Lwm2mSecurityType.X509) { + this.serverFormGroup.get('serverPublicKey').patchValue(serverSecurityConfig.serverCertificate, {emitEvent: false}); + } }); this.serverFormGroup.valueChanges.pipe( takeUntil(this.destroy$) diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-profile-config.models.ts b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-profile-config.models.ts index 56ae00c5a9..ce2824fb12 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-profile-config.models.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-profile-config.models.ts @@ -129,6 +129,7 @@ export interface ServerSecurityConfig { securityHost?: string; securityPort?: number; serverPublicKey?: string; + serverCertificate?: string; clientHoldOffTime?: number; shortServerId?: number; bootstrapServerAccountTimeout: number; From ab76d5a7a6c84053a93013c01237a13e84a0d5d0 Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Wed, 12 Jan 2022 13:59:13 +0200 Subject: [PATCH 381/432] fixed timescale agg by timezone --- .../dao/sqlts/timescale/AggregationRepository.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/dao/src/main/java/org/thingsboard/server/dao/sqlts/timescale/AggregationRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sqlts/timescale/AggregationRepository.java index 6559ea2c9e..8628d3e160 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sqlts/timescale/AggregationRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sqlts/timescale/AggregationRepository.java @@ -38,15 +38,15 @@ public class AggregationRepository { public static final String FROM_WHERE_CLAUSE = "FROM ts_kv tskv WHERE tskv.entity_id = cast(:entityId AS uuid) AND tskv.key= cast(:entityKey AS int) AND tskv.ts > :startTs AND tskv.ts <= :endTs GROUP BY tskv.entity_id, tskv.key, tsBucket ORDER BY tskv.entity_id, tskv.key, tsBucket"; - public static final String FIND_AVG_QUERY = "SELECT time_bucket(:timeBucket, tskv.ts) AS tsBucket, :timeBucket AS interval, SUM(COALESCE(tskv.long_v, 0)) AS longValue, SUM(COALESCE(tskv.dbl_v, 0.0)) AS doubleValue, SUM(CASE WHEN tskv.long_v IS NULL THEN 0 ELSE 1 END) AS longCountValue, SUM(CASE WHEN tskv.dbl_v IS NULL THEN 0 ELSE 1 END) AS doubleCountValue, null AS strValue, 'AVG' AS aggType "; + public static final String FIND_AVG_QUERY = "SELECT time_bucket(:timeBucket, tskv.ts, :startTs) AS tsBucket, :timeBucket AS interval, SUM(COALESCE(tskv.long_v, 0)) AS longValue, SUM(COALESCE(tskv.dbl_v, 0.0)) AS doubleValue, SUM(CASE WHEN tskv.long_v IS NULL THEN 0 ELSE 1 END) AS longCountValue, SUM(CASE WHEN tskv.dbl_v IS NULL THEN 0 ELSE 1 END) AS doubleCountValue, null AS strValue, 'AVG' AS aggType "; - public static final String FIND_MAX_QUERY = "SELECT time_bucket(:timeBucket, tskv.ts) AS tsBucket, :timeBucket AS interval, MAX(COALESCE(tskv.long_v, -9223372036854775807)) AS longValue, MAX(COALESCE(tskv.dbl_v, -1.79769E+308)) as doubleValue, SUM(CASE WHEN tskv.long_v IS NULL THEN 0 ELSE 1 END) AS longCountValue, SUM(CASE WHEN tskv.dbl_v IS NULL THEN 0 ELSE 1 END) AS doubleCountValue, MAX(tskv.str_v) AS strValue, 'MAX' AS aggType "; + public static final String FIND_MAX_QUERY = "SELECT time_bucket(:timeBucket, tskv.ts, :startTs) AS tsBucket, :timeBucket AS interval, MAX(COALESCE(tskv.long_v, -9223372036854775807)) AS longValue, MAX(COALESCE(tskv.dbl_v, -1.79769E+308)) as doubleValue, SUM(CASE WHEN tskv.long_v IS NULL THEN 0 ELSE 1 END) AS longCountValue, SUM(CASE WHEN tskv.dbl_v IS NULL THEN 0 ELSE 1 END) AS doubleCountValue, MAX(tskv.str_v) AS strValue, 'MAX' AS aggType "; - public static final String FIND_MIN_QUERY = "SELECT time_bucket(:timeBucket, tskv.ts) AS tsBucket, :timeBucket AS interval, MIN(COALESCE(tskv.long_v, 9223372036854775807)) AS longValue, MIN(COALESCE(tskv.dbl_v, 1.79769E+308)) as doubleValue, SUM(CASE WHEN tskv.long_v IS NULL THEN 0 ELSE 1 END) AS longCountValue, SUM(CASE WHEN tskv.dbl_v IS NULL THEN 0 ELSE 1 END) AS doubleCountValue, MIN(tskv.str_v) AS strValue, 'MIN' AS aggType "; + public static final String FIND_MIN_QUERY = "SELECT time_bucket(:timeBucket, tskv.ts, :startTs) AS tsBucket, :timeBucket AS interval, MIN(COALESCE(tskv.long_v, 9223372036854775807)) AS longValue, MIN(COALESCE(tskv.dbl_v, 1.79769E+308)) as doubleValue, SUM(CASE WHEN tskv.long_v IS NULL THEN 0 ELSE 1 END) AS longCountValue, SUM(CASE WHEN tskv.dbl_v IS NULL THEN 0 ELSE 1 END) AS doubleCountValue, MIN(tskv.str_v) AS strValue, 'MIN' AS aggType "; - public static final String FIND_SUM_QUERY = "SELECT time_bucket(:timeBucket, tskv.ts) AS tsBucket, :timeBucket AS interval, SUM(COALESCE(tskv.long_v, 0)) AS longValue, SUM(COALESCE(tskv.dbl_v, 0.0)) AS doubleValue, SUM(CASE WHEN tskv.long_v IS NULL THEN 0 ELSE 1 END) AS longCountValue, SUM(CASE WHEN tskv.dbl_v IS NULL THEN 0 ELSE 1 END) AS doubleCountValue, null AS strValue, null AS jsonValue, 'SUM' AS aggType "; + public static final String FIND_SUM_QUERY = "SELECT time_bucket(:timeBucket, tskv.ts, :startTs) AS tsBucket, :timeBucket AS interval, SUM(COALESCE(tskv.long_v, 0)) AS longValue, SUM(COALESCE(tskv.dbl_v, 0.0)) AS doubleValue, SUM(CASE WHEN tskv.long_v IS NULL THEN 0 ELSE 1 END) AS longCountValue, SUM(CASE WHEN tskv.dbl_v IS NULL THEN 0 ELSE 1 END) AS doubleCountValue, null AS strValue, null AS jsonValue, 'SUM' AS aggType "; - public static final String FIND_COUNT_QUERY = "SELECT time_bucket(:timeBucket, tskv.ts) AS tsBucket, :timeBucket AS interval, SUM(CASE WHEN tskv.bool_v IS NULL THEN 0 ELSE 1 END) AS booleanValueCount, SUM(CASE WHEN tskv.str_v IS NULL THEN 0 ELSE 1 END) AS strValueCount, SUM(CASE WHEN tskv.long_v IS NULL THEN 0 ELSE 1 END) AS longValueCount, SUM(CASE WHEN tskv.dbl_v IS NULL THEN 0 ELSE 1 END) AS doubleValueCount, SUM(CASE WHEN tskv.json_v IS NULL THEN 0 ELSE 1 END) AS jsonValueCount "; + public static final String FIND_COUNT_QUERY = "SELECT time_bucket(:timeBucket, tskv.ts, :startTs) AS tsBucket, :timeBucket AS interval, SUM(CASE WHEN tskv.bool_v IS NULL THEN 0 ELSE 1 END) AS booleanValueCount, SUM(CASE WHEN tskv.str_v IS NULL THEN 0 ELSE 1 END) AS strValueCount, SUM(CASE WHEN tskv.long_v IS NULL THEN 0 ELSE 1 END) AS longValueCount, SUM(CASE WHEN tskv.dbl_v IS NULL THEN 0 ELSE 1 END) AS doubleValueCount, SUM(CASE WHEN tskv.json_v IS NULL THEN 0 ELSE 1 END) AS jsonValueCount "; @PersistenceContext private EntityManager entityManager; From 6c166b90773092db02c702e24cd7739abddbec8e Mon Sep 17 00:00:00 2001 From: Andrew Shvayka Date: Wed, 12 Jan 2022 11:20:18 +0200 Subject: [PATCH 382/432] Restore alarm relations update script. Add Bootstrap upgrade script # Conflicts: # application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java --- .../install/SqlDatabaseUpgradeService.java | 40 +++++++++++++------ 1 file changed, 28 insertions(+), 12 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java b/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java index c98e46d86e..6f142bab4c 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java @@ -1,12 +1,12 @@ /** * Copyright © 2016-2021 The Thingsboard Authors - * + *

* Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

* Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -475,14 +475,30 @@ public class SqlDatabaseUpgradeService implements DatabaseEntitiesUpgradeService log.info("Updating schema ..."); schemaUpdateFile = Paths.get(installScripts.getDataDir(), "upgrade", "3.3.2", SCHEMA_UPDATE_SQL); loadSql(schemaUpdateFile, conn); - log.info("Updating server`s public key from HexDec to Base64 in profile for LWM2M..."); - schemaUpdateFile = Paths.get(installScripts.getDataDir(), "upgrade", "3.3.2", "schema_update_lwm2m_bootstrap.sql"); - loadSql(schemaUpdateFile, conn); - conn.createStatement().execute("call update_profile_bootstrap();"); - log.info("Server`s public key from HexDec to Base64 in profile for LWM2M updated."); - log.info("Updating client`s public key and secret key from HexDec to Base64 for LWM2M..."); - conn.createStatement().execute("call update_device_credentials_to_base64_and_bootstrap();"); - log.info("Client`s public key and secret key from HexDec to Base64 for LWM2M updated."); + try { + conn.createStatement().execute("insert into entity_alarm(tenant_id, entity_id, created_time, type, customer_id, alarm_id)" + + " select tenant_id, originator_id, created_time, type, customer_id, id from alarm;"); + conn.createStatement().execute("insert into entity_alarm(tenant_id, entity_id, created_time, type, customer_id, alarm_id)" + + " select a.tenant_id, r.from_id, created_time, type, customer_id, id" + + " from alarm a inner join relation r on r.relation_type_group = 'ALARM' and r.relation_type = 'ANY' and a.id = r.to_id ON CONFLICT DO NOTHING;"); + conn.createStatement().execute("delete from relation r where r.relation_type_group = 'ALARM';"); + } catch (Exception e) { + log.error("Failed to update alarm relations!!!", e); + } + + log.info("Updating lwm2m device profiles ..."); + try { + schemaUpdateFile = Paths.get(installScripts.getDataDir(), "upgrade", "3.3.2", "schema_update_lwm2m_bootstrap.sql"); + loadSql(schemaUpdateFile, conn); + log.info("Updating server`s public key from HexDec to Base64 in profile for LWM2M..."); + conn.createStatement().execute("call update_profile_bootstrap();"); + log.info("Server`s public key from HexDec to Base64 in profile for LWM2M updated."); + log.info("Updating client`s public key and secret key from HexDec to Base64 for LWM2M..."); + conn.createStatement().execute("call update_device_credentials_to_base64_and_bootstrap();"); + log.info("Client`s public key and secret key from HexDec to Base64 for LWM2M updated."); + } catch (Exception e) { + log.error("Failed to update lwm2m profiles!!!", e); + } log.info("Updating schema settings..."); conn.createStatement().execute("UPDATE tb_schema_settings SET schema_version = 3003003;"); log.info("Schema updated."); From 69f060a48ce37cfc757ca93ca6bba4c975c1c9ad Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Wed, 12 Jan 2022 14:50:16 +0200 Subject: [PATCH 383/432] - license --- .../server/service/install/SqlDatabaseUpgradeService.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java b/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java index 6f142bab4c..4a6d64caea 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java @@ -1,12 +1,12 @@ /** * Copyright © 2016-2021 The Thingsboard Authors - *

+ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

+ * + * http://www.apache.org/licenses/LICENSE-2.0 + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. From 949d3065609ad712df8df7ea5af03abea746679b Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Wed, 12 Jan 2022 15:42:43 +0200 Subject: [PATCH 384/432] Added functionality to support 3.3.0 edge version rule chains --- .../service/edge/rpc/EdgeGrpcSession.java | 9 +- .../constructor/RuleChainMsgConstructor.java | 187 ++++++++- .../rpc/processor/RuleChainEdgeProcessor.java | 5 +- .../RuleChainMsgConstructorTest.java | 358 ++++++++++++++++++ common/edge-api/src/main/proto/edge.proto | 6 + 5 files changed, 543 insertions(+), 22 deletions(-) create mode 100644 application/src/test/java/org/thingsboard/server/service/edge/rpc/constructor/RuleChainMsgConstructorTest.java diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcSession.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcSession.java index 46b36ca99f..2fc8cdf841 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcSession.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcSession.java @@ -52,6 +52,7 @@ import org.thingsboard.server.gen.edge.v1.DownlinkMsg; import org.thingsboard.server.gen.edge.v1.DownlinkResponseMsg; import org.thingsboard.server.gen.edge.v1.EdgeConfiguration; import org.thingsboard.server.gen.edge.v1.EdgeUpdateMsg; +import org.thingsboard.server.gen.edge.v1.EdgeVersion; import org.thingsboard.server.gen.edge.v1.EntityDataProto; import org.thingsboard.server.gen.edge.v1.EntityViewsRequestMsg; import org.thingsboard.server.gen.edge.v1.RelationRequestMsg; @@ -73,14 +74,11 @@ import org.thingsboard.server.service.edge.rpc.fetch.GeneralEdgeEventFetcher; import java.io.Closeable; import java.util.ArrayList; import java.util.Collections; -import java.util.LinkedHashMap; import java.util.List; -import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.UUID; import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.ReentrantLock; import java.util.function.BiConsumer; @@ -109,6 +107,8 @@ public final class EdgeGrpcSession implements Closeable { private boolean connected; private boolean syncCompleted; + private EdgeVersion edgeVersion; + private ScheduledExecutorService sendDownlinkExecutorService; EdgeGrpcSession(EdgeContextComponent ctx, StreamObserver outputStream, BiConsumer sessionOpenListener, @@ -525,7 +525,7 @@ public final class EdgeGrpcSession implements Closeable { case RULE_CHAIN: return ctx.getRuleChainProcessor().processRuleChainToEdge(edge, edgeEvent, msgType, action); case RULE_CHAIN_METADATA: - return ctx.getRuleChainProcessor().processRuleChainMetadataToEdge(edgeEvent, msgType); + return ctx.getRuleChainProcessor().processRuleChainMetadataToEdge(edgeEvent, msgType, this.edgeVersion); case ALARM: return ctx.getAlarmProcessor().processAlarmToEdge(edge, edgeEvent, msgType, action); case USER: @@ -655,6 +655,7 @@ public final class EdgeGrpcSession implements Closeable { try { if (edge.getSecret().equals(request.getEdgeSecret())) { sessionOpenListener.accept(edge.getId(), this); + this.edgeVersion = request.getEdgeVersion(); return ConnectResponseMsg.newBuilder() .setResponseCode(ConnectResponseCode.ACCEPTED) .setErrorMsg("") diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/RuleChainMsgConstructor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/RuleChainMsgConstructor.java index 11b14a78dc..e564b921f2 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/RuleChainMsgConstructor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/RuleChainMsgConstructor.java @@ -17,15 +17,18 @@ package org.thingsboard.server.service.edge.rpc.constructor; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; import org.thingsboard.common.util.JacksonUtil; +import org.thingsboard.rule.engine.flow.TbRuleChainInputNodeConfiguration; import org.thingsboard.server.common.data.id.RuleChainId; import org.thingsboard.server.common.data.rule.NodeConnectionInfo; import org.thingsboard.server.common.data.rule.RuleChain; import org.thingsboard.server.common.data.rule.RuleChainConnectionInfo; import org.thingsboard.server.common.data.rule.RuleChainMetaData; import org.thingsboard.server.common.data.rule.RuleNode; +import org.thingsboard.server.gen.edge.v1.EdgeVersion; import org.thingsboard.server.gen.edge.v1.NodeConnectionInfoProto; import org.thingsboard.server.gen.edge.v1.RuleChainConnectionInfoProto; import org.thingsboard.server.gen.edge.v1.RuleChainMetadataUpdateMsg; @@ -36,6 +39,10 @@ import org.thingsboard.server.queue.util.TbCoreComponent; import java.util.ArrayList; import java.util.List; +import java.util.NavigableSet; +import java.util.TreeSet; +import java.util.UUID; +import java.util.stream.Collectors; @Component @Slf4j @@ -43,6 +50,8 @@ import java.util.List; public class RuleChainMsgConstructor { private static final ObjectMapper objectMapper = new ObjectMapper(); + private static final String RULE_CHAIN_INPUT_NODE = "org.thingsboard.rule.engine.flow.TbRuleChainInputNode"; + private static final String TB_RULE_CHAIN_OUTPUT_NODE = "org.thingsboard.rule.engine.flow.TbRuleChainOutputNode"; public RuleChainUpdateMsg constructRuleChainUpdatedMsg(RuleChainId edgeRootRuleChainId, UpdateMsgType msgType, RuleChain ruleChain) { RuleChainUpdateMsg.Builder builder = RuleChainUpdateMsg.newBuilder() @@ -60,18 +69,19 @@ public class RuleChainMsgConstructor { return builder.build(); } - public RuleChainMetadataUpdateMsg constructRuleChainMetadataUpdatedMsg(UpdateMsgType msgType, RuleChainMetaData ruleChainMetaData) { + public RuleChainMetadataUpdateMsg constructRuleChainMetadataUpdatedMsg(UpdateMsgType msgType, + RuleChainMetaData ruleChainMetaData, + EdgeVersion edgeVersion) { try { - RuleChainMetadataUpdateMsg.Builder builder = RuleChainMetadataUpdateMsg.newBuilder() - .setRuleChainIdMSB(ruleChainMetaData.getRuleChainId().getId().getMostSignificantBits()) - .setRuleChainIdLSB(ruleChainMetaData.getRuleChainId().getId().getLeastSignificantBits()) - .addAllNodes(constructNodes(ruleChainMetaData.getNodes())) - .addAllConnections(constructConnections(ruleChainMetaData.getConnections())) - .addAllRuleChainConnections(constructRuleChainConnections(ruleChainMetaData.getRuleChainConnections())); - if (ruleChainMetaData.getFirstNodeIndex() != null) { - builder.setFirstNodeIndex(ruleChainMetaData.getFirstNodeIndex()); - } else { - builder.setFirstNodeIndex(-1); + RuleChainMetadataUpdateMsg.Builder builder = RuleChainMetadataUpdateMsg.newBuilder(); + switch (edgeVersion) { + case V_3_3_0: + constructRuleChainMetadataUpdatedMsg_V_3_3_0(builder, ruleChainMetaData); + break; + case V_3_3_3: + default: + constructRuleChainMetadataUpdatedMsg_V_3_3_3(builder, ruleChainMetaData); + break; } builder.setMsgType(msgType); return builder.build(); @@ -81,6 +91,104 @@ public class RuleChainMsgConstructor { return null; } + private void constructRuleChainMetadataUpdatedMsg_V_3_3_3(RuleChainMetadataUpdateMsg.Builder builder, + RuleChainMetaData ruleChainMetaData) throws JsonProcessingException { + builder.setRuleChainIdMSB(ruleChainMetaData.getRuleChainId().getId().getMostSignificantBits()) + .setRuleChainIdLSB(ruleChainMetaData.getRuleChainId().getId().getLeastSignificantBits()) + .addAllNodes(constructNodes(ruleChainMetaData.getNodes())) + .addAllConnections(constructConnections(ruleChainMetaData.getConnections())) + .addAllRuleChainConnections(constructRuleChainConnections(ruleChainMetaData.getRuleChainConnections(), new TreeSet<>())); + if (ruleChainMetaData.getFirstNodeIndex() != null) { + builder.setFirstNodeIndex(ruleChainMetaData.getFirstNodeIndex()); + } else { + builder.setFirstNodeIndex(-1); + } + } + + private void constructRuleChainMetadataUpdatedMsg_V_3_3_0(RuleChainMetadataUpdateMsg.Builder builder, + RuleChainMetaData ruleChainMetaData) throws JsonProcessingException { + List supportedNodes = filterNodes_V_3_3_0(ruleChainMetaData.getNodes()); + NavigableSet removedNodeIndexes = getRemovedNodeIndexes(ruleChainMetaData.getNodes(), ruleChainMetaData.getConnections()); + List connections = filterConnections_V_3_3_0(ruleChainMetaData.getNodes(), ruleChainMetaData.getConnections(), removedNodeIndexes); + + List ruleChainConnections = new ArrayList<>(); + if (ruleChainMetaData.getRuleChainConnections() != null) { + ruleChainConnections.addAll(ruleChainMetaData.getRuleChainConnections()); + } + ruleChainConnections.addAll(addRuleChainConnections_V_3_3_0(ruleChainMetaData.getNodes(), ruleChainMetaData.getConnections())); + builder.setRuleChainIdMSB(ruleChainMetaData.getRuleChainId().getId().getMostSignificantBits()) + .setRuleChainIdLSB(ruleChainMetaData.getRuleChainId().getId().getLeastSignificantBits()) + .addAllNodes(constructNodes(supportedNodes)) + .addAllConnections(constructConnections(connections)) + .addAllRuleChainConnections(constructRuleChainConnections(ruleChainConnections, removedNodeIndexes)); + if (ruleChainMetaData.getFirstNodeIndex() != null) { + Integer firstNodeIndex = ruleChainMetaData.getFirstNodeIndex(); + // decrease index because of removed nodes + for (Integer removedIndex : removedNodeIndexes) { + if (firstNodeIndex > removedIndex) { + firstNodeIndex = firstNodeIndex - 1; + } + } + builder.setFirstNodeIndex(firstNodeIndex); + } else { + builder.setFirstNodeIndex(-1); + } + } + + private List filterConnections_V_3_3_0(List nodes, List connections, NavigableSet removedNodeIndexes) { + List result = new ArrayList<>(); + if (connections != null) { + result = connections.stream().filter(conn -> { + for (int i = 0; i < nodes.size(); i++) { + RuleNode node = nodes.get(i); + if (node.getType().equalsIgnoreCase(RULE_CHAIN_INPUT_NODE) + || node.getType().equalsIgnoreCase(TB_RULE_CHAIN_OUTPUT_NODE)) { + if (conn.getFromIndex() == i || conn.getToIndex() == i) { + return false; + } + } + } + return true; + }).map(conn -> { + NodeConnectionInfo newConn = new NodeConnectionInfo(); + newConn.setFromIndex(conn.getFromIndex()); + newConn.setToIndex(conn.getToIndex()); + newConn.setType(conn.getType()); + return newConn; + }).collect(Collectors.toList()); + } + + // decrease index because of removed nodes + for (Integer removedIndex : removedNodeIndexes) { + for (NodeConnectionInfo newConn : result) { + if (newConn.getToIndex() > removedIndex) { + newConn.setToIndex(newConn.getToIndex() - 1); + } + if (newConn.getFromIndex() > removedIndex) { + newConn.setFromIndex(newConn.getFromIndex() - 1); + } + } + } + + return result; + } + + private NavigableSet getRemovedNodeIndexes(List nodes, List connections) { + TreeSet removedIndexes = new TreeSet<>(); + for (NodeConnectionInfo connection : connections) { + for (int i = 0; i < nodes.size(); i++) { + RuleNode node = nodes.get(i); + if (node.getType().equalsIgnoreCase(RULE_CHAIN_INPUT_NODE) + || node.getType().equalsIgnoreCase(TB_RULE_CHAIN_OUTPUT_NODE)) { + if (connection.getFromIndex() == i || connection.getToIndex() == i) { + removedIndexes.add(i); + } + } + } + } + return removedIndexes.descendingSet(); + } + private List constructConnections(List connections) { List result = new ArrayList<>(); if (connections != null && !connections.isEmpty()) { @@ -99,6 +207,21 @@ public class RuleChainMsgConstructor { .build(); } + private List filterNodes_V_3_3_0(List nodes) { + List result = new ArrayList<>(); + for (RuleNode node : nodes) { + switch (node.getType()) { + case RULE_CHAIN_INPUT_NODE: + case TB_RULE_CHAIN_OUTPUT_NODE: + log.trace("Skipping not supported rule node {}", node); + break; + default: + result.add(node); + } + } + return result; + } + private List constructNodes(List nodes) throws JsonProcessingException { List result = new ArrayList<>(); if (nodes != null && !nodes.isEmpty()) { @@ -109,23 +232,55 @@ public class RuleChainMsgConstructor { return result; } - private List constructRuleChainConnections(List ruleChainConnections) throws JsonProcessingException { + private List addRuleChainConnections_V_3_3_0(List nodes, List connections) throws JsonProcessingException { + List result = new ArrayList<>(); + for (int i = 0; i < nodes.size(); i++) { + RuleNode node = nodes.get(i); + if (node.getType().equalsIgnoreCase(RULE_CHAIN_INPUT_NODE)) { + for (NodeConnectionInfo connection : connections) { + if (connection.getToIndex() == i) { + RuleChainConnectionInfo e = new RuleChainConnectionInfo(); + e.setFromIndex(connection.getFromIndex()); + TbRuleChainInputNodeConfiguration configuration = JacksonUtil.treeToValue(node.getConfiguration(), TbRuleChainInputNodeConfiguration.class); + e.setTargetRuleChainId(new RuleChainId(UUID.fromString(configuration.getRuleChainId()))); + e.setAdditionalInfo(node.getAdditionalInfo()); + e.setType(connection.getType()); + result.add(e); + } + } + } + } + return result; + } + + private List constructRuleChainConnections(List ruleChainConnections, NavigableSet removedNodeIndexes) throws JsonProcessingException { List result = new ArrayList<>(); if (ruleChainConnections != null && !ruleChainConnections.isEmpty()) { for (RuleChainConnectionInfo ruleChainConnectionInfo : ruleChainConnections) { - result.add(constructRuleChainConnection(ruleChainConnectionInfo)); + result.add(constructRuleChainConnection(ruleChainConnectionInfo, removedNodeIndexes)); } } return result; } - private RuleChainConnectionInfoProto constructRuleChainConnection(RuleChainConnectionInfo ruleChainConnectionInfo) throws JsonProcessingException { + private RuleChainConnectionInfoProto constructRuleChainConnection(RuleChainConnectionInfo ruleChainConnectionInfo, NavigableSet removedNodeIndexes) throws JsonProcessingException { + int fromIndex = ruleChainConnectionInfo.getFromIndex(); + // decrease index because of removed nodes + for (Integer removedIndex : removedNodeIndexes) { + if (fromIndex > removedIndex) { + fromIndex = fromIndex - 1; + } + } + ObjectNode additionalInfo = (ObjectNode) ruleChainConnectionInfo.getAdditionalInfo(); + if (additionalInfo.get("ruleChainNodeId") == null) { + additionalInfo.put("ruleChainNodeId", "rule-chain-node-UNDEFINED"); + } return RuleChainConnectionInfoProto.newBuilder() - .setFromIndex(ruleChainConnectionInfo.getFromIndex()) + .setFromIndex(fromIndex) .setTargetRuleChainIdMSB(ruleChainConnectionInfo.getTargetRuleChainId().getId().getMostSignificantBits()) .setTargetRuleChainIdLSB(ruleChainConnectionInfo.getTargetRuleChainId().getId().getLeastSignificantBits()) .setType(ruleChainConnectionInfo.getType()) - .setAdditionalInfo(objectMapper.writeValueAsString(ruleChainConnectionInfo.getAdditionalInfo())) + .setAdditionalInfo(objectMapper.writeValueAsString(additionalInfo)) .build(); } diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/RuleChainEdgeProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/RuleChainEdgeProcessor.java index 5ead8c5623..eb32340e87 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/RuleChainEdgeProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/RuleChainEdgeProcessor.java @@ -25,6 +25,7 @@ import org.thingsboard.server.common.data.id.RuleChainId; import org.thingsboard.server.common.data.rule.RuleChain; import org.thingsboard.server.common.data.rule.RuleChainMetaData; import org.thingsboard.server.gen.edge.v1.DownlinkMsg; +import org.thingsboard.server.gen.edge.v1.EdgeVersion; import org.thingsboard.server.gen.edge.v1.RuleChainMetadataUpdateMsg; import org.thingsboard.server.gen.edge.v1.RuleChainUpdateMsg; import org.thingsboard.server.gen.edge.v1.UpdateMsgType; @@ -63,14 +64,14 @@ public class RuleChainEdgeProcessor extends BaseEdgeProcessor { return downlinkMsg; } - public DownlinkMsg processRuleChainMetadataToEdge(EdgeEvent edgeEvent, UpdateMsgType msgType) { + public DownlinkMsg processRuleChainMetadataToEdge(EdgeEvent edgeEvent, UpdateMsgType msgType, EdgeVersion edgeVersion) { RuleChainId ruleChainId = new RuleChainId(edgeEvent.getEntityId()); RuleChain ruleChain = ruleChainService.findRuleChainById(edgeEvent.getTenantId(), ruleChainId); DownlinkMsg downlinkMsg = null; if (ruleChain != null) { RuleChainMetaData ruleChainMetaData = ruleChainService.loadRuleChainMetaData(edgeEvent.getTenantId(), ruleChainId); RuleChainMetadataUpdateMsg ruleChainMetadataUpdateMsg = - ruleChainMsgConstructor.constructRuleChainMetadataUpdatedMsg(msgType, ruleChainMetaData); + ruleChainMsgConstructor.constructRuleChainMetadataUpdatedMsg(msgType, ruleChainMetaData, edgeVersion); if (ruleChainMetadataUpdateMsg != null) { downlinkMsg = DownlinkMsg.newBuilder() .setDownlinkMsgId(EdgeUtils.nextPositiveInt()) diff --git a/application/src/test/java/org/thingsboard/server/service/edge/rpc/constructor/RuleChainMsgConstructorTest.java b/application/src/test/java/org/thingsboard/server/service/edge/rpc/constructor/RuleChainMsgConstructorTest.java new file mode 100644 index 0000000000..4e8a21a8fa --- /dev/null +++ b/application/src/test/java/org/thingsboard/server/service/edge/rpc/constructor/RuleChainMsgConstructorTest.java @@ -0,0 +1,358 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.service.edge.rpc.constructor; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.extern.slf4j.Slf4j; +import org.jetbrains.annotations.NotNull; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.junit.MockitoJUnitRunner; +import org.thingsboard.server.common.data.id.RuleChainId; +import org.thingsboard.server.common.data.id.RuleNodeId; +import org.thingsboard.server.common.data.rule.NodeConnectionInfo; +import org.thingsboard.server.common.data.rule.RuleChainMetaData; +import org.thingsboard.server.common.data.rule.RuleNode; +import org.thingsboard.server.gen.edge.v1.EdgeVersion; +import org.thingsboard.server.gen.edge.v1.RuleChainConnectionInfoProto; +import org.thingsboard.server.gen.edge.v1.RuleChainMetadataUpdateMsg; +import org.thingsboard.server.gen.edge.v1.UpdateMsgType; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +@Slf4j +@RunWith(MockitoJUnitRunner.class) +public class RuleChainMsgConstructorTest { + + private static final ObjectMapper mapper = new ObjectMapper(); + + @Test + public void testConstructRuleChainMetadataUpdatedMsg_V_3_3_3() throws JsonProcessingException { + RuleChainId ruleChainId = new RuleChainId(UUID.randomUUID()); + RuleChainMsgConstructor constructor = new RuleChainMsgConstructor(); + RuleChainMetaData ruleChainMetaData = createRuleChainMetaData(ruleChainId, 3, createRuleNodes(ruleChainId), createConnections()); + RuleChainMetadataUpdateMsg ruleChainMetadataUpdateMsg = + constructor.constructRuleChainMetadataUpdatedMsg(UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE, ruleChainMetaData, EdgeVersion.V_3_3_3); + + Assert.assertEquals("First rule node index incorrect!", 3, ruleChainMetadataUpdateMsg.getFirstNodeIndex()); + Assert.assertEquals("Nodes count incorrect!", 12, ruleChainMetadataUpdateMsg.getNodesCount()); + Assert.assertEquals("Connections count incorrect!", 13, ruleChainMetadataUpdateMsg.getConnectionsCount()); + Assert.assertEquals("Rule chain connections count incorrect!", 0, ruleChainMetadataUpdateMsg.getRuleChainConnectionsCount()); + + compareNodeConnectionInfoAndProto(createNodeConnectionInfo(3, 6, "Success"), ruleChainMetadataUpdateMsg.getConnections(0)); + compareNodeConnectionInfoAndProto(createNodeConnectionInfo(3, 10, "Success"), ruleChainMetadataUpdateMsg.getConnections(1)); + compareNodeConnectionInfoAndProto(createNodeConnectionInfo(3, 0, "Success"), ruleChainMetadataUpdateMsg.getConnections(2)); + compareNodeConnectionInfoAndProto(createNodeConnectionInfo(4, 11, "Success"), ruleChainMetadataUpdateMsg.getConnections(3)); + compareNodeConnectionInfoAndProto(createNodeConnectionInfo(5, 11, "Success"), ruleChainMetadataUpdateMsg.getConnections(4)); + compareNodeConnectionInfoAndProto(createNodeConnectionInfo(6, 11, "Attributes Updated"), ruleChainMetadataUpdateMsg.getConnections(5)); + compareNodeConnectionInfoAndProto(createNodeConnectionInfo(6, 7, "RPC Request from Device"), ruleChainMetadataUpdateMsg.getConnections(6)); + compareNodeConnectionInfoAndProto(createNodeConnectionInfo(6, 4, "Post telemetry"), ruleChainMetadataUpdateMsg.getConnections(7)); + compareNodeConnectionInfoAndProto(createNodeConnectionInfo(6, 5, "Post attributes"), ruleChainMetadataUpdateMsg.getConnections(8)); + compareNodeConnectionInfoAndProto(createNodeConnectionInfo(6, 8, "Other"), ruleChainMetadataUpdateMsg.getConnections(9)); + compareNodeConnectionInfoAndProto(createNodeConnectionInfo(6, 9, "RPC Request to Device"), ruleChainMetadataUpdateMsg.getConnections(10)); + compareNodeConnectionInfoAndProto(createNodeConnectionInfo(7, 11, "Success"), ruleChainMetadataUpdateMsg.getConnections(11)); + compareNodeConnectionInfoAndProto(createNodeConnectionInfo(10, 9, "RPC"), ruleChainMetadataUpdateMsg.getConnections(12)); + } + + @Test + public void testConstructRuleChainMetadataUpdatedMsg_V_3_3_0() throws JsonProcessingException { + RuleChainId ruleChainId = new RuleChainId(UUID.randomUUID()); + RuleChainMsgConstructor constructor = new RuleChainMsgConstructor(); + RuleChainMetaData ruleChainMetaData = createRuleChainMetaData(ruleChainId, 3, createRuleNodes(ruleChainId), createConnections()); + RuleChainMetadataUpdateMsg ruleChainMetadataUpdateMsg = + constructor.constructRuleChainMetadataUpdatedMsg(UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE, ruleChainMetaData, EdgeVersion.V_3_3_0); + + Assert.assertEquals("First rule node index incorrect!", 2, ruleChainMetadataUpdateMsg.getFirstNodeIndex()); + Assert.assertEquals("Nodes count incorrect!", 10, ruleChainMetadataUpdateMsg.getNodesCount()); + Assert.assertEquals("Connections count incorrect!", 10, ruleChainMetadataUpdateMsg.getConnectionsCount()); + Assert.assertEquals("Rule chain connections count incorrect!", 1, ruleChainMetadataUpdateMsg.getRuleChainConnectionsCount()); + + compareNodeConnectionInfoAndProto(createNodeConnectionInfo(2, 5, "Success"), ruleChainMetadataUpdateMsg.getConnections(0)); + compareNodeConnectionInfoAndProto(createNodeConnectionInfo(3, 9, "Success"), ruleChainMetadataUpdateMsg.getConnections(1)); + compareNodeConnectionInfoAndProto(createNodeConnectionInfo(4, 9, "Success"), ruleChainMetadataUpdateMsg.getConnections(2)); + compareNodeConnectionInfoAndProto(createNodeConnectionInfo(5, 9, "Attributes Updated"), ruleChainMetadataUpdateMsg.getConnections(3)); + compareNodeConnectionInfoAndProto(createNodeConnectionInfo(5, 6, "RPC Request from Device"), ruleChainMetadataUpdateMsg.getConnections(4)); + compareNodeConnectionInfoAndProto(createNodeConnectionInfo(5, 3, "Post telemetry"), ruleChainMetadataUpdateMsg.getConnections(5)); + compareNodeConnectionInfoAndProto(createNodeConnectionInfo(5, 4, "Post attributes"), ruleChainMetadataUpdateMsg.getConnections(6)); + compareNodeConnectionInfoAndProto(createNodeConnectionInfo(5, 7, "Other"), ruleChainMetadataUpdateMsg.getConnections(7)); + compareNodeConnectionInfoAndProto(createNodeConnectionInfo(5, 8, "RPC Request to Device"), ruleChainMetadataUpdateMsg.getConnections(8)); + compareNodeConnectionInfoAndProto(createNodeConnectionInfo(6, 9, "Success"), ruleChainMetadataUpdateMsg.getConnections(9)); + + RuleChainConnectionInfoProto ruleChainConnection = ruleChainMetadataUpdateMsg.getRuleChainConnections(0); + Assert.assertEquals("From index incorrect!", 2, ruleChainConnection.getFromIndex()); + Assert.assertEquals("Type index incorrect!", "Success", ruleChainConnection.getType()); + Assert.assertEquals("Additional info incorrect!", + "{\"description\":\"\",\"layoutX\":477,\"layoutY\":560,\"ruleChainNodeId\":\"rule-chain-node-UNDEFINED\"}", + ruleChainConnection.getAdditionalInfo()); + Assert.assertTrue("Target rule chain id MSB incorrect!", ruleChainConnection.getTargetRuleChainIdMSB() != 0); + Assert.assertTrue("Target rule chain id LSB incorrect!", ruleChainConnection.getTargetRuleChainIdLSB() != 0); + } + + @Test + public void testConstructRuleChainMetadataUpdatedMsg_V_3_3_0_inDifferentOrder() throws JsonProcessingException { + // same rule chain metadata, but different order of rule nodes + RuleChainId ruleChainId = new RuleChainId(UUID.randomUUID()); + RuleChainMsgConstructor constructor = new RuleChainMsgConstructor(); + RuleChainMetaData ruleChainMetaData1 = createRuleChainMetaData(ruleChainId, 8, createRuleNodesInDifferentOrder(ruleChainId), createConnectionsInDifferentOrder()); + RuleChainMetadataUpdateMsg ruleChainMetadataUpdateMsg = + constructor.constructRuleChainMetadataUpdatedMsg(UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE, ruleChainMetaData1, EdgeVersion.V_3_3_0); + + Assert.assertEquals("First rule node index incorrect!", 7, ruleChainMetadataUpdateMsg.getFirstNodeIndex()); + Assert.assertEquals("Nodes count incorrect!", 10, ruleChainMetadataUpdateMsg.getNodesCount()); + Assert.assertEquals("Connections count incorrect!", 10, ruleChainMetadataUpdateMsg.getConnectionsCount()); + Assert.assertEquals("Rule chain connections count incorrect!", 1, ruleChainMetadataUpdateMsg.getRuleChainConnectionsCount()); + + compareNodeConnectionInfoAndProto(createNodeConnectionInfo(3, 0, "Success"), ruleChainMetadataUpdateMsg.getConnections(0)); + compareNodeConnectionInfoAndProto(createNodeConnectionInfo(4, 0, "Attributes Updated"), ruleChainMetadataUpdateMsg.getConnections(1)); + compareNodeConnectionInfoAndProto(createNodeConnectionInfo(4, 3, "RPC Request from Device"), ruleChainMetadataUpdateMsg.getConnections(2)); + compareNodeConnectionInfoAndProto(createNodeConnectionInfo(4, 6, "Post telemetry"), ruleChainMetadataUpdateMsg.getConnections(3)); + compareNodeConnectionInfoAndProto(createNodeConnectionInfo(4, 5, "Post attributes"), ruleChainMetadataUpdateMsg.getConnections(4)); + compareNodeConnectionInfoAndProto(createNodeConnectionInfo(4, 2, "Other"), ruleChainMetadataUpdateMsg.getConnections(5)); + compareNodeConnectionInfoAndProto(createNodeConnectionInfo(4, 1, "RPC Request to Device"), ruleChainMetadataUpdateMsg.getConnections(6)); + compareNodeConnectionInfoAndProto(createNodeConnectionInfo(5, 0, "Success"), ruleChainMetadataUpdateMsg.getConnections(7)); + compareNodeConnectionInfoAndProto(createNodeConnectionInfo(6, 0, "Success"), ruleChainMetadataUpdateMsg.getConnections(8)); + compareNodeConnectionInfoAndProto(createNodeConnectionInfo(7, 4, "Success"), ruleChainMetadataUpdateMsg.getConnections(9)); + + RuleChainConnectionInfoProto ruleChainConnection = ruleChainMetadataUpdateMsg.getRuleChainConnections(0); + Assert.assertEquals("From index incorrect!", 7, ruleChainConnection.getFromIndex()); + Assert.assertEquals("Type index incorrect!", "Success", ruleChainConnection.getType()); + Assert.assertEquals("Additional info incorrect!", + "{\"description\":\"\",\"layoutX\":477,\"layoutY\":560,\"ruleChainNodeId\":\"rule-chain-node-UNDEFINED\"}", + ruleChainConnection.getAdditionalInfo()); + Assert.assertTrue("Target rule chain id MSB incorrect!", ruleChainConnection.getTargetRuleChainIdMSB() != 0); + Assert.assertTrue("Target rule chain id LSB incorrect!", ruleChainConnection.getTargetRuleChainIdLSB() != 0); + } + + private void compareNodeConnectionInfoAndProto(NodeConnectionInfo expected, org.thingsboard.server.gen.edge.v1.NodeConnectionInfoProto actual) { + Assert.assertEquals(expected.getFromIndex(), actual.getFromIndex()); + Assert.assertEquals(expected.getToIndex(), actual.getToIndex()); + Assert.assertEquals(expected.getType(), actual.getType()); + } + + private RuleChainMetaData createRuleChainMetaData(RuleChainId ruleChainId, Integer firstNodeIndex, List nodes, List connections) { + RuleChainMetaData ruleChainMetaData = new RuleChainMetaData(); + ruleChainMetaData.setRuleChainId(ruleChainId); + ruleChainMetaData.setFirstNodeIndex(firstNodeIndex); + ruleChainMetaData.setNodes(nodes); + ruleChainMetaData.setConnections(connections); + ruleChainMetaData.setRuleChainConnections(null); + return ruleChainMetaData; + } + + private List createConnections() { + List result = new ArrayList<>(); + result.add(createNodeConnectionInfo(3, 6, "Success")); + result.add(createNodeConnectionInfo(3, 10, "Success")); + result.add(createNodeConnectionInfo(3, 0, "Success")); + result.add(createNodeConnectionInfo(4, 11, "Success")); + result.add(createNodeConnectionInfo(5, 11, "Success")); + result.add(createNodeConnectionInfo(6, 11, "Attributes Updated")); + result.add(createNodeConnectionInfo(6, 7, "RPC Request from Device")); + result.add(createNodeConnectionInfo(6, 4, "Post telemetry")); + result.add(createNodeConnectionInfo(6, 5, "Post attributes")); + result.add(createNodeConnectionInfo(6, 8, "Other")); + result.add(createNodeConnectionInfo(6, 9, "RPC Request to Device")); + result.add(createNodeConnectionInfo(7, 11, "Success")); + result.add(createNodeConnectionInfo(10, 9, "RPC")); + return result; + } + + private NodeConnectionInfo createNodeConnectionInfo(int fromIndex, int toIndex, String type) { + NodeConnectionInfo result = new NodeConnectionInfo(); + result.setFromIndex(fromIndex); + result.setToIndex(toIndex); + result.setType(type); + return result; + } + + private List createRuleNodes(RuleChainId ruleChainId) throws JsonProcessingException { + List result = new ArrayList<>(); + result.add(getOutputNode(ruleChainId)); + result.add(getAcknowledgeNode(ruleChainId)); + result.add(getCheckpointNode(ruleChainId)); + result.add(getDeviceProfileNode(ruleChainId)); + result.add(getSaveTimeSeriesNode(ruleChainId)); + result.add(getSaveClientAttributesNode(ruleChainId)); + result.add(getMessageTypeSwitchNode(ruleChainId)); + result.add(getLogRpcFromDeviceNode(ruleChainId)); + result.add(getLogOtherNode(ruleChainId)); + result.add(getRpcCallRequestNode(ruleChainId)); + result.add(getPushToAnalyticsNode(ruleChainId)); + result.add(getPushToCloudNode(ruleChainId)); + return result; + } + + private RuleNode createRuleNode(RuleChainId ruleChainId, String type, String name, JsonNode configuration, JsonNode additionalInfo) { + RuleNode e = new RuleNode(); + e.setRuleChainId(ruleChainId); + e.setType(type); + e.setName(name); + e.setDebugMode(false); + e.setConfiguration(configuration); + e.setAdditionalInfo(additionalInfo); + e.setId(new RuleNodeId(UUID.randomUUID())); + return e; + } + + private List createConnectionsInDifferentOrder() { + List result = new ArrayList<>(); + result.add(createNodeConnectionInfo(0, 2, "RPC")); + result.add(createNodeConnectionInfo(4, 1, "Success")); + result.add(createNodeConnectionInfo(5, 1, "Attributes Updated")); + result.add(createNodeConnectionInfo(5, 4, "RPC Request from Device")); + result.add(createNodeConnectionInfo(5, 7, "Post telemetry")); + result.add(createNodeConnectionInfo(5, 6, "Post attributes")); + result.add(createNodeConnectionInfo(5, 3, "Other")); + result.add(createNodeConnectionInfo(5, 2, "RPC Request to Device")); + result.add(createNodeConnectionInfo(6, 1, "Success")); + result.add(createNodeConnectionInfo(7, 1, "Success")); + result.add(createNodeConnectionInfo(8, 11, "Success")); + result.add(createNodeConnectionInfo(8, 5, "Success")); + result.add(createNodeConnectionInfo(8, 0, "Success")); + return result; + } + + private List createRuleNodesInDifferentOrder(RuleChainId ruleChainId) throws JsonProcessingException { + List result = new ArrayList<>(); + result.add(getPushToAnalyticsNode(ruleChainId)); + result.add(getPushToCloudNode(ruleChainId)); + result.add(getRpcCallRequestNode(ruleChainId)); + result.add(getLogOtherNode(ruleChainId)); + result.add(getLogRpcFromDeviceNode(ruleChainId)); + result.add(getMessageTypeSwitchNode(ruleChainId)); + result.add(getSaveClientAttributesNode(ruleChainId)); + result.add(getSaveTimeSeriesNode(ruleChainId)); + result.add(getDeviceProfileNode(ruleChainId)); + result.add(getCheckpointNode(ruleChainId)); + result.add(getAcknowledgeNode(ruleChainId)); + result.add(getOutputNode(ruleChainId)); + return result; + } + + + @NotNull + private RuleNode getOutputNode(RuleChainId ruleChainId) throws JsonProcessingException { + return createRuleNode(ruleChainId, + "org.thingsboard.rule.engine.flow.TbRuleChainOutputNode", + "Output node", + mapper.readTree("{\"version\":0}"), + mapper.readTree("{\"description\":\"\",\"layoutX\":178,\"layoutY\":592}")); + } + + @NotNull + private RuleNode getCheckpointNode(RuleChainId ruleChainId) throws JsonProcessingException { + return createRuleNode(ruleChainId, + "org.thingsboard.rule.engine.flow.TbCheckpointNode", + "Checkpoint node", + mapper.readTree("{\"queueName\":\"HighPriority\"}"), + mapper.readTree("{\"description\":\"\",\"layoutX\":178,\"layoutY\":647}")); + } + + @NotNull + private RuleNode getSaveTimeSeriesNode(RuleChainId ruleChainId) throws JsonProcessingException { + return createRuleNode(ruleChainId, + "org.thingsboard.rule.engine.telemetry.TbMsgTimeseriesNode", + "Save Timeseries", + mapper.readTree("{\"defaultTTL\":0}"), + mapper.readTree("{\"layoutX\":823,\"layoutY\":157}")); + } + + @NotNull + private RuleNode getMessageTypeSwitchNode(RuleChainId ruleChainId) throws JsonProcessingException { + return createRuleNode(ruleChainId, + "org.thingsboard.rule.engine.filter.TbMsgTypeSwitchNode", + "Message Type Switch", + mapper.readTree("{\"version\":0}"), + mapper.readTree("{\"layoutX\":347,\"layoutY\":149}")); + } + + @NotNull + private RuleNode getLogOtherNode(RuleChainId ruleChainId) throws JsonProcessingException { + return createRuleNode(ruleChainId, + "org.thingsboard.rule.engine.action.TbLogNode", + "Log Other", + mapper.readTree("{\"jsScript\":\"return '\\\\nIncoming message:\\\\n' + JSON.stringify(msg) + '\\\\nIncoming metadata:\\\\n' + JSON.stringify(metadata);\"}"), + mapper.readTree("{\"layoutX\":824,\"layoutY\":378}")); + } + + @NotNull + private RuleNode getPushToCloudNode(RuleChainId ruleChainId) throws JsonProcessingException { + return createRuleNode(ruleChainId, + "org.thingsboard.rule.engine.edge.TbMsgPushToCloudNode", + "Push to cloud", + mapper.readTree("{\"scope\":\"SERVER_SCOPE\"}"), + mapper.readTree("{\"layoutX\":1129,\"layoutY\":52}")); + } + + @NotNull + private RuleNode getAcknowledgeNode(RuleChainId ruleChainId) throws JsonProcessingException { + return createRuleNode(ruleChainId, + "org.thingsboard.rule.engine.flow.TbAckNode", + "Acknowledge node", + mapper.readTree("{\"version\":0}"), + mapper.readTree("{\"description\":\"\",\"layoutX\":177,\"layoutY\":703}")); + } + + @NotNull + private RuleNode getDeviceProfileNode(RuleChainId ruleChainId) throws JsonProcessingException { + return createRuleNode(ruleChainId, + "org.thingsboard.rule.engine.profile.TbDeviceProfileNode", + "Device Profile Node", + mapper.readTree("{\"persistAlarmRulesState\":false,\"fetchAlarmRulesStateOnStart\":false}"), + mapper.readTree("{\"description\":\"Process incoming messages from devices with the alarm rules defined in the device profile. Dispatch all incoming messages with \\\"Success\\\" relation type.\",\"layoutX\":187,\"layoutY\":468}")); + } + + @NotNull + private RuleNode getSaveClientAttributesNode(RuleChainId ruleChainId) throws JsonProcessingException { + return createRuleNode(ruleChainId, + "org.thingsboard.rule.engine.telemetry.TbMsgAttributesNode", + "Save Client Attributes", + mapper.readTree("{\"scope\":\"CLIENT_SCOPE\"}"), + mapper.readTree("{\"layoutX\":824,\"layoutY\":52}")); + } + + @NotNull + private RuleNode getLogRpcFromDeviceNode(RuleChainId ruleChainId) throws JsonProcessingException { + return createRuleNode(ruleChainId, + "org.thingsboard.rule.engine.action.TbLogNode", + "Log RPC from Device", + mapper.readTree("{\"jsScript\":\"return '\\\\nIncoming message:\\\\n' + JSON.stringify(msg) + '\\\\nIncoming metadata:\\\\n' + JSON.stringify(metadata);\"}"), + mapper.readTree("{\"layoutX\":825,\"layoutY\":266}")); + } + + @NotNull + private RuleNode getRpcCallRequestNode(RuleChainId ruleChainId) throws JsonProcessingException { + return createRuleNode(ruleChainId, + "org.thingsboard.rule.engine.rpc.TbSendRPCRequestNode", + "RPC Call Request", + mapper.readTree("{\"timeoutInSeconds\":60}"), + mapper.readTree("{\"layoutX\":824,\"layoutY\":466}")); + } + + @NotNull + private RuleNode getPushToAnalyticsNode(RuleChainId ruleChainId) throws JsonProcessingException { + return createRuleNode(ruleChainId, + "org.thingsboard.rule.engine.flow.TbRuleChainInputNode", + "Push to Analytics", + mapper.readTree("{\"ruleChainId\":\"af588000-6c7c-11ec-bafd-c9a47a5c8d99\"}"), + mapper.readTree("{\"description\":\"\",\"layoutX\":477,\"layoutY\":560}")); + } +} \ No newline at end of file diff --git a/common/edge-api/src/main/proto/edge.proto b/common/edge-api/src/main/proto/edge.proto index 8586d9b920..e54b5d5765 100644 --- a/common/edge-api/src/main/proto/edge.proto +++ b/common/edge-api/src/main/proto/edge.proto @@ -30,6 +30,11 @@ service EdgeRpcService { } +enum EdgeVersion { + V_3_3_0 = 0; + V_3_3_3 = 1; +} + /** * Data Structures; */ @@ -61,6 +66,7 @@ message EdgeUpdateMsg { message ConnectRequestMsg { string edgeRoutingKey = 1; string edgeSecret = 2; + EdgeVersion edgeVersion = 3; } enum ConnectResponseCode { From f115f3ac00bb0826ce60a2d812af80cd59014e7b Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Wed, 12 Jan 2022 15:53:16 +0200 Subject: [PATCH 385/432] Added edge version to connect msg --- .../main/java/org/thingsboard/edge/rpc/EdgeGrpcClient.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/common/edge-api/src/main/java/org/thingsboard/edge/rpc/EdgeGrpcClient.java b/common/edge-api/src/main/java/org/thingsboard/edge/rpc/EdgeGrpcClient.java index ec6670f807..f1f36ab4a4 100644 --- a/common/edge-api/src/main/java/org/thingsboard/edge/rpc/EdgeGrpcClient.java +++ b/common/edge-api/src/main/java/org/thingsboard/edge/rpc/EdgeGrpcClient.java @@ -33,6 +33,7 @@ import org.thingsboard.server.gen.edge.v1.DownlinkMsg; import org.thingsboard.server.gen.edge.v1.DownlinkResponseMsg; import org.thingsboard.server.gen.edge.v1.EdgeConfiguration; import org.thingsboard.server.gen.edge.v1.EdgeRpcServiceGrpc; +import org.thingsboard.server.gen.edge.v1.EdgeVersion; import org.thingsboard.server.gen.edge.v1.RequestMsg; import org.thingsboard.server.gen.edge.v1.RequestMsgType; import org.thingsboard.server.gen.edge.v1.ResponseMsg; @@ -97,7 +98,11 @@ public class EdgeGrpcClient implements EdgeRpcClient { this.inputStream = stub.withCompression("gzip").handleMsgs(initOutputStream(edgeKey, onUplinkResponse, onEdgeUpdate, onDownlink, onError)); this.inputStream.onNext(RequestMsg.newBuilder() .setMsgType(RequestMsgType.CONNECT_RPC_MESSAGE) - .setConnectRequestMsg(ConnectRequestMsg.newBuilder().setEdgeRoutingKey(edgeKey).setEdgeSecret(edgeSecret).build()) + .setConnectRequestMsg(ConnectRequestMsg.newBuilder() + .setEdgeRoutingKey(edgeKey) + .setEdgeSecret(edgeSecret) + .setEdgeVersion(EdgeVersion.V_3_3_3) + .build()) .build()); } From 926642bf8a5eb32a61d412adb833c8fddbfe37e9 Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Wed, 12 Jan 2022 16:20:46 +0200 Subject: [PATCH 386/432] fixed column name in upgrade query --- .../server/service/install/SqlDatabaseUpgradeService.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java b/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java index 4a6d64caea..51741fad5b 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java @@ -476,9 +476,9 @@ public class SqlDatabaseUpgradeService implements DatabaseEntitiesUpgradeService schemaUpdateFile = Paths.get(installScripts.getDataDir(), "upgrade", "3.3.2", SCHEMA_UPDATE_SQL); loadSql(schemaUpdateFile, conn); try { - conn.createStatement().execute("insert into entity_alarm(tenant_id, entity_id, created_time, type, customer_id, alarm_id)" + + conn.createStatement().execute("insert into entity_alarm(tenant_id, entity_id, created_time, alarm_type, customer_id, alarm_id)" + " select tenant_id, originator_id, created_time, type, customer_id, id from alarm;"); - conn.createStatement().execute("insert into entity_alarm(tenant_id, entity_id, created_time, type, customer_id, alarm_id)" + + conn.createStatement().execute("insert into entity_alarm(tenant_id, entity_id, created_time, alarm_type, customer_id, alarm_id)" + " select a.tenant_id, r.from_id, created_time, type, customer_id, id" + " from alarm a inner join relation r on r.relation_type_group = 'ALARM' and r.relation_type = 'ANY' and a.id = r.to_id ON CONFLICT DO NOTHING;"); conn.createStatement().execute("delete from relation r where r.relation_type_group = 'ALARM';"); From 7e71e909e39f669ea612dc9d4763fcd767c013a5 Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Wed, 12 Jan 2022 17:31:30 +0200 Subject: [PATCH 387/432] UI: Rename variable persistentPageLinkMode --- .../app/modules/home/components/alarm/alarm-table-config.ts | 2 +- .../home/components/audit-log/audit-log-table-config.ts | 4 ++-- .../home/components/audit-log/audit-log-table.component.ts | 4 ++-- .../home/components/entity/entities-table.component.ts | 6 +++--- .../app/modules/home/components/event/event-table-config.ts | 2 +- .../home/models/entity/entities-table-config.models.ts | 2 +- .../home/models/entity/entity-table-component.models.ts | 2 +- 7 files changed, 11 insertions(+), 11 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/alarm/alarm-table-config.ts b/ui-ngx/src/app/modules/home/components/alarm/alarm-table-config.ts index 6c4e0a22e0..9a200b8a3d 100644 --- a/ui-ngx/src/app/modules/home/components/alarm/alarm-table-config.ts +++ b/ui-ngx/src/app/modules/home/components/alarm/alarm-table-config.ts @@ -60,7 +60,7 @@ export class AlarmTableConfig extends EntityTableConfig this.loadDataOnInit = false; this.tableTitle = ''; this.useTimePageLink = true; - this.persistentPageLinkMode = false; + this.pageMode = false; this.defaultTimewindowInterval = historyInterval(DAY * 30); this.detailsPanelEnabled = false; this.selectionEnabled = false; diff --git a/ui-ngx/src/app/modules/home/components/audit-log/audit-log-table-config.ts b/ui-ngx/src/app/modules/home/components/audit-log/audit-log-table-config.ts index a61d0c54ab..2a5d339230 100644 --- a/ui-ngx/src/app/modules/home/components/audit-log/audit-log-table-config.ts +++ b/ui-ngx/src/app/modules/home/components/audit-log/audit-log-table-config.ts @@ -53,12 +53,12 @@ export class AuditLogTableConfig extends EntityTableConfig>; @@ -206,7 +206,7 @@ export class EntitiesTableComponent extends PageComponent implements IEntitiesTa this.displayPagination = this.entitiesTableConfig.displayPagination; this.defaultPageSize = this.entitiesTableConfig.defaultPageSize; - this.persistentPageLinkMode = this.entitiesTableConfig.persistentPageLinkMode; + this.pageMode = this.entitiesTableConfig.pageMode; this.pageSizeOptions = [this.defaultPageSize, this.defaultPageSize * 2, this.defaultPageSize * 3]; if (this.entitiesTableConfig.useTimePageLink) { @@ -640,7 +640,7 @@ export class EntitiesTableComponent extends PageComponent implements IEntitiesTa } protected updatedRouterParamsAndData(queryParams: object, queryParamsHandling: QueryParamsHandling = 'merge') { - if (this.persistentPageLinkMode) { + if (this.pageMode) { this.router.navigate([], { relativeTo: this.route, queryParams, diff --git a/ui-ngx/src/app/modules/home/components/event/event-table-config.ts b/ui-ngx/src/app/modules/home/components/event/event-table-config.ts index d6eedb7ff6..a10200060a 100644 --- a/ui-ngx/src/app/modules/home/components/event/event-table-config.ts +++ b/ui-ngx/src/app/modules/home/components/event/event-table-config.ts @@ -92,7 +92,7 @@ export class EventTableConfig extends EntityTableConfig { this.searchEnabled = false; this.addEnabled = false; this.entitiesDeleteEnabled = false; - this.persistentPageLinkMode = false; + this.pageMode = false; this.headerComponent = EventTableHeaderComponent; diff --git a/ui-ngx/src/app/modules/home/models/entity/entities-table-config.models.ts b/ui-ngx/src/app/modules/home/models/entity/entities-table-config.models.ts index d6ddf40735..d5866cbd74 100644 --- a/ui-ngx/src/app/modules/home/models/entity/entities-table-config.models.ts +++ b/ui-ngx/src/app/modules/home/models/entity/entities-table-config.models.ts @@ -160,7 +160,7 @@ export class EntityTableConfig, P extends PageLink = P addDialogStyle = {}; defaultSortOrder: SortOrder = {property: 'createdTime', direction: Direction.DESC}; displayPagination = true; - persistentPageLinkMode = true; + pageMode = true; defaultPageSize = 10; columns: Array> = []; cellActionDescriptors: Array> = []; diff --git a/ui-ngx/src/app/modules/home/models/entity/entity-table-component.models.ts b/ui-ngx/src/app/modules/home/models/entity/entity-table-component.models.ts index 4cf41f0fed..3c1a7428ab 100644 --- a/ui-ngx/src/app/modules/home/models/entity/entity-table-component.models.ts +++ b/ui-ngx/src/app/modules/home/models/entity/entity-table-component.models.ts @@ -50,7 +50,7 @@ export interface IEntitiesTableComponent { displayPagination: boolean; pageSizeOptions: number[]; pageLink: PageLink; - persistentPageLinkMode: boolean; + pageMode: boolean; textSearchMode: boolean; timewindow: Timewindow; dataSource: EntitiesDataSource>; From 104357b7b9afcdb6b7337a589e436465bcdc8bc4 Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Wed, 12 Jan 2022 17:42:12 +0200 Subject: [PATCH 388/432] Use widgettypedetails instead of widgettype in edge processor --- .../constructor/WidgetTypeMsgConstructor.java | 32 +++++++++++-------- .../processor/WidgetTypeEdgeProcessor.java | 8 ++--- common/edge-api/src/main/proto/edge.proto | 2 ++ 3 files changed, 25 insertions(+), 17 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/WidgetTypeMsgConstructor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/WidgetTypeMsgConstructor.java index ed911297f7..6f45f46327 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/WidgetTypeMsgConstructor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/WidgetTypeMsgConstructor.java @@ -19,7 +19,7 @@ import org.springframework.stereotype.Component; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.WidgetTypeId; -import org.thingsboard.server.common.data.widget.WidgetType; +import org.thingsboard.server.common.data.widget.WidgetTypeDetails; import org.thingsboard.server.gen.edge.v1.UpdateMsgType; import org.thingsboard.server.gen.edge.v1.WidgetTypeUpdateMsg; import org.thingsboard.server.queue.util.TbCoreComponent; @@ -28,26 +28,32 @@ import org.thingsboard.server.queue.util.TbCoreComponent; @TbCoreComponent public class WidgetTypeMsgConstructor { - public WidgetTypeUpdateMsg constructWidgetTypeUpdateMsg(UpdateMsgType msgType, WidgetType widgetType) { + public WidgetTypeUpdateMsg constructWidgetTypeUpdateMsg(UpdateMsgType msgType, WidgetTypeDetails widgetTypeDetails) { WidgetTypeUpdateMsg.Builder builder = WidgetTypeUpdateMsg.newBuilder() .setMsgType(msgType) - .setIdMSB(widgetType.getId().getId().getMostSignificantBits()) - .setIdLSB(widgetType.getId().getId().getLeastSignificantBits()); - if (widgetType.getBundleAlias() != null) { - builder.setBundleAlias(widgetType.getBundleAlias()); + .setIdMSB(widgetTypeDetails.getId().getId().getMostSignificantBits()) + .setIdLSB(widgetTypeDetails.getId().getId().getLeastSignificantBits()); + if (widgetTypeDetails.getBundleAlias() != null) { + builder.setBundleAlias(widgetTypeDetails.getBundleAlias()); } - if (widgetType.getAlias() != null) { - builder.setAlias(widgetType.getAlias()); + if (widgetTypeDetails.getAlias() != null) { + builder.setAlias(widgetTypeDetails.getAlias()); } - if (widgetType.getName() != null) { - builder.setName(widgetType.getName()); + if (widgetTypeDetails.getName() != null) { + builder.setName(widgetTypeDetails.getName()); } - if (widgetType.getDescriptor() != null) { - builder.setDescriptorJson(JacksonUtil.toString(widgetType.getDescriptor())); + if (widgetTypeDetails.getDescriptor() != null) { + builder.setDescriptorJson(JacksonUtil.toString(widgetTypeDetails.getDescriptor())); } - if (widgetType.getTenantId().equals(TenantId.SYS_TENANT_ID)) { + if (widgetTypeDetails.getTenantId().equals(TenantId.SYS_TENANT_ID)) { builder.setIsSystem(true); } + if (widgetTypeDetails.getImage() != null) { + builder.setImage(widgetTypeDetails.getImage()); + } + if (widgetTypeDetails.getDescription() != null) { + builder.setDescription(widgetTypeDetails.getDescription()); + } return builder.build(); } diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/WidgetTypeEdgeProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/WidgetTypeEdgeProcessor.java index de4e0e9a06..6e481de21b 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/WidgetTypeEdgeProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/WidgetTypeEdgeProcessor.java @@ -21,7 +21,7 @@ import org.thingsboard.server.common.data.EdgeUtils; import org.thingsboard.server.common.data.edge.EdgeEvent; import org.thingsboard.server.common.data.edge.EdgeEventActionType; import org.thingsboard.server.common.data.id.WidgetTypeId; -import org.thingsboard.server.common.data.widget.WidgetType; +import org.thingsboard.server.common.data.widget.WidgetTypeDetails; import org.thingsboard.server.gen.edge.v1.DownlinkMsg; import org.thingsboard.server.gen.edge.v1.UpdateMsgType; import org.thingsboard.server.gen.edge.v1.WidgetTypeUpdateMsg; @@ -38,10 +38,10 @@ public class WidgetTypeEdgeProcessor extends BaseEdgeProcessor { switch (edgeEdgeEventActionType) { case ADDED: case UPDATED: - WidgetType widgetType = widgetTypeService.findWidgetTypeById(edgeEvent.getTenantId(), widgetTypeId); - if (widgetType != null) { + WidgetTypeDetails widgetTypeDetails = widgetTypeService.findWidgetTypeDetailsById(edgeEvent.getTenantId(), widgetTypeId); + if (widgetTypeDetails != null) { WidgetTypeUpdateMsg widgetTypeUpdateMsg = - widgetTypeMsgConstructor.constructWidgetTypeUpdateMsg(msgType, widgetType); + widgetTypeMsgConstructor.constructWidgetTypeUpdateMsg(msgType, widgetTypeDetails); downlinkMsg = DownlinkMsg.newBuilder() .setDownlinkMsgId(EdgeUtils.nextPositiveInt()) .addWidgetTypeUpdateMsg(widgetTypeUpdateMsg) diff --git a/common/edge-api/src/main/proto/edge.proto b/common/edge-api/src/main/proto/edge.proto index e54b5d5765..3d4cdc7fe8 100644 --- a/common/edge-api/src/main/proto/edge.proto +++ b/common/edge-api/src/main/proto/edge.proto @@ -333,6 +333,8 @@ message WidgetTypeUpdateMsg { optional string name = 6; optional string descriptorJson = 7; bool isSystem = 8; + string image = 9; + string description = 10; } message AdminSettingsUpdateMsg { From 7820cb22de4c9cfb1d1b19b36945d69531428eb7 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Wed, 12 Jan 2022 17:51:27 +0200 Subject: [PATCH 389/432] lwm2m: preparing for certificate validation in bootstrap mode --- .../secure/TbLwM2MCertificateVerifier.java | 91 +++++++++++++++++++ .../TbLwM2MDtlsCertificateVerifier.java | 54 +---------- 2 files changed, 93 insertions(+), 52 deletions(-) create mode 100644 common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MCertificateVerifier.java diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MCertificateVerifier.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MCertificateVerifier.java new file mode 100644 index 0000000000..620d7243c4 --- /dev/null +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MCertificateVerifier.java @@ -0,0 +1,91 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.transport.lwm2m.secure; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; +import org.thingsboard.server.common.data.StringUtils; +import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; +import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2MAuthException; +import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mTypeServer; + +import java.security.InvalidAlgorithmParameterException; +import java.security.NoSuchAlgorithmException; +import java.security.cert.CertPath; +import java.security.cert.CertPathValidator; +import java.security.cert.CertPathValidatorException; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.PKIXParameters; +import java.security.cert.TrustAnchor; +import java.security.cert.X509Certificate; +import java.util.Arrays; +import java.util.Collections; + +@Slf4j +@Component +@TbLwM2mTransportComponent +@RequiredArgsConstructor +public class TbLwM2MCertificateVerifier { + + private final LwM2MTransportServerConfig config; + private final LwM2mCredentialsSecurityInfoValidator securityInfoValidator; + + public TbLwM2MSecurityInfo verifyCertificate(X509Certificate cert, String sha3Hash, LwM2mTypeServer lwM2mTypeServer) { + TbLwM2MSecurityInfo securityInfo = null; + // verify if trust + if (config.getTrustSslCredentials() != null && config.getTrustSslCredentials().getTrustedCertificates().length > 0) { + if (verifyTrust(cert, config.getTrustSslCredentials().getTrustedCertificates()) != null) { + String endpoint = config.getTrustSslCredentials().getValueFromSubjectNameByKey(cert.getSubjectX500Principal().getName(), "CN"); + securityInfo = StringUtils.isNotEmpty(endpoint) ? securityInfoValidator.getEndpointSecurityInfoByCredentialsId(endpoint, lwM2mTypeServer) : null; + } + } + // if not trust or cert trust securityInfo == null + if (securityInfo == null) { + try { + securityInfo = securityInfoValidator.getEndpointSecurityInfoByCredentialsId(sha3Hash, lwM2mTypeServer); + } catch (LwM2MAuthException e) { + log.trace("Failed find security info: {}", sha3Hash, e); + } + } + return securityInfo; + } + + private X509Certificate verifyTrust(X509Certificate certificate, X509Certificate[] certificates) { + try { + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + CertPath cp = cf.generateCertPath(Arrays.asList(new X509Certificate[]{certificate})); + for (int index = 0; index < certificates.length; ++index) { + X509Certificate caCert = certificates[index]; + try { + TrustAnchor trustAnchor = new TrustAnchor(caCert, null); + CertPathValidator cpv = CertPathValidator.getInstance("PKIX"); + PKIXParameters pkixParams = new PKIXParameters( + Collections.singleton(trustAnchor)); + pkixParams.setRevocationEnabled(false); + if (cpv.validate(cp, pkixParams) != null) return certificate; + } catch (NoSuchAlgorithmException | InvalidAlgorithmParameterException | CertPathValidatorException e) { + log.trace("[{}]. [{}]", certificate.getSubjectDN(), e.getMessage()); + } + } + } catch (CertificateException e) { + log.trace("[{}] certPath not valid. [{}]", certificate.getSubjectDN(), e.getMessage()); + } + return null; + } +} diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MDtlsCertificateVerifier.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MDtlsCertificateVerifier.java index babf385bc8..5703f5b366 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MDtlsCertificateVerifier.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MDtlsCertificateVerifier.java @@ -29,7 +29,6 @@ import org.eclipse.californium.scandium.dtls.HandshakeResultHandler; import org.eclipse.californium.scandium.dtls.x509.NewAdvancedCertificateVerifier; import org.eclipse.californium.scandium.dtls.x509.StaticCertificateVerifier; import org.eclipse.californium.scandium.util.ServerNames; -import org.eclipse.leshan.core.util.SecurityUtil; import org.eclipse.leshan.server.security.NonUniqueSecurityInfoException; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; @@ -44,28 +43,18 @@ import org.thingsboard.server.common.transport.util.SslUtil; import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; import org.thingsboard.server.transport.lwm2m.secure.credentials.LwM2MClientCredentials; -import org.thingsboard.server.transport.lwm2m.server.client.LwM2MAuthException; import org.thingsboard.server.transport.lwm2m.server.store.TbLwM2MDtlsSessionStore; import org.thingsboard.server.transport.lwm2m.server.store.TbMainSecurityStore; import javax.annotation.PostConstruct; import javax.security.auth.x500.X500Principal; -import java.security.InvalidAlgorithmParameterException; -import java.security.NoSuchAlgorithmException; import java.security.PublicKey; import java.security.cert.CertPath; -import java.security.cert.CertPathValidator; -import java.security.cert.CertPathValidatorException; import java.security.cert.CertificateEncodingException; -import java.security.cert.CertificateException; import java.security.cert.CertificateExpiredException; -import java.security.cert.CertificateFactory; import java.security.cert.CertificateNotYetValidException; -import java.security.cert.PKIXParameters; -import java.security.cert.TrustAnchor; import java.security.cert.X509Certificate; import java.util.Arrays; -import java.util.Collections; import java.util.List; import static org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mTypeServer.CLIENT; @@ -80,6 +69,7 @@ public class TbLwM2MDtlsCertificateVerifier implements NewAdvancedCertificateVer private final LwM2MTransportServerConfig config; private final LwM2mCredentialsSecurityInfoValidator securityInfoValidator; private final TbMainSecurityStore securityStore; + private final TbLwM2MCertificateVerifier certificateVerifier; @SuppressWarnings("deprecation") private StaticCertificateVerifier staticCertificateVerifier; @@ -124,26 +114,9 @@ public class TbLwM2MDtlsCertificateVerifier implements NewAdvancedCertificateVer if (!skipValidityCheckForClientCert) { cert.checkValidity(); } - - - TbLwM2MSecurityInfo securityInfo = null; - // verify if trust - if (config.getTrustSslCredentials() != null && config.getTrustSslCredentials().getTrustedCertificates().length > 0) { - if (verifyTrust(cert, config.getTrustSslCredentials().getTrustedCertificates()) != null) { - String endpoint = config.getTrustSslCredentials().getValueFromSubjectNameByKey(cert.getSubjectX500Principal().getName(), "CN"); - securityInfo = StringUtils.isNotEmpty(endpoint) ? securityInfoValidator.getEndpointSecurityInfoByCredentialsId(endpoint, CLIENT) : null; - } - } - // if not trust or cert trust securityInfo == null String strCert = SslUtil.getCertificateString(cert); String sha3Hash = EncryptionUtil.getSha3Hash(strCert); - if (securityInfo == null) { - try { - securityInfo = securityInfoValidator.getEndpointSecurityInfoByCredentialsId(sha3Hash, CLIENT); - } catch (LwM2MAuthException e) { - log.trace("Failed find security info: {}", sha3Hash, e); - } - } + TbLwM2MSecurityInfo securityInfo = certificateVerifier.verifyCertificate(cert, sha3Hash, CLIENT); ValidateDeviceCredentialsResponse msg = securityInfo != null ? securityInfo.getMsg() : null; if (msg != null && org.thingsboard.server.common.data.StringUtils.isNotEmpty(msg.getCredentials())) { LwM2MClientCredentials credentials = JacksonUtil.fromString(msg.getCredentials(), LwM2MClientCredentials.class); @@ -201,27 +174,4 @@ public class TbLwM2MDtlsCertificateVerifier implements NewAdvancedCertificateVer public void setResultHandler(HandshakeResultHandler resultHandler) { } - - private X509Certificate verifyTrust(X509Certificate certificate, X509Certificate[] certificates) { - try { - CertificateFactory cf = CertificateFactory.getInstance("X.509"); - CertPath cp = cf.generateCertPath(Arrays.asList(new X509Certificate[]{certificate})); - for (int index = 0; index < certificates.length; ++index) { - X509Certificate caCert = certificates[index]; - try { - TrustAnchor trustAnchor = new TrustAnchor(caCert, null); - CertPathValidator cpv = CertPathValidator.getInstance("PKIX"); - PKIXParameters pkixParams = new PKIXParameters( - Collections.singleton(trustAnchor)); - pkixParams.setRevocationEnabled(false); - if (cpv.validate(cp, pkixParams) != null) return certificate; - } catch (NoSuchAlgorithmException | InvalidAlgorithmParameterException | CertPathValidatorException e) { - log.trace("[{}]. [{}]", certificate.getSubjectDN(), e.getMessage()); - } - } - } catch (CertificateException e) { - log.trace("[{}] certPath not valid. [{}]", certificate.getSubjectDN(), e.getMessage()); - } - return null; - } } From c3c23e079680669f3068b036eec9d65167a311e0 Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Wed, 12 Jan 2022 17:54:28 +0200 Subject: [PATCH 390/432] Added optional for widgettype image and description --- common/edge-api/src/main/proto/edge.proto | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/common/edge-api/src/main/proto/edge.proto b/common/edge-api/src/main/proto/edge.proto index 3d4cdc7fe8..243a77bd6b 100644 --- a/common/edge-api/src/main/proto/edge.proto +++ b/common/edge-api/src/main/proto/edge.proto @@ -333,8 +333,8 @@ message WidgetTypeUpdateMsg { optional string name = 6; optional string descriptorJson = 7; bool isSystem = 8; - string image = 9; - string description = 10; + optional string image = 9; + optional string description = 10; } message AdminSettingsUpdateMsg { From b4a1c0f83607c723fce2451c5d7a6212f89d33eb Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Wed, 12 Jan 2022 19:01:11 +0200 Subject: [PATCH 391/432] Increased timeout for timeseries with failures test --- .../src/test/java/org/thingsboard/server/edge/BaseEdgeTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/src/test/java/org/thingsboard/server/edge/BaseEdgeTest.java b/application/src/test/java/org/thingsboard/server/edge/BaseEdgeTest.java index c412e86ec6..1a3e4eef0d 100644 --- a/application/src/test/java/org/thingsboard/server/edge/BaseEdgeTest.java +++ b/application/src/test/java/org/thingsboard/server/edge/BaseEdgeTest.java @@ -1137,7 +1137,7 @@ abstract public class BaseEdgeTest extends AbstractControllerTest { clusterService.onEdgeEventUpdate(tenantId, edge.getId()); } - Assert.assertTrue(edgeImitator.waitForMessages(60)); + Assert.assertTrue(edgeImitator.waitForMessages(120)); List allTelemetryMsgs = edgeImitator.findAllMessagesByType(EntityDataProto.class); Assert.assertEquals(numberOfTimeseriesToSend, allTelemetryMsgs.size()); From 5bf75acccedca62b2f628d7a95ce203822c51a68 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Wed, 12 Jan 2022 19:01:47 +0200 Subject: [PATCH 392/432] Update material icons font --- ui-ngx/angular.json | 5 - ui-ngx/package.json | 1 - .../services/material-icons-codepoints.raw | 2142 +++++++++++++++++ ui-ngx/src/app/core/services/utils.service.ts | 2 +- .../assets/fonts/MaterialIcons-Regular.ttf | Bin 0 -> 337868 bytes ui-ngx/src/assets/fonts/material-icons.css | 33 + ui-ngx/src/index.html | 2 +- ui-ngx/yarn.lock | 5 - 8 files changed, 2177 insertions(+), 13 deletions(-) create mode 100644 ui-ngx/src/app/core/services/material-icons-codepoints.raw create mode 100644 ui-ngx/src/assets/fonts/MaterialIcons-Regular.ttf create mode 100644 ui-ngx/src/assets/fonts/material-icons.css diff --git a/ui-ngx/angular.json b/ui-ngx/angular.json index 7565ae770c..0691b25b4a 100644 --- a/ui-ngx/angular.json +++ b/ui-ngx/angular.json @@ -63,11 +63,6 @@ "glob": "marker-shadow.png", "input": "node_modules/leaflet/dist/images/", "output": "/" - }, - { - "glob": "**/*", - "input": "node_modules/material-design-icons/iconfont/", - "output": "assets/fonts" } ], "styles": [ diff --git a/ui-ngx/package.json b/ui-ngx/package.json index 1153524a26..d3174bfc4d 100644 --- a/ui-ngx/package.json +++ b/ui-ngx/package.json @@ -61,7 +61,6 @@ "leaflet-providers": "^1.13.0", "leaflet.gridlayer.googlemutant": "^0.13.4", "leaflet.markercluster": "^1.5.3", - "material-design-icons": "^3.0.1", "messageformat": "^2.3.0", "moment": "^2.29.1", "moment-timezone": "^0.5.34", diff --git a/ui-ngx/src/app/core/services/material-icons-codepoints.raw b/ui-ngx/src/app/core/services/material-icons-codepoints.raw new file mode 100644 index 0000000000..a1f9b8bbc7 --- /dev/null +++ b/ui-ngx/src/app/core/services/material-icons-codepoints.raw @@ -0,0 +1,2142 @@ +10k e951 +10mp e952 +11mp e953 +123 eb8d +12mp e954 +13mp e955 +14mp e956 +15mp e957 +16mp e958 +17mp e959 +18mp e95a +19mp e95b +1k e95c +1k_plus e95d +1x_mobiledata efcd +20mp e95e +21mp e95f +22mp e960 +23mp e961 +24mp e962 +2k e963 +2k_plus e964 +2mp e965 +30fps efce +30fps_select efcf +360 e577 +3d_rotation e84d +3g_mobiledata efd0 +3k e966 +3k_plus e967 +3mp e968 +3p efd1 +4g_mobiledata efd2 +4g_plus_mobiledata efd3 +4k e072 +4k_plus e969 +4mp e96a +5g ef38 +5k e96b +5k_plus e96c +5mp e96d +60fps efd4 +60fps_select efd5 +6_ft_apart f21e +6k e96e +6k_plus e96f +6mp e970 +7k e971 +7k_plus e972 +7mp e973 +8k e974 +8k_plus e975 +8mp e976 +9k e977 +9k_plus e978 +9mp e979 +abc eb94 +ac_unit eb3b +access_alarm e190 +access_alarms e191 +access_time e192 +access_time_filled efd6 +accessibility e84e +accessibility_new e92c +accessible e914 +accessible_forward e934 +account_balance e84f +account_balance_wallet e850 +account_box e851 +account_circle e853 +account_tree e97a +ad_units ef39 +adb e60e +add e145 +add_a_photo e439 +add_alarm e193 +add_alert e003 +add_box e146 +add_business e729 +add_call e0e8 +add_card eb86 +add_chart e97b +add_circle e147 +add_circle_outline e148 +add_comment e266 +add_ic_call e97c +add_link e178 +add_location e567 +add_location_alt ef3a +add_moderator e97d +add_photo_alternate e43e +add_reaction e1d3 +add_road ef3b +add_shopping_cart e854 +add_task f23a +add_to_drive e65c +add_to_home_screen e1fe +add_to_photos e39d +add_to_queue e05c +addchart ef3c +adf_scanner eada +adjust e39e +admin_panel_settings ef3d +adobe ea96 +ads_click e762 +agriculture ea79 +air efd8 +airline_seat_flat e630 +airline_seat_flat_angled e631 +airline_seat_individual_suite e632 +airline_seat_legroom_extra e633 +airline_seat_legroom_normal e634 +airline_seat_legroom_reduced e635 +airline_seat_recline_extra e636 +airline_seat_recline_normal e637 +airline_stops e7d0 +airlines e7ca +airplane_ticket efd9 +airplanemode_active e195 +airplanemode_inactive e194 +airplanemode_off e194 +airplanemode_on e195 +airplay e055 +airport_shuttle eb3c +alarm e855 +alarm_add e856 +alarm_off e857 +alarm_on e858 +album e019 +align_horizontal_center e00f +align_horizontal_left e00d +align_horizontal_right e010 +align_vertical_bottom e015 +align_vertical_center e011 +align_vertical_top e00c +all_inbox e97f +all_inclusive eb3d +all_out e90b +alt_route f184 +alternate_email e0e6 +amp_stories ea13 +analytics ef3e +anchor f1cd +android e859 +animation e71c +announcement e85a +aod efda +apartment ea40 +api f1b7 +app_blocking ef3f +app_registration ef40 +app_settings_alt ef41 +app_shortcut eae4 +apple ea80 +approval e982 +apps e5c3 +apps_outage e7cc +architecture ea3b +archive e149 +area_chart e770 +arrow_back e5c4 +arrow_back_ios e5e0 +arrow_back_ios_new e2ea +arrow_circle_down f181 +arrow_circle_left eaa7 +arrow_circle_right eaaa +arrow_circle_up f182 +arrow_downward e5db +arrow_drop_down e5c5 +arrow_drop_down_circle e5c6 +arrow_drop_up e5c7 +arrow_forward e5c8 +arrow_forward_ios e5e1 +arrow_left e5de +arrow_right e5df +arrow_right_alt e941 +arrow_upward e5d8 +art_track e060 +article ef42 +aspect_ratio e85b +assessment e85c +assignment e85d +assignment_ind e85e +assignment_late e85f +assignment_return e860 +assignment_returned e861 +assignment_turned_in e862 +assistant e39f +assistant_direction e988 +assistant_navigation e989 +assistant_photo e3a0 +assured_workload eb6f +atm e573 +attach_email ea5e +attach_file e226 +attach_money e227 +attachment e2bc +attractions ea52 +attribution efdb +audio_file eb82 +audiotrack e3a1 +auto_awesome e65f +auto_awesome_mosaic e660 +auto_awesome_motion e661 +auto_delete ea4c +auto_fix_high e663 +auto_fix_normal e664 +auto_fix_off e665 +auto_graph e4fb +auto_stories e666 +autofps_select efdc +autorenew e863 +av_timer e01b +baby_changing_station f19b +back_hand e764 +backpack f19c +backspace e14a +backup e864 +backup_table ef43 +badge ea67 +bakery_dining ea53 +balance eaf6 +balcony e58f +ballot e172 +bar_chart e26b +batch_prediction f0f5 +bathroom efdd +bathtub ea41 +battery_0_bar ebdc +battery_1_bar ebd9 +battery_2_bar ebe0 +battery_3_bar ebdd +battery_4_bar ebe2 +battery_5_bar ebd4 +battery_6_bar ebd2 +battery_alert e19c +battery_charging_full e1a3 +battery_full e1a4 +battery_saver efde +battery_std e1a5 +battery_unknown e1a6 +beach_access eb3e +bed efdf +bedroom_baby efe0 +bedroom_child efe1 +bedroom_parent efe2 +bedtime ef44 +bedtime_off eb76 +beenhere e52d +bento f1f4 +bike_scooter ef45 +biotech ea3a +blender efe3 +block e14b +block_flipped ef46 +bloodtype efe4 +bluetooth e1a7 +bluetooth_audio e60f +bluetooth_connected e1a8 +bluetooth_disabled e1a9 +bluetooth_drive efe5 +bluetooth_searching e1aa +blur_circular e3a2 +blur_linear e3a3 +blur_off e3a4 +blur_on e3a5 +bolt ea0b +book e865 +book_online f217 +bookmark e866 +bookmark_add e598 +bookmark_added e599 +bookmark_border e867 +bookmark_outline e867 +bookmark_remove e59a +bookmarks e98b +border_all e228 +border_bottom e229 +border_clear e22a +border_color e22b +border_horizontal e22c +border_inner e22d +border_left e22e +border_outer e22f +border_right e230 +border_style e231 +border_top e232 +border_vertical e233 +boy eb67 +branding_watermark e06b +breakfast_dining ea54 +brightness_1 e3a6 +brightness_2 e3a7 +brightness_3 e3a8 +brightness_4 e3a9 +brightness_5 e3aa +brightness_6 e3ab +brightness_7 e3ac +brightness_auto e1ab +brightness_high e1ac +brightness_low e1ad +brightness_medium e1ae +broken_image e3ad +browse_gallery ebd1 +browser_not_supported ef47 +browser_updated e7cf +brunch_dining ea73 +brush e3ae +bubble_chart e6dd +bug_report e868 +build e869 +build_circle ef48 +bungalow e591 +burst_mode e43c +bus_alert e98f +business e0af +business_center eb3f +cabin e589 +cable efe6 +cached e86a +cake e7e9 +calculate ea5f +calendar_month ebcc +calendar_today e935 +calendar_view_day e936 +calendar_view_month efe7 +calendar_view_week efe8 +call e0b0 +call_end e0b1 +call_made e0b2 +call_merge e0b3 +call_missed e0b4 +call_missed_outgoing e0e4 +call_received e0b5 +call_split e0b6 +call_to_action e06c +camera e3af +camera_alt e3b0 +camera_enhance e8fc +camera_front e3b1 +camera_indoor efe9 +camera_outdoor efea +camera_rear e3b2 +camera_roll e3b3 +cameraswitch efeb +campaign ef49 +cancel e5c9 +cancel_presentation e0e9 +cancel_schedule_send ea39 +candlestick_chart ead4 +car_crash ebf2 +car_rental ea55 +car_repair ea56 +card_giftcard e8f6 +card_membership e8f7 +card_travel e8f8 +carpenter f1f8 +cases e992 +casino eb40 +cast e307 +cast_connected e308 +cast_for_education efec +castle eab1 +catching_pokemon e508 +category e574 +celebration ea65 +cell_tower ebba +cell_wifi e0ec +center_focus_strong e3b4 +center_focus_weak e3b5 +chair efed +chair_alt efee +chalet e585 +change_circle e2e7 +change_history e86b +charging_station f19d +chat e0b7 +chat_bubble e0ca +chat_bubble_outline e0cb +check e5ca +check_box e834 +check_box_outline_blank e835 +check_circle e86c +check_circle_outline e92d +checklist e6b1 +checklist_rtl e6b3 +checkroom f19e +chevron_left e5cb +chevron_right e5cc +child_care eb41 +child_friendly eb42 +chrome_reader_mode e86d +church eaae +circle ef4a +circle_notifications e994 +class e86e +clean_hands f21f +cleaning_services f0ff +clear e14c +clear_all e0b8 +close e5cd +close_fullscreen f1cf +closed_caption e01c +closed_caption_disabled f1dc +closed_caption_off e996 +cloud e2bd +cloud_circle e2be +cloud_done e2bf +cloud_download e2c0 +cloud_off e2c1 +cloud_queue e2c2 +cloud_sync eb5a +cloud_upload e2c3 +cloudy_snowing e810 +co2 e7b0 +co_present eaf0 +code e86f +code_off e4f3 +coffee efef +coffee_maker eff0 +collections e3b6 +collections_bookmark e431 +color_lens e3b7 +colorize e3b8 +comment e0b9 +comment_bank ea4e +comments_disabled e7a2 +commit eaf5 +commute e940 +compare e3b9 +compare_arrows e915 +compass_calibration e57c +compost e761 +compress e94d +computer e30a +confirmation_num e638 +confirmation_number e638 +connect_without_contact f223 +connected_tv e998 +connecting_airports e7c9 +construction ea3c +contact_mail e0d0 +contact_page f22e +contact_phone e0cf +contact_support e94c +contactless ea71 +contacts e0ba +content_copy e14d +content_cut e14e +content_paste e14f +content_paste_go ea8e +content_paste_off e4f8 +content_paste_search ea9b +contrast eb37 +control_camera e074 +control_point e3ba +control_point_duplicate e3bb +cookie eaac +copy_all e2ec +copyright e90c +coronavirus f221 +corporate_fare f1d0 +cottage e587 +countertops f1f7 +create e150 +create_new_folder e2cc +credit_card e870 +credit_card_off e4f4 +credit_score eff1 +crib e588 +crisis_alert ebe9 +crop e3be +crop_16_9 e3bc +crop_3_2 e3bd +crop_5_4 e3bf +crop_7_5 e3c0 +crop_din e3c1 +crop_free e3c2 +crop_landscape e3c3 +crop_original e3c4 +crop_portrait e3c5 +crop_rotate e437 +crop_square e3c6 +cruelty_free e799 +css eb93 +currency_bitcoin ebc5 +currency_exchange eb70 +currency_franc eafa +currency_lira eaef +currency_pound eaf1 +currency_ruble eaec +currency_rupee eaf7 +currency_yen eafb +currency_yuan eaf9 +cyclone ebd5 +dangerous e99a +dark_mode e51c +dashboard e871 +dashboard_customize e99b +data_array ead1 +data_exploration e76f +data_object ead3 +data_saver_off eff2 +data_saver_on eff3 +data_thresholding eb9f +data_usage e1af +date_range e916 +deblur eb77 +deck ea42 +dehaze e3c7 +delete e872 +delete_forever e92b +delete_outline e92e +delete_sweep e16c +delivery_dining ea72 +density_large eba9 +density_medium eb9e +density_small eba8 +departure_board e576 +description e873 +deselect ebb6 +design_services f10a +desktop_access_disabled e99d +desktop_mac e30b +desktop_windows e30c +details e3c8 +developer_board e30d +developer_board_off e4ff +developer_mode e1b0 +device_hub e335 +device_thermostat e1ff +device_unknown e339 +devices e1b1 +devices_fold ebde +devices_other e337 +dialer_sip e0bb +dialpad e0bc +diamond ead5 +difference eb7d +dining eff4 +dinner_dining ea57 +directions e52e +directions_bike e52f +directions_boat e532 +directions_boat_filled eff5 +directions_bus e530 +directions_bus_filled eff6 +directions_car e531 +directions_car_filled eff7 +directions_ferry e532 +directions_off f10f +directions_railway e534 +directions_railway_filled eff8 +directions_run e566 +directions_subway e533 +directions_subway_filled eff9 +directions_train e534 +directions_transit e535 +directions_transit_filled effa +directions_walk e536 +dirty_lens ef4b +disabled_by_default f230 +disabled_visible e76e +disc_full e610 +discord ea6c +discount ebc9 +display_settings eb97 +dnd_forwardslash e611 +dns e875 +do_disturb f08c +do_disturb_alt f08d +do_disturb_off f08e +do_disturb_on f08f +do_not_disturb e612 +do_not_disturb_alt e611 +do_not_disturb_off e643 +do_not_disturb_on e644 +do_not_disturb_on_total_silence effb +do_not_step f19f +do_not_touch f1b0 +dock e30e +document_scanner e5fa +domain e7ee +domain_add eb62 +domain_disabled e0ef +domain_verification ef4c +done e876 +done_all e877 +done_outline e92f +donut_large e917 +donut_small e918 +door_back effc +door_front effd +door_sliding effe +doorbell efff +double_arrow ea50 +downhill_skiing e509 +download f090 +download_done f091 +download_for_offline f000 +downloading f001 +drafts e151 +drag_handle e25d +drag_indicator e945 +draw e746 +drive_eta e613 +drive_file_move e675 +drive_file_move_outline e9a1 +drive_file_move_rtl e76d +drive_file_rename_outline e9a2 +drive_folder_upload e9a3 +dry f1b3 +dry_cleaning ea58 +duo e9a5 +dvr e1b2 +dynamic_feed ea14 +dynamic_form f1bf +e_mobiledata f002 +earbuds f003 +earbuds_battery f004 +east f1df +eco ea35 +edgesensor_high f005 +edgesensor_low f006 +edit e3c9 +edit_attributes e578 +edit_calendar e742 +edit_location e568 +edit_location_alt e1c5 +edit_note e745 +edit_notifications e525 +edit_off e950 +edit_road ef4d +egg eacc +egg_alt eac8 +eject e8fb +elderly f21a +elderly_woman eb69 +electric_bike eb1b +electric_car eb1c +electric_moped eb1d +electric_rickshaw eb1e +electric_scooter eb1f +electrical_services f102 +elevator f1a0 +email e0be +emergency e1eb +emergency_recording ebf4 +emergency_share ebf6 +emoji_emotions ea22 +emoji_events ea23 +emoji_flags ea1a +emoji_food_beverage ea1b +emoji_nature ea1c +emoji_objects ea24 +emoji_people ea1d +emoji_symbols ea1e +emoji_transportation ea1f +engineering ea3d +enhance_photo_translate e8fc +enhanced_encryption e63f +equalizer e01d +error e000 +error_outline e001 +escalator f1a1 +escalator_warning f1ac +euro ea15 +euro_symbol e926 +ev_station e56d +event e878 +event_available e614 +event_busy e615 +event_note e616 +event_repeat eb7b +event_seat e903 +exit_to_app e879 +expand e94f +expand_circle_down e7cd +expand_less e5ce +expand_more e5cf +explicit e01e +explore e87a +explore_off e9a8 +exposure e3ca +exposure_minus_1 e3cb +exposure_minus_2 e3cc +exposure_neg_1 e3cb +exposure_neg_2 e3cc +exposure_plus_1 e3cd +exposure_plus_2 e3ce +exposure_zero e3cf +extension e87b +extension_off e4f5 +face e87c +face_retouching_natural ef4e +face_retouching_off f007 +facebook f234 +fact_check f0c5 +factory ebbc +family_restroom f1a2 +fast_forward e01f +fast_rewind e020 +fastfood e57a +favorite e87d +favorite_border e87e +favorite_outline e87e +fax ead8 +featured_play_list e06d +featured_video e06e +feed f009 +feedback e87f +female e590 +fence f1f6 +festival ea68 +fiber_dvr e05d +fiber_manual_record e061 +fiber_new e05e +fiber_pin e06a +fiber_smart_record e062 +file_copy e173 +file_download e2c4 +file_download_done e9aa +file_download_off e4fe +file_open eaf3 +file_present ea0e +file_upload e2c6 +filter e3d3 +filter_1 e3d0 +filter_2 e3d1 +filter_3 e3d2 +filter_4 e3d4 +filter_5 e3d5 +filter_6 e3d6 +filter_7 e3d7 +filter_8 e3d8 +filter_9 e3d9 +filter_9_plus e3da +filter_alt ef4f +filter_alt_off eb32 +filter_b_and_w e3db +filter_center_focus e3dc +filter_drama e3dd +filter_frames e3de +filter_hdr e3df +filter_list e152 +filter_list_alt e94e +filter_list_off eb57 +filter_none e3e0 +filter_tilt_shift e3e2 +filter_vintage e3e3 +find_in_page e880 +find_replace e881 +fingerprint e90d +fire_extinguisher f1d8 +fire_hydrant f1a3 +fireplace ea43 +first_page e5dc +fit_screen ea10 +fitbit e82b +fitness_center eb43 +flag e153 +flag_circle eaf8 +flaky ef50 +flare e3e4 +flash_auto e3e5 +flash_off e3e6 +flash_on e3e7 +flashlight_off f00a +flashlight_on f00b +flatware f00c +flight e539 +flight_class e7cb +flight_land e904 +flight_takeoff e905 +flip e3e8 +flip_camera_android ea37 +flip_camera_ios ea38 +flip_to_back e882 +flip_to_front e883 +flood ebe6 +flourescent f00d +flutter_dash e00b +fmd_bad f00e +fmd_good f00f +foggy e818 +folder e2c7 +folder_copy ebbd +folder_delete eb34 +folder_off eb83 +folder_open e2c8 +folder_shared e2c9 +folder_special e617 +folder_zip eb2c +follow_the_signs f222 +font_download e167 +font_download_off e4f9 +food_bank f1f2 +forest ea99 +fork_left eba0 +fork_right ebac +format_align_center e234 +format_align_justify e235 +format_align_left e236 +format_align_right e237 +format_bold e238 +format_clear e239 +format_color_fill e23a +format_color_reset e23b +format_color_text e23c +format_indent_decrease e23d +format_indent_increase e23e +format_italic e23f +format_line_spacing e240 +format_list_bulleted e241 +format_list_numbered e242 +format_list_numbered_rtl e267 +format_overline eb65 +format_paint e243 +format_quote e244 +format_shapes e25e +format_size e245 +format_strikethrough e246 +format_textdirection_l_to_r e247 +format_textdirection_r_to_l e248 +format_underline e249 +format_underlined e249 +fort eaad +forum e0bf +forward e154 +forward_10 e056 +forward_30 e057 +forward_5 e058 +forward_to_inbox f187 +foundation f200 +free_breakfast eb44 +free_cancellation e748 +front_hand e769 +fullscreen e5d0 +fullscreen_exit e5d1 +functions e24a +g_mobiledata f010 +g_translate e927 +gamepad e30f +games e021 +garage f011 +gavel e90e +generating_tokens e749 +gesture e155 +get_app e884 +gif e908 +gif_box e7a3 +girl eb68 +gite e58b +goat 10fffd +golf_course eb45 +gpp_bad f012 +gpp_good f013 +gpp_maybe f014 +gps_fixed e1b3 +gps_not_fixed e1b4 +gps_off e1b5 +grade e885 +gradient e3e9 +grading ea4f +grain e3ea +graphic_eq e1b8 +grass f205 +grid_3x3 f015 +grid_4x4 f016 +grid_goldenratio f017 +grid_off e3eb +grid_on e3ec +grid_view e9b0 +group e7ef +group_add e7f0 +group_off e747 +group_remove e7ad +group_work e886 +groups f233 +h_mobiledata f018 +h_plus_mobiledata f019 +hail e9b1 +handshake ebcb +handyman f10b +hardware ea59 +hd e052 +hdr_auto f01a +hdr_auto_select f01b +hdr_enhanced_select ef51 +hdr_off e3ed +hdr_off_select f01c +hdr_on e3ee +hdr_on_select f01d +hdr_plus f01e +hdr_strong e3f1 +hdr_weak e3f2 +headphones f01f +headphones_battery f020 +headset e310 +headset_mic e311 +headset_off e33a +healing e3f3 +health_and_safety e1d5 +hearing e023 +hearing_disabled f104 +heart_broken eac2 +height ea16 +help e887 +help_center f1c0 +help_outline e8fd +hevc f021 +hexagon eb39 +hide_image f022 +hide_source f023 +high_quality e024 +highlight e25f +highlight_alt ef52 +highlight_off e888 +highlight_remove e888 +hiking e50a +history e889 +history_edu ea3e +history_toggle_off f17d +hive eaa6 +hls eb8a +hls_off eb8c +holiday_village e58a +home e88a +home_filled e9b2 +home_max f024 +home_mini f025 +home_repair_service f100 +home_work ea09 +horizontal_distribute e014 +horizontal_rule f108 +horizontal_split e947 +hot_tub eb46 +hotel e53a +hotel_class e743 +hourglass_bottom ea5c +hourglass_disabled ef53 +hourglass_empty e88b +hourglass_full e88c +hourglass_top ea5b +house ea44 +house_siding f202 +houseboat e584 +how_to_reg e174 +how_to_vote e175 +html eb7e +http e902 +https e88d +hub e9f4 +hvac f10e +ice_skating e50b +icecream ea69 +image e3f4 +image_aspect_ratio e3f5 +image_not_supported f116 +image_search e43f +imagesearch_roller e9b4 +import_contacts e0e0 +import_export e0c3 +important_devices e912 +inbox e156 +incomplete_circle e79b +indeterminate_check_box e909 +info e88e +info_outline e88f +input e890 +insert_chart e24b +insert_chart_outlined e26a +insert_comment e24c +insert_drive_file e24d +insert_emoticon e24e +insert_invitation e24f +insert_link e250 +insert_page_break eaca +insert_photo e251 +insights f092 +install_desktop eb71 +install_mobile eb72 +integration_instructions ef54 +interests e7c8 +interpreter_mode e83b +inventory e179 +inventory_2 e1a1 +invert_colors e891 +invert_colors_off e0c4 +invert_colors_on e891 +ios_share e6b8 +iron e583 +iso e3f6 +javascript eb7c +join_full eaeb +join_inner eaf4 +join_left eaf2 +join_right eaea +kayaking e50c +kebab_dining e842 +key e73c +key_off eb84 +keyboard e312 +keyboard_alt f028 +keyboard_arrow_down e313 +keyboard_arrow_left e314 +keyboard_arrow_right e315 +keyboard_arrow_up e316 +keyboard_backspace e317 +keyboard_capslock e318 +keyboard_command eae0 +keyboard_command_key eae7 +keyboard_control e5d3 +keyboard_control_key eae6 +keyboard_double_arrow_down ead0 +keyboard_double_arrow_left eac3 +keyboard_double_arrow_right eac9 +keyboard_double_arrow_up eacf +keyboard_hide e31a +keyboard_option eadf +keyboard_option_key eae8 +keyboard_return e31b +keyboard_tab e31c +keyboard_voice e31d +king_bed ea45 +kitchen eb47 +kitesurfing e50d +label e892 +label_important e937 +label_important_outline e948 +label_off e9b6 +label_outline e893 +lan eb2f +landscape e3f7 +landslide ebd7 +language e894 +laptop e31e +laptop_chromebook e31f +laptop_mac e320 +laptop_windows e321 +last_page e5dd +launch e895 +layers e53b +layers_clear e53c +leaderboard f20c +leak_add e3f8 +leak_remove e3f9 +leave_bags_at_home f21b +legend_toggle f11b +lens e3fa +lens_blur f029 +library_add e02e +library_add_check e9b7 +library_books e02f +library_music e030 +light f02a +light_mode e518 +lightbulb e0f0 +lightbulb_outline e90f +line_axis ea9a +line_style e919 +line_weight e91a +linear_scale e260 +link e157 +link_off e16f +linked_camera e438 +liquor ea60 +list e896 +list_alt e0ee +live_help e0c6 +live_tv e639 +living f02b +local_activity e53f +local_airport e53d +local_atm e53e +local_attraction e53f +local_bar e540 +local_cafe e541 +local_car_wash e542 +local_convenience_store e543 +local_dining e556 +local_drink e544 +local_fire_department ef55 +local_florist e545 +local_gas_station e546 +local_grocery_store e547 +local_hospital e548 +local_hotel e549 +local_laundry_service e54a +local_library e54b +local_mall e54c +local_movies e54d +local_offer e54e +local_parking e54f +local_pharmacy e550 +local_phone e551 +local_pizza e552 +local_play e553 +local_police ef56 +local_post_office e554 +local_print_shop e555 +local_printshop e555 +local_restaurant e556 +local_see e557 +local_shipping e558 +local_taxi e559 +location_city e7f1 +location_disabled e1b6 +location_history e55a +location_off e0c7 +location_on e0c8 +location_pin f1db +location_searching e1b7 +lock e897 +lock_clock ef57 +lock_open e898 +lock_outline e899 +lock_reset eade +login ea77 +logo_dev ead6 +logout e9ba +looks e3fc +looks_3 e3fb +looks_4 e3fd +looks_5 e3fe +looks_6 e3ff +looks_one e400 +looks_two e401 +loop e028 +loupe e402 +low_priority e16d +loyalty e89a +lte_mobiledata f02c +lte_plus_mobiledata f02d +luggage f235 +lunch_dining ea61 +mail e158 +mail_outline e0e1 +male e58e +man e4eb +manage_accounts f02e +manage_history ebe7 +manage_search f02f +map e55b +maps_home_work f030 +maps_ugc ef58 +margin e9bb +mark_as_unread e9bc +mark_chat_read f18b +mark_chat_unread f189 +mark_email_read f18c +mark_email_unread f18a +mark_unread_chat_alt eb9d +markunread e159 +markunread_mailbox e89b +masks f218 +maximize e930 +media_bluetooth_off f031 +media_bluetooth_on f032 +mediation efa7 +medical_information ebed +medical_services f109 +medication f033 +medication_liquid ea87 +meeting_room eb4f +memory e322 +menu e5d2 +menu_book ea19 +menu_open e9bd +merge eb98 +merge_type e252 +message e0c9 +messenger e0ca +messenger_outline e0cb +mic e029 +mic_external_off ef59 +mic_external_on ef5a +mic_none e02a +mic_off e02b +microwave f204 +military_tech ea3f +minimize e931 +minor_crash ebf1 +miscellaneous_services f10c +missed_video_call e073 +mms e618 +mobile_friendly e200 +mobile_off e201 +mobile_screen_share e0e7 +mobiledata_off f034 +mode f097 +mode_comment e253 +mode_edit e254 +mode_edit_outline f035 +mode_night f036 +mode_of_travel e7ce +mode_standby f037 +model_training f0cf +monetization_on e263 +money e57d +money_off e25c +money_off_csred f038 +monitor ef5b +monitor_heart eaa2 +monitor_weight f039 +monochrome_photos e403 +mood e7f2 +mood_bad e7f3 +moped eb28 +more e619 +more_horiz e5d3 +more_time ea5d +more_vert e5d4 +mosque eab2 +motion_photos_auto f03a +motion_photos_off e9c0 +motion_photos_on e9c1 +motion_photos_pause f227 +motion_photos_paused e9c2 +motorcycle e91b +mouse e323 +move_down eb61 +move_to_inbox e168 +move_up eb64 +movie e02c +movie_creation e404 +movie_filter e43a +moving e501 +mp e9c3 +multiline_chart e6df +multiple_stop f1b9 +multitrack_audio e1b8 +museum ea36 +music_note e405 +music_off e440 +music_video e063 +my_library_add e02e +my_library_books e02f +my_library_music e030 +my_location e55c +nat ef5c +nature e406 +nature_people e407 +navigate_before e408 +navigate_next e409 +navigation e55d +near_me e569 +near_me_disabled f1ef +nearby_error f03b +nearby_off f03c +network_cell e1b9 +network_check e640 +network_locked e61a +network_ping ebca +network_wifi e1ba +network_wifi_1_bar ebe4 +network_wifi_2_bar ebd6 +network_wifi_3_bar ebe1 +new_label e609 +new_releases e031 +newspaper eb81 +next_plan ef5d +next_week e16a +nfc e1bb +night_shelter f1f1 +nightlife ea62 +nightlight f03d +nightlight_round ef5e +nights_stay ea46 +no_accounts f03e +no_backpack f237 +no_cell f1a4 +no_crash ebf0 +no_drinks f1a5 +no_encryption e641 +no_encryption_gmailerrorred f03f +no_flash f1a6 +no_food f1a7 +no_luggage f23b +no_meals f1d6 +no_meals_ouline f229 +no_meeting_room eb4e +no_photography f1a8 +no_sim e0cc +no_stroller f1af +no_transfer f1d5 +noise_aware ebec +noise_control_off ebf3 +nordic_walking e50e +north f1e0 +north_east f1e1 +north_west f1e2 +not_accessible f0fe +not_interested e033 +not_listed_location e575 +not_started f0d1 +note e06f +note_add e89c +note_alt f040 +notes e26c +notification_add e399 +notification_important e004 +notifications e7f4 +notifications_active e7f7 +notifications_none e7f5 +notifications_off e7f6 +notifications_on e7f7 +notifications_paused e7f8 +now_wallpaper e1bc +now_widgets e1bd +numbers eac7 +offline_bolt e932 +offline_pin e90a +offline_share e9c5 +ondemand_video e63a +online_prediction f0eb +opacity e91c +open_in_browser e89d +open_in_full f1ce +open_in_new e89e +open_in_new_off e4f6 +open_with e89f +other_houses e58c +outbond f228 +outbound e1ca +outbox ef5f +outdoor_grill ea47 +outgoing_mail f0d2 +outlet f1d4 +outlined_flag e16e +output ebbe +padding e9c8 +pages e7f9 +pageview e8a0 +paid f041 +palette e40a +pan_tool e925 +pan_tool_alt ebb9 +panorama e40b +panorama_fish_eye e40c +panorama_fisheye e40c +panorama_horizontal e40d +panorama_horizontal_select ef60 +panorama_photosphere e9c9 +panorama_photosphere_select e9ca +panorama_vertical e40e +panorama_vertical_select ef61 +panorama_wide_angle e40f +panorama_wide_angle_select ef62 +paragliding e50f +park ea63 +party_mode e7fa +password f042 +pattern f043 +pause e034 +pause_circle e1a2 +pause_circle_filled e035 +pause_circle_outline e036 +pause_presentation e0ea +payment e8a1 +payments ef63 +paypal ea8d +pedal_bike eb29 +pending ef64 +pending_actions f1bb +pentagon eb50 +people e7fb +people_alt ea21 +people_outline e7fc +percent eb58 +perm_camera_mic e8a2 +perm_contact_cal e8a3 +perm_contact_calendar e8a3 +perm_data_setting e8a4 +perm_device_info e8a5 +perm_device_information e8a5 +perm_identity e8a6 +perm_media e8a7 +perm_phone_msg e8a8 +perm_scan_wifi e8a9 +person e7fd +person_add e7fe +person_add_alt ea4d +person_add_alt_1 ef65 +person_add_disabled e9cb +person_off e510 +person_outline e7ff +person_pin e55a +person_pin_circle e56a +person_remove ef66 +person_remove_alt_1 ef67 +person_search f106 +personal_injury e6da +personal_video e63b +pest_control f0fa +pest_control_rodent f0fd +pets e91d +phishing ead7 +phone e0cd +phone_android e324 +phone_bluetooth_speaker e61b +phone_callback e649 +phone_disabled e9cc +phone_enabled e9cd +phone_forwarded e61c +phone_in_talk e61d +phone_iphone e325 +phone_locked e61e +phone_missed e61f +phone_paused e620 +phonelink e326 +phonelink_erase e0db +phonelink_lock e0dc +phonelink_off e327 +phonelink_ring e0dd +phonelink_setup e0de +photo e410 +photo_album e411 +photo_camera e412 +photo_camera_back ef68 +photo_camera_front ef69 +photo_filter e43b +photo_library e413 +photo_size_select_actual e432 +photo_size_select_large e433 +photo_size_select_small e434 +php eb8f +piano e521 +piano_off e520 +picture_as_pdf e415 +picture_in_picture e8aa +picture_in_picture_alt e911 +pie_chart e6c4 +pie_chart_outline f044 +pie_chart_outlined e6c5 +pin f045 +pin_drop e55e +pin_end e767 +pin_invoke e763 +pinch eb38 +pivot_table_chart e9ce +pix eaa3 +place e55f +plagiarism ea5a +play_arrow e037 +play_circle e1c4 +play_circle_fill e038 +play_circle_filled e038 +play_circle_outline e039 +play_disabled ef6a +play_for_work e906 +play_lesson f047 +playlist_add e03b +playlist_add_check e065 +playlist_add_check_circle e7e6 +playlist_add_circle e7e5 +playlist_play e05f +playlist_remove eb80 +plumbing f107 +plus_one e800 +podcasts f048 +point_of_sale f17e +policy ea17 +poll e801 +polyline ebbb +polymer e8ab +pool eb48 +portable_wifi_off e0ce +portrait e416 +post_add ea20 +power e63c +power_input e336 +power_off e646 +power_settings_new e8ac +precision_manufacturing f049 +pregnant_woman e91e +present_to_all e0df +preview f1c5 +price_change f04a +price_check f04b +print e8ad +print_disabled e9cf +priority_high e645 +privacy_tip f0dc +private_connectivity e744 +production_quantity_limits e1d1 +psychology ea4a +public e80b +public_off f1ca +publish e255 +published_with_changes f232 +punch_clock eaa8 +push_pin f10d +qr_code ef6b +qr_code_2 e00a +qr_code_scanner f206 +query_builder e8ae +query_stats e4fc +question_answer e8af +question_mark eb8b +queue e03c +queue_music e03d +queue_play_next e066 +quick_contacts_dialer e0cf +quick_contacts_mail e0d0 +quickreply ef6c +quiz f04c +quora ea98 +r_mobiledata f04d +radar f04e +radio e03e +radio_button_checked e837 +radio_button_off e836 +radio_button_on e837 +radio_button_unchecked e836 +railway_alert e9d1 +ramen_dining ea64 +ramp_left eb9c +ramp_right eb96 +rate_review e560 +raw_off f04f +raw_on f050 +read_more ef6d +real_estate_agent e73a +receipt e8b0 +receipt_long ef6e +recent_actors e03f +recommend e9d2 +record_voice_over e91f +rectangle eb54 +recycling e760 +reddit eaa0 +redeem e8b1 +redo e15a +reduce_capacity f21c +refresh e5d5 +remember_me f051 +remove e15b +remove_circle e15c +remove_circle_outline e15d +remove_done e9d3 +remove_from_queue e067 +remove_moderator e9d4 +remove_red_eye e417 +remove_shopping_cart e928 +reorder e8fe +repeat e040 +repeat_on e9d6 +repeat_one e041 +repeat_one_on e9d7 +replay e042 +replay_10 e059 +replay_30 e05a +replay_5 e05b +replay_circle_filled e9d8 +reply e15e +reply_all e15f +report e160 +report_gmailerrorred f052 +report_off e170 +report_problem e8b2 +request_page f22c +request_quote f1b6 +reset_tv e9d9 +restart_alt f053 +restaurant e56c +restaurant_menu e561 +restore e8b3 +restore_from_trash e938 +restore_page e929 +reviews f054 +rice_bowl f1f5 +ring_volume e0d1 +rocket eba5 +rocket_launch eb9b +roller_skating ebcd +roofing f201 +room e8b4 +room_preferences f1b8 +room_service eb49 +rotate_90_degrees_ccw e418 +rotate_90_degrees_cw eaab +rotate_left e419 +rotate_right e41a +roundabout_left eb99 +roundabout_right eba3 +rounded_corner e920 +route eacd +router e328 +rowing e921 +rss_feed e0e5 +rsvp f055 +rtt e9ad +rule f1c2 +rule_folder f1c9 +run_circle ef6f +running_with_errors e51d +rv_hookup e642 +safety_check ebef +safety_divider e1cc +sailing e502 +sanitizer f21d +satellite e562 +satellite_alt eb3a +save e161 +save_alt e171 +save_as eb60 +saved_search ea11 +savings e2eb +scale eb5f +scanner e329 +scatter_plot e268 +schedule e8b5 +schedule_send ea0a +schema e4fd +school e80c +science ea4b +score e269 +scoreboard ebd0 +screen_lock_landscape e1be +screen_lock_portrait e1bf +screen_lock_rotation e1c0 +screen_rotation e1c1 +screen_rotation_alt ebee +screen_search_desktop ef70 +screen_share e0e2 +screenshot f056 +scuba_diving ebce +sd e9dd +sd_card e623 +sd_card_alert f057 +sd_storage e1c2 +search e8b6 +search_off ea76 +security e32a +security_update f058 +security_update_good f059 +security_update_warning f05a +segment e94b +select_all e162 +self_improvement ea78 +sell f05b +send e163 +send_and_archive ea0c +send_time_extension eadb +send_to_mobile f05c +sensor_door f1b5 +sensor_window f1b4 +sensors e51e +sensors_off e51f +sentiment_dissatisfied e811 +sentiment_neutral e812 +sentiment_satisfied e813 +sentiment_satisfied_alt e0ed +sentiment_very_dissatisfied e814 +sentiment_very_satisfied e815 +set_meal f1ea +settings e8b8 +settings_accessibility f05d +settings_applications e8b9 +settings_backup_restore e8ba +settings_bluetooth e8bb +settings_brightness e8bd +settings_cell e8bc +settings_display e8bd +settings_ethernet e8be +settings_input_antenna e8bf +settings_input_component e8c0 +settings_input_composite e8c1 +settings_input_hdmi e8c2 +settings_input_svideo e8c3 +settings_overscan e8c4 +settings_phone e8c5 +settings_power e8c6 +settings_remote e8c7 +settings_suggest f05e +settings_system_daydream e1c3 +settings_voice e8c8 +severe_cold ebd3 +share e80d +share_arrival_time e524 +share_location f05f +shield e9e0 +shield_moon eaa9 +shop e8c9 +shop_2 e19e +shop_two e8ca +shopify ea9d +shopping_bag f1cc +shopping_basket e8cb +shopping_cart e8cc +shopping_cart_checkout eb88 +short_text e261 +shortcut f060 +show_chart e6e1 +shower f061 +shuffle e043 +shuffle_on e9e1 +shutter_speed e43d +sick f220 +sign_language ebe5 +signal_cellular_0_bar f0a8 +signal_cellular_4_bar e1c8 +signal_cellular_alt e202 +signal_cellular_alt_1_bar ebdf +signal_cellular_alt_2_bar ebe3 +signal_cellular_connected_no_internet_0_bar f0ac +signal_cellular_connected_no_internet_4_bar e1cd +signal_cellular_no_sim e1ce +signal_cellular_nodata f062 +signal_cellular_null e1cf +signal_cellular_off e1d0 +signal_wifi_0_bar f0b0 +signal_wifi_4_bar e1d8 +signal_wifi_4_bar_lock e1d9 +signal_wifi_bad f063 +signal_wifi_connected_no_internet_4 f064 +signal_wifi_off e1da +signal_wifi_statusbar_4_bar f065 +signal_wifi_statusbar_connected_no_internet_4 f066 +signal_wifi_statusbar_null f067 +signpost eb91 +sim_card e32b +sim_card_alert e624 +sim_card_download f068 +single_bed ea48 +sip f069 +skateboarding e511 +skip_next e044 +skip_previous e045 +sledding e512 +slideshow e41b +slow_motion_video e068 +smart_button f1c1 +smart_display f06a +smart_screen f06b +smart_toy f06c +smartphone e32c +smoke_free eb4a +smoking_rooms eb4b +sms e625 +sms_failed e626 +snapchat ea6e +snippet_folder f1c7 +snooze e046 +snowboarding e513 +snowing e80f +snowmobile e503 +snowshoeing e514 +soap f1b2 +social_distance e1cb +sort e164 +sort_by_alpha e053 +sos ebf7 +soup_kitchen e7d3 +source f1c4 +south f1e3 +south_america e7e4 +south_east f1e4 +south_west f1e5 +spa eb4c +space_bar e256 +space_dashboard e66b +spatial_audio ebeb +spatial_audio_off ebe8 +spatial_tracking ebea +speaker e32d +speaker_group e32e +speaker_notes e8cd +speaker_notes_off e92a +speaker_phone e0d2 +speed e9e4 +spellcheck e8ce +splitscreen f06d +spoke e9a7 +sports ea30 +sports_bar f1f3 +sports_baseball ea51 +sports_basketball ea26 +sports_cricket ea27 +sports_esports ea28 +sports_football ea29 +sports_golf ea2a +sports_gymnastics ebc4 +sports_handball ea33 +sports_hockey ea2b +sports_kabaddi ea34 +sports_martial_arts eae9 +sports_mma ea2c +sports_motorsports ea2d +sports_rugby ea2e +sports_score f06e +sports_soccer ea2f +sports_tennis ea32 +sports_volleyball ea31 +square eb36 +square_foot ea49 +ssid_chart eb66 +stacked_bar_chart e9e6 +stacked_line_chart f22b +stadium eb90 +stairs f1a9 +star e838 +star_border e83a +star_border_purple500 f099 +star_half e839 +star_outline f06f +star_purple500 f09a +star_rate f0ec +stars e8d0 +start e089 +stay_current_landscape e0d3 +stay_current_portrait e0d4 +stay_primary_landscape e0d5 +stay_primary_portrait e0d6 +sticky_note_2 f1fc +stop e047 +stop_circle ef71 +stop_screen_share e0e3 +storage e1db +store e8d1 +store_mall_directory e563 +storefront ea12 +storm f070 +straight eb95 +straighten e41c +stream e9e9 +streetview e56e +strikethrough_s e257 +stroller f1ae +style e41d +subdirectory_arrow_left e5d9 +subdirectory_arrow_right e5da +subject e8d2 +subscript f111 +subscriptions e064 +subtitles e048 +subtitles_off ef72 +subway e56f +summarize f071 +sunny e81a +sunny_snowing e819 +superscript f112 +supervised_user_circle e939 +supervisor_account e8d3 +support ef73 +support_agent f0e2 +surfing e515 +surround_sound e049 +swap_calls e0d7 +swap_horiz e8d4 +swap_horizontal_circle e933 +swap_vert e8d5 +swap_vert_circle e8d6 +swap_vertical_circle e8d6 +swipe e9ec +swipe_down eb53 +swipe_down_alt eb30 +swipe_left eb59 +swipe_left_alt eb33 +swipe_right eb52 +swipe_right_alt eb56 +swipe_up eb2e +swipe_up_alt eb35 +swipe_vertical eb51 +switch_access_shortcut e7e1 +switch_access_shortcut_add e7e2 +switch_account e9ed +switch_camera e41e +switch_left f1d1 +switch_right f1d2 +switch_video e41f +synagogue eab0 +sync e627 +sync_alt ea18 +sync_disabled e628 +sync_lock eaee +sync_problem e629 +system_security_update f072 +system_security_update_good f073 +system_security_update_warning f074 +system_update e62a +system_update_alt e8d7 +system_update_tv e8d7 +tab e8d8 +tab_unselected e8d9 +table_bar ead2 +table_chart e265 +table_restaurant eac6 +table_rows f101 +table_view f1be +tablet e32f +tablet_android e330 +tablet_mac e331 +tag e9ef +tag_faces e420 +takeout_dining ea74 +tap_and_play e62b +tapas f1e9 +task f075 +task_alt e2e6 +taxi_alert ef74 +telegram ea6b +temple_buddhist eab3 +temple_hindu eaaf +terminal eb8e +terrain e564 +text_decrease eadd +text_fields e262 +text_format e165 +text_increase eae2 +text_rotate_up e93a +text_rotate_vertical e93b +text_rotation_angledown e93c +text_rotation_angleup e93d +text_rotation_down e93e +text_rotation_none e93f +text_snippet f1c6 +textsms e0d8 +texture e421 +theater_comedy ea66 +theaters e8da +thermostat f076 +thermostat_auto f077 +thumb_down e8db +thumb_down_alt e816 +thumb_down_off_alt e9f2 +thumb_up e8dc +thumb_up_alt e817 +thumb_up_off_alt e9f3 +thumbs_up_down e8dd +thunderstorm ebdb +tiktok ea7e +time_to_leave e62c +timelapse e422 +timeline e922 +timer e425 +timer_10 e423 +timer_10_select f07a +timer_3 e424 +timer_3_select f07b +timer_off e426 +tips_and_updates e79a +tire_repair ebc8 +title e264 +toc e8de +today e8df +toggle_off e9f5 +toggle_on e9f6 +token ea25 +toll e8e0 +tonality e427 +topic f1c8 +touch_app e913 +tour ef75 +toys e332 +track_changes e8e1 +traffic e565 +train e570 +tram e571 +transfer_within_a_station e572 +transform e428 +transgender e58d +transit_enterexit e579 +translate e8e2 +travel_explore e2db +trending_down e8e3 +trending_flat e8e4 +trending_neutral e8e4 +trending_up e8e5 +trip_origin e57b +try f07c +tsunami ebd8 +tty f1aa +tune e429 +tungsten f07d +turn_left eba6 +turn_right ebab +turn_sharp_left eba7 +turn_sharp_right ebaa +turn_slight_left eba4 +turn_slight_right eb9a +turned_in e8e6 +turned_in_not e8e7 +tv e333 +tv_off e647 +two_wheeler e9f9 +u_turn_left eba1 +u_turn_right eba2 +umbrella f1ad +unarchive e169 +undo e166 +unfold_less e5d6 +unfold_more e5d7 +unpublished f236 +unsubscribe e0eb +upcoming f07e +update e923 +update_disabled e075 +upgrade f0fb +upload f09b +upload_file e9fc +usb e1e0 +usb_off e4fa +vaccines e138 +vape_free ebc6 +vaping_rooms ebcf +verified ef76 +verified_user e8e8 +vertical_align_bottom e258 +vertical_align_center e259 +vertical_align_top e25a +vertical_distribute e076 +vertical_split e949 +vibration e62d +video_call e070 +video_camera_back f07f +video_camera_front f080 +video_collection e04a +video_file eb87 +video_label e071 +video_library e04a +video_settings ea75 +video_stable f081 +videocam e04b +videocam_off e04c +videogame_asset e338 +videogame_asset_off e500 +view_agenda e8e9 +view_array e8ea +view_carousel e8eb +view_column e8ec +view_comfortable e42a +view_comfy e42a +view_comfy_alt eb73 +view_compact e42b +view_compact_alt eb74 +view_cozy eb75 +view_day e8ed +view_headline e8ee +view_in_ar e9fe +view_kanban eb7f +view_list e8ef +view_module e8f0 +view_quilt e8f1 +view_sidebar f114 +view_stream e8f2 +view_timeline eb85 +view_week e8f3 +vignette e435 +villa e586 +visibility e8f4 +visibility_off e8f5 +voice_chat e62e +voice_over_off e94a +voicemail e0d9 +volcano ebda +volume_down e04d +volume_down_alt e79c +volume_mute e04e +volume_off e04f +volume_up e050 +volunteer_activism ea70 +vpn_key e0da +vpn_key_off eb7a +vpn_lock e62f +vrpano f082 +wallet_giftcard e8f6 +wallet_membership e8f7 +wallet_travel e8f8 +wallpaper e1bc +warehouse ebb8 +warning e002 +warning_amber f083 +wash f1b1 +watch e334 +watch_later e924 +watch_off eae3 +water f084 +water_damage f203 +water_drop e798 +waterfall_chart ea00 +waves e176 +waving_hand e766 +wb_auto e42c +wb_cloudy e42d +wb_incandescent e42e +wb_iridescent e436 +wb_shade ea01 +wb_sunny e430 +wb_twighlight ea02 +wb_twilight e1c6 +wc e63d +web e051 +web_asset e069 +web_asset_off e4f7 +web_stories e595 +webhook eb92 +wechat ea81 +weekend e16b +west f1e6 +whatsapp ea9c +whatshot e80e +wheelchair_pickup f1ab +where_to_vote e177 +widgets e1bd +wifi e63e +wifi_1_bar e4ca +wifi_2_bar e4d9 +wifi_calling ef77 +wifi_calling_3 f085 +wifi_channel eb6a +wifi_find eb31 +wifi_lock e1e1 +wifi_off e648 +wifi_password eb6b +wifi_protected_setup f0fc +wifi_tethering e1e2 +wifi_tethering_error ead9 +wifi_tethering_error_rounded f086 +wifi_tethering_off f087 +window f088 +wine_bar f1e8 +woman e13e +woo_commerce ea6d +wordpress ea9f +work e8f9 +work_off e942 +work_outline e943 +workspace_premium e7af +workspaces e1a0 +workspaces_filled ea0d +workspaces_outline ea0f +wrap_text e25b +wrong_location ef78 +wysiwyg f1c3 +yard f089 +youtube_searched_for e8fa +zoom_in e8ff +zoom_in_map eb2d +zoom_out e900 +zoom_out_map e56b diff --git a/ui-ngx/src/app/core/services/utils.service.ts b/ui-ngx/src/app/core/services/utils.service.ts index f8a4ad279b..bb74a5f2e3 100644 --- a/ui-ngx/src/app/core/services/utils.service.ts +++ b/ui-ngx/src/app/core/services/utils.service.ts @@ -41,7 +41,7 @@ import { alarmFields } from '@shared/models/alarm.models'; import { materialColors } from '@app/shared/models/material.models'; import { WidgetInfo } from '@home/models/widget-component.models'; import jsonSchemaDefaults from 'json-schema-defaults'; -import materialIconsCodepoints from '!raw-loader!material-design-icons/iconfont/codepoints'; +import materialIconsCodepoints from '!raw-loader!./material-icons-codepoints.raw'; import { Observable, of, ReplaySubject } from 'rxjs'; const i18nRegExp = new RegExp(`{${i18nPrefix}:[^{}]+}`, 'g'); diff --git a/ui-ngx/src/assets/fonts/MaterialIcons-Regular.ttf b/ui-ngx/src/assets/fonts/MaterialIcons-Regular.ttf new file mode 100644 index 0000000000000000000000000000000000000000..be4be29c8664ae8199bd0fa6c8df9e8e140d354f GIT binary patch literal 337868 zcmb@v2Y3}#*SEiB=Iq%+Z%Kgk(3Bzyf>JElP_Ro;5d{P*h$xB`#fG4$h=7P8mTd(BP+pZEFR|Mgwhmvi0u&FtA_?X}kInKS1E#1oMk zGC~3wa_-sZbT*Zwn~0Z0Y5KXBT-;5Pr84^w`&G~F*5l0N%l14hazhJ|f_fKsJHB=0 zp$+}}5R@f<(tMhb$%euDiW>^HjcmOJh)x@^xCBEefC zHRlbwwST|rkIsEcB&n}R&W*S9yL(79$GepJCs03oaKBrwODk(TLd3^j@7^J|4!z^> zNNLUXC3?KvHV>Qp*rdwLmD$GIRZ;!%c?EI|WydBCxO&l*UbfULKdQBLI-R6tT*B=1 z=kOys&VTu#t{)fsa`;fZ9XsQwnnB#3m*}W`SpIffKN_}}$$1>&Cam=f&4d9=j5pu%e!xgs0rAJ$q zEyP8v^uilnq7vJEWl{OIC+RY+eA}1mGO>I+kjsR~#`P0N)iIJP&C1I|wnQ$JesYIg zC%4N@Yz>kw(qC?s!7@~iqmS$42Dy{cejM)^*BVMaJ)SMC@cRk;K3O`)C3nPnJ1wr` zXzTcBwsc_oKgY;EY7|$aEu)Yfs|HsJxTl=#Zdx+c<+kb=H$Xs-6wW}Rl=W_H` zEET|Kz7RQB9Uk z(gW=jt8TabXK$bkq*QCUn$2ZIyfyQmGCit2XuBR9)#I*?_Sl^E6XK(~*MOQ@tKyZ+ zeslH|x2=68<0IFrZflKB{MHfFhEB}8hunn@j9XTeYA-sPt2Z#-Yfd!vxcj+^UIxZ! zO^N%|R?XPbQS`@oLVMA&PSTz7PU6!}%PPj#aoo0+IZIA0Ki*t&{yD1s>C4qQ(n3db zeN@cL)pEV+v5MCOyyspzeh;Wo{!*Xm9FDwnoG5Oo*6U0?>bS8^q&%6UmEsz@HmFS# zI6JecIYAz0PhV25Ztv*d6KJ8HcQr=Pt}P`!Xsxw076Xa9+R!8JTl>E&-qK@gyL(-Z zCd>J8J?%l;>uj}7+wwiN?#Pe&zQP|mTQ_T$WjeNQ&6JPh(MQBJb@mlMIMcorNQ?v3cwp?NQ5gd}oETC|PQY zMnwCm7uV3^I*%*S%(%q$ND+0kmkNt7i0x6Ej<&+J)*f{&8}lCa^sLZO%HZ zd83h5PiY@LZ2m4)HNJg6mJWHTx^d)H)r-mAm#@=JuU8owY}7uGshD zTFwp~uemggd)E=P^vFxI&YeL$xU##tI+nK4+39#)SXW$M75%GSdc@7&m1z< zxHkG*YrAq+s&(B65|1I&Q9oBfD~>qt4P?I)*K9qmkxb?~>AX5HR_(i290ga}T-wAf zbTnt3D_6fe?{-49Z$0kLauR~Huf6JdnoM1_Lyzcht*icbedrq2i5|6;*6+kBIxt=bI&t^Yg?+W42PK-{6?Ujr zc-NKvzx-V>1829h*_G*bCoEPwwM6Hx+ZAzkwX{UbbgnvEUEQ>m`Y(#hbj$UnTW

?Ybv9RcK)s_@ zxX}m7sJK_>Jy-5>QtNAf1LNbGL3*E~b8e1Z+PY#-*ZAW=kLh-D90OG?)9iEo9*gQY zZhTk22mNTz&T{v=B8FM9S9Sf=cbD3GjkvYWwL5#-u3{A3(pP5O(*)76T*bR${ z)q{KFOkOGF*J9lsNa;XS>mRXAZP9$vHqImNxa(CTbXj@*ZgC$K<2kQ6KWW|W^ihl2 zMhZjsQ0wotc)n z8ZL@D=Njdu?ruP9Xs+sS7ek$WgtB!S3hDMIpzh`7?CR(|1v>_EOt+7;Y#Q%r znf6{`p^l>M2lCWFOJ~L{gsmQN6f+sGlXQ(+>4>hq>tO>*}Df)-n51rd!Sy?WsojUUJ;8mb+fvx#{|FZ3a?PTexTpWP4!z()#MhWOQKM z-dU%=wSGm5in!=~h-;}wC$M+)*scfHN`I@ZF0Sea?MwGHntE<%ncM5bwt7U5YneME zE4-pDGdZqfHRB0_+poxp3VV8Sv@P_IC#mmV>c?!_IiG2nmgv5|&W2>{&{6do**5mD zn{h>pfgH)EUXR%3PXBmCZBX>MuC3ai_M$H>bAHybddJ7od1tIY6}7IGrtxS!rF~qc z_nwX8^~3eyY)aPm!SQjmTgwK%T)fwx)#z*^V5cj24Xr#2i330je=meb_{?q!4IHp_L=S*}U``Vw{ z+o`H=e>*V?IC(}LDIw)Unk_j4IiK|i+j zdESHYG)#e6@ENRtjj#)T;~`ZDtm9rII1$bSeZJQhZiNSc=YQTyFcUt7uVDie!U3L` z@I1`td8XeGcqZqc0X+Zn`@mor4j=POk$OQ}n96gpD$omdiH!eJPLn`RJse6iBx8s%5R8NNrn62dpO7=ROV3i5qJ@JMp}(=s`Z2=BGv1| zV9GDA# z@VxatSSZo}dm9kj1{2{sk%pY54TnMjk8FuoBkDKC*Ns0CX@WnRFt;Xm!mB`^O&IH# z9xw`aiX3~5aMA+vY(_kqJpuDYnlrcNABwc#V2ir}pB{(p$6W-^0rgvA@9~{rvB(Md z<^=k0h5fCl(~3H+eiUg<3|l`5zl)sM8Rm$z!Ok}H-F6X=ow4zxr(lQ3$?XBVPtFx- zcLK~7X-|LcAB3MpI$Q{h)v*b@C34EK@P){!NpK204J$=X%LZb5+IDXI==1bjV1-Dh zfv`>Fj5O#2W8q^UHfO#9Wg=%?0aJloJi8&B3bZ?$xt`5@&Zz@e0{fjO0QPpq_vbc% zUckK0qyO_B0Lr^iw+mx*tqEOWoyhse0X{u{pU4Ho{Q_cnVT#B_y@7dMoC)^=d3MQp z!0}5XxE7|vpPb%ZU=(~Q(v3d4Jp=nix>MeL0gD{{^&n?@d?nJ8v3m{$=5+Z5@U_Sl z#O;dLc<^uN-|9a71FXrBBmB>}yfbn~0z}q5Mw}XQs*HGu0Eh2q-z+iY4@*gsU18;!uLFuMxSYF);Ug=84=(yL(@U-$m|AgUetw(C7W+!~K&*hS!3AuuJ3tjz91)%wfr{ z3$%am9gz_pbc0PI4_yfO{h?KW%@5Zit$FB0k?>ZW)7pf!xQk6$P-PWKQQK#%;U-T;TMrHX9E5o z^Owj|_i~A;0oMUJ^Gpt~{S0=Ey%QFQJX;-Z78ytRIBXhsSmZhU@Z4h}_wiVO~qW5m{CT$gO1`h%9G&`Q3mIzpMw3LcYjXlSRI!{nyOt zYiwC@KFk;SraCZ}Z~hcnc{z|5t6IR5P$;r`o5-5AB5T{hCnD>xYuzg%-(uId&%siW z?@j>X{#~xf_cy`UB0toEbt3B-cRl_5cq!zGY`72b(MDpq@fVRzlyA-g_P5l8-auTp z9OlzMe7=piZlk}S20^h%?s>3WB=0!54X`PX+}hp~7;6VU-0>3NpPfxa@(uI{=2~zg z;M+pRD*TRHFY;*D48XpkD}h`pX70r|0sWTLf~#P)$ZmYOdl;+{`MD!}EV73@+w(RM zhrPD|ao$@bQi`ui@lEM&k+L3uJ!OkU_Duxl^-Fiao?o_#>}Njvv0?w8BEQn+*WX1B zyudBtG4Q&`@2vrU{7xMHps$0CU^py*?IM5nf^o2(kDjsNuPq{fhmZkXp&t;-zwyW4 zzlj{G4;^4IVDBMv=FmYt#U-wXncv}M;z=DC058H?_(MFeFM0f>*^0tHKTNws^K7OyT49)8S+BDxC|3;#Iy0&?+5aBy19| zDr0jm=~b%>iq$&aTQDzujWAbTD)3kzzEnWUhUI>aqF~$IegUL6vjdcx7r=x z9{5wdl#2k{>-K~t;??T}ufsYxEMEO9f$h`_U;+FsUK+kgn+Cs$m!1LNikC4Qeikp2 z`DL|%S>k0kgu7s?cscZwvq8KD=fL~oHN=L7)NRxcCINOe?gmdofp|^&!UXY-vB3O} z!PaBZWA}^K^iJ3KX4*~Hzl{`B23-L}f zFa~}U?{wmL`g`Ja8U%lfcSbX~92W96sR@uLXJW@$)q(P}=<6(eboTM^AZ!%xoD3jl z=ZqJx^Nm2;b8Ew6fNketOBd$aMAQ$@J_ddkA&nNEf zW8aP_{qWjvc6+RN58|r_Pl1oc8_`0%hdg*% zyoZ^?!?ywBJwpCHatAB~^5ao*>QQ|6=rw@PA7lHmhhZ*k6>lW58Hq0+4}o*I69SR>xk*NgYe z@xXaK_C@iYrN42tV4Zl+P35abmx(u_G5jXp#9qL-&o35l68?E%h75w-rzIu&w{k5gyO{LGNe~I@x^Pk3Cr!mhrdO*H-)5nVU zCjNaB``>y}ycy*649=Ignfu$L0DsTKj+q~cH;Z`BqW@Vl#CwM^-(haEvFBatzB>li zi}zkOjDrK>y?++G0Y&1?!Dn->h85z?Z3WYT{P+<2Kg7o$GM^7=^HG1m7aymM7;Hky?&r@DTm(hyLcNo|2N?Kjo7sD3-LDHFWzS6ym^dxTiOFQZ(S$e zwhXulc8T}XJ-{4uCy1Aajd|4F-UzM-VzT3G@pe+a^EL6fAM^50hBtX^6#)5Ccv!q$ z%%`Z2c*XdxcqZW2l3C*I9sryRy9>nonYr$%4#Z_Ie&&A5+soWaZ-t%WmE8{H!@hjigxkfhO`SSt z!2%xpCBe($C%1#m;-}=mD)H+!fGMy|{CdOTWAW?vhF8T;W!%))#80aZ^TkiUSp1B6 z;%8nhe%27c*6cL#bCQ9!Id6*JAVd6yEnutojj*ZlL*h5-C;l<%z<$$W@ta)&+r@AG zqxdb(7XLWf9JfjQmaSlc_{VpF67f$sA7+T(%7d%LZ;c(Tr;C3gerq#R{I*w!&oe6j zq|d}Z`D^jpbp(9Z?kUI@zdil7A1Ho@Ot?$@j-6ny_@^-bDNl=k>Px`>X%CBkI(|7F zTTd?(zY{U*^r84?90QDX<}HvX{#j$hKO29Y(;gV(T;_T17V*zJ94y#PRY|;5jG~|B5qVzW7%{FMM)UZNMMB@ojJHzZxH1{f+q7U`Q6Mqn63|cDwEyU=SFU21`K>S1lV<3nfSMN5r61? zum*k?{|@GU2l;x(-{RkSC5!~}e^?V(C;nY+0GsZ%uvz?j7Q)Zs-!yn?`hd=Mf zm&5Vt@S6ae9~dY8gEgQ7OcsB{>#$AyhZc$dFy9${_yl185o~;fxjo9c@+kg(bg%f2 zVbjP{VVC%ie<=Pa{PaY=_)k7BKG#`)Oo8}M?HB)<+r%G>ontvapB*m#IQkg(3}E+j zr-?rvACCV*{0aDWVimx~=i38yCN+d9utoeAnD+~e{la44Teg#%!nMG>Cga~1;iaMQ z2J8@j3c2}mEg&CXsSL#R6>Q}i?7x-+cZfgrcqkJ8^}g^KY!!bR_P@d0rgLoiXz|~~ z2XC$w|1EqlqZ;6+8D-+XO)Pmv;?MHoM!@cO>H;yHeLLX)cZtb+jP)M+{`oLn{13?O z4`@4wwsV>1+!FCWWSox@@TT}5cZDV5&pQtmi2q3?z`vg`=BLNO1Hk+~s{#1$GyF5Z zC*a=&CyBo>g1g~c@jpL9{6*Nj=w=|^i~bb*THu2e`G#Cj(|^qu{WF!KZ(B)e{TFu{7sw0-+UIV z5`PPJZCNh<*52@o_}jXO|5GZg5I>Lc@~|&2SNt8E6Fa)WHt~1j&-~Hi7i7Xn@e3P5 zvG}`=5x9U;F+Q|Q{KLZ~;EEc^ItjdNm@R?d4z7g{B?wN3 z7bQs4gi9p|Tfoy2*xnLECreN%4d|nCWeKVncwB<&SHLO>YV?ISC8&8EjDepes5MT4 z+UEe{)wu=Ul_04;ER-O*vji!83%u^t64d)jg8Er7U4qoQ5~NWl?J)_`tH3i7@R?GO zF-L+-#?D+WLDq8;WSSstpguO z&=lL7UJ0+l773c&Bti44a4Qr@(4rskE%X+@Nx)}8LCYIpy9CFhCp3i{;Ts8BT?6>9 z)t?fyW-hIFNpRxbutb73Z%NP=|F*psK9%4k{Cd)t5}f=bY>=Scvl6t&=k0%yphLa{ z9UqtA6a$Y)aO$ZNoYn^L*J-;YIDM@Io$$>W*n9@DIkP47ht(3CMZafZ%h^LEIEOmt z%z%RubS74v_egMV7x-F&^Eh_i{StIZz{3)B#ee7L0BtXrE5U`M;gAFu-6z4t`0|p$ z5?uO&1l@*6&>cVZm?J^Y3jy0Nzg~hXPL$xv_7e2kB*9h3NYMLS39fDm`0yIWxQ2Q6 zVg7vscwd5k`z7d4U)Q}M!S%Gg0e|1{m;^U+{H7`r+{}Ci)so_!7E5q{0||y>-|$5eJkUXc2RZiO3<*Zy_Yr?d@X+UQ zK!S%`19|yK4GA74ZjbhWMNBNc=Pszl>Zi!Q+?0hZ2lp&ZDq>6n2ebKBKW~ zH1T?3n*>jOB*B=c;TH*>nkvE5XTi&W51yf~XRu)`=jYfH0H2N>E5Wm81NJ;iJjRia z&!xb0_*H`OqhP%R6K;TyC76g0Cr*;!d2D@todlCk1N{6#J)q9yyCiri31~CrVK^wk z%U$73VBW6`1#Efs9tmD!oY#86LJ6kguc;#?cpbZ5$M$LT^#(qBV;F3fU^+2*^H^BR zpWS2ubDPl^UXbAJx`5B#{zHP9^gr`U31(dmze(^;JHWo#&49YI_e=2Z#Xz3E$NBO8 zMhQL`08avTe89OsXNLrH$>F(+CHRoJe26U{?v>!9TJ{`llVCaL%W~$r99zC*yf4X(FJF}4t1%LMO`8>ry@Ggta}3-I zt0h=@r39<)1nR7sEx~H?ehp)&g*g|__iDTBEfe>5_~^If*(!>Y+4UL zHiGf+vjiKaNU*Uz{3QJCl!zoC5NSB6e4D!B#rr}0S51wiDo3Q@9r|0ic=3zRDEQ7z z+)nzS3ZI7v&&TCn;B$~%Bv<=B7Om_E`Aj0WiX+TN=~)T2KJArI>(+3Dl~8R1p|-2# z2(@mKBhHnm{;WK@r}V*3>IM9_J4LOVh? zw$DX-fX=@!dMEH~KU7;rJM1*{U6@au5$Hnrob9L4C9st3vFLIrWt-0!^7vdsu~(y~ zIqYPV&q4C;p$?x(m1<}^gBnG zf&SnKZ$&r2X6k35xq$6nL$t(UiCx|yk?lU^O;BYJ+s#pYydC?!+fnS@{x#e8q1dB% z52Ey~gx{hCju0ES7dpbWXt5(CKejWj63#$(J3?Z^eWL7$=yL>0Uhb&J_QNQC+0lXR zXVDiN;ZBq}?_fUO2Pkvev4`ygXqm{)I-ENJnhfL|pYzDh6QC2@uoFKk5&5=rqa!*G z#V*AX$DO}8!d>WoN60*O{^|(#qKv16#Cqp%4qFW+ZPY`iR5oIFCB4j{lg$rl2DoR>yf9 zMqxu;bhN`Vhx{iTHVu8!Vac`pG4K@iu{-~1ht+vJVrhdl<}>hQ_af}b3|+Q2*% zpEwrccf|xKV=D>zDeT~|$D*e=EdDDz(_x#VXTjOby%lJ8U!bT!%dYJrD4S zZHe}ESn{HfIViR*dac8rh~gi`wnGOvEIuj3X9~|XrSJxaJsG{pVad6|TO9T@bg;vo zir(t5I;SBH+Yu$!iq$#2;IOBolO6U9^hJm5gudjk>W``LI&JYq;X4ki^M2Q1b>8ne ztor6FhrI;-+F>t5S2%1}^c#o07+vYG=cB6}_9Aq(!(NK6ao7vcwGNA~3%_&N%TQuo zxE(vYp*tP67n<*|SD*zBdpTO<@L9hK_lWHB$eF`v6{ybbOdYg_!(NHjbl4s!IlYVX zHGp099JVJ~-(h>BsSbM;N1lOiGe72UbKe#gV1&G zJ==Gn>j57pwCz?$;(jz2@ONT3N`5K{^)WfABu1bFPDwn3?uMV)R^RV+BpyZg!7r3Q zhVFM*wfR>#K>6e7AC3fZD*DTjcmgHYl>~7s79c+oJoZ-=2?@zoA<7fP-urYcIVC?*^2 z3pdf{cj!QeRr?1yEcsJ>i^FO^gB^AVs^Gr_@h`s9VTgV4Fo*dR)iz*mK*<%we1_iR zNE}8Va9Gay;t>w3c99>7)xL?hVzIUODTh^ipLW=O=tPIr`Au?IwfzN$y$)6Xg1r%a z(P6JeUvgNreTu{0ioW8oYWu4Wt3H_Ous5R`1F-6|=??oK`liF`T;Fn7ozo15eFS~m zVeds}IxOcx@ho_UK8K^T9rk|oU56cszUQ!97;fuN-y^`nAK3LsvMg`hKOuK8db!*yqtT4*MLs)?vq@tRadWg?{U> z8Y|5|u%prM9adxhgTp?7u6J0C&yNnPG2h^@8pDkat8v@puo~yh4*N2y`3m+8beqEx zzv7=9R%4s%u&<%pVF&d!wmThGbD_XtHJ*hIt8w1tuo~MUhy4sKcGyqR5{La5-R-a% z!#xf=AKmM)8uL2PMZl z>{9duhb5;#*ch$w>}No|c^KunW<44oi-gsNG;W z4@x>X?AK^VxPUc{n3r4x7qg8YOD=KPW$2|2OTLy|=CEtfZVvkm+TCHlLVG&wTJ&;< zU4&lYu$+G-S2`@`P)RR`U4Zs+Sn{r{Bh(6@7sc=wpt^M@KsB&nRn+5(zrWVgEv(aM)kaCmr@rbd1AlZan3%CFs)*dl-GjVgEqK zI_x3zS%>`_9p{J==yMLc7ai}gyU_`bs6IN;5hbC|JEAJ+Bu7*eeZdjcMJGF=Ec8W3 zl!CtGi0YtI98nGQWk-Y~N?vh9A^NH#s)oJ>Q}IfpZh*Hrv z9Z@>^mLsZ!&TvE)ecKUbpfep&8am4nRYyN^M3vEbj;I0pi6g3oe(Hz}`k5oDjm~#O zRnY~G=ooaNBWi{&bwn-EWsayZy4(?+fPUrBziTV`+7UHDS2&`k=r@k&SahW$YJ}=} z4pDP-wIezXUE_#ap=%vc3v`_$YKVU8h}xmwIigPJ_YOYCl#(ADQG0Z~BRUQJ(Gi`3 zZg52Bpc@_0iRdOr)EV9Eh|Wg0IHK0*R!7tp-R6iopg%dHGtpc})CSdc3i!UZlx%lI zC!sqW(OKwDM|3Kh?}*Mo3mj2Lw9vtKp`>J&Bf1+O=(BB+U50SmZY%eiM zP_`F;?PX4hgDCOX%e)hRqr^!u9*V#A;saw)e5#l#DE?ARU6j};ranq66_bV%zrE+N zoq=MjVscP?q!@B_FSaU%eBO(#iXjK~;$Ow6z4%BmIwtd1%(*CjQH=J7PZgtzFBF46 z_u@yz^g?wXOkY%eK}<}4l=vy;dX$(c=0@~Npq;rDy~<(kM0-2T{pi&W^8k8{!;C=t zILug7$73Ax96G>ZCZX5C4V1r#>UcM?{Th0+!%Ra5I?OC|5DccyY*cLm^D#QaVLm}` zbC^}=?GCdR9qKUOqIWpVMpWkmhI4E0Fo)s1*?X76knel%c9>%HO^3M!)iKud{I(9d z0XDIniEf4xwi}?k9i}1rGwh-KM078dvV9U-2IOGa9{m#zvrT+CETtja#J0CW~Jm)X=AqWLFuv3hHd6i+7>#o{U~|{kUQbCD0x~+eufiJ9fRBpiACuJ(1Y!l zQ5}PLhi{|AS~0()#JZHYhVP+$pG(QAR&gv6p0zmyWAa0yC$6k7vT`|xx4C93w} z-*7d0FWkrWT9kY$C6B`I&<6qA!ynPdU=-Wi(9w=?2Ra6xp`5vujs@ly>O96d47Qd& z?+713Ux3NfS%$vo2-l-;Im{w-mLvQK)p>&X0@XHP)PHLnhCC`==P*y9qw^v!6!SE?+hM*ze|4C8D7m1RS5WdnF+ZVyIm|AUbxJX>qK6zt{c+e~ju9yn zhq)Z}9ESOp`3`d$nsAuQP;yN%FQep}V%|U_hq(eJ_Y^~n%PKoeOSFo^T!L10n4xGj zhnb01cNp@hjGR!+@n|iF!LMbt9R|OaB{>ZKD@$>hYtS@@A@9nDJ4{dX0f(86J_HZb zzuHS4DMtPAxWin4l1qwVy(xRbVFsa3I?PQdK2^*>l$_DO1vAO$6u?iW5lWmC(+VXX zia8y9&0)?!r#j3z=<5#C1)Tdamn_N~*YxI4G*@1rGFiX)n4$~H$>o5z@4;^Mc%DJH!?c-yINucu_M%%F# zE9O4*Gl${)D_iI=oY!TaJIqPwB8TaQe&H~S(Q=HAzra?Cik ze{h&l=z52F4Bg-`=b>s7nCnp148=4>e{z_U(OlS0`Dj#Qme01%Rr3H0`(?WvrU)&^ z=s3j=qrTtkFnZpUIn0CTK8HCU{l#IvM)x~RD*CI#Xuce9n9k^L4s#s(yTdd<|8f}o zO7}75Lez5@a%~^}RZMR*aG0Ga`J|ZJP~$KcqoKo)@B6Ac%x<)@ggU?Gj?kjyjS}jdS~|?1=m`#k|MsCq}UE1>vn|pH;xz%!O#J3sgH+@-mtdF}E}%eyCULf%VxFXv6oTavdt@2k9ZdEe#zkheK+ zdtS+QfBT^AOSgZ$edYGe+Y7hv-VyDnx1+<37k1?C*t4_F&Xzkn?Od^QI(6uwuuw(z^c?S%z}MZ3IR)pw=tYQC%e zu8zCT+;!=$p}RiXwYrE;t%_N}8i%&1^QhagomBoFEZz>*Kd`Iy;#SaueRQ!1H)5Q~urxd?h{Ce@6;w8l^ zidPkHF3v69S-iXW&yuW?rX?LpE-2|<(yQd!l7S_6m5eHxRq|2E!jk1B`%8Y?d-vWq z_paZ&X>ZBi(!B>uZE1FCQXep#ZdMp^B$q_UKAn{GTJAex-^u$r@^4V ziR?(rZJ2v(Zp+*gb35kt$i0*7csF-p?vmW)adw=OH#W|WSMy%aTS|7Uh_houUT$7V z-l6SHw$I&cGX^6c16cI+$94n6}TJDL=CDDG6;wfK_aUd4Tj2Nn-0zLV@2L3TVvc1$XM zrFd%b^y0=<75P@Em3%U&cq7M86n`=0FBT=rAhF0!MH>|h1nS9f3P zzGL<^kF%roz7B^EAO7y}?8EP5v-asvc2aho?AqBiva4rT%dVPTrSVJ0q-CwkTAQ^h zYh{zhO?qeDopo(i@5ad@Sv}!0kw#q`P0l(u>#W9SW*wVlGC#`vFmp~rt}r5*_hjCk zc~`^pGm|ruGHYkn%BQPOFv1 zN}AO^m1}5LZtCpRS?oeSR%Qm3T8m^wLiQtHIi36zgbeLD52 z)G?_eGcHbjjD4=hsrSH8xJ4wL>sb1B;ClSue^R-EiPY!*=jfmG?nm~Lm#1{*b*@Ot zd2mt6#R^-Orr`6G9$GUQi<5Uly_CwywUQo8dP5{>WfE7sB(8Ev7ipcO)k)_i(Mz3C zb?&dTOiSv-o=1o19{MzJXH+LQ-qn&-b-1$d!*$60_(^`MAKP3}^1rFaJ%z`0%j0_Z z-+sLP`i-~${^M=;xu7vxBR%eu9shSfes!*hwDlYL&9tT8(&y@oo}#}|uB-gMK!5+= z{QP_Ne$sz$>vQ*T^pAIlvAA3Ct3wK;LUsjyGrtA)o#%J;FY~+mgZ$h5VgAD$o$SBF z?~nY&{tADszs=thROVY57X()Xy@R>IM-?L^xCcpaU*UcdXR9X2mPGFau}zEtVq5W( z7^Pc@k>!j}Om{~TQ_J<`#59g=OB~R9Xp=CZVU`A~_1@65FfC0deK*banfh)ltQqEq z)x*kRrLam^Evyk%4Y!APhU3HM!ye(*aBR3Ze9KGo(!C5XGn^8x3fqP`;f%0dxGO9U z_lAGiYGF}WW~+n+;UVjVrQvQ{HT=zrjl#n4=Wt*6OSnJ$HT*q182)LE4Xw46Y~`>d zJZya%gnx&B*+jUcCaVg)9k7C6x-3BWly(f*iQCLd!FrVFR>TeuJ&SkzP-p^YA>)|Y%hC- zz1&`DdjxfZdO`glHAoB6gACi#_O@5q>h>CYTjFYSx4FmMo47ggSYo8TKJj>Blu0*{ zX^z)=nA^<^GtbmClT9;ok$K%*Wv(=LnW`q+-fsKbyX+8?XFfGIn9mZ2ZC`t*9ccU6 zTkLiAMtiLtW^c83+rjo`JIFq0@39ZrN9?`!VLRMDVDGmh?W6WSJHkF@pR&)|7wiN( z#*VX3+b8Yw_BlJ&jNX#2Q*!cMUh?MwC*`=Wi>zF}XtQ|)VZx_#5WYG>HD?A!J; z`>FldzHjH-ckL|up8dprXy@5?>`eQC{m9O>v+W!+%sg)w+aK&YyVS0<-`mgaYWs!# z)~>J%?U#0m{W`Hf@vB{Czq4!XH})&L)-JNk?JB##?zB5>p51J>+pRX=Zm`?z7F%SC z?RvY>{$z7)fi1MV?2mR+6xcF*z?RxyBhMbRzuP@_pZzWJ?az_ezw9sePrKii*u(Y@ zd&vGBCG1|iJE|WgMOC7jQQasjN{Q-3HKHgAqiRuhloQp9GNa@uHA;^vMK;Qa(xU27 zgQ!+yqS{f_=$NQk)G}%uoe&)#HHn%=$3~5!=FxFctEffPFlrZdicXH&N2f)nMCU{& zMxCRxqt;Q|s6%vS)FwJTIw?9UIyE{Y>KI)ZT^@Cfu84X@mqr&w-J@>NCDFxEm*}$S z{OE$HN8-1{?}>wnKNEi^4jIoF&Ms@Jn7XFENi!KH(`1<()5M%$PBiVzS>{~R)m&=2 zn_i}`>2C&@>&=bkRx`xhY3?@ZJW~!NHW|`UMUGtv# z*nDDEnYHFyv(aoZxu(z*n}*?uVVm%z@Z|8^@Vu}~*fl&qyePalyd=Cdye#Y%b`N`o z&xYf|=fVl$#PIEKW;iQ+C!8I=Ykm*k3*Qev2Vm6_u&uWkKu-JW4I~Y9Bv7>g+GP4VP3c+ydb>L^a+=R%ft2NDf6s(+I(YP zF+Z7I=2bJs9Ahpw>&l^oNmrA=a??$A@i_##5`(7niXcNDPVQlW>%ZWO>48mEH!P-0yE#d&w4i3+-H6? zCz)<$vH8%Hm}TZov&k$mo6Se&ZS%SD%`@g$*17M^4`!ShWgauvnWpAsGuk|1o;1tN zm*y*zZ;H$Yv(P+f&NpA1RP%x9Y>qPx%!Ou->1}qJ+swu09ka*$YWA7^=79Ol{A~7` zKTMhV#qel2OoTyb!!R`Fkonsj4x`XB2YFwoSK7*wDJ{es)bEbLyrYY+B;32}5%2av zH{C#)yCQoW)1w|GUj7Pcke}E&b!W8Wr5%HJgxhnsf4Y7A+8dYM{J~4p`o7d=Ov>o0 z5A7b_>;9d0@4jVa|HM^Yuk6%$_BkmXch^5qqqO?{cA9LLx1=jQo-M8U-%~0F--_k^ zWIEf`Bt_Er211pi_bE-4>XH$B$M_ZX(xrjq_)kgIf0tC$72dh>ws{AmRF^EN6|9mZ zYSIR3NNwt6^IMPA6#btAYEe>$8d-7?jph&I?WpS_aucP5*a)i~p6s$p6%z z>W}pA@UQhd`%V1XzV8)#+q{L|Ti(;&!`@)8r`Of%LNImCBE0pc#~9 z@fod_WwD(cdrbY*j0kC2n#MT_aP<_tm-b@~-R*$Vs4)zn%@@;C@ zkGC1kz8R0EGfJjBo!Qk1x0JWzI8S=2R@CLV&Q^0FNow;Q;>!Ozl11wb?m^UJIXV;i za`Ubh_pbKm$ey@woqaanY*w2Zx;fE%GJ9!K%RiOb)?mMSoGd5vYUi>i zP3OXQqALB<4r|miUZbPRG>@2{{~I2u=-)-5n4T+2^qkblHKI0a7@z96^FM_;8I;66 zpdZb4UBBWOtIxc~N7=1MbILs!&x&u}9qH$P9Hk%iwf3GB{>1MJYyQ`ow9*!uy_)N_ z!d!m;Z!O)Ko<}al-l1(Ho=U4X)Pv>mvXePm^}4|M#dllXTCb7NGF|I*^{&k~KPyp! zhhnd2_GJeviMp26OVp;R;Ag zN?rEo*_WbaeA;293A0WiQ<_lYbncVpg|G6C=w|M)I)%rEktyY#Y$f+%GdK`z2o?vg2BWx=_2fF1;ve7|w!(kUAIJN} zYk2?Igd2!0{1ZnXc;mf6US}_rb@f|WB-3S_jIdYZarIqIEYfIZ^IaUhrs(xWJ)+*M z&G%z%HeY1FGh zuQ|Nv+q>rfr*8S`tz&t8)Jm-QKlQ6UW`wnw&wtjcg(bR%>I`aNCs9n)Wv>5OPxD7J zFUQ{!uMIV5@lRCczId(Dvq@LH^3{h=yS4YDOWk=;J)Wt0yV3_l9O)Uy z=SWZK<$0>>Nt{>Q{^@F2QNv|&ZMmQ8#F0|HlI#6cefrattD?5f%grZCn(&=-T}La9 zxphiM(a2|q8{>8K$kCj*Prc{4JYEsp5%oZ-Tya!gS5kgfd+#z{#TZF(UCp*5*S@Op zx#;@(FUP4HuMWZdcz(4xm$bEBS#(XS9xRBxQBkfdWOZp0ER1LEO4S~>3hE5&2cI9+ zldf6yb^VYuzhmtAiZ+__?#}a{c~e6@|L+=2YytiMkJ8x6`sC0lv1g8M<5sX7Tlhc5 zD?d`v*6xb)??~HYnAxJ(_pVIuyP5=F95q+HBI~_N`O2Ai@+gZnuIjriz6+|k;`*pZ zNg6TYcd+=V@w5ldmSD+IbyM+HExbhz1WS+VIg>J7PjmRhU$5D&XI=R;uJJWKSawuD z?krSGQ~5rr=BI0+xu@q%x%I*FqwHx!IrlUEIr02;4bkf-=P-XIX=tabdG+AS*eV@a zvrhZT!9!m$lFsH|rHmVAmcNxYdOdYlmGV2Ng!<)3X?lETuJ=H38+ilEDvs)Pkg@pI zpT1wxJ0|sLx?IVOE3!*-Uaw(|xMH4(ZU3d58hVeDBfb8kU8-BF= z;U?}6vM6)&tmO^xdV6PkCwWc0P=1#JSuG#Q%QBKR=|0OpP2YOmY(P65QCAV( zF-1A#%hBb!HtSt=4&R4}uu<14%?Dl2@|bBF>fRfs#1YxX{e-Rq>HZu>NQ=+d`s}+A zxa08W{ztjyFn#hltJcrJq8jwB9?^5BmV6wSXUFCGzQJ8BYKK3>UU2s~@d_FIf)_Gq z5x=kDZ~SW<*<*Znwb4~r=UR*J0jal>=r4Y65w4G0t4G;SJi(}X)rt3LUB0S&4SCm) zEj9RyYpco;7xfz|?WvSoX;Y1HV+{7^9*(y_a$?~x41JIAKuUV>(1Pn)HA>H z1Z5LXI_7e3@&r$uF5{V0ib?QXcv0f*_`c*?-eb2(G)hzsb_NTBaly4gyCBs+ z{SSCoJ(jzYp8nZ9*-qzub?EK(R(qdvZ}O7&fH%bJMaDGnD$4=cAZr8ubq)MbBbdc+ z^_kvBq%mWSy}ql_EUv}hyXgIj^Jw|KsCP4-J5uJ(UhWR~n;bn4E9z<%>8hje9W?@+ z7kr~i->Dv{p=W0{-)}j(RL>RGCT}{?s;Haey~*}Jd)TV|)uLZr5o&pF9o2(A9nkfm zX5!I!hDm;_cn*5MsPBVy&B;#ab+~$b7P@C4E_=$~)%%+`N8Ej<8%OVa^?Yc;cSQ7^ zyq<^Iq25{RRkdEYicF2SV#{<@-WXfd80*{`6W{Uh*J^q{r~Y+WnabZf={-Yg+`q0c zdY4p-mp-w;d;ING)qfq=a-DetdpPbZi?&+AI_8fgV|5($Hf8+HklrhD*No~_LC-9` z0uW>G24YxoOfz4ts>Km~M}4GR&s+6nj-7r~Upn4VeI+z{6>T&k8gtDa&8Un-mH5uV zS@G|q`t0GTyUIjWsrz60iSNMZOCymK`>uRdPq=r(|Jn2Ztglw6h5ysWin*_7~XiI-j*r^OM_Bf8pW`>p@k*K?qDVk5I~_Y3MDy|%g4O;^Dt z!8=6s=%d-;YO+X6Gz#gO59--)4O#L(N@EY{9d>#!J8q?SSbA2M&n?h(E}4k@t2Ay! zz9t@Hl>c_rt$i+sbAoqc3oH7-uR#XBIMR-ie|j9r-2U^(zk7S{D2wzRqHA4lFW=&K zJ!`hB2XyvvKJvGh`d+zSykF1XOiOnUQ}Ikh&#(Boo_``|e#QNbp0#9tu#Y)ZlxZf{ z_D_oMX5x1bew%-eYIG9(i)(A~qN`tCLitgvq~DepA2}X|>lpi}{r{+a@;?^+b7#Zf z`s@2cwXR}abG|6Q&hf7Cc+N_F9;D}#{?_$}eeb5&a(&lcJ9wYfj%O*s2bAeOBdb;7 zaWWyDv&Nk_9|L?(|d0{yLGhs!Mu1L|E|H=<4=jpHJ3Ej?#_;p!|%uq-hJ}d zGkQ;>*Li&hnPRq5&fPkn%qQZ~+Tr&^T#xf^RA(q@{3TQ+O8$KhnMPh!l>Kx6$lpon z)yvg%PjvN;^~jxP2J`xF$B*=o`L7z9bMc+&QGMvMts{LLUE`l#f=~XjSl3lu9nykN zQP=LDGD>ts&+*>oX>mjU0INzv%HlODF&a(i_;S%b5>XPueVAgglb?#%U>^D?JqPRtyX z*){W|%qU}D#+HnQ8M8CSWjvhGJELVrO8UX{J?Wd$SEj$0{!;pg^g-#p)0?FoOxu&T zC2fA%^t4H752p=D8<2KUTBEdj1Y~FGO1?oeJ@wwy3sSS|@2g)>e^dSC_1~)hbp3nl zUsV63`Yq~b)~{Y~SG}e6X4jioZ&bYj_0Fr;qF(K~zt{b??)kg~it8Rz7DJh3i zwxujenVRxI$~7tHrF2MXnUazs$@`NxB+pHrlze~kpyaN}O_D1o6(_CdyDamPrY4O{ zx;JT1(q&0qlUgPmB-K7tySVn++H-49 zu05>wwY4v)-KKVS?L@7=Y8BL4Tx(jbakWO&>RNM8&5vqMta(w*mNliumKyVFjID8f zjdnFESO1`Tuj);z?W?w;+RN2$uhz5L1=UWdmRhZH)xWA1RQ&Pe*;ZM?WR1%xC9Q`82<$J(h1QNVt>FQ~y8q-afvrs>&Ze`@G(~=icT$ zZF6ta-jt*TOq!-b#aK!~TCiYK5E-lp47P{`0TH1_L}ZXbM2m=s6%nyT1`rVuu`&#U z$RIL+jKd(qk6{=j-b_l)qm2z2WwuZ`iJ`qy(#Y@taaUp7~!Sf zdALGxy|>(3B&%Jo!YY3lvBDd$r{sLtm*+|xySG|i#J zpd~E24;x^)>ZIN^=4S8*a5$wQWmShW033bpd6LFCOW%z-1)LJ5WUNS&6#BgXf;q2} zi_vC%A~f8^fzrapI{Zr#>ev*#Q|m$|Mg}ugp<$bPZT5{Z)9&Clsgw3BZPbD} zS=uA=7-tjfktWZORJ4a6O$;TB%3GF+W6F$(QyNnS(lu`qn$El!4InXL2AXGyW0QoR6u)b?;B(!sAIIxv9vCP z+l5AP4%0C{IPJ-iqu)+F8}lYO5%;LLSSRGVH93QH0!_mm0+qbmHqweKnJ(0zT%`7# zL>9fzVic412Dbwyc|&QD$>!_e63!ONaq@RLydEv8NC7OZ$T&jq9gM z4dQ!ba93i&+kEMp^$`7T^q5{8twvf3zmgWy@}%diW6~Y`5O181vyeiYP}izBk8HW{ z?=TB>#{R23f#3W~r4%`jc;dgA7)*4PND9q~BY3f|$M!Jp#`TcbP@eC^L~7GBrk188 zDFlq~Dm3SW+9r4keuU?2IxQ{YfVUpG(r?zlGR24ytQ3|Otc;b{i84%&TgNBm9IoS0 z2GGA%&ol3J0sD05N}GpNoDMS$m-7P|$?BS?!`XS`Ar4&wullBx(Hd2nR^IDXYq_e2 zX}M`7aHfR(OFD4$X~$h;Q%DW5xo}>Pbfbi{DS)QsEKv&?*KCyaZ$*DpL(?0j22fe6 zK5o&wSm;s-%lRCyE~~8?dszkVb7)6(OBlJCC#jq@u)e*|%cxXiO>8ltEmt8a&#STN z+~@`lK2_pSs@tfGcd774B?L>T7tHZ1d0(hOInt2vMxBx5333puU+;@DdX*Tn(CU{{ zs$1^xw*J{AIQvkOcUcYEWb0^0uV96HU#c;RS-4_i3C#8`uR)18Qm%Tc*ZVR?wVIxD zM3SQ~-W4@-8Hs~@#(m?IsFie~HlW-Q@DCt4t@+Bsu1Z)FXvyI_chSGRu1(wIeQy$R_CjxEk(P~;u-Q#DzPuoV$1?_ z0<;vN8FeFFB#IT@V%yGCYQPe1YE(F`{1FGKTnfKudn}ydyi58w4}GKGTJX0>ndBWM zK`-|Z{ACn~97X+4D~_=;Sdus^#yu*KKe#!8`cYS@)#_?P8L@u|Jh}dy*J^l&d{5* zhn!F8r8b7z;`Cs}!?pAkS%{RBCcXc!;!Wwt`MG=gY1=3bd&2MkSC`NwUS@+;SWTz z*UJA(#yT>k8S9bWhqt5OwObv>%(#a{<`7z+^fvsVv-mG4_ZPJ}yo0*0=7`j4Q?JbT z?&yCYtF#n#Ga${?l0v;=y$|=FL0d}vBn3|#b@4yKAIT_J=Gv&7j2qVmbxoTV8B0;R zV77(0&mMT^;9g^{->P4o_>ssV{91V7U4#M*=OWhv4ik7y(;Zaw>?x6pQHa*F4zBqK z26quKP~y-cR{v|h^AWs}rznqA6RTCn{eKEM8z;aUktdQGP`cZOHh*vUV<{EqR9IHw z&WcjH`YK*w_!G1v#YaqK^9{)OI4!X#{NG8cMvs$SP5#Tat)vDiqx<4yUz3Yl{eh?G zJ|ZRQHE?B4yb}2Ln?V!KQ^pIadrCN!uF;NoorUmX1%O6<&f(BYlr^&%35g=~h;Q>j z1MA~!3!?Xcvo%LrgnO>*?R&;6it3>G6-uek9Ykn9PW&?}j#h1>A;m<(qcAlIpPk)nt9T4*bKPwsI>}4qbKx7gyM#)X|xq| zowm<#Ju~x;H?E=z?Yyr~%i|c*<|ulvOKTE5fK2l6ED{oXC#rF${QU_~-r6kQ)u1Dv z8DmSVtB^Z()aNRJN=Y;ax8bs+%nYB_Qye8K;=TalQQjc`i|qC96Pj11GLFMs)adV! zo>b?Hm6*VAJwJh5>I1L0p$+Bm?y4M)KT8*Uu6t$6FlM5j ze4o$tpKKmEm9`zCBL1ya)TA#&egh?9YT>@f5NB3sBeSM^F)qm)Fxzp9{sTRx#lrYc zV#oWFc&D^d>N1bCq$Qoe;LZhlfms;pBx6ow1V6KL)!i-x))a&I46I(3r;Hf(AmQjJI-NI?-Mc*@Y)^3DX!MWp3HO9Q+wW zCi`*2e-!Eyq6ha#<^Z7-leIv1v6RWAa5Vf+3g;0!*NZQ)FdD(4jl>;AM}yCai+cyi z-R*cL*AOrIhC6_?u6VZfxqC`W%A|^WE8=I2fKTfM%919;Mf;2t#6COs`>5s5foFT9 zXWlnKQ;-nGcBgeDJ=x|Et6Da^WnYYl|5JRkhC;7i^GUf1?ZQN6(O{FAiP znE)=G!HSJ-p;RX3yhH1jw4m)yUxG5X=zS}bs<9KSxcMG1#;{2$Fi|eBWM$8;18rky zjbxR)Z=;T?w5n3y247S|h>cf`-#-`Q#Ie8#L_d@E$}{j;&j$AtH^&fZDxTQZ5^nNk z&*L(dgK=+hwv0_p%KRK-o|Z|t7&ix#qhef1dQ$Eem}O}`MlyN`QoJH1fu$#x=2*%B zw~P+HE5R{{E#{a{XwlH3QtLg5X+`TGiT-S8X#uPY|5LUF@wvPTUUc^YToxzWrM7r; z@UW#%T+-4nc*OQLPERO=+Y*!xaZcjfMO@o0gSRMaxpN0Gc=u7rai+EUj6KRzOgHzJ zc#2afuecVWyDsy%ty^)m0>;KE+{aLJ46kcc3f&X_6s38hhV}`4X3pRlSINTr(4IdV z8rb61x1Yg!`Af=iRwQRG-G7nZrfsBjuq%Mxc06SYdAT#N*LMw0u-D_f{9`zwe=cqeScN+c7DdgtL4msoZo>}Wi^CJc zBXRS>ys#eodmqR7=WDQ|;5eMCUV-z_jX0P7jQFv(%W>mD!SiwU=qc>;-R@rIp5<D)I6J$}EWt_E zXW@Z9=-e894Wp{@0=wd8snQ&7gS?>CMk*d`pP@y(5=KO=IYt#TF$BCN-VSBBM=3uO zq-Yo5QVX5hsTvpLBrwoECwETIr#!Bx&p!<~G(y0!r%l7LlZcN0OY~Fc9oO%P(XP_s z#%S)7;JRy~mvI|4_p54JI`_`SY!y2YkhCJK%@BSa8iX>)>df$J=*;-NH~2f?r^P`% zLcakeqlI{58g+np*?8vcVT-L^@;(i$oJWi;K&uBgq6e9Gz;b3XYO-3e5K=8p${)3u zivHnM1(>qNNcovkJwdSDXc!grB0t&DWFq1&R9(bqUK zRr1caZ?vg;aK?>mF3>K)s~BfKaUY<12h^Z!Cna;)y;=IIXWbx^!*77n#K0exq=x6) zKMQ_Rk#hcF>395Ap-r7fV6U;XLRRLnmyC;8Kfpi3))vE3AJU6CRp^xBQ0tQtj(!yF zkb?hF=}`*9C-GZkL^0a#LOf+#Le3%8>8TaG*JQlY@~V+&si-x=mU9M{yk7{7$UlmI zjnIPj6nF>Ut>M_%H(+NE4gnWerxpBKrG@aj zPJnJ{5ebv14C?t!PEjzzVaL04E8>bM+U)GKbud#SZ1+GqU zZ$%svRO?zjuRP?N_C1DFdGi@SC)iNFQjdi)!*pz^DVVS8OE=-UU`JhZ2qm#2|Krko z>O7W!CJ4VN{6shzIi!jXaW9rOX*w-T&a9IADdF&{RFomVBcknHAmh$__NCyH)+#gP z9grzssuu(v^8P4&NlF3A_9f)`qC|GV`o9@er?o^LVB~H-#)f-DWB${~0{3$laQi)@ zjT#du;og06jeWy2$KOh2+yl>ZS~|*{y{S71q-+O{vfKQ%K zhNBao7$q&(#-jfcdKN>F>U|=Ik>~D#InObPWoaXLld@h5@K9&rdLTFA4P&LZyXDYf7cQ=u4P0 zinCz8CL=;=h8*vA@{5I!uXA<&eC2m422G@f-G}0upG;9Tq%sa3J!FNE{$~3h$*dkKmQ-Gq3 z)<_Ah6v`ZtoZ*!8G|tnRSArLJ9&oY@Q`BGP%;i2NSC9T z#m{%nV|ucjVW(L9nx0BWwwP-`UjdcaPR=M&n-ZD)MJ-Hkg;q;!(OfC?pBdK5#enBL zVw{{!thJ0=$vNuqQSm(~wwq(s>|9-#ESy-_r!ZJ(D}?!%^0((N$)A}&I=^3jINy_Z zT3>2?sP&fC^IDH-J-BtawcOg)>b5-5@^H)DEjPDZ*K$S6mX?!Rj%qomWnoKW^V7{Y zHecAhx%tTE<;}&W*P0$`y0Pi@LI!54LchyX*i}~MZ>}dxBiLxyX&v7--eyK$JVc^Us#{3dj;p~cGg{6cTwHu zy0vvnV0FKiyEk`zZX0&(o|iisH$TnCty9lNJELoG@76}#5VjQ7_6xWN={DS&bWwOR zZ0+S?BW_%}2lsuQiCwz~;nuIVAjI8R55vm7!QbXz3_JTse@|Qo^n&-K_aM&EUFTip zo$syn7Q(`Q2)lJRyZg8W^AfD;+s!uINwdYAW{$Oo<(>Wbd! zn34J%+m4^dNKk|2-Pux((na<`c)u4|&O1te$WnX*gf?s@1$nAj=2%!AM~pr0!=vTS z_zOpt+@N}w_Jy@Q07KiNHjG#&uHFh$2~i`GfiDrThBt*n&6L>eBY4{X5M)$!DP2)v zj~Q9ly;}wUWZ?d@AS-LYU4GN4P!%BvxXY^=cNI(())MAkbqPv8N*9$FVlM|`tnTg^00kfo^*e>wK&5|g$F3_c_x87Y`-8J74NF)b>1PI zNNH3EzbL#U&!|6ZpRJJI)yk=~-1e8zs|{CSU*psrL<(a@kK6LcpP7PQS@FBvBh^VXx%VUr_>Al&Z&DhuFps00O|9r}bdR(_R%F>n@1xQNp3ftt)eGhL zQa33ab(urV)4rxFo^UGuCN#?QY9B7h;O7Q&1>cY%J)AEIIL_J96&&Km6p3+*x947DN3J3jZOP2e;7Yt_@lvN-?=kplRf{uualhF! ze2=0M2j?Os3!*8}faO(fgU&7T1lKiSOS#Wg^h@)T7$m;1!59VYBeq&OnU-L8uua-l zBL|R#Adhjb{035v8n75~{&S}uHI{I#^JT~{Y9H83<|`;?pYcR#oSgJ_??-FXylMN9 z0k8WD?VbVmHIz@`Idb${7@2}4hPzs`xmBa@pHk5d_92O)y8i?mDPG#teUQzhG<%zO zAE+qHK2q1S_AYZJD4CXJ1jxR*Kd;EK(OJRwU_}mP3$+1j`b9+!<)=#Hy!k3@>$o0` zhjcmL%CtL9Q;y+UeF66orW8r@ZA%Qfs~RKyMD79ocFmIXd+4uhuURi^3AGc~?7Q9lEgvhknM%;>?gRA-?#e$4 zo~O=*!=pdK2W-b)rCp#aJqy@x;r~c9K&=})YHk^M)DLVIWeVv{e}obAS>7j*Qkkoq zEa!jYGTy%f=1rjlGo-WoM`;CXN_QJTi|{YW|^7LhCQl_DwKXMP7ruv;wx66%sYEG$Am)+c<4jTApq|s_q}|myN>}<1 zUHBe6mW}MMoxmtyL!7->@<1PYP!}_ULuY>gswkx;FSG_)2g7p;ZdW=H+b) zXN~Bu@XJV{)}tI^&x^sel1F%Q66Gaj17~W%|0?VqM$?vE{EO$Wg5r+0DtT+E!Ny&_j`#iXqQ9@uh z-@(Y*XW(Glx>qn!2{6oo7lh;ph*gYtJ%`X9TxYTKEDBc{bzjb$Xc%=9n(4Ya zq&5}fMe4(_9If z0@MJEyV6(tSJYOSBe?xdfT>Jp&B9IYf8j4JO4`=?l-)&rF>-o^K3bD{v>fq-_TCGi z5bZ4TF-FKc746}g3%QvsWcxT`xZ4P+efSm@_YP+B8DE8b^FD(1SLU$R`Qaa@VU%=W z*7?R8ZR2t_HXHS!miR=RT4`zr7V%vrjwsh-$vOG(5*Z79mpC-OJW0OLlm-4hsE2Qq zDdcJ0XDjPE_+Fpp(Vv!Cig(fxxxu9t3-v$=cakY2d5x_n*QhRP!&hsyK0TXvAa20F z6nE{f!M6g!@X7Gj@QUyx+>yRtxG3xiTd{8bU~n_;T;GD5*pJ3tZS9Uu?f|d1(!Tgollw|GVFc=voM<{^V|I_#!Njo(zk$bkWq4xgXJB+tE5nP zA;w=Jbf-BzNpfLd$Quc>IXcg|caq~|H90V{25_bOTRd0iaNa{NyFWu4D)Ta43cey- zjWeF>t`7~tEN$d;^st?2Pfh5KE4`9 z$soJ@@T5`{@{73qM^G-#<6J>xBD@GAmQ9nA!K6qW#X`s!A4gf{v9C8iYC82UbvtaR z@NXe!)R)Taq{9tnyp>XSUr?HLNe}Ti_$0WG>6Rn#Rbkp9e5dVz_6O&p)l8vv&H3Gh z^`MvV&NNCoLNc0X^;LK=(q_m*i5b^=gHPF-RdTTA^K9EVw_s(3E@(x}w90r2RbueL zr)@b}O0=_zp@)$sT#|xk(#^^z|CLNW`7xGmq%K!4&j%isPovm+ha2C^kQ=n(NO9=k z;4_x4q(95kmL=a@VAItGOKvm5SDrZzw2G+RxW7bn6~5F=862lqL|vry&~YIn9F)?k zqo|qLUweiE-$0~AN2{+rxKJo1&nT@NUJ583ECf=?xo9=Mk4miMZ*m6tfR;UdUiM@> z$t9J9kF^|r=iM)f++$hNmNZc5uabiDQDhvx1Iu0$PWhBABjj0P*W%ebMMjaSYzNj| z!p~KtU=A6cu^<+-Fnk&<<+Gmcqy25`ip%3G53IX31g)odCpBku$)jYc4PEqd;I$d@ zq_)_KD|i}nu2rYn#^N=2yg_4Te5&_(OUmwGdcC^cwkjJPB28(d#2mwONmjn$HhGSW z<}u>SeM==+cU#4hi1+OjofGSCtiQPar20eam)6g#Z>*cDdmQU`+i>H~MRlj*&YgpB z>(1=DTy7U`$-E=?#oVd5d1oQM2NOmw<9^JC@O_$Fp!?6q&bc+%IX4^MAKHa)m)sd% zgL`;3!nt7^zUA=%zTk5?zPxf0w0}8h!}naC#(LgexUGBAKNI?Y+~3>p@teKZ zy=UTml>5NN;a%HrDhWaPPp4-527E69?nI?hxAl9(-%!3UdK$&SRnf7aCm8 zi(4@t$F8Oa!FyuOINyOr&?l7>$)2KUuE1a(L|+t3p*K7m^MV|s>woc_QK<~N;S2D* z-6zf0*eCrJNXhUV;g>X*Qh@UxHne+=)G#Mx%$%b`j-f?QDaMf_hOXd5%!)XdQn1zk zYq4DzJHib0Pn6Pn&%4HVs4uALFstzGUgFkVwdOe|~$cm?NZp@{Cek%_I!v zhiVd?DVGTrjbw{Aj?!O}K2)Yv%|K@vW(7R5;KQI3Ju_-ET3)Q3^N5s{u?jY$#WO?n z;@ho^6A}aM6WZkappBZM7*0VO`A$7f-HP?&;8ehq$Lar(7uBz)h1~8N!N|QcmalT} zf;8ngldf4C>LW;{e&mR1w2SpqYN+kT-q5Fz5qGu-KPX-3OEHI|O{+t>soVW2=z?># zW}%Ezyz7^K7p*kfWjse*HhYN9PxGax&Ub|q(^R&MQb0Y|#DfmcMW2&fgn*HJ%Ne7y z<5Qx&(K5pu>UH&pEu_q%)Pi0$?*UEY9Oc(icpflSr3p@YqSi(WKP~NMuQ^`U0*(%o z_Gl{GKz^g0%9Z}^kT>YYc-77z72qQUrzPdcFL7MV?s_sO3Jp0ToLvKewX;lG)$4vu z><;Fa&HJT4@+`Tu%RZBoCwC}?Nr$4)G#{KUb}VZXJrFS}Ne;B{c%#on?ka^BNK3PM zw9{<=UEU+ZlH9MSXPQ(yq?T&Y^JG*&2hRt8isg(NsI~IJ8PXHZ&%Aq|z+u$g8->;! zf7LkTpn>3{(o;<(Jy4T-Qzp&su81bZ9xm#>%J6T1MeP>0GiyVW)45^=8U$xbKT;}Z z+7Bq9VDK^Fq?uuQLr1uHCWyoW3b>DT<~Aj8pxE<53Dwq&;mIjEqhDl^7)!)^(z82^ zapyetzOl`u2YHLLlrn(wb3yc!jJ@V@*WA7`0-VtWm)eKr;`I>HI^jL{VBzLCH?uw! z{y`|t97s}sqvK*#Z5QgJheK-EIfQnoMg?Eti}Q@pXuj-;z&qy%B)Xy9ALr@ZpogfV zMa?wZ{~>CW{^NI#+X*W1EtRH_$1d+fNKv!% z(4JbkRwJS2{bqnjcImlWP_yFTTuG?ve5fI;f3^MrShL&e&#ynLeslfN^#|22!=AJ* z>`L2(o8KR=d$8_yShg48F3FSXR@E)4YsKDc8Z49Sm~Vnf91}yMMiZrGJ5c z2EL)gUZN}v?W|UFIeuqT8FONLBx>v4E^XmVpsW&G#oH(~)4D`0 z?qA7U8FQ06VUNMAB=5?bv_m6EeZdRhII*%Nk8Pqv&%5>L8Pjz}fxq1b3&|AD`FQ8Y zD|jZPN(+u3@8;z^Wb3Ri5FCqVu9T>bSBYcqeRdlm)0tijDZS+h&}!fI;ad^3PNvN_ z|9DWNMmkE8$`TF4oFo@z%VuX|bzU+L!!yB?R(pl7VtmqAmfi8@@RVAdsxqv_ds14Y z(Jh;X`YSjxI#J3|6O%%;?u*`kNe!CDF_rVY-gDA#P0eUib3De9yg-`MUQ-U`c>Wx8 zWKNg!pBO!TV*Swe?mY1N4l>&R;R?#C)ZrKu-OUy4QQeI` zxu;arp|rH|M)%Z;9@2s%rA6j~AGzL@_FwHg%ry73s&v}hu(;jRD_U&V=!4@bT1hj?OM^yTb5PSGElrzt$)uX+Fp0p3Yhj^njSpJ)LPjxr()LROofUzi~fS zF-tf?1^289$`BWKe%bXA_u~~kB{s+|k6&uink=W`-L5*C#-y)l9_K}7|04Dx#w|@@ zDq>I07ZO^g5K65tCS#J#=?y3!tJ@^KFw{WRIqW+*fI36wt9O!k7+huGZG?oU#!FU; zJ;qJqR2y0FPPTOtvQpl2uT2cCBLROcpv}V-Z`2rl6;hVZw7@y{`~4FjK{W-o489Lf zSnmEQy1e_$J_9;*TPofox3%Iu=jJQk>s)?CHZ4z?R&aR+HBHlXt}&qjd8timrw>qY z{zH1ns4G{U8K>rN$Z?N%N#g!3P?ENKIV3MpHZZ<5%@Yql4r!#hoH4YtYr+L@0BdH= z#D5s|Tl)qjGBOt5`OuRR+i*_e1bhc^uIIWBx|ib%zKihn-Y2n!|3z4x2b;393nzZA z=eG}?&CZE9bGSTw1@xzFL|aEVAo^?6qjws$RMr!H4)!7Z>F5t=8BZx#?P_>GINuZd zDLg}PWKsYt)G?o>_Q}FZj@@r1_0h)bH5a`J95p`ZX#Q5Ls_L3jd>kXONeuT6?5<{v zviTe!s$r-_ISX`!5pv92QUepU3**0by*2te%2Z?GY}Xq+pdX^^YP7rp0@RTEmEh~w z#>KTAS-*;S7e%ew5{MXAbctxyN_x?*);%O@m!;HGi@P`a{9jbcj!kqaXIRx(&sJ^H>#H$pSY$aq0_beqUzP2+ElQD5|f3}ifhyyso_kueI9@WJqc>+wDDC-8-Z>%23tp0ms=dyVjbA9SyGFLF=Bdd^(eH?QIA;SZZ@ z%p}fft;G!pZTJQ&rO^3UNj%Y68~!(XNB*X*#PdKL7xd159CTs2Mmb@xyKv9JhvM(K zltA_wCE07rXxi6otF`@tW6w;(;d9=VO zOEfB^+Ju$|H91Dl`xWeW+Mwi4+PRE%Gx8oo#vY=s7%cEU0F9@oPiVdAnn#r`_l}n~ z$etjxR-i}^+Ue}CT9PI6VLWl=d|D2mDr^IM+kuhcO4w`^`f%xIib;J3^|UmyRxs}d zO|lr&FDD1d2$*$MI7kKczAT48(@cQ>vN&k1!c&Z>FS6-2(tv)@qo&=|W!6{GA&H3w z?*sR;bUbT{(XVY=$rW5r&@m>@OSB|<(o!SM&sYz^2EdV{^h9;idSGE|Y2otDJM}Ng zd&P*cJuMO2z{ThoK*VXfcTV|3EfDexPYuVup87@Q@N}V&`hPYJ^#<+cICHubwp5!Jx-Z~MF}LGpm-F3|@dd|KZV@-TyoQ@y9yGU@ zYq3&&CM4V5X0GWnq4Nr2%a1xYJC}zifIDj1cHv)xIW@M?YnSJGT&H!kNN& z9I3$5cHHx$X*{QgC;uTy;Z75J@f`DG5M|DXTz%%;p_G(Je)vIfVnqt_IL|2e!9l@c zkeZrLU!OIq$Imur;9LVerEubtg!G>??^Vz)?D{yjH{>4BVt6usPfJCewCs2?k33p7dfNlbvX3RhZ%k<^ zc?UeDXsfwtTDtV!4a6$u+~$mI3qK4@EKi?+`)YNxNWt_=Li{=%VW?eECO91Q&%C2l zmCqRcEqF>HD0eA|$^uDMCN*uWIHA-H}JlS6z<$uhEi1_%bNNGpa&k?-=w+Vn=8x#yz0? z&%C21SOm_zU_Jg;rc?IWs4bwR_UIF!6(f3uh`04(CtLIi@Z)a+p?aHrVlo zD8p*^-UkfSdj*Hh<_kjZFiun0ua4jdl!?>Wd+IA%1UhGv zwQB!!nX-0=N~ovh$b|#IK@K6^WA3AFVH}y#qYxa4C-r?RVX1%6UZ3A`4yLU1%VpKz2Mq(8@AxG$P5 z)Ylxgo)YK|9T&sn@(epw01GJ*^Us6voofjtPwtrX~E+y;^{{m`YzhT60D{|kV^2~yW-^u3e=#F~i39a;B#gmMP&vhZ%GK42L6F0^(+yE@} z98`DY!}num>O18l*6%|`;5CIam40@?a6L`;hH+LeK>PCe&NKBtr9|wNq>GquN}t_stx%~yfmfP=Xyr`PWgu&-ku}v zAa&<>M)KtuwXm=GXzz+NmA5>(Mx93wu3{z57M(A&*0(%|dsFVj zohfJIi-s#(_HOBE@ta?1ezy6E=G&VuZ{EC*lBro?%3Qq+?P_$<)T-kr=t6#o!D!6CC*u# zhVPND#rMd|QDgXQ_#jSOTp4b`HxF0fjzSkVr#y_kmRAL5;O>-tg85jVeieHyAHo;N zZ@>!mh1hL*0&Y(khi6{!Uc`Be>tV~D>K%jA7W2GjNP(Ad-r_-=x46zd7q=81=`O>L z%Ql?!dCJ@+-yy#cJ1#Nzy~8jQ=(`pIo`jVrOKnOh{idwQGo-3t$r%Ej5w6Fa**(0B zV?aJuI7&g-Fab|sG9~sWX^VE{8o@`Js@nPh%qU6@YEbG@YP#4ar1l#Ie^5IRi|*W0 zYdG(WU{1$5EM?b}-7BRfEMfPodxuL3>Uw0_<$Jo+s}^KI4Ct`J_{_ z79U*+ImA_iGf^|`H;o$6(ojD@Ed%ODw&Y`gsD|RKp*)-&9)Zyzmb|wPEtMx}ALtcz zgWokW0$m)e!VIIF#7O%8DzL;Je|t$+V;OUzm5@jK`<#dXsODfQ+zRVfYT#j2D>!!tzL zx~R{suN54Kd6>-;3q1NU=sqnKrG$#+rK()69K`<4eDgcuskE;dF9dL$b==ETG%s7a z3l)(=-;Q&=+59)&vbA%^q_rQ+D^=~~e!D)LQPh!&aoL&W$Lldw>C#@bFxm;;&(;*r z$hfB(i%t7N?G0WtuUcM<@p6_Ciq;=>FV`ymP(>xqXtlNJ2TVxs>E*Mpx(`onB1V~* z!W_;Tj+Dqw?+NK8ts>4>U6%sJ;2>!YVX5)C_g1Af_ZYK1fDYa%SQUn6WR%({?cXJH zqM|1E2SR09LF|)_h546Bs`fJ3jT#*%vw`OoY3)BJy)KbTC{2qeJN`d|EMsrlBHn^0 zPXdv|G6UX#%XHk8Z(g&{Xq)*X>Sj9oLvEAUhIt)rPg9jU{{;TeruBwL0zOXR2#W^_ zECL_C2T!$gd&8qFF0K?xl*N57dYj;g7)egvq$i50=sha^OY34f#?)sI*1=PZb48m$~?2>(Z*du=$bSr)w`Yzv7;{SCXqkS3dkJP*LBl z-5jk4e)X=)=4?VbCknYUNfO?!poKnuslRLpo)-B}o=ALD=T*bOG~H>9drftF_5 zp;B6A1L`A3#;aHG9?kx{g=X0-^h#i;#H~>o#vl)<8Z(X<L-Hp%ocCTv-Rl?GRn}HMu%2$<1`5P%Uhr;h^6Fw zPNXR#ay`!dkiATe{h;?-DGOMk#hkrXx;tg&rP)3g`lIF9pzfVW>$ zJJ4dW5dv7%&vSl)cI47z1r2;GK3TLUVB=i+Qo7=xQBq6mXesb=j8tywx28{MB#X|PTx+x|dJ?|)HheGOxM)RG#QmkOVvqR4 z;T<^jxCN&kkAx?_Ff0VS@U?&kgWIuJ{PN(mU_-DnSQgCpclr1Gx4;iS8K)kX`E&85 zfG51Wu}A!T@xk}=7U4SqPq}xx+pv-(aWu|~l6!^Vp}$NW!WucZY}6QW$swc* zB>r-QDSMPd`rHdMdBn?nJ1*e_O2y@>@}wqO?ffcZ45RV1Lii%^SEkVlXA~^KjdO-` zVTr_0VkHF2GPuZX=za8A&f_*U7qzz?EoX0lz1^eQ6bq?1!DE0Eea`dA*SIcwn5@*Z& zfTuL7VK{4OO9+Pq`+-K45Ui7Wh5SR0g*HJkc)QrayupXmB*$C~TCjKUd!oglq3*Ay zXTrH$&aDRKsx;tLY0B~(1?a5Y8c(Z_mpN#>@c(8ZuwRmCv)fJf2s8_+?4(Jp!Jxt3J!2XSjQXDCc z7bxssQ&Eby0a44+S}FS91dpW{$p@5()a|4c?Eu^3fZyMy|EKz&traSIKSvv~Yq#{- zbk8zZ7*dS%LNM~~i=aXlp1!7z9QQFNyQOeTc%7UYQ!5c#6*Vrz$m^c5K4%Y@j zVrrVhIm6UL(Q45;Xrby#S)1_Zz+&e-M{V0C8^ zsl_OhRqG@8&)>#(@>~?8S4fQ;D+_9v2w7vesA2*@CgsdP<{r)6gB62Iawp~v&kaXY_?FSF(RtAZ*e1*{xmDv$ zoZZEcv0GXk^eV}9@Or!hC5;E- zMXA?C&YB?8TFwHE*ga!YIh#~=gJRLIFyFbenlX|-|0j@Y)bd^CaY?6!M*qEoemz?t$gl9BUahDfEIEkMSG+=nBN$u zEaXhUsyN;#DdoO^9M^3s^Qf&^8s0{(Zd%FY)>HR#sg<&eI!t5=pc8KJ`1J--m{vTa zPe~D(l2QQZ#U~w+^+?Cl<>E__ePbE0O*1X+LFawtMja zK})99@VgXjQJQX7jlcuAKhFFcWGShux}<16E%4+pawoL{IW6g7_yWdH$F62RU{&^V zMSMD(on7X7a2Ipc7Nez(^?oyeG03KB)QPbZJ!b<>HaA+laY=eW+*hc3?jz|%3*<=QO8-G%;}i7-F=sf|JzUDGHJMn0E`6J7k6nEtv9;axGv>=afbeZ7 zUAw&GqYXBugcjvpdP=pSDJS;>eP+z9!Za}hCh-Hpx6gn{a;q?{2iMoCRq0HRaIYEa z5>9lFM9*rKr&Oc;L`$t4j^pV~p{iPT!3^~>YSHWR8|Aey(iVxoiTV!k?wi0=)yc1# z*D9g*FnG&-&kX%dEoMl>aK#M$t$?bk`=}XsjTFRZvoJFTI1|Jwum-`=f_?&WjjT1GI!I0W~cZ z*hrO9c)$#~s=ZeMu2xyd6!-6KNwwNznQv=FtLcfQyKl&CNt@!@-Iw14O6SObqxZYR zh1P@zLSnrM3~Hr!Ky9KPH|Lj?gn{mhOWVt~LX!vF?~uhy46;ANoDcg#&fZ1X$th2a z1`;15G#qnUaw1FJHy~#pxoO~e>ooEmv#oYPs-Jm9IGL9)VKX^1)f*z-7 zst1`%jSe{fJ+Q%clMl#>5snyn+C99iCiq98<+b3{YS4AjD%}2it8l9YuU156A4f0> zNd=wg^Q#SN6~`+}u?=!GAn?^L!?Oq2FXLYUNPe4_^^$g!g0dqg;O^(@9P(0+b93R& z!qtTf3L6V+3VRj``B(A}=5NSfo4+W38ov28o}Zr&TVHN{vh{)1J6gB5Ue#40L zwjSELXKP2x%Pmj0+~0CX%T+Dsx18Ftq2=(Fc`YG!uRYp)ee(s)Co~`2Jlx#X95%h! z^gz?i`0m%1rsJBHH_dB&x$(Zn>l!a>Jg@Pz#x;$5HqLEqZgd(RZ@8=BX85HSHf(4( zsA12BVncI-U;kqLGuY8~L;dCW_7`stTvk7~zEJl<-5qsT)t!xRe;tjlf8mA|+#L8s z?!nw$xhr#9;GeF^4d>?O+~~#VZrmDp7WT0n6%9u{Q7cYmJQ&^*UMr_Ejt%z-%W`Y* zGr`@#t?*Y*#l68t1&3lk+dSMH{EYt~?pwLmKNtJh_V(xbtrA1O2Pe!f@=k@vx*u*0 zEMOJ9nl|3C-8N+*gk{jy>ZM8$^%-f zd3Optt|uyr;c0ppc_3qhzAgq%TNmq82NxU7z@?b2)PeS@zX?tSn27%$-u4 z>9m{n1h-UUNMVwi!o5&xW;mXHz=+x{urJEl;w(|R}$@-T)< zBd(u@tVmO-6{+#_&W(^BwbJ9cMv0}e=X}%=L#jni8n2XumRQm5N7}9bo1x0g&Z>hqm z@`^GV^Vs~O&?zm+o`OTnz0=YuZMs9MnCjW#c=J~Juv0lhPyL~XL_CB2~? zK^ub{2A&LvJI;-@EP0i7R6^b8;}$pfbQZ$@w0WeLay`dI&*I3ub@eN1tU>opl>Nuh zD~(}Lb0(N`j3F_dbCcZ9`P_#+_q+{AQ^_mPu;!=uo%9^gY^_GnIJTq|`_^XeL+fXP zBX*vZ8UfunL*NgEOHh}623F3*Qq+O|GL0Nk3P+Ky^NF#)is-cW4nSq|ND;P%+O8bT zM+=$D=uu25<|h4jF2FbuqU2l#3h5KQ9NJlGY4OhDTIsRuvDT3LE$Nd))x5dVCwWGD zX}d1)`e2iAMkudK8uBXa5P_xqM`XlX0lAUFtM4clf%iY?P0gHYe9?kTJJ?S2J)$2K zm$qq05&I^{!gD-fQ@hvMc5sI-M_A+jm{IPxEv7Vwwvp_f@%bfYwMIDyb?z1X|3cr= zRJFOtD{}Xww?C+py`@m48o4RfeRz(zLyJ)-xj7^#IG zZ6!uaeZ*q$TZ}w8jdYJW4L)SRs8*bwat~XR#Hp}GPCO!goxcIK<7cad-0hOjC|Ds_ zD6N!d)MNc%9L7Uvqf?^9bW389!5-kC8FPWL$}95M0n6^-#e*~-u`R@!y*UkI z%@SO{ub5|s_wA%P)>klR*!C(sQ!`$M;hkb>8LjP1p>4A^?F12{mDK1JTFW~Cb6(a8!e_QCMPL+gb*cKQspgy>ehCDsBW67K*9)<{QL&Ungb;=qc9xnJ5w`jETHH;7Z1 zf07nys;o&kj8@XOrLKbB2?nK2$-7_{i4m>DsAV9*Mbmg9`i}IErC|a1dTR~e=-U>| z1GX-WlNY@IKwF8?z5^fIPC0-Gw0o840L`VPrt_RKr9#IwKy)UUdmW64#7 zvU5*@Bh4Y*{xNA+oX!@r&xPpycJye0uolihn}=u2knq2RSD9A}Lgrj_tjwjEU??NW zjnMGXok@SxS}ZxAK%VxT+)C?)I>=hU=I2S<<6KgV<5@BfT7FTBh9#3cJkv6ZSF~w0 z6ryuvMsa4tzY3R0OGr1X0la^M6jVwk+A;W@&{Xv)R|U!Ah|>p)q}B0Fe1ac%=%-<( zM4d8^82=Q`2o?(#uA`8O)ZnbA=-i7IsqRF&`2^aWya5}zmtG)ekKH5WtpX;(P=j!^ ztgReACo_3kIv`Y9z7<@PEf+^~3sDzjEc@G%V~mSWw2Ubu)T%>k%|8na+H8IS8j%{@ z7w+S^$!RpaQy@+YkrJ4PGbuTwMCOr93QslW%%hnUiKUreW^mKufLu3^2}QL&wYTD( zAh7PuzW`HQGv^U)8uA8OZhn=?i)TD}4s>%56e=oKmRCEoVE8Sn7@yvItmDZq%W&MO zr8V+y+ZX*7`U~?kw*VtSONXtdZ$++>lMQ$levSS`IIxPZ_Xi zZSJj@0eZ_a=XL>KnRuf9{`%XnkKvN~GwL_iudCmueow@UUaq^R?z*~*>o(S{LA0nb z_cHF|y)$=B?!w&W-1^*-Tr<8i@l5m}_A^|G-Ig11>Tyw2z#SfshxddxBUZFIT#J1T zUAV#HMcm=>tKdGIeB2hChi^==bl%&gKjgvG4%qzF?B1xGjTa??>I@mGqns~nkqO` z&O<>v^b#XS9O-lnV@*@xyF~PysI%xhvlPZ8=m7s~8YM3Cc%nw1;{DkLZy!hqO@lNG zIx!Z>8*q_tWeoja!8T;P271W9A34_gk=DuVl6lb?GA++f@|H}?OTQaM-;?c1aZ(m3&ZX1xxOYMG#-`;_Vrky8X?c`*lIOfO zEiaLm&L3rzvu#lh$$Gc3SMj=xX%^Pzg#21O6k!ZI`qzi>+ey z-skBXYGWNe{CD z8{^MhT368Q(J#^Z%scRkmU0gR=P*jis2qD)2ztQRYIn>IdeJi7hp#JBY@dvFFdO)3 zbMg&s3J3A7cDnkcymf&bjae2@bJ=G+#iykx>+<0c_?>z5IVk6u$}jG6FAmo;w8nOq z=l`nGfQz!5GhsI51MyarLB7th*d}HF-vHL>aKw>WqYW3;tc~L!@lwOv@~30TSY3c) zyyyGUbINkIMSXFNV)vQbFe1dE9uDEfW-~v)h{WkKM&@>*twKV!`=1vd4SLbrSDtuE z`$b?Qttjs(|EZ;b(OV8|nr?loD339%NI?l%NsL&3%^b8W@4XE)sm^5zqk-TY`88gd;$FW>3`Mh8JV9HBv=oxk>?yd@RJMaN5R%XACH+hD;+3L4 zv-h+dT6yS!c?AsZYfc zqg6R-M?qE_u1;lfQLD+#+h(ka5@OMsWkS=mRVu4AZj4q(kBPTmcFtf+(GSLxgg4Pk zuA->yw!Gp06ULAuLS3f20%`GT2`OcMi1sC|mHw-D>zg}f$O+7kX2=Q6oipS_=EpPS ziBf3J3~HYEzceCj(}R_$vyK8Pg>N~vsv_WYt(~`)JE9JHLS-54K{&pJUjcqMhBHn)BLEe3<>kQV$_uh`OJi!dD6!b}1 zc?MK0^U#~94U&j;YyZ$+ca30+&n{C6K$7@}K?-okCZ&>6p@e&J^*gvC(~wv6pFv*< zm83{*s<%kFuNHa=VgA|t1NqzXSLL_lkIf&PpV#_2R&VcXy`}Za*7I6VZe7>9ymek{ zPs?j9kG0$&>$V5A6q|Q7Ki+(2^L5RaHlNviV)MG@eVTik-KH0s?rplh>5`^nn^rW< zZ}JDW@5-)F9h;`c#`-z{bf4F{U z{dL$+d|Lf+_(H~#`sTW)>TbmyBuB#nFV;2Vn;6gJewDjDw;fjaiMi#uw&)eyK5|cV zadc!fH+&|%F+2_Do92cc!4&Qqc_O$4JBlw3&JK#?`iN@B@B4V*B!p`zEissOKPU|AV%c@UD zNk}_1vE)6TD&9>#;E74+a>-k0>5#?7wGY~Hl~^*f#^)K#%3Q`?V6pkHVNNg-9gj}Y z{V~Rk-)Q=g{LQ=Ex62(uoJsT>;&Uea7I~b`-f#qIhoxzpK_%x-jK8K)zb^3qh_=M< zm2>YFX-gcHM~@@kcA>B~UgC4zGET9cjq_uSPMoIJ5oi2P{7g@!U6ZjU4DbDqp%@>v zF<_skOf_BieXxFx!AnVt)E?<_|0d~=TBnqgx?=k}Xs$S_a)g$!y!_R8QV1)zKrxmF z|G0;OgEcRuxk@wDwt7aX5Y9>JSDl;qb3SiIPz;pku+F?ec_)Q+r#s`Au^v|nmx9-m zQnXmG%gNuB)WDXp#ne-<5e(xAT7%}0H%LLX^M%83Pu0yyFBK~7PtoChdgmW=7z-R8SQJVZ_EmK*x4J}#yu#-7#5{K zv-^L5b*45}m!jREs|DTe(|G=K%aIp!&7FPxkKMGBkU9n&w`@C~*-bmEOJ&*_y%Sif z+euDDBsV%3T$ar%hTIRx6x|c6ZBR>?R#(aSgJ_m)emr+Mjyn5jKfemTt;CbUaU3gQ zRa&QYrm*6@q1NhFWg&WTS2#WCxK(AJr=|3r<3*0-jHl$29S+`*c-A7dJ)W@PR_T z?PvG66WclDs(y;O%9lYaGJal2FKu_Q*%s?rowya#@d{7*YlL!~mmFo)c|4m&?V)Mp zZqresj z-IJ&~yg%jPV!)ev)piG*w-;)sOkrJ+DS;;?)UU95%%jIkFI8<0Qp9S>un0*Ad)xmp zN@?6E`L0jEdk3Ihf&iuU&P4V>VmU&YwjcyQXbxvDR{+?0)qtWw16qy>Q6;<4Q_8+l zv@OA|8jZY8X3tFoMy(us@hi`zX;??$;%iHF7P8HXou`?vL;{Uf)epk^wl&9RktEb^~K)Rdg2GJQJQ|HU;%)`%F;q4Bgu*dSvU5tzY-* ziqgtwV`;7QFT?~4p}XbbU90``w1)h9kdvy<}=z`guk{(*RhM)p@>W;2>j zJw%;P&w)@Y1Zt&)+J6S9w+qxeEYx@vR0ykYt#dH$TSgQxV{DLsFM{F=c8(Ip;`SV^wwW8|1Wi>YOj)MC#dyOCRN|z}Lfz zxS5|{&WY*JJ`)|>F9W8|@x1xqOY$HkHD|Hq*O0f5%+PXwiL{A(uCo1Ks%;88kvj+6 zakz7kvmeH05Uqme;J-ymjVP4A2vk)LS&S!Ncx6xg;_Z5K{Nc*_ zK+o;Y73lwkh-;pKn_Z7}js(?LI?HiO?n1;i$&ns7u?P%WQwdK}Q}jGi0w?t6;azL& z$CK7LA5U820zC01zd3#xPrUPGjz55>dU;xiC$T#HJ@CYPS?2hI(#N67mWK4$Ij?JQ z0pR&{>_*1{?dPM8GFD59NX;YV%lLYW2V8sJWSqU0-yHeQZ-#FQgU6TO?74V!Zt|E6 zL-RMoH%Fn_wftto^pX5XeqbcupTFRvC!Am=rgr4bh+}{+`R^_N_cft~gG)sIFL6?G zyag;b~HUWMdi%dHKPm^_lz@ycyZe+Bx zv%NGrHo9afe}+5S+dDeiqY-w;OpFhXj}LBHJTb!8d{p$+L~J$4jXwS-@{w=CqSef*rgjn9#DHa3+9zafpH9Vl3F7*YBWxv zdwq|O?rt5L+CDV0xG=l0cx0%nknetEVq#)&aHzd~Xyfp~4J}QxW;L}m96X#E4bl`8 zjVT#g%Az+iDt{<6HWnIZtzEWk?XsNE)wCm_vG748EL;0O@eqxJs5`O#M|6XbmCjNU z1SpmYnx(@7BZ_f!$=GOTG!VA8bqp^ZT~Z!s?{Bl9lZ}O@rot=o`)}IUZr;3Y^C6#~ zds^v;vyV7<>7dlA&6z8W+JXGdYd5^re17gn_88soh$Hq}wl25FuZe?tdfb^ni*}%M zdpU1+9D}<0`{#x2sCZ-qRdWzW!80?Yk6}3TZDD^2^v^F@I$|ap>&EMvn((W!I5c#+ zJV+AW?!(~aryebIcNa{1M_prM-Fp7&Xc%v(e7meC|Av$A0T{*%jhsLucc77+6Afr2 z+EYTKC~VEd`t@%(>j&4H@#lB!FzctbLx9I*<^@*h68K>hoxsnu=8jKJV(hnT!}!~b z4?Q|GG&nTLmP*24z6U5LoJsRDGl?ezNla(dpYJs7x8Az*Rx>#{X`lvOXA~eiVvt#5 z`Tl{i-vi)QIBm2n%wxIH7BGz!MF%rOwQbw=eSW3w=Hm=FE)2Fm(RXI?+$L3>+ghyMG0 zaZz92qEnYGn|r_k&*Zy@hWlr=?oo*5?9tYF#Fq6#Z#!zgeDnN;4NaXnGf2q3A1&Jk z*t-sx`fyLae>iF%>*$!fV2{DKuV4T6#ry5IxY*a*J9l2Wk*YpsEDx;Jk1O&a$wn|Y zv+RXo0gFY#VjQE9_G#lYI#jd_)mm(=Yus8KDi*VR^yK(>gD??(6^o6HlcS>$U(Z+Y z4+pOuBg1PV=dc}}(J0t;$yg_+*DP>wTQtB)*55ubW}JzMRmb=CwX7bse5yU3nNUIGUXBGE`;2um3nRFl=-Vi2S-=W z-~Z_Sk62PJFDaY$rHAEKt;!v?bg#F)Enn`L>?!jX#y3Se8y3|xv;&-<7~?SxXvYk7 ze72>bzQwe*wJw=n*-huww=_4L*U-}PPuXh6ML<0QhoJ;x$eCpzgVOGd437~2=5jC76+*dH@F(Vd^#p6~9?cMOh0W{(e11?`xkV#pf^ zjrIHw1dQhzWx#x3#O#mtQ8kxE`BJ+GFtc@HXkub$6VX!u_2k!^A)xLy?M$DT*cqpz zrtXQUM+Up|hSBV}G8Is9g`$e6l6F(!Ba@SlJo5bX3O5Z7?id<^eyv?)+CMHKlrd6q z9|F`@h6ESIF-_o2*#1mRG#5IGnEsi*nn~NC_QBH|C>c7=*qH4vh|2vv&zoQ4iILmH zI9U*NM$tetFfhh{W1VB2osn1x##s^_vhbbnTzE*dBzaQ1Wz)Xz%CGF}+rRLxeU~4~ zr4;ZNrAswNWXHurGz_=3wV&XVwzjK3QP~-nMgt zXe`djNsz|clw*|Av?D|=!<_+pfmScTkJ+?w9CE7MlWU%OWQT3OnH<^);k2aemj?%- zQL>bMuX_7rMF%Q`-w&)HFjw zJ6QD+er_l=J%t+M5W3U1# za&l4p??5u`fZ!d*4|@#e|Bu|u@EZd zqlO0Fv-3#iPMvbqDW_buru6P&@$ll|(y+MU&a6_tG|5)5$OBaNI99}iX$GMtp=2tW`m6fhUS)B#okgD2KD*?v*j%gbEXB##goYj_z zbzm?dCNY^Ng@wo3VY;cm1OsZMgi6e&iHRmoQk{rRra1B3#A?1h%3mV&$7ME(4=Og9 zI9x<9G7z-WX>4y_WzOnd8HS3dbsw|!x98P0nMbD1?_KE&s(lW4`nQdBtATG5EUnMN z(hBHJ%^DfY5A-i+i$*&-Hcf2WG+~NMJBns})717&-vow z;d2oPYGPc>#+^WoufWm$H|+zMTmxY=3boxn097#%V5m`r7~2D|8u4tL#b?5DTvS@z z-TB^46UQHKCidOy9qT%Z4WnjBN1xeo)Z!Je92d=QzyY53Ub1QO_-~FJ+PtXwgDdwM zEcMQ*^Ox+^KremVIRNzeA$r5DIF9LnOO2Wl{TP6Kii#FUAI;D^)~$QTUi^@!-6Waoex9a=38&twf(Xal@& zWKOCVWE}Nj;YJU_jph#5x0r`;I=f#BLz%qc(4Yp5rZ$PcoXY+s z&c4pO(A+k-AY-5sv}XUjD1w~m7;D2{7`*g#;p~EffB-3>=I6Sdh&1(&M$kVI8X%sZ zTE-fF>Z!-YK(1TodY2Zw?_Yadk{r%y*_V#|D6jDGyzdQzAvJE=b1b90^7mozmj^4X)qO5Sg55Y|MeQK^=a9B7Ovd=3E2Vf&jUG z)AN-S>8eRiAgar?G=xf7QnSeiO5e}5xS`*I>ir<_a;V3I2199F6SN8hTG9f}jHx{A ztOA8YumjE4Xc)qC6cMh@jx0fxgGOSS4-Az12Wkw;>yg_Oj4W_n41CT*#i$*0Xu%)! zGmjPqE_vhI6?A;UGu~b;vs`102a?n^13X8fpvlek=#tyy2X0d(RVw)8e?JST)TWtG zm9roo;99fby_^M|YH?u}tXZ;Y(_c0VK38R)rL&+N@w1OQpUuqiB`^hQ&hr0Hc)liO z<~ER(Fh)K$p1ZMp_}{bsNG%eAC)^5A^1tK#?^TgHoeE2^I=Gvu(Ckq*)R+pRHJE2t zs(dC+R!S{?#;B+>8zp4}Qy2MWCdS1H^LnCoT+dH9csCzsZSdwb> zj$LKgF*Ru>3*DwWziIm>2|^=u#ASxd#2_A`|AinZRsW;ic8qawmihm8{uWXkK0HE)-|Y`fj<{(Oz7zVph}Y z)lFDUVN<5iFl53_Xva@OdvgJ%^y0dulka>d;=p(-ya*r-okN*#8y|0nWQZ*kew1D; zYpxd2Zs(5%@M*8a(Qn!n1AOhQZl(ENPgieOZ&Td_VyqJrqobosdzSX}jG30$TkR@5 zvT4KW|A)DEfp06V&xG~*BKdCXawJ=_CE2niTgS0uJF;?hPA-#7;v|zyMoQ)enM`Kr zSTK{JWSAKkP;W37C{R%Pm3}~&F0@#s<)a|ML7V@A8ELMAF+M#YiYJcwcdO8Gq}dw-VDQ zSkDO!LZRL z;mW1}EM+M&3+@PF3}KhLBz4gcB#alfPedl33ww(cyo%niNnmERVr`FaFXE6F!r|XE ziRu^Ac%q{Y0tRx7FBe5miP zNABvI?mc?^XzynP-houw7(NUP<(Vk)XNM%C=1PGrH_)*WtOZUVN)T*nn!$_xg$FE+9TfsDX z)y7Q>q?2)BBGKg?U^X>c{AWuL8vu$#;>!^N5VLvWwzyD`6@LaMLj09|Lna!=GWF~& z%C%*g!nq;e>MEqi`s8i2KBaf!@+iLjCF#SeGPWQN=1UQVY1cHy=~pm9m>iMzPRQ_Z z|FCtAOt3W@3>lC{gD}RVvTjdeaWRXp)FO~kHxgSsc!nmEGyfwxzCChiv3(>u}={K+gOxCGe}b$I!C+B zX8o9yPL(5>NM!LXag)@}?DMTR=m&^fMN^DoaajnQ|D(;M;~7Kdo+i0;qLF9cp#M}V zmB!3~ny_g)P!-uw#1<`4**LulmbIynjiZMeCElG{-wkxrh3Yg%gxtr?bB=Nz=G%w}+6!@F%c@;0?M(QISG%Ta^3P`?To z#-LD$6!(=5)ditwCYh?ZefvZ*9#7s0Ffne$n=H8%%i6vjmvP#%F2v(6 zY38jNc$rHC~k!rzv$HB!{g#Kz{lT-@cI}e3kvDmw@O&azfW{hB*JsRC% zHmMMdB`KIlvLO$tU^YY!2Y63_;LAz;TYie$6Hhnoe?tJ|x7~1F-vfQ#L<3gQfFyTx z{)ph21dUDD^%q>b(CKJHAfFj=k1*Jp38NJ+%wy-X`50g_^mkz4rkRH|3jc`e@6W=QbVGh{&sYUk{^Fr2EiHA?cH^(=zRWhD!ZC6jbHT z9;382bQ~f_Tj$iweWUKq_LlKq>*+i`v{o{DI#c7lo#Pkg(r(p*VqLCZYH>k$KyRus z4|QCRdkh-fj_hJQ6eLI>#&GDyuu9GJ#E0BIcgF30K#e`%#*WV&O!UkvtN&nsdp~l+ z@XV!4`W^#5sRsw}3@zJ~0E+_#Lt~=f5|wKDJJIjFU6rbD$2Vx$>s=?+Q*iU86F)HE zP{P1%89#a&#+l_}^mWB!(PJui;lh)}=nucX_MMxfH%qI$9W$UnyAGKw3daLN>e*-o zHlmBKR|V``ESs;#tp%6{=njEeC=aUvZmi1Rc{?hi-u|65>VaA~a!v>2WS8Fq7lTa7 z1C7_m}QK% zG&6)d#xDI6yCUuQ0Y4Mol*8Ia=Ytx7w*?TuOR(9ZE|70nA4~q$fH?_093mEG;HJ2;WsqUKDwTi;)BuXVEn7NGCX;%8T6~68nE6` z$aP2^^Yo^nQS5f60hBJx0}*gBDP$%%Qz47i*Yc7KjEoEph+v5fCrMA|)hd8pnI^M= zv&mUcM{C>oWYDloxR3DV^TFrjhU!(`t)|9$J7<$;1GAo%o)>~aA@{i32%4~%bYbXd zcL}x)Gp(mUL$dG=I!Xx6F=hsB%cEnaaE={|U) z{j&d?vaNlt=|c0ZYF&=**XM57|D2rB+xN=8-q!RNW{Ja8X>Y?g$Gi*GN4TRsmie!# zqv0S>Fjq8c2^n25U6!P04P8xLiu#Jo5R6SDM5dJz{e`2ax3ii>R77vsS@%lW4m30;xcg>cuEoAd6Z^fuMjLLaBw-EnT7q9aOffrQFr4GR@+c zW`7`tyD?M*lN}Hj-YWy63T!GtnC9ujG1G#f2JQoLG8et&v7|5fv-iU;nEV@0WcTde zk)!F6;J}`UGS$1c^KxPKz5n@D_m7#u9RtZoM`U+$Bz}JW(9dV9Yv(vr@0x-{{(LKH4q4dyDT6lQQvT~xMPXvY&3kwOz zd}F1mBNcBu9Qk-hXy7KF6<#_we$pFL-LF0zIXXDg-R%k8bl}!l zcMx~H%6HfwIk&X^rc?cc!I*T9DV{%c#>T|Z-j0ku4s;PkCH=f)A>0?Cw79;jS0G;k8K0|u_?%0O(Yy2b$R97Ne6 zOqhfRWs0*2v^U!viJ4>Xhd7d&22x17j@8c|F<{ZUrrNw=HP)FnMiPPO=uFC(+ciC1 zH78>8`_4ZRiyQaNCDeSPvn>$}!=vo^Ago*;gtXo^<_pXXO?dYtlCjv#;><0fiQ#*9 zAK$gDJrIjMaenVYEH!oHzON?QI$?N8bS`ITO>(&`2tG_NMPfaRu7b?7kWKZq1cGQQ zaDDAI;Cm^zfhRgT67jSz(bJRgrQ=u5pFaOy5jU@kqLt^iYD^nxvu{2Y^g zVghDYSCTj0zd^EYuUDv5Ae01^W9mG{_ozoZY=WVzs;+KT0abz&Z^4LOEWY%!p?n3w zW7#B!&?HstQ3wM?@`-V*dsSlKHLf#N7K3To`m@$OJkFtwA=^3~S*S zLyW`7vp6q%aQl3stFN!?ac=faUKok)d_TM|yQkj-`f*1rS1woky1vAVU+U_wOyV-G z{^;~{G)CIw_>YJttsrepK(rt?a*!e0?deA#C)KegRanD39P-LW2%G@|r)v%hkns9Z z0BJ{^csKu`An??iL7JsN7W?m~A|!zY%=I#{I0YUmW)OQw3TGv=LhI1s8tk>0v%r?X zmB?o8Js5dQg#AjK5@5O|awdI%Zgxm)lenrCS1PY{gjICT>*oAJ0w49NgUK(vo}@an+>w3bocaFf&$!VLa6g|VTZ z`%^P_ckj^&c-mwpj#fpw+MCbi67w)|(j=^9f^`rj!t_n!2I>mDVo)YZ6J;1vlCx7u zOMFY~75uKqY& zD1)EaTs0XA28NoRH_X1h<=kn9Qkq&!W#wx}N|{Y_Pnm&$;qx7woD7bPzjTAQ*dqv1A>^`D3NlgvvpJK39}W(ai&?l7 z!!(*o!ipXW@erE15dtH@VUV|D$Z3jE@2X@x6p9BQ4YjodTiPQX-EHmD?zZlZNPCL` zV`m6|t*U;dy}hk(7bgTNETG#4dbaj0BW@URx38^rqOGN?y?t2zU?81P?aHS- zZSEFdYg^-5OD9ad&NUC3!a<~He}FI!Uj~ZITOsb%G@RJ->l*uYtT1$H%ND@e!>cFQt*WvG{}PLy_IJC-98EQT3_dBV+j%Ps?TH^$iZ} z@m3~##$x}yc4uTataEGrp3&O%p`J(Lw`^1Dp+T7KOc4?5017~ttfLhjmq|gJH(8veX2l4XE3gIG8LtsRL=1qPZqP4IGbLZc<@AjpqerxXs9*#_gBmO`{ zO}+8_((TXv)>99E;4l1<@MI){#&ih3hk&^gbVW5lkR~YV@DXl1@B|LO#u_1 zJer{~?94IGB4dX_TXAdep+w-;!-wx^qBP%_y`y{F+MnN&cUvw?#O`i_vKvgT&fC=y zi#l`%;I1P0v8c06$i(a`W;=VwfhJnK{QM?ieDD==V|2HgiT%a6eiYk!wloIz@>rY zP~~q>V?G8Z$BmeFy?h#G2+T6nHA=FfvH~**^KnEn&^`2ahux}M#P9Hy>UV~iD>p#=Ke;Sh|7|c(Twd1936K#)~QK%G<1}>spkt#zZ zO5i)Tj5(^F8Q3+mYhZZf^l-#GH0YiB>7|b^4KKWFLET>~!{={#AQZyYk%-qjb#-Ye zvanG5ZN$blFmCO{I!Y;jd@Pw-2+n60+>U_apgagsky+(@tBK=#dJ{tzhZ4OXZgPkJ z>98Ne|Howe%+zQ)J^D&*VAY|Chj7vPgJkcFPAzb02lXTvp^GvL;ZuQ7oAw>XuZiYD zJM4`mEq3LhSK!}gJv}|1+J`&3{puk7p)0T%7lCKWw!5SDVP02v_)SC$&@t1czJ{Ff z&Ch2JvF(_J3#kMw7lN!i--J+GNejKHc2o*(k(51n6|fGN4&ieLTHmEA!&a?4rOuk> z>e9Qb>GG1lfExs9moZ3q{h`{yVc4#wK9XMbFXd`~ZGPIn#4zXry1xYV$IJ1IE&v!_ zS2ZwU>1(WI_|Lxa9Pp-MXOETBu7j$2ZfSXTj_UK=^r@xVXAJ}UpsvK6OK?Yr!{~&_ zgBd_k#)2xLY4C@b4t(R$PM>I6l%eSR5|*0+f&=ntnX1|%xi0Yn`Kq3#w%1~Vx{5iz z*>vR~jY^mF8i{|f3%R~k3BUQxpF*zT$x?^<+?@?nC0s4Ql((+g)64{ z&Yu3-Kgd+?>hBpxgJWpfT0O(uVbO;gp8_2WWkZe%HVWego}fx6pr@XUp2XjYR|s9I z1p0pXhx-D*!c+Di1przT{U80PA8+7rEGNnaDvvl~r+{;0NsJm)i19Sv+V+qgP@{u} za}s&;t?{ysy?KXj>Z(v%kzv0fuupBhyyTNK2!sccTdVazhlfHQO=M+JZD0D(S=`w zNJ4ZWize$10DdT$@nG;RO+fTx%43!0J@hS41p4Ra`vcGokIbuzan)Q7eqv~RXlVQ| zW$Ued$0#}1J@d|QWGErd0-a4!gusC4MG5aqK{X3P##Jf3mVUoP_uA8k-F~|#o{oE< zD_9mJK|~2NBpJfB1j|t>^bZdDF|aI~r!xdq@L{k5*vHyok4&gvPn}Ky%b0i9ihq6j zuTQHL9^=sW0uJ$GEsavKAtZ=F*-lDAdP=ujuzuIaKK3#76Z)}%|MZ^%>kq!_Rc*qh zszW^wKdeKJix4UpM<>n^?@CX#W_GxjMu#W&W|eC9^mPsI@%9dOC+53-1O3X|?RniqvLo5+>HJ^gJspu~ zEIOGQ_YV4k<9oAXnVXhUkxK@5@Jjocgu`SS zbU}Mt1K+9UfzJU($K0<{cCS>cjJO0g3|}&ducl)-$pN?p+K?<%E9+zrbn>8E8{DTC zjPbh23Ii2HS5=r^TAI%1BdJs*zp`4Z;S1u2oKgiys#8#Hr;6$Hc6{-$K6n^J@Xt54 zP^kLnm!zPkz-WM1=Uf0jD8vua5e9^M>O|$#_N9ea4$KFy9LuTb$;!#e!*c_N^D-pY z!43_yooj+_RpMN;PTuQ~R)U`b^wmjeVa;!|sPvZX2_7#FEppfs$6zyCT3K7$z>^Nq zqfNX1Xrpv67?LpN>JL5aJNf=n3HIzCx$`yWBz92ie7uh@>)h#qX&5n3hW!ILeKh@w z*cX1=%<>#IYy@p2!5@N8bt;1*(p^EXH|TveW0NjJBDl*N92f|yI1jH~-c*X1a}!Oa zY>?}%>KjBeDvPt57=lojDuy$HO=E4i0`&k0YkC?`bmCp~3O6dnGQ0`}$-_46H326; zJpf)ri5)^?86aPgR{-VW-Zfy5X00sZ8@5nez2UON`9diI)4~PZiVsS|2}X_K@+yi# zFVn$;&ZzAWZ!;4UnRaCU0IjTmFPSC!eOR`O&nB{JpthEnia=J2b*f6ekrG`QLsq;r z;Yr}3Z#+UkJoM6ZO`g6xFnwSAzUjahL^muJlC$gUvv+XFnV2jP7H&0JrQNh}EOEp}bz}LS0$RkZ-i-{fM7~f(mh5Y@JrNiEJ zHs!iEjKPUscMJqx*!KmWHNXx505MDpWx{S>Hx=NRN4Q4d&p-I0YtWC8ItyV)W0GTG zcy7SqW5yFVrl*a#XU03U680AOzyjOWvb=a92g_noZkmdbjX@D|!l>hP(>jTSBvC5I zhdv>ekqee#nZ%Q6{wb9ZP*sAVCs5Dn6ak~1j_&S01rMzK z(+8rl_VEzTVMrN(h`tJ3jxW%p1QAvtjP9-j1OPq{c4%`~Ld@b~DriioZLRAor10fQnWe6oYav?xPW$cU=3ela= zrS*IQf&BX{Pi6n#N{QnGOvY0$$|2;oUk>}s1K&L7TRE5~@k4M8XwQ&UG6`4+jY0t< z9$WbHLcqZo#aIu&tAKx1oGx0yLJf`^a#r-A3+9R`b51KE^sOXgT40mt;V6-74GqM+ za>XdhR0?~w2BKV7;zf~gHz*&Z70b4e!Ze@M;Xv1tHV{H;iQzdPQpb-+r(YBO{E>x) zBlAV8a%HjKy^K>2MyKX^?tPY-oK-^LpejJAAAoZ_(K!Ct@oS@(8|Xx=rQYf!+$v9PCT&uX1GnzMauG}&7?{rgNyo-8y9`A?Qn8)x#nSoH#F!?-#V}WH$c=Z^a)@<*_XMtIPZSh-v(dy zsyelMY|uY47WVqWW4p(~K5uwz#6O7L!O6ilg}s}u;3{q!$9DJ2{BC@4e2X%9c5+ai z_4cH_y}e$3(mh^pPtPlRr<@a0`uwMFxaXv=`By&ZW0)=uG}F!@!9GjD+>2@NIE?)H z+oBInN4GUQj8xwqeP~zdjLiZ&!f!>S4;m7Vg2@6JSNmqO z*uJ0-YHI*9T>{}+5nFmcD8$7`*ZETwdo;E|)fyF)i#*)MnM57b1~(=^STC**gpJ|; z+FJjx5gt$lMBETV9r7L+?D;#gh`;L@JOC#_M_>PAl-%zy2uCD##OSO65|bew41a+v z0IYgA{PVei`wlT0{$_;51G=w=!bdL8hxZomMKJuW2#T*i=1=~qkMUkQc&|L>-eLPO zBH@M~UI;H0FP@2?ITOE4n{G_>PZbYjUQw_**4#0`IU>I5zA$ikt_cHGh0D7lhl{oA z&B$lH(p>4Cf%K$}D6!Gs4LAe#IS?5qZ2&V!p{J*s8mf^u09=lL>rIVS&l}Jp(i$mF zzaYruT?QBhf@vW^L)kY{6co_yRz#hSyaA@H^y-@n<-?9xq%@Tk3@}wLGRL zgno%lp>EP#;5y~}<^prq9=Z0yrqWcsG-!5?HKDl_b*iaKs{Ake^F{+PmI^K~l1c|= zhK5t#W}m#~7Mtsbt`$d$yv{&i%-278v8k$m*KZI;Ku?5mH8kM6XKD&8bz@sn!7$b1 z=pd#{V>Cw!-m{3qW}-99ToDu0zRAgbcir{4agq4oMdLqAolzZUrtZ4yv1j#}XYpGn zp9u4AFws9cn;y~_jW?9%LBR?NQF>-$xrELY`Pf}IJfKSMMw_5^A8f%~6+uSw7uZ$B zP=`pvvW>~fXVuQ=++D2k+be0~@dMGZH%?CdS?zbDb9b`RZ|}UxEIf7~nrN!IZUH8E z-?9}#TI}0_KsW9w|K#M}rbhYw*yxa9>&Qwu%LRHVD`d%pgTk_=LurMT9?8thuS1(l<@@AAah{kxNI9Ueepo4GonmmGo=t zCypHXkEc#;C|J^jIP}Yb0TAW4;Q@at`8nc9%d)bp%;qPk93j&qKZgs;D{pLi4n|6I z?dxbr`-Xyz(DQbojY=OWN?|_x9r(1S!US&u-Uki{F}tY|jF58Cf2F*sq|a|GM{BKL zfnourg1BLbz%ZqDs!V~P-_B}5)k(QV4*PdnuRj08LuVF`pF4ZzA>YofD_y->>FKQUWVN%$T(>OfnI<`)m%}g_@UE>FbOaqKk&q8nL?~*aIAa2@F&m+lt^D z&@FTTFDe9l2royyXI)I=bYicMCkjAt4#vZiN$O&Yi$sBfLC2t^g$i}s^t9*F{`CG! z9%tvPGNucVIL^KCZ1V-VL&>nlxNCmw_k8F}KJ29))AU|kY;vA7MTQ~ZT16(k@y%#z zWaJ?RCj|7A{i^EDFZcS+Eg6~GKTyk@-j>y`(-Q7iXQ!vz2jbo5mZFh(Yy#(>{<1e? zES>YINvfOE6K>rep*_A!>C{L(5?wmi9Uo}t*?-@a`&aLpW@bg>2FE+JNe~^R=HiqN z;XB35b6`?ALVhrtf-}Lx4WZCTWxA?XYx=;Jk|;m6po>QpQu*W+{H>WDuEVvczN0E) z5dmM?o~1os{i=HIId%B4+GB9Jdf^3in|Q`KkQ?Kv>6(wJhWY?b0`>|DLpsK^ybDMm zD06TF3|mB{(yLYw-hII#?^SvjHQ+cMbAx#6?JzTe$_({vhxb-hoYjiWh9{5#rxr9g z(jhKIBe@t~QGrZ5T86|VOTXrG9NY0}*Ep+*4@omWcqamoByHT+ zX0pYFZ|vv~_IpW1VIAbx3ZuH>mj984Pyy_dm_dr#(R$Zi0H32(s;*3zCn@IKDrm z-Vs)2EAwdxo&C}k+~D$iW^>K7OD_PAhU;Nv>&i*f80xzitZbST8kzdZ%RHGDM{yVl zPT1jjii45(0mVDmU$g4|V@5P6O@)M%Y^vI~htKp~dUr>>eOVQ{x}NL|cfIK9>UwME zaOaNbw#WYd(b=eazPr2MFy1S{bL=|8Kh={}8!IZFG(hb_iDdHHh+VJazyIWmt|#BG zl&)Rv#ZD}f+1L9H`?~w^qFs-HCzb2T58!$j>uO?!*UsKP+!>audzpOEkx4ZkW*bbz z&j6FR*_Q>lV$n44zsx~IB>vpL&8@^vnj+L-me~tq-#I%skf>tpH$as?~ItAdh-6-yFS@OoZ$~S(Mr1P z`VMIFqRI$8?sSbjNBU*)zUyJ*$>u}BTw9LdATz{oF}IG8jOWpdD3 zcsmg;hSM*;l$A4v5Z4u%jD#(i!iST?LmKrk=s4sXI?y-lAI4wbfg#^?UnCHT1crO3 zSHX+5e9Z2u3QYq&a8ht$S_nzs*gGk9oJS$v*ppOMb_Yq8$jhG+LV8cdyFjawiD*nyz`YB6F&3qvHw`F1)mD9>9Z~kfe4wsYeZy zf9pnY+hLc#@UbU$%>`4lmwxh+L?NkMV#G*8Qe|iol%{uyLyM}s@%G*K4o`$`nK^Rl z(vjIy5_fd_?TJ0!iJ>`$Jm{z-C`;W#`~`*z{rj1ivx9mAeHww5ENp;Za9DTrufhZ9 zL#ksd-F`IT6fUJ2RQDj^FLd>GYcqyQIa6Y`$QIDLa|B2u+Ay@La&0{m0~Ru%E7h!;RrTtbTs7lN|^0^_Uv75oD7 z)F8N1)~*83gUQ{$?^ihrcZgeDXE8ibb&vgN#kbhm@J%MnW4;!z%j?)LAIJy<_bSJuzZLws}C@;u*? zV}Nz$b)I2=nNW?=Qn$@^Ts}*SOC!d>i~@744d$u0PP!bH-^1 zbznQP&DoB857v$8uca@r&pJE%yqCwkPsSzd%ztcVRM0*|%jPPc?aT2|!8BPV86b5+wNML6 zKrC73`>J7R;2#G657uDLfa8nHpu{)xgR?<+uKAmd%FcBfjr;uly0i&f3(bTvY0qGt zvQ0N3+Z2^utv8F^NT@H{NMi)oLLQB9EO5$a8Fnz5$*utp2^ zH@b)li9p+{zzbN{)W;w_%O=Hd0Gek`tWg zxCDZ{oqe6>Quwfyo!{_VCXEaLlmFP-M6Tq3lZSiuo9L=Kq>68jGkWT5cnR`8{B6y| znHvTUB**||r+UG@C1t_=QCbr#RR9aAppkV86hFjIE2nT3Xie>S8bH!-XE2=j@4y1*gR!{As z3;L{`bwxDh+7=N1RlLuKG;9`Cy`3}L#(w%O<8#kJDX}URws#sk#%7f{e=`^--IU4* z?vQN%Xnoj7vWZkG1SSfXz!a#`8^^ZwFYMjzRy!h(jaob21Aq9_)8l*F+H2289y|4h z_W-SEFk!CZJ!Z3EM^sANS{v+e%VUE$6vxB*}at}-Kk&b3edg5ol{fLV23bYd4!R|9y1Xv<}_ zGqP)9HnTi@RGF=x+}&p$Rqw3*Ze(YCIWx9+^aK69zqUNE_y))gQhA7ywlk!k$*}#B z44cl7U%Y?8NMG3=dduMUDU{|mUjZD0b{t^sYM0rqxbfy!O z%Y6s_rQ4b+T4m(;K{gVjzCH(X0I71hLfvXTN8Od#SS9~|0si?VIQr-`K%!@3UP{H4 znYN1Qb<=|6g&;QIeMPQGW!bq7NG4=$2@y6hvk^#>00FQpWvo~QDvhO58SuHH^vqxB zcBAMbErtOs@*#&Dsa;v6SD5<03Na3)z&+E#;|lhh)82>lo*B5rXHxWZqk|(_79Uk% zs!>;&U;+j^9HW`JC{H8;dGk?*gLX<8Sq>2_CA6`OG6x+Zvve6?J*70f!kfw{fRL3$ zBLqQU8OTD_P<5g53ZDIimE{Z~B{Kyx2itEsW|}cLnaC``{L!-nC?xFyNO+dYz`VJ# zQhL$#%rlrKg@R=k!EYLi9%%K`c0ti%-4^QuU>>5vcI2q|CYJK~wY95PozN@|o1$C? z5Y^=h?AzdA;zv@?e6}I&8A6|&#AhG?mi*CPP|thT)W|xCq@?_J3_kuHi^_Q9ky06G zzd*=C%qdx*h>v?8?GB(-Uf{J;}mz$5r~maXSK14~Q2o6fb1> zCfaEgefUqyFX)UaBob2_Q|DEkQIm&p4H_GR5ZLK>lvCq>QmhyuD+U-a4Fi!j5&{Ch z1-Nh*MYXA3y;>};kw4{JpgYQfSVPhYZv$xX;EFI3xEMQ;le$10!rYFzcA~hz0y6j~ zL1U6I8-hjw4JGgk$Ba}G(nWR$y-{VQLxl8aC=}3NHfa3r(p;}sAvgaQRq-sMaSs_o z1O4NH)GsZJcef4<^j&Q0h{twhqOor-jt}&8w6tK(wj&F{KEJ!w(?2r*=(eC6>k)Ld zBYi_}XaZ@ohZ)+G6A6k?6yFsu3HLjS(K>a9i<#OAW;vg)(qAoSBd5F>21v3)`}S7d zN=?67;ZLCsu7b|xYd|fqxZS45iMZVK!@T?iT4nul78=g+i>D_V855|hEi>w6umq7P zkg~!h5Qbb#ov#y0EGh#u8t1sI4p}bkFsQ;gyzxiS9RZ4ZP3r^-;)jLFGAYTFML`Im zMv3HWRW>r~AGJoO0r%~l=vzK}>{tDLu|A&_C+4R<0=aCv*Q4RS!119y$41>TPrJtZ zid!;}5T3`J7P$gElFh|QEpml=9umQt3Kk$( zP_D2FTCivs+r}83Pe(+-gIP@knlJVK`gJsyLv-ylsxr1P#*oK&BMH_K?3HFhY?!j1-qj|0OgD<0Euc}?umxKY zr_obf0g@oaO9{57ph?Ui&ri-uCMnrMOt9c@01}g@4tF024J5}Kxw4Pgx=j3>&=z+JG9 zB^HC6#2*$8^v5s2hT!0RSZBVfq#QP<=t=wFn=_`7a_w;*qE8KXwbiBA84 z_*h7InD0*Z1U>U*)umPfaTreOjy-!G-Mjbo@R%#IW4`=l+;2f$tEi$)DI7sulqL${ zMftd(jW{9FCVs$B00?9f^`vRMBR!7=V2F}f-g@d8^YGjYB=*nIigWGR&dyKrm0pNV zPsg5re(rOQ8OStX?qjwv&>Y8A5C}V>M;(m@W*tV$2G#qfcJH6At!I`G%^D}RE#9rt zt^3l``hlc&o1pDa^YTu%x zp84I(^34lsY-;zm*l02wKRh=aj;ChP+9pkP19Z?!FK2cfZ!uAYY&_;mhLhcMhkIi~ z>;dP+wC{%=67ndwN7rbJrc)($0iHCu)ZNdjsF6*rSVV{58QUjNg-vhXc%*L21=vE3 zg{|7sq-K?W?WUsFp=y>kHYT-A3YIqtTcX^lG{wuJxn6?V53hW~%~|alAU8AEIaf6E zh$<`!SJi$C6w2uNQuo>-DX7A`2AYtaPoWHAQWYxTl4wd&<|;av9yTCn8=byHISDZq zrrCcE#-A!+l%{e_{M;#sv=&&n<8aWt=BG3D>|#rMcI?sFlC4Gs0S5&Ap^!gV2Dmmf zcE^UNkTL1%cGC(Dj|>iR&6qa5^+E_xAHfd;o#V3f`{hxF0|GST!nQ);4$ zj|N`3KVPqqP226KmRO_0+WrfH#8taqO>>J2p1b@I8{lUNMTP(b-f$F8Lcc*^Wg<04 zrG_(OwMwAQ?jDRNlw?3oTo*Z!xh5XAtVX2fxEOAiLT#Z~5$!Cdtk+11!O&G_8 zgJNvSqnd}VG|2*Vzg)3U0K>)>sCO0qo&1M>)=At=1T4d748De)-5ux&iT0UYVh;41~`RYS~`lS#u zVI*1^z5;Cxc>yk5xnf;_??v2#ENNf|nkrA|1D*v*u|#59CnKQ)58s~xj_u<`Arr&n zW7jSxk!KWsy$lbqv>|7vC>i-0(@<0DO-((Do4Wd{Ta@%fa=c>yvl_Q=4JcDS3kY@{`W*9iglP zO#=g!enzGChbMT$2?)?9xpNZJt%xTT)l+C%_zV(vX1HR=Q^Ye^=O`4zFUk&#^`>|Y z(egl?q^};mPSrIHYPN*eNiAeIwf_&)7p~l@(*ZBp9Y+4TgBe;-TLG=gA=FqL+J8+% ziW;aEQGs_5vC+)|UmLUbo4Os~MOi4;n}oS#F}2YoJ^TS=U$$_Txl_vN^sh?G)xNA| ziD>>;Int5$rf_<(bt$abNevkuZj$kaE?^jIGV;{Japq(8d=$}idDb?j5)lm=;eVC-09WyF~AC5<0_*^I1tbw4fg4lp2 zLs77Bzw=9~afwD`N~^F98x-8cI{r}-I$Z?=0cp%5vwNM16eQP^ieA57TPJY~d$02g zoBG?bjvzq|wv^G0=kTS(X2ygF1(>SVP19)V^=8a_!DTy=Ah&UyvaC+_mEJueo#*5ilwzRxy5!#iS?`J&Z#^=<;wnZSJhvA2NRGE+lgquuYv8Wl z@p13AZD?{!Sh!}CR9sOFR)?xmGs_#DKl}3Yv$n-x{40hcD`9<<+n+TmkTdosU7fO%&s+Hd&Xv)sCsCK2bzPrjF{s zKaP<44I%IW$(Ab%d7@qKAT@*wEo1)#dHM-v%RR3`2(ck>U02*-ulPSLF;o|)R9AyBbOT?STJr*& zYmc~2xXz=(=v?@Rz^nsY2ok~~uwt(Cjr_t$DiV@N$51ec{>U!quf;{Kf(N<;Ng&|P zCg!q>dytVkln6DQR#jgtFybByJcxA@y-^emPtY{BUgY!(j}H3V5`)I5`xWj{V=&R? zAFNdv837~w$&;b>{;~8}e|zX;o<@0`uNsNLwtQf4Fo3uXl;d`rvh}3koIIH74#fuj z{=rzNJGD>Bz;DV&`umTRog?XQtt*QZ;;3Ys17MxF8@*;Nd%4uq>EM@ks4Fc(fS1ti z9<-^;M|Wc){VK^}7D7QCBmF`$Vyqem4sfF~5=mW5oH8DNeEt{aAAfuYv~LWEr^rTBj3o#}q|Z zG-nN(|4>ny`Z5Ty6xE9J22e~Tx6;wq*HL7bzFx-X@nA4#7@%-6bC8^^T z?-zviUQ7le!+~VdKQio3LMqjIFM^thbAY)+m?iCsaDupOQsLAFM3-E`Ak@E^WvQQ{ zuZr)W)I(qthfRqt4=jb(ZRmawoBUHTI{ zw#oqhH_2qLW$sKOOO*QY09bNf$UegJXs zU#;aLGp)JbjwRC&qDnibj~au~@rQ4D_XFvr^Fn=0P>8C?QFtD7(t5)>8Yt>`gz6{R-NN6tHy>y@roxgLTMNK8P<9ie$H;D~gmn;NOz zKJQ#l;T|j`5pV*NoMX@C`|RVOUA{IoA?xE9^`G8gS6BD_%?)qiL^nPeZ2fWz&n)BU zI6jN`9Psrbm<7MZc3t+C_=Dx$R@OT}9VhTyJyzU#@FZg^j>i#_9dgJOhs&k;gQT|GX*fSAz z=kRI8hUjc-+1ujl>GcnE@5KoyNbV1zLmrTy>*m(mPx4GJmSX$|T;|yA?;22SzTQqL z^93}yCATgGgV)gwmNb7${j~B#Y9ET6X=#HN=Ic>=y9fNeJw80W4I&Fp{7+bTF{p9z zqWn@1;19@|b13EMApWhYfv$FD_3>Yj3z9Hfcb!8DCJ>9bfB=$1aAr7*g{|&&Jpf{G z#q|c)kGY<5z038}t`E3=-u27mh}w_S=}4!$oawB4#5vNP4jv}m=={d{cJ6YnJ3XO$ zsg(zWvgh@l-Mtg-XUimL64vh(LL9K!KE8|P8zD`=j7HY zxs4PG|2Q=M0bfcF3Z$$2MfvffGh*~F^;Rv*T+tKhq@4S#ocWtz@VFeZlPa>Or=#vV z-I*b|^(ncE@d3ObSith>kAc|lGPpYqxcq%V}j#U zF@!F(7)qDpvREmm)T;)&aLZ=c(>Yi_%$;^yJudtZ0&@GyQ;v~|22ep5OB#1rSo zq6g2OJs6eWbOs*&$%g}6Qo+dp)GL-LG8O3bK|IhC1Y$_nbVwWU&p-|%oxCR;8J(IM zjr?|ViXn=+J^lMn?CJ~th;q69cq@Cq^Qt%OhMH$K>9T7r**mlY|HF!EU_^V&KW#&-))z{ia)lamIhVFO& zEKmH;7P%PQ?s+ot*1&M-t=^+A{>Gqx?6zg3ki0GYv2FurZfU`#b`d|Rpi+Pn&-F!H z$nhh=DPFGGQ)Iz`4Zb3{gjq}-ru?aKlf#M0os*M0OB$09XYoKleW1-yX000YU9mZ4MV$ZF!rs%+w4It?5Pt~jf! zVJ`rzAulqfAgbN~Tms_-^vdQxWRt4!9%XsM;%9HrknGG4ouVee4xqNm=VmCf8_+y5 z)G+yQ11Scyy5leuSUw=RLvA;7_Ud)mf1gemC8wF#8`=jn5ZqJE@$Qn&7}bdQAe$Y; zfKRhEoWbTifdM4nt2TNyCWa*wIj;llItiGz#aNLs3Qnb02Vz z0-5?DVZGaAd#-7}bj!p0rziS+1HQh~moM8|b@Kv3KP0m2FI_r1z2xuh4)pZ-n53RM zo27nFj5aesSs-)h+$~ho+*@&)oOvXmsij2w4GV|EE6r z>H9t-C*5dDtpl#3AqSYtpy8YV{XEl}@%Z5efuZGSf+aT73fx{+R!nn6+N`2yQ3bBJ zX01{zVo1YKt>DOgeAp)5pyCVLHV&hSYcOJF##`d&zEieOf*=prZR> zi?xcjuzYN6LPE7U!EWp_wobdoLFh;cTa8cR^3Omtc?KOy9;$=tK&1I!QY$f?j(nbh z{oW#vrIk31jbbo_X$1* z?!pU9dWaZ7>yo=xDVK}?EjT`2q(6anTHs8C(VZd;Z_H#Dv*MDT7z1jGI1vbu;4dCG z{v*4c3cmT*Zuj+iTDpd3W(J4MmOX*?Hcy*31dorS!x+ju9gT5GFh&uiqC`djjr(p7y>@d%d*$=cV$!{R92IecglO zgMIDp>0aMpIM6;oMeG;w0=J_U290wHRv6l0&?cZw;O+uhdYc6%px?d)&!`X+aIUbhq; zp57B1Xm`8Y2O|4HXAB^xq`sUaL$E||@LF?5j1XZ1#uFR&t>}fnFlWW1>#CWnt<$XK z4eOxJymN)igONVN#et5TaQbOHk?E2rC6^u=nFh2o$OtR>jg=A&?mX6p0+DO6C-ZiP|2p&V*gM@+p>S^4bx8Y z3*xfjfp&|i{U_G8c%!49zeJP`rLW&maPw0mmwdsT5w2i+3+-(Iuk=% ze;_zB&7y~riOq0DExgMu~C6<7<`0qZNvC;Mh1v$qd7bRzVC7!)C~eDq~0h_+cahj zC6(_{E9#TJLCzSNtlW9IW@5IJAw6~CY*(G&?d4l+>)y;XSvfh=?b>gZptU~1pb|(o zVxsfm*S=_Ol;te(QK!YfWmZb$-96;2iwA>JM%c~nyRH^`D1OyzN>ibc}wU>&<0w~uu zPyyS1_{%S;f44yYqGw?lum}U@s1Tz`Z738>pKd9^g_jG~*gZa#F{$Qn2-onRom{-z z4%e9NzG)iC+ct!3j4zxJIS~LH>cIF^DE|uV6}l=E;2RPI1BJD-0AD!1d{1+51A%Bd`( zW&lgJV=ov=;RH-W5QI{T*~g;e+argboE?uX?0@Y@yV*KCaG%(Wf2(~YI^{k&?B*$T z%00}Z=)^2;-aZ~(*nekKF7?QT!uV|XP~d}NS`Wjq9rjhf(_1ZAM=Hi@%XlJIaL-w=^ew~nANY^u&{l5zZLTi_qmZk(z_?& z?i=<_9PRGJN#98QB;evk|5Ar(&Q%7tX?TbL@z3Jp7=9@KX5kYAoh9SJH_^ED^!sL_ zGaru5M1Ncws$49N;6yH+!YNfmw!a_2A^xJjD?QMjelrg4Ef(K}QwXueC?i7iCjfaF zH;m99S^Y_Jzhp-jJPWOvgnHHdkinG_`loKHRiVR{EOqxOtPX8fDlfXIP|j&&{lsusX`^KUTS=fT>WzZwvS>rh;ET zuLQN=Ds(k0Fhx+^L6CHYT(18#BmgnA10a+EH=f3LX318?MB_v&6Qf!fupMEDWVYfX zC?yWpSZwN^_j+`${yOgIAT^Jpf^Rz@ckoXxBk6)1?Ul@`dj&b)BWFI> zyluKlw+}S)*VWfC^gJM41H$i!-0#DfK#(2Qn8T33hVVIJ+tH-5^f*{DRv(x4O)>t4 z%a7ZRz4o`t#bW8626rFt$rt&_ z=T!{9Py@Ba2p!Xon=vS~FoAr+jHUB9;s#^Ku{Ab>|9U~ACKCYbjhQF)-@NZYsE!(_ zkXQl#pgz~P&8&!-uu(bI&$Y!~(J|8SHxOc@uBiGVycGiAeWOfM?+;=oV;(!hlj9os z1X3bqGmAootLSN=8_T-k){AO!@Y$Q=aT9+XSN^dhKH2M!Uog#%!DX1&{c-=Gdj8(p z7emh;i$9RbU}Rn?#r?fg@lM0I5PHDhi-n@L>5OI-V0IQrR4=Cd2qlmWK5)P~>XQaJ znlNPoQUOjPbS?mjG?RZFx1=f%|CZ(9an#}k%evt2MQ$)Wy~sLrL9g%Hh660nM8@0j zaDyk5!%iIZ*RiSJAp={?4GU^ioC%vP40po}yS#E^aht(phrX+u#f?@M^mDSWIg4H^ z2JW-)vc-T;yV7b66qD}tdNHgNQklwn)J~kFV>ED#30y!uNT~_3RH%`MjHrcPJdgZP zGKLDv6aYxwd+OB5sMzn1iS0fn`{O51p85?rzAxwT+~w}c0#?j zRH7MWNJ1>phWOqbxLOwW0SECLadV-vd7Z1WfdX>nCZB*fr0!lUw5%BeAG29LS4gG+ zq_4}20}A|h0|hL_ksGJB_HCXv%?r(>{reOro6T%JVp$$1v^4=nX~1C;>tbOt*#~sQ z&CD;7yUI7sj~V4ep|00MQj6RxB6x4>?5AFNtbBHi1mV~EP{OV zu~^fGU#$U1jTx*j;7JkFgGlCl@#$QMJ_F}xxk=r;YyWKe;8-Nu^VC=@SYcH7K7ZQR zi!@fFq0GVj$kAYIYJMzozI&`yb&i?AgJa!bj{A4T(z6l9hwqDw85wUhb9nsrNM0cI2o8dbrUjg{XwJg3~IeeHB^>>4Om{+ zH|Xo@^MTrGw?=>+@i_E3@_1;_NLu(y8+w<%@rZwbO{kk*nb5(s2E>MH+W)|3(e&3Y zo4@q<`84e8$N=*6J-0mk@GbXb&Lehs|MXH*%{xI(g_LpxLU6jFs;Em&j3>5^xJJgY zDN|QtVtNUH(ReMbV7CB}+8c^xNCj0~F6vx=M+<@%UL5+kS*)L=wWXoYa#{A2JOTq1 z)=#E$kY>K|AvD7v=e;~-^P`Fgq5wpVckY7_NTi-E$Zf2Z>mtAghtu zIEY1kF?Cqx&OdQogogTx>gQp;d*WmMCLCVdOCrSKi6w~N6C&qGBt$3Ah#r2!_`!N> zi1sgUTUy#SJUKbc5BJ3}K|6%plq@C@?Ht^9$5L`~cj_s8lGullquF{cX*ZlueOR#& zHwilAh&}K@N!cG&%sEm_kRi2<*filGOs`>W&=lDS)4K@4y$Bl+(}1yA>VA{Blmi$r zk3|(!CAWq|4@VYA4+_vuen$Nv6(eUMutp#NWbWEpamO*NA9?Z@&Zg71b>uTk=g%)? zwHd=y{{_D!Fz0f7FM(mx3IYsC&`Nd_rcK5!@fl%;rOh?83& zoA;beugJOzdCPtrYS|S0t7xpx+Ht|^q7xq66#eVx4XG*uaW7s}$PJG#kZ5Nljesd+ z;J|wlEi~4L6?LO6oNX|G=o&9#f2O55wgg$ocnR-&bn$FX2wpcRIb#O}o8ksZ<3o^wvDkSND#94brA zlT3zBeNw^suRfXRHz+^M!RAOHizIR$U?DIE8j|2M?iKS9EJ-{{8H6Cz@AdSwv|ad} z3vDgV&hV+b&!4^Z_VZ^|xv%y+eJzPZOP|^;-`T;zZw?OPDNY=mUW;M@b3TF2pnDkJ z6@nduh~R!c3KvjB61@#S`sSc&Z`oL0?(E0-oI>N#b{(2tLx_xTKGqTp^tZUjW?Paw z_O}G_Iuf3Q$Nb8B@AkWWKDYmFXXjgQ%lG%^xl!eTR{z1b9P}g6oV^q2+kJU=A2)c2 zWh>Q<&LWiRO!r1-!QG(&RlZQ~D-gu67fi!xjD7(MTxt|V7YjV#?HAGHNe{pRj|YgG zKzC#XOy4o|^DCK5egW8tU0>G16G1r)3)(Z7W=9G}&20{mBSKyqBr zs6$YF4uef?M+bn5qj?;#nlNvcY&}Ds<*~Wg{31LhMdpE)b)%SL8tX*W;R#~A0L3ew z@%3dgeZGRfHxoB{{ZOUrB);3SuGrBh%fVnUUQEY>7IiXzHi&K7|Izxb@SDOUc18$A zcyUOC-RTBU)(?@Ll9A)qzS-U7+m(ZR51t@f8s5UkqxSUytU405Mv@~V4F5Bb!FOF< z0~KeSW)nC9Oq#)wSR={}hwId$#=CV?=J5NA!^1^xY^+;HWB&g6n{Pgk4~q3k|9%T^ zAuAcX#KV_lARAnmUuuD4aS{jyST~n|OJzW@)mvspM?={&b7njm8(JCy zzj^A^si&WQMm;ri%fZv3orAI7@c91uCExT-cief?r*U!b(@#H*#yjUa2aEhV5V`>R zJC44Vhi1f$8P94Jz&F)^cCi%I{&VN{&+OYbbI(0*iiM)vceM`ybv@u~GuS597MY|j}Wnd+&Df$NR7c*QlS@`kgP!Iy3yaI0HmHQL_-0TLF+QJRuDC;cY`Yu z^Rnwdot{QBmNHUU>VF&jwc22A-wrw9x6wwukQ9J%WHTY~O-Gc|PQGLj$y6&DE!1@I z+K_@9aMpO@cnk}?i#Dzfwf1+v&)wA%YG1+L`#U?jgYC614D@++-1*jzhyOnbeE2Y~ z54Ih^b>+ftu${ZLk9*<+PiP#M?5YZY4MYb4TbN27P=U>oya;&K@^TS>1<_+9Jo<2| zn0jt`d2tb+isQXQ*itfPItf=cmyKM26jht)yfRSm@#97G0G7PNimE-G3dy3KvXAF$ z*YnGA7D=O#BDx{H=(WcGtupgA{5YBFgkUg81bW3o(I=5rNc8}D2-^wvSL%1Z`zgrp zX}BMxbK#%c_g!^i$X)wj$YXtX-=}~)=M)fKZ}_|We!~;0J?jZ!I6G{B)MpFd#&JzH zKs7S+%~FVp#e>Gc#7gpx;0A%j7vC|xV<4Hlqlmfba=i&QwjTv4in`87=rM&n$s0=- z7la!xE~ab`7lyb^j7dIO*irbOk_1H=<|0`@F4~#a6lfM@4e^Odps0x~Jv*_UbC)O7 z)e&k@1JfPuwl|!e@&|7{tA?X~cWa%$51?)k>)&4v$@lptXlK&fC z%Omd&!FBXBYwz!UU!^m*KPKmSf|`(%jk=V>1p4*2Z% z^Y?r(Js3JZYj*c~(=*|rcxOv8+|`=i?j1;`)o4$*>hZL;ZFs$2FJG^gpT@bVcsgPghZ52q9?$00Ht$dV1vaX zk}3E{=uIo!u>!$*?!^zaw7lnXPwSiG(WUpaw7m1ptv#2QqQ}8}+9VRF>K+JM-uB>9 z+dw5a;I_bwmI4E{kE>hBg481tG=x#6(;9JgIB4a-Bt+2zUAGqy!03TQ1*r;=9Ny6? zO;K1W1U|y6Ou)e%m4-zM&Z|YqH3tV@D74m#E+B~xi_<1UTY#Y4MtwGfQYC5~-`wZP zR$jmd;0G8GJbPfrg3Ae3Qz=)gPy^v+K)eSj>CJQ%AEZHDOG7NwN%ZM0$VWM*F3Kwm z&j2PM8Z@54=Qtm+TjG$%lpme*G|)j!&*dulO0JSy$9H}uXUG9;<)vH|*W}+y9w!l8 zFDiSUOqfF$7D71VH932RU}a+%JseVN1*8S272pS1T!lLWZ-WDY`rpvIJQ$T2^T>cK z%fL?{izy8GDG8FKsv24d0jxk0;;&5}HV?zZsX9{A6Y+Sm#kh6u=%q_XZ(SG&$H(He z|HIw8fVXv?XM*?v0w73`Ac#9af*?Tx6b?v=7Z9>Ykw-Fhu_#BkfKud3=!@)_aBA7L z;%geDx!AFjG>JnxP18ilOw$ZmPugzXPTEexI-Tw|O4BAOIhkad$L-9vvtpZcyX$t+ zox=OR-;V=Al++MJkJzfl*JQft`s#_ny5vG3YHA(U1-KW7MniboDAgR$}C=TvGIC^es)k z>{gnF)rDjxiNtGVsbrY$u56i`x!=nqGjH$CB)@FD+rKxBf`x_jUjO~;uw2g0p3Ww- zSQ@&y|67{7dQ`!?P-Y#Mx0VC_L!m3V1D4ep&C>#X46VE~ceGZB-ZZChC-{$JE9O(! zc@!-bW@pusSU^(7p?nZ@=juucgiaSM(Z5N-la$#~?d9Xs- zZEI_(mmAfDdOSNtHxvE34qnHE^T;=!rL5M7AwlX}JUXdbI}(WwifM_C<;tRY86P$~ z52S6<)Kxn@D{p;031G;{KEc`!q+a?gNy$^s7Ty6DY z5}!eUNx*RZVWnpgnep*X@IUs3W9Ov6^?bFWH&h%BxLR8qTG0`kr={lW+DMYT_4 zs3wAnF$EEoS@>EbYyiS=46E)}lwJngto&B+gmmT|OLjcEz<^X5JG*mT)vXzx_~I59F|`82jNRWg zU)VKOeSPmB5MYr>nfh}JM9MFSgk*C@qrllLizXNeSQ|U5wvhLMzi|;kCo6nyu&W!F z^0A>A!(2uXB4@!G8#4{_-=UrEuEC7l$WP*kC@Hv|%?iIZ4IxSzv7^XM`%W!uh1<$r zaYGFHfqXs~#OwUjR3bh#6<@n9CavV0U_KsC$a#X5;2zl_CjW2?W(^4AE%f0QB5q7U zkY?F{KwmvHpf0^Cv3GBRuQKlduLvCv1pQuLSB6T+mx;YOeT%{TI{SqxFbDSNGs~kRDu6 z07kUNArf)c3C+POBNs;11llX$RzM9G*c|44EvglQBaPMsTeQQU*dMS=if}r^psTLE zqy0w9>FGP{!OMrv+XKh<4fPtnXMfxX8&4SFUCmPxkOjZV7~`%^Bo2p@9qo@+)cyA! z>-y$f+ud*<{$#nmIXL#E2TsRUk9mg5^PYUT3{3yb(=Ue)cEO1D$%o_qo;LpysHq+u z>d5RhiWcN6J5~!)Jj-;%OvTiMp<@A(9kQ6{sMl4A1=}%Idwy)*trN%4&oqP-R-jwfbQF`A5?8AM zj2jmvO+jN3_;`U`Rlf~W?2|Pc3WBxfau1bCu(v+R1l};FxCk(qk`ac05Lq&u5)fY~ zOBqvK=lR-LPk!cDl2bGA(n|q^v&!d9-1=XH+8=$iJ*0vXpJoXUIx82U3T<3NcI_bY zTGjj-Sby9&dbI5E<`(|7%e4;YgmwLP88y35V#@SwAHp~ELX%wOucG&Tz++f@8csz! zT{g19|ETZQ{3T$;&Sov*S@#psLj`4UCXX!g-REXz&h0xmk~`@2PB(`GzFn#O?2!Mf z$S*&WPoCQc3z)iHyr<@IAV2dQ&fa(K&e3--;p|TDwAZ^UWeoX|X=MA`-xI$mOqvpi z##-Ge1Wbl*Xx7TvCY~~NpuBU|&^lAtuG5vF=jqqQ1odxaYn=V;Sp*UzMtHRiTW?r} zkf~SdGHWH0ytqt=g5x^*!F#ZSt0P#jYTm(W1^&rSIjH%G&l#tW`on%9*NZ z3-{B{qB#LnSSTm~DT;#2aCKtxg(6`$^1o*>XIvts)pp5}i-1AGu#r{&Xi)he5t{(>ld)qG`55qjf{VKxNz4aTL`AZLg6 z=c`~|)Y~zZmR7`1&-LnfIz9est$}~xXJZm#czZ&riV5c7fU7p_7=+ggBn==IX&7P= zO;%f?Uz;Av=8d7Y;lnfCVPDA6>UhY=EQ*(+I#B(_no+rAn1$R#U&uak?-AcEdf91z z5vI5TIUC4^BCstLPz)X~-F=AqSu^I3=2lm+Y*1zGVk#91rBW9Qx$;GtDKC~m6t$Id z8JY(3N3hqWrW2Hg@q(4iMJ=btrNGYGwD|d|@_2gPG?lr&LWlOugb>$R@LBQ=n70SO zIGHkn>Kp9AHqVDM>+6{hwft;)eLcPAez<#ix%k`Qd(spZ7f=VpGsC)T63suvO`Pc0{&no9QJ z`jh8A6dL~A?&?-gAPFs*^!gvyQB)YUY)1PJoF%Vo{ect+Tt(IggV(fdD9fBACZwIY zwv+iINDfwZP!%8`dZ(h@x?-KL(=I61!RnQ84ulZjhwD4&Z|inE5{`v#$}&>EI0;0Q z>xPInov0vIlibjN8R}EVB8SfP_TF|la%?T;*CKOglza5Q^nd)!UgsO%=-hi|^iW@1 zoIntN1Wbrhf({Kf(TnRCF&Lr)0esQ?F#If2|I$F{j`f+#Jfeb%-oW z>y%o!)EWFr9grY36jjl;YioR)3m_9R>on--C}S*LNspJ2p${+vB2+q~CJWwkifK;% zJzP+e_&sobeuIcZ{}Y5BHac`ou?Ptt**vbZ`vWcjz)ycQB`qS3p zWla=i`=!b%<<*enyI8G+b4V@K-O@4ui{y3o@KD=hD^ec&N;^xDBvaj>NmKxCeBp<~ zwn9S1Fy;^vw;LPg>cXlC2+vjqY={5hkQoY_uv#pru$J)kVsK#1)3K%4i}aoXl*02Z zh`?k3RG7nA^^B+bs^_f}nN&xIS%H3Uk9KT!MD6tHy^@Is_67n+jJTSsKGhKlbqM3t zqP81qW|4x6jV?N1yzYr2`lh;`6W(VP|r&u*h9TOUvD_o(!`w2O)aUgeD3iyG3#lQ zr{}*ueEi|#`2TQiO1_LKNpun6otBX6Mh6cF=fRDz+ojG2=c!)B>?pZW2wxyJf#m9s!_ySYwWn_g0-$)EdY6`_e38qNll2la$s(I*+`q`h|M4bN32Pq; z8r*gT)&ho(`mOG1%)K$7UEwvZAC>X?G9YsI22UV9(nsnp#R*Q%L93*@(7zg zh+^Mm!3=e-zHts++cK%FrnPgA$Hoqo1g%l6Vy|TOHg9LqD!roMJX!snCu05SG3lqC z8oz^gmaWFf-EdCpbA#lL)sj-0CoVj6^5jDoR7v>c!}C{;9lL^&wzN`uq-Nzg3UG79 zoJ%w1G0>0*2D}k0goiASAit4;3mK^9Rgp=gJDxt5TQex%l8NVE%*63WZLfxO(Ek$C zT#H+p23v>|<``)U03dmhx>)-x6M&EM5?KIK03?8a0C@06Oi1sdP$b9<#7>4`T04Li zNAB* zkK$2%#%F42hBIRkhvR!9Dw-k*_x;(e>+9>Xnm;4zoC%XJg6#iABnFF-Y3&__=0cI3 zOB24D_~S^`9G{RpwhXzU(S#4)V&%^u$M*?f55c3UHjhZPd0mWPFGdo*Es>Gpaw(S7X_adm_x3L)EwxU{U$D?Mf$1{9uPpl(xE_NtJ4ODjkNAI6L zhneMXsBLpl<}BO*rpIxstDyHI}2Hw9}!i~EWEk;IoVV5CJ7CtdvFM4T$B~~ zQsH@d|NT;#w1%%OSPbeqH>nE+G5`SoQ#yA6#N~(4y9<@V57NAAD4CXUh~y&e6SxFS zz({Exw)g~sUce6s`(SPU@u8yub@mNsRp1%XZa#GB!pWJ@(V3G^!cQwR(A}jxLcC8r zeEh(D{?SqYeFu)$2?!rqoVBwsO@LzKnr=7UD*=ubVcdMJwfXVNBM#Y?|9y{hVrUa9grQlf=(>p20W?RfyNvm>tXhR3PTZsYJq@PbX7QP#q7MI(Zx6B^X_|R zbF=rlt(|W(SZ7RUd^+9ug`A;uERV7+f@WQU&gR6Vhm{R}UbaiV4}aLFHmXnhOw)%u zD}(7S3$oJ&I8a3Q07(xNi#``zB;D>|JLb?BQq2QzUD6r<*UVI^-8c+dTY^EC`VNHz zuJiu88>OdHPIG-tcv}f)m-4YK559lV3YC z({tj`zD~b8a&Z5to*CSyg~-vRP#21Dr^kzv(6-$*kPkYMTXOkVE*gu47n++h&F&Y7 z%o3~yTn>BD3(anv{=#JqmZDw}9RL2wh=T=G(L~77DHfay;|pa0cnV-=C$-cz!=p22 zfWpNySGHxZ3QUJ723wT(XX7m3C1uV<0;9B10&iMFH~IBsg^*k0?I4$s|FfW*%2rV( zl5}sP4#7ewgzCdEgadu5fF6VWfyG(gXn-ki7&mTVft0N2unSLaYj7jt?5ArTHtxe; z33?p5|_=P>fgH7ve2JMmrZo1TrG?QDxcBqxq^Hd|2Z zpAPN$2oqag}!0f$WV=8dqW-V7#r+@eNJ+}oBNJwC4~u71 zqBr3SG5jUpAZFXc+17XX;}?B+WQ%@>F)=bw?GU8L@|$8;0i*>20aqCSO|VSECk39@ zba5GjKYiM|g-LQD=uoP1U}oxIZzS5Enogynk=`a_xVkWG7@zr#jg1zO{@y2w-AgY} zgn1#-8*NUdnxnmHxMOap`rlM^Xs*M*T-FMrRs?Z_T7TkrQvi)HIN6e~7{pBx6l_u0 zcAzHsgCxN72XunNhT;(Fl(uXj$g+l+S56blHgYF(y8)Yb6$;BDU%d;Ix3nU=b==%A z1UXOicQCP~wUQ`rF-u89>vaDduQv@+3iiyogsws^XH*Z_yhCo|faxu2_Mq0PakUx)3t3 z=wSd(ME+LL>^N`tSyasWP#WggTvC?)(=Qe(H~QG+z5!P zTK9NUA^h`twsHmR=df3<>`v`gCUzF*=NDnUgEYfWsTB58i;L)fE`FL}+5Jd5!RNB3 zAJY1n@NJ__^Te$eue`c8%)LEG^4BnI3<8FIAK|YeM=}0YQ(@7+;Q-Y@kpp}3Gx-cE zhM;apCSx>G!M_ZSMG<=1!-^r^U|Uyc-@t$x*hvhx6E$fEWiqi_&`pSR&lW6um^F8^ z)S4>Sh|U*2ZT+gPnkENHdklWK8a$E^`@d&tVvT7PM%qVZ1^nmK!P@+v#t+0#v( zO+#w!w*L5Vd0o6AeoJQDTaDQ(dd|P~?986i%?A=N?bUHpRD{_WPpkcc<`ao8lSR@l zg*!wX0Xh<_gz0G`oNN^A5j%VMrtHYzsk=`NPLGsI2TrT&go|F`2dv#9AuBH2V0t_G4L}3c~k2^Hlf3(jOYWKe);`0okxrJU6RfJaFfm4^+RX_M_6&hdi-N&&Qw3$)+rBXAutVLWUd;~ye!CANjylk$5L7+pJ%6N@V-TS z453Ad(}X)?{S@JAvz<$CditqzOZktAW}$Y)ao}t@|7(Ys;|L_v!U41s7~MvhvIN?M zALZ-(y;mhx5MtS|W-Xx*1CYi#6B9vBl53h_gHoGVPD+jY5*}|rf<@%8*Hht1*j)W- z6}}-Q$i-_S7i+5C7@LodCpYJd%iE224k_O`C=R>`gfDC|WVM1f#!AwiDyor6<>MSP7WI2eC zVBsP0gTSR%b)EK&g;nhZ%xhpOgD&D4&_$QaWsvqAH$e%gx6li7 znta{%Sn}uf8}8~K9Ye}s*)nAGWl-cgf_Q;N}4SiBm@EG|aELJm#M$k&~kk_{nKf=j84Y$aXB<6TMWTMZIuG2MfQqxkwPKk zJ|ry|^hFQ`csf5ZwsJ5tL9BP+a9h6p_Nhbn-g_u{SRV%x!ED%Y&Fsd+{v~Kb{0Y()yGv_pJ&z&b@Aj(0iOgOQ? z*3H*#*prJA_?B~7ZkZmwGZQe@Lcf$?HqasIDk&Ar$4pb9J z5T1|R>wPk9JS02*v@YdL*xSRZz=+p=-IkO+oc&mh*GZk_?V`f;r~OX-Y^f%EH|}B` zoE4e2@H>#cET|d8P*S4}95?lGM4oMwLF#bS2Ctp(t8bvEZ2?i!zW>ronQweUy(Diq z;XRPQDjK-L;6eF*PiA8y^Z6448yf?^C~JxS7k?rXP!KiCzGsO$um=J1pbakqFD4a7XT3Q5sh(LA$H=W43aXUf8Dh&=!-+ud(p}R@1 z?hbvWr#BV~EsVCb{OesORrASRx8MH6XY_ZUxp!>ebRm{In_C!-MPm$4wOFiM1YxX| zy5=Yb5iS!tfs=&jBw0B|7+{g8E;t71%t612&;qOxvkYSnma)ZdYE%L0I)oB;I2%L+ z57wZyoR#g+`GN24egvEJ51kMBs$UKH{))S*qOVJ3-@>>4X*|AY=U2u* zXwye`nOMQJC^;nZ2Ra#Wb%>`|S@F>Olpfrq8(6U0k)Q;yLa?Xxykjmh^p^6KD=b+- z5D!iuFrymy`vv)GM?*l1|DlE)GSxtMKufOI+!rDf6ZjwI|LZnd-Oy*q7Sn9|A&FI| z(K=WgIm-uJ@?R;7W}KE8;hJ67Aw5mL4r7OL11@`*?@H zc%-}gNYOuA-nJxFjOD|-T{qwC+I@K7cWafj#r0b*t%czx3bopc)*31Si8appH{0Ma z;MGfwuy7NIlxeqt9q84O*@gow8e_e0#|UImnrB=+D_(`VUIyGopeU(=0J*P(+kgDW z+k>xa)v00oRXr8xlZxS|mjD$AH_Tw7`wNCvb5N)usNji$%A=whf(-G$SA{^`)^X7i zb*d$9fTb4(_k^lf)Qa7`rjzEvE0y9hPD;^PVR6r(E6{DKmETqkgWm_=)Iou0&}mdy zAhV-Inm8GzNl%3^ZJ@w}!r2hqW638q$rA#o*4Tz+{j|GBf~PYh?q)|*zatn7p7Tvj z`9@pz4G-^YdAY$Ls&@4?Ia-_}nbW}$x83_ogTV`f!6$sv)4tJ@JozNX)x;WP-}KR$ zksbeo?ydl#zJP==H@qPPgZ%?Hu?Xp{TwjuUGK_)8fv(Yyg;5QBcmLo!L9l*2Kbt!< zbK(NEx9j!}RIQAGY)WU4=W71OJyXA*4PbU5j*}#c;!F_NA+eD1uH101n*>~w0qhPG zHXPCaLFYl3aa^s%Iy++_MD}<+9`BLDso_Giy~Ezxj1uCGL^yUhpII38w6(b3;8n|E zE|&1pQka!qzcV>Ey1LI_~-7JfzM`m!%4Iq;x z_TLAv!40dccA}PMRZEG1q-jbIxSnE2su53e+VPdCUNx+(L14UZf8$~?6#eI zgx9R)kD@n608eG{AY3g3Zoj;Jtu0i$fq;kjfSUOom!dFX;ak)ocHCZ_o@sL$Gzj<= zD;a(EcA@NoBt(Ua^BPvDzm0x4<7+Ff~v^A~D|YA4uTDW6j)uO;CSqX5&V zA-E_GbT#k`w?go9MC;N89ITFlW-#Fi|N0x@@gLtUWW#T9RB^A^j%%L>wUS0k0aNg zSVh$pOyy#l!<6G~$`}o7i6SzY2=v96BFDEU+gjy3Hc4UN1O9o-CS29)F zs{eVOU0*135Nl)>Y6+WTEdwPNZUfcF#9?{au?3EVYgy6^z77feSvsQ%pD z;yr%Lay(O+N5YpQQE#mJDEz7_`I+2@ym43mawfi3X>VC>bvBdN(`6b+as}0^1FjQ{eXqasj zw;v_s#`BajNO+K+HPoyl;9CsgI&34C^ag5@)_V1`zK99Wu{C6eT&6#aM#H~}LCw+x zH~_th1Dl-<9swZ1*$8ZK{03@%c-)@JOip6QrOrK-I{A_CKvTDhb|~dk{HE zg6S@IOKZ9d_f@hLz_d0I#L*`rRc+WrDu;`L_$VO%LqnHL0uf-}tF@l_2jiLUfC_XZ z{WryD_8k3Ut&>M2RrVWu<}>l90^J?Gf#}G{@sRFqx>Mr62n#gF(7S}f0?b+#Yp3*4 z6s(Rk;5rcrB8=p6S4eQQ0AfWWbVk*DF1INEFQFN6cGb}c)E?26)`A!!=%N$=%*=V6 zd|ZIVC^oJyGf6{5AvPGQ6nwN}ou4`6E0uhQl(A5Pe8FlQbOh#|FeRJ*QktPc!MWw4 zUy*VbtY#cS*Yv~{zoJsT4Hfg3SIfLn6)LTva@O|cnM;!m$V%0hc7XoW!%42WDx4>H z+uN5!E7!Rkv1}8V7+0>gfYJ*=cqrL5UTUEu4jeSzfq?OxDknNF&YR}^#f}8HHb#*W z={g`asq+VW|(f`9^e)FQG<2ps@75-kEBs8py{yj$@XQ_oNS7=+1sK`lV45`p4Q#6)seH!U+3EdE<;zFg<*#B8ULIGQlG?pA@jj1#Y(*xI+x=tN#JBY}f=-DMmHWDX@ zk&|Wf_O8&FZ?o0sO+}6DXlwVOP&GI8Gsk259vf1D)(J<{*BNs@DkKtMs+bUoq7A&u0xTjPkmhP+>6e%jr97ayh8=*KPO9(!jO%qVIkk zXS4Dr{m9*L(2`|L_ynKyQl>Qg@xL5Tyt#F0UL8)%{dvn}tm%$~y6?MVi8r@!Svws^ z5(j^#^>P8LJJC_=7$PHdljzeV0^X|G0&?kV8tLd&Y3NJtELQ^EYk(HTn$xct2Q)GK zj_P3zf`s~1B8Q>`@j$y;j)G*iwWeRo9ri6O_zpwNx82f(Zllkz%@=WCHgGLmQQyK| z7z7k-S=P0K4bhe?dK48Wh(h6_JA+;1)yBf!NT{X6i?Nx`T(-D-bkNA|R=a}7ZhAWR z#wQCWKedcij_<20i5KIYIhFN|1hYmq@rKr1b(rG^NVzfP(0xTG z)*o20EC7&jE;=DYA9gU60N=>DQ{@}Y;WU`MUuz!$3v%};*zN%YY6?^{GF1wxLLQ5m>2 z_+3cHI9xZph9=LrKf1nP&OY!__vxRPId{f=W^w^J5s?h4`J;PJk6V~~3H?vI66rb= z`OezxbJgB)Tj&Y)!*`|@rl%L0g+6aEQw7pls2Gn;T@bo{`<}rp5@j%&@@-gS%Vb+n zj*&JYi)qS9lz~^Fcn1{K#{L1f;fgJkDyd7QeN&}drjkd_-FJAOdhnL1Bjdw&E#UaV zp@S1i^Y~o-lF#8TwRD)@+;KL#jXPIC;{hzSv`j#SpX;!vVzqNICwzU;(-izMS z(k{iLZ3hFL#cCYsZv;Vyu3jL0#2l5E1N;1Jy>@{*p3e<6Ghm^%EUp(lrCy55YEZpVfLBqlU>-%CM~Bf1Wn2$ zQl+i~dn!5i7xo+|RyX!MPAB>SL@0rBZ*}xX3Wa=9$$O-KFOFIN!6&WcRg5*uAxi!L z#uN{&8T5F;IW|cc2eZmWWG5WyYj=p*ZW!r8g@jAuxD3QwXp=lsZSYBvxF-VfI~$2| z8}$zjXQQeV%?{^}`}}@is4o!c+u!at0E&Z~7);q+KN&kAcYCl4JjLG?Y-rF z999GRHxb- z`@@?OK!?h^Qd3=Z-f|h!B?fE)t@q1w6p=PS+G*&(2%=3Or4E35r6C4%_QwFiZg*wQ zp6^bcc201o19~7oa3!2On81oA1>P9xI#rj8!=s4`xMpwPEJK7gig|nE@TG zgrWUHtbj`;MU2eOU=GP-Ys=5thnfIH^iI_G9uowvp4N7GHt+GayTNKU>w9Knd>pLx z|J=lzAYvIx&awy=5!ixvA?ypO=&YD;OKrqDl2AqKa|BBZVuEHXvdF|tN5(>UP(3WL zf|p5V@_*N`|LWoXc&0UV_{d@8`&q2!7LAe7QFT#LVcd@VHpYzh4%Yjhj<uQNFW_$MT?Ljg_2!)OE5PT$XA8fkD%D(*I#p>!;C3tFM1e`r{4#|VY4`G-o#%_ri zML>_C+44gsX9Itv5plfE4_kN@@ChdM`Y#O^dk+toWqnENNm?>vl$s<8!QIqu$I>WJ zHA$MWI`LKW*lcxm_7=J5JI^ktribXm9^dNBA%Rys_jP7KI`pf(-blpzClGF83~np| z=Um1>iC3#CBCgksl~=!SRaneTE=n~H^%Ifm)}OZ8S;ZQ~;I|i&=5e&bW8LC$+3?-lS$M192@}quW_sxZcfCq}W#|zBZeB&-Pma_c!E54S{PD&!K7# z#S{t2OH0ey4jD7r2mcy6V+ssG%)ccVc_qQ?WI<)Y7GQb$lf~N$jf&N>(`vV zL5$H372;fC`7l|6!_FI^PS==wy0O)ts8p`XKi$~cVyK}#fT zJbb{>o$l-QdIBRic=WZ_u%olH!_&I(Lp-=e2;jOPaum?6^rYpBf1@s-ER~Mk9ZR>x zZ*UKgr*gU8Ge5))GzgF^x!RZcL5(kOw(UK#H+rLnGb1DCZrH2^q}1w@1Yj4@I=S1O zg{1@`E27T9_%H91L+jgjk72ZX{;GXR`KU|f@TS6Y3Y%>gw}70;!5E2d}zbPk2-9cm^tVv-8W@J@i(N-jrSxVp*h@_G-_&8=G>5h_bu*t!%| z3XxnIFXDu|JVh0Y!iv=|M;T>1;*)6=t=`puZrvHsnnjI^=Bia95{)L#dL3T#Q;Rn> zUgF2R_htenoCt zpX?O;BtoAroDE@(zf-mop~H9fZ#TS1w9Dyo`eM;!!sqSk>FDT=$GUtS;b`}f?vw5E zqoa1)Gxtm}CF=ik(^GwJ|C>g<;pR*zyn4E|tEI);l@-f(W&=!=_8vfMRva8-BP3GD zk_dXars!HkR;7*zxi4&lI9J6u0>?&RjImDb@pgE1)d1j3hew)eP+}Z8XE7hG^}zXv z@YNy(HV8yI)-F5-j|WL_Wv!BmvYkC~c3ohGZ)xvI-QaR4)IBips2~u?`=VEj*pe)9 zL=#}n_@Wpd8uJAR!uy@M`KwX|d`zIX`+$}qPe8YFOQZK$ZmA(iIbTATvm(S0k)GmJ zse2$X0=bBcPhxIi9=gLd7}*-qq82MfRQu`eOg@K#L1%x<%Dj8v6m$HnOBvALxI0mjl%-WB>E)Qm0P!o=(*{?Kd%7 z$Z3VMBk^fn0<}1;)g)X@if+6VWN19kF3EDB+eF5vGecmd#|`E?0!|UT-Gj z1P!DjMj>;&VP8EqXm>c9S{;K!_YMsNr|}e?j`s#`LlvXuwT6i=>0D$*U(YR!uo&Ez zcKW4g$({~1F%pXFW$2^84{(^<0^`yfi{v1Z2C+FyDqsC0wa~~QwDMXAI zFri`4cbqgeV1o$QXhpa3mRy4%Ok##a5KBQVO9w3oZlPs?H@Q=}lv@GgED7|>Tx85? z)%a|IXf#lNF8UPH8wOr)76N9qY-yl3xPuBv?#G3)>Hvys?xLIo?d?t~n~=z-eux`k zm^GM7J$nQu1rgQ24yg)BQP2f{D*+n>Pyx(X&sTf?Ww90hKGXp^I$B>!l3zZ&#bCCe z6SfQJ4Z7=&6s#w|!4tzTxa^TuuX)yW1Zb7PEN}3T*EWdgY^c;$5`-HxXan?Q-e8Pb ztZ3s0Hb*i8FicCQ|8Q#?Ysn83lkdC!^DVC>-(O7Ls67G>Atl=29BHRLy7Z;N~OZQ?_s=pu_#8j z45t!G=xY$6N|F2$Zz?#74ac635IIqYx@C)2>u6&6q%7|nNq zDA>e#%$3c$z-lr@L}^V@+;OY_>Q>F8KHn?-CzGj;;GO2}nX{>+-&bx5xOv#;Po~ah zZZ~i5Y)>Um_G5S~=uNzR5e}PWwP^Z=K(ZW&z>NU^NRhY+m zv^;@RmParyZiP)TREt?{0`6W!rNMUgtm=?-t#Z#eL$B6P7>&^+^XU|_aK_@{fy|l=aUF>#5-Si&7X1BK^x8!HH* zju866T2KssV{|p@#*IfDFp?5aMC1!Xt&WD5!k1ZW6)ZxnAr*G0x=vpz^eLLQhyWeE zS|l&(c$WM|cuvGpE&`Z(D)hFunX9WPg;8_J$LcmOzKT@>{!+qSi4)nvRYfD&LkxPa zvois`ac`Uiq=gon+j;!mBG@a5ai>k%>lwM`2&M+b`uiB=4mbq3Xmw50zWe2a9LCzb zK@@iPXa9=?V`D@;fb_qQIBo99M8^bRxORl{rziPXQk{bj$m2b4dghtrGk?m@N%`rU ze&^Zbv-p*X39qFXO8Jl>dPAs218RH~4kG?&6u~$sSE%xlCvz4c04`i+7+M7mB#psu z>j+)n21X(TMH|s)P7u@$6_2z4>6}bmq1e2zL68Jf?ZM(#zgkS9+9GMOgw~<>Q;t=^ ztN+)Y+#Y-*vsy28Y7UHhhbCfyCSl9ZXXNDPPY%k8zZ`693$}gj^Cv&Abn=A#_}CUi zZ&RnFzYWG5x5`;aK8RZsn}=XfAX%`5Xg@jukZV5C>g6yzlv6SP$-dovC;hQhw6`~k zj|&Lc!n9H${cat$&Z_;0>G&*#mcpEsQ4U6YDm+;iab)X}ns(@%0Cn8q#PIoe?{THA zv8pB9(Gl*rAluUUL*clyFmNL6@*b*LWKScwp#uqexs~U>38X~a5C^iu4$&qeTzM*Pz!-y5) z`2^#70q)j(Zz7^(>R@&RuLvz5ffLiGk@9Da;wViYdPM~X*uZfs_>#44u z{0y?EbiTP+r|+(y<4U$k^<{7z$tyzNWFdZ805fhfNPxO@x`KfoTwGTAfKKizCNKiEIxHk#kKr*`n)zoqAXc)0WXvGl;tjio1#>Q5jNddX{9qyrp} zN-Q%tu}0ejTso#n26Va%IL=DmVn4vvpo`R;fDtv$@c=m>x;0I2HwVi46DNuVs zT`JOPIKi?ioqWckE>YAsDscFSb>i4E!-QafdfkT42!4mtAZR=lAAU6O!wos3GluF< zh$#YzYrJ>5pb(fCl(JM3UPC%n1P9=F%i67x>Hv-_y!^a#J_cWCK3Cb;AT8S;lVDf@T~MybD7*9M9P>PJiOcDv0N;c zyIC4h9lHxe-?14AH#U?mAENBSwErhY6py!$7VEj8b9+g<=)$9s=QlKFke z0r2!0bHRQZ!v49TcyR+*S#P8#kL&?wW)>W$PsrevqydgIls{Br#9U8rESVb{=F&n5 z)&ABhmd=hsW6c?FFZ z69(ShbPm@S0tg?d|Fly7$%b{N z+0JE-y)<_3;qJqsv9TxaRE2X;l8=3V>;w09hsHiI_5?=JsziyDWALdK+AhN5_?UY9 zjyu}ISJ?Ac!s=b`dRM3PGoHx$O_P>pvPk{8zeld1&F|JP(NbU4EbYOf zP$@AM(|2({9%UQ}EYdJ~(^b{QY!+!(FcQIsaCWi?me0823>FF=65kYE@PVg;5e`~3 z;Ep3M*Ad6A*kt=`OU&W8*WnoJYCF|-leaTgY-=mVf-NVGI2=b@YdrdR`(&)s`;w4} zjjm)@DF1x(P-O5_C?CTAckIgNH;rB#S&a-e_YdZ9tSk8i9L?i%uTe`Gu`NqBlYUUk zU{;PaXHRW%(_%;ELxHn=E%~)$OCpkzw9`Le`52B>HYVLa^< zSkJ#hahSZ2Tu)dAa-?t6UKMaKu%|K;sDl?klh8Z3l2%OqSr??$qyt18NF;BZ;`h>1qqqZq@k{a5e99o8RV%# zgmhz(Yj5G2#%Hb*uCd)Xy7+n#8@1-Q2~h|1Kg4VdP&`MTRAx&hYK6pCn$KLDw_aW7 z=m|%B9X?+q+~d3LB{6mFNMrx&9r+$#M~9Cm-ln|b_pl?Uy;d7G>^4!T8|aSAM$8+4 z1O>IW?H&edn1ioLL%RP;NjS&0I@``r0yUlufSQ5Jgc$r1xK^R1r6m`>N~Nv-4Ud_q zCDN$Wa_y8b%hxoKRGM{JM3NM<7j00%;Z1|Z;1X9zCQ*=WlgbtrjIn@1&k}DHH#Rmz zV7ton{i9r!+Yze`xnPMRA?{KLJY-HrpMbZL4J!c-Rk#fATR?~$>&7gdOA6Ss(DNp>H9yeMZ}yX zWvQ0e(BzK{bfLDTg`HOMU##(aiiO)_3P0>xxDH|w>SHVZi?sw`5;VLrG-E)VGiHWX z_+Y5TncV{S!_Z?>3nLzCK0LxQJ|l;lhZrRSZ!H7QW!9hrN&pZ$cA6ioTd^=RO2vGs zZNq~!RL2pF3XQ$pp_;+rK1<`LZ5d>MP2x}eJ(il=cGUL9Z7Vio1Kc6E3&^G09Rzq( z$ijC39}8Kq=?Qpz;Q+$4$m5C=@L55u0V7HxA!wvXd;%(|LGCo{!L?*B51{~k$k7yc z_?lcfS5tFK+-VOfdqk;-!yd9b<6f71(bQi5;`o6(?SBi2p?zKmh23v=C^g`;w>sS2 zO-GLKoc@^IJ%mey6m1-dlSA?c6+D8ZEs$^^FVXETKii& zNNl+lcW;4`S3#22s;z5Zuq<&TWrL#KIjxCY70bU_sZgCFg7(kh&&Y8z>^2dK!$g_t z*?TPZq*ds;wu!`J^M(0WISpBh6*_c<3MIrfcpog9i{@|OIs8;3&HO2m=IdHMoe*($ zT0D_T;5z0`=nRlGTQQoifym=dAZsFbHZpoMe_22+FD{lA_k6CT-=u!WJ=MPkBzuo) zZ|FCMd)dVLBmD({gCZ}DK$&coH}muy6r;heWF!U6C>6OSr#`axEbBS-FGQ1px$YUL zOWkvww*ud#ps$G(C4(Pz{f}+NuMP3QkD>4tEN*Y95vp~uSclQD2-$FOm*d z*YUlz_YM#9sfSyymRE%+&S&R7!&?1Xc{S+IUiRq2beO zmhl+6upR>@6{3KYvK=6uMwUWiiV&WqP0MO(nHQ}!Q`Z-@e?bH*h9DFurdoUJP}*#6 zHq%3IW%)O4;?&y)lfejljyt?pENJkzvMnU0-lZ9Nm4t}FoAYO20e0fAzKhjgewEEqIQ@E$#qBml_a=+bt$#v%1rD%dGgT{!8VspfV~F? z{jS~#E?nK!=3mQmf5oHOB>;h1R&uZAo+^HEv6~ z8~hUq6Sy+ub{b8dLdXYBxPVu{U+^>;PWO;fH~#8n1Q_IJTGCF>Q8%hIxb}EFdz#xq z4);-yGwtqj-{=d>BU6Nxb=#C}-gX+2!-P(w1%DdcIqo0N0;K_4Dh<$v^-j204CC(c z43Hl1#MoxDI|ZA%lz2gwMMZOl3IpwGbqh zqxjzhozW)OgwyV8ab{hvLATpyca1BDQ$?NlN;w^B=a;Ug=pR@Yp}4dxzzv4ZR(ovP z6m*W*Yw)n~361Mbj{Tz4yPgXtGov8n1jI__mRw1#gYHNC$%Fu6rP7I6(GHt@cRo(@ezi-7wE2lq9k%`}ZoV6lHNctW{P4BmG8lSrBQIMQi;rV6xG zBtIw6Fz|o0W640YRW%r9Eh)%qg)Mlz7`>*v{ z0>Sp%E~@XT=dnk7o-S^M^;^smf*`ssPy};B7S&UaKH7W79S;E-Uo+x&+|m2!qw4wR zpHE!4@E%GY{Cm%Z3yJ5S7c$x>rY#mJLAnp{N9JgPikzNsl5^s61(JD^cYr+gFF*Cl za|VVUIQ=b2(@frik_SCM{`47Eugj^e=k6l!zw0B1^p}U)`k8>R{|jf3wFx=zFg><2 z4>8LLJt_~9h}TPQI6^Wjq-AYX*Ed119z~~Fl!IxrK(l1O@pM(LL<0sMzQTHqD7c#g zFR7MbT?jZT>U#J;@UiQiM=fqF-&96N7+$+z$ zAV=0Z+mRTH8y%X$gqWROZxG)mj0V_Wv5JBEXrt|i)ECE3$q zLujUHv>Zi167t;bL*|+OII5Hr=v1GcILm0Hfm5Mm<_J@ECr#h!jg2ZBq$YU|I_hUZ zpPPY|$0a)>-F@hs>#iq-fhHj~AB%xnL|fVJxjDJ#(w^i&PyXqAvTdk;sBKCZOqnt@ zoFlv*yX|0d56*aJ9w&5mwtd?2pLpFS@gxwz@!aG_%dp^U7&lE=0>Zqe9SjtJD&wd< zDdGnS#Dms_f;^^{=L@;QeE-e2-#iLh;uMqZnxTxzQ_Y7CHJ_RsnVA`Zfe?RN$h8D= zk4^P^0!vs@b}i!&y!DX!0gKFXK|#oPP5WHGbSboutLXZqc!RVIN5C>JTHO+uEo9K; z1|1rL&_!nieN8A2fT{{|RZD3u)UWCc_0}Npg0fw_h;odyW^_iEVx9DqSVts1KgZzZ z$fmTc4O1sl|0xU=nmgG@HdDh9`LlyI(`;bv| z(CJB4ucSPas?BrX9WHO1Q%fNqzVl90#{6)gr{{O=O&;(2JuH#Qr&|}1G7TMtv6(^) z{u#^WvciSsHbMtpJ!Oa+)Km2LqnqFx&iK7^uz)T`Kn<^eo=heDMBB)nl1t zEl~I$Rb!4IQW?Z%8KbKEv2Hynz^99_RINmKbrr^hW!7ay*MKKuk{kHx27bz{L%L8K zq8KH6#Ux^Cur$T_M(3=sVs+QU-Q&x}11}yuam6o-^lda~_iVYkhIbbt{irb=-@QA& zC{D{$8iOS=1Q#MSL_C=p!9eQ@u*rrn#HcX3va-3dQc@;y?+RWly;=qphh<3rBA^lT zh+xp;SVk<~z|5KY$Ef^-r?-ZLZO|=V=s5-!i*{VwqQUso#R94+UgBm*24)>*-^+L% z)uTcUwt(sJGC(03ve5~3Dnc3p^Hwi{h#cZ%Fs{}GBLggkfcFZl$MOj3WhR5&Kbb3n4>D#Tc=>;4bwO_)9Sv-2%d^N|DZlpCcXS@>t)EtWkWz{>0Yd(s%)J!%^-?=vKVq%!jUCGo2-6<+`m69WuEp5hN%XQ zN}-guF$3^lKt7vadR2f-OaqJhFm<>V^MqVj5?>K1w`&p~++pfs;P%l>R=qew8gw=k zhRz@E>W5hzX}tJ4S5;YA~QK58u9 z>OW9UzI8Bagt~^q-&@J8%(e_8{mvaXy>0_Dv^|(Vu#_z43xhr5vj(U`>SSC=Z&bio zDs;+%+(ZV8e?SCA-%|QyvQm2QXk~j3r<*oN%c!`G9KT==m^cLmqPLDZCpOaht1k${ z0eP?v5D?Vnsl4fhVDN=ERWKxa!ZUXrwW40&0hl8Q&D7cCcYLPrugItX zm>R*R*p`Tyvf0?)#n@Y1SCdv7f?&rTwU=5qO*j{9VGMCu9TE+H402H|64ZXfH3&f( zuTUB(E|%~U_)C>HQKUG>(|0yOOo&7j@9L&Uo_XYvPdw7t02`7 z#)3%7v~<$Qf{+IhYz8kZjC6#wjMEYu$Q}IC5eAGh2yHB^mnx-oY&YOJc7w~Q5Ym<5 zQVv{|+DR`jj(y!rA#_#suOE2?o%J04s+-(C_uQrDp2O4ayge|KbRkf?j*~sT{{2Vv z1^9F8$I{oFWBTEABrvsy-iEGjm~T)oT&8x-xoUa|IJzwA3gzrSukXn~mauTwWCD+1 z{#z;~RTjui1CS7bH@L7*5O*@WRi`D_yN4VXyJ^U|={qeEc0<(b1XaStiYE8jnWuv)*2N zChlr}F;RVQ!a332dG<(r*6+<1n}>a8k4)ue0zo8b|NnuV$zq>ef^@#YdgIz9@g`M( zo&cpmLk8nlhsP|GN@DX;NZDS7uo;3r-5Fa#nVcAQqN3%{5V}!QGKWBEv34vWlC2P$ zvjC#H)y;woLO|jm=bEG()zKk2R@#nNj4YJI(B~5??TE#7N!ogr=inTI_ z8c1CoM}Q~I!sd1Z3xZD|vg6vTQr?)yL#+eVm5kajFu}rfwWlq7h}jekPO7}rQ+9O} zLW4c2U_iWOj-EYLICazBlfib^#!{->;c5#8dYV~;b+A;r=~UhNWEJZp5CUbn7fIfG zmF7G(`0OjhJ=GlK=>H;vYRI7KL^N5AsRs$DONK*%)~)4lnWL%O z{PCeNGZ%~oA!Fry4VG#6w^qi|iJKykUSGJKH9wk*|iuQ48OH%Tu5 zD756~R<~TIDTvhV*KNfNEnL3^8fzf`C=-)F$IjH0H=>Ms>1v}%?O8*7rx8UjKmdQ2 z4THG_jnu`(RB8pUQYvMnQmQo+Dg@d>Z2_Z_N}-4_U#&)kC~$pIuh+~p3~bd=L1>lv zIR^0Jn6MRyD^Sm2YJ$w8mXN1oT`icKTVj{OM-%SRriq1GfckM6bb|SQZ3CHXw$Nk8 ze?(xqTv;cly>aU4zMkOHuBnIH+8j;cw(7^!N_FWgkyOi%HIH@uV(WUcDbm*Fb==H# zpT*_ArG7!(}amu&h|Ua|uH1#=2R36JQa22`Qb_hpKhLGaJ3h%XsbhH`FxadCcw zssX^_*B)D3#PF0cP^cY-$^K4QE zyNIDdAf zAn{D@h@*(~VbU|Oc034`U+d(c!qEBC6WL5Q(->Rv^}#`3FcS_X2SJcBy@621;k370 z6=adv>)PvYiv>D&=UlrYi9o2!?P{^Nfa6=vEqiRoZ1-bgyucNJ1}rNg7CGF87z0L= zde}wa*m58d8w9P7_yTSOt}LY)D8AeW6Tz8CB!_nan=yvLKJDUIJKcegFvr8LfL~yV z^TdoB4GrKoFy*_XDL%B@rDhz%y@5n#GK*Bfx0%Do0^W8<(9z)wote1h{_JE1Dfb4u zavr;VUvZbc-Q!XAR&V=Ye7v>grY1+CBXaoO!{NQB_6FJ#&CQPITJ5RbV~>xG_Sid` zlDXjrhlfz*A>X8?ruR=eTbz3j?>9ZpCd1ns*q>m!IDa(ipI#Wr#?pfWEiTV4BbywW zyysxNzaQFj%)e)_t5tcMKQS$-#+{xw(;+7BI2w?!HJj3au%7 zi@j+$8jnYZn(TPkU7?7IMh2TMAfVF$rP+~6IXy0s8ADk18pI&1%{mKM@or>fQtkmz zkyDRPKk?Uiotsv})78hsBtH4X^y7bx*SYEH*Qeu#ELQF3(hf{d9II-%hJqstvXORu$=b3DFCS$_zQZ5sN1T-N!L$q31Sy^YIGn|VJ$kur<;-3TA>Y}Z1 z0F=-TQHmZlG_r(|gI`;zFrVw|!L0{FeI(GKI=vr8aXua93V-~Uc4YQ;X*H39i+u#h-GV|~L&2VkEs;0};Rj(s4glvXq*k+2C0IEKDf zlmtUS&c?HNbKn4~Gw+`1&(Dmd1JO)8)H|6AE4K?E(w;FB7<3sy7tBarNsrCs5vrJn z6c^7#zZUIkQw~>8Hn-~*l$2PC`~Q=bR^P$_1hGdYNsf-YAY};v)Rz!ZhYhd*RIkEE zGuJ?pSk03h2140DO@?pe0wV5UwsI1QP=I%h5op%H(PUjuj4kovtu09{gWw>P0Rg&9 zaeIXuSTMF32FWo9J+r?vg?tg}SOHF^Sr<~N)-XO5+I@@LY<|m$iu;z`C*IP0W$X=a z7(-V1lMlL&>^|{;`^xSk?)~`s9nA|5E;R3Fg8Al#7T6IKGpq)#bNxiy$C@8FKIrW_ z{y_5;J`At^rRLPF54x|Unm^`#@YX?h-(a8nWBS^yAmSx(%r&&KZ346U4q_B>5z4Hz z9rGQ_f{j|-*#2gFtSkJ!T1cklxR+O-9U zOe^6q1Ow@uGNkYdZa+wFXr(oS=rm5=BYXvmxMuY(aAj%l1E$%COsF?YP~=bU+vm-4 zHFWg+rsyVW$W`ne+*2HUDR=9g3(HtZJ$a`}4Zxffu22pgw7cwy-eE2?V?kjNmuzFO zB77A(3i4@W(4Jb|ff*m9y>8RA}XGo03J14*|F3=Q0khz5Bc<{JNlOpwD1Hw;^W%Gzdz zwrlItWv$ak>}^eL4zKb!oQ~G4`*c@R*J*dQ)e-cETY6hM15FNBtJmph3Uqq<91<(~ z4%vRHVgF0G21+%$I^6!IT(fFvQO&tvt~1;^*cx`(;lu92?n#M`xF{Vg9hjPwBj~I( zSYCnK=%O*m7RiOEsa!a0-7t!|m^q*#Kuo2+!4}HWt*;@CW+t7_r&Fo^_V$0roWBb|xyKHn_QBdr-}t+B52Vkg`U69O zRY@iMeo5L3Y1fi0Ei>`<8X3U=2_8nEi2>2HZ&?(^QClBWH~7M=1ge02EF-mUWa3Lp z`B}sug3Q!xTwEavA1P5TEwOA<^^5$(&)j0OCI$<@hdC|)dU_E4rS+8b&MmH4%r0xNoDu~fe&G?6pofI$LLLId$Y|jhvLXdiNS#I1denE@ z#)qf!PvudMsDEY*m5Pi#@JQLSCvyD2@yK2s6}&Vwjlk*7ePjFjS+!{2@#3C6#h=|1 z>Fte7qg@L^l8iI-)<}oy@sj8Kizyus``NC&4^?WVX4r!^wPm-7mk@ar*}h)Rb+)e; z2Ids!Fru;LU2To0f2Ke7xrB1JxLvn{?S}wYhVUN7OFduxa(XPb7I!%&s?=>)E|d3P z{#EY(>f5lz;91=ScR=LOWeQ!Ldq`&;qUZq!9?I{StZ<0M7MV0nShD|L*4_lpk*mBH z)zMO=eXlAlt>n;o6Qjcj2GZxU%I)# z3z?8W$Oy;_!3078LC8(Ozz;&yBq58#d)(Z(UlLvdgybdS{=ZYIZgtPt#@sv8DwV2A zs#9nAzW=vZk1yOBUE0ss{-x-x3+f3OCY=1y;Oif^S|5LX@aTiN!pzZmO;81G{%9&% z$c?8pzu&K=$NS)v?2-!5PK{GFu91ae8mk8PA;(4q#=P!UCqL@|nlfYi^lJd8IaORX9C zV*a+n(kRh;!uv;eYvl-ICzAVoQYaBte_&5@;k9aF5wn7VAc=DN{dM+5#7REEF{LZ8~7K;FW^<8uT`2l1wtMTBN(9j7` zxgsnDxDgdekhYvC0F95!1?8+)XK zN|_oHdWVy*tFskDG=b3wfSHQ3kV=yS6bf_^6=*idR~F{B%``$w$9W#1H%(5c6aByI zX%M-OBXn1v>z|lZCnrBe!Vu;I`q7kcd7>nu@t^TUl`boK< zh?_M@T8bD591reUmpcl0&UuM;EXPXnvlRI2& z&<NcX7%;=J%xTjV0VD z`AB(Q07&KvItM7vL4awFNvE^kLSj_9dWolc(a5fo_z5q@gh{2rSli{YImrrF@FO>o zgJELWQb)_B^^(qWieXJsOdO~Wyg_K$;OPvla0`0`;|&Oney9J&sKEKf&m->EpZp>WDvkTk~Iz^SJV1AYnvB|j(geNmF z2_+SH%9El&zkm>#rE)r=&ZYJXqoeUa@=(CPyC9WRwUoL!7mMX$7vQBpwP@@6repEw zX?7+rJ0hXNyq86AO{!$aHL={U@HzHI-ht;Zl|KaZ&eeVhkcL$g;wGjB#6$&7Vl5pD z9R7YAQ&Su4LwfJW%>B!!MuWGHM^~cbxA%YInXR8dr^3AkJ%d%v-5qND7tU;b=bX;m zy&vD+EImIp^*nx{hDGxM_HnZfBZ%K4YNpg`Xaz`GjZNREelGp{YJPsIbaOhgG?o4b zUHu&Xe|G*=;eSX^orq@6<9CkXcYc?B*!&$v&IpwA-}!y@_qM*pcHx)t ze|Ua+?0hDAVlwlOmv@T!L=tpKsB%-RD1&`sJk9nlp}F%62t>bE5xY$$Y+k(1=o0qK z&W;@XNqov0+ThCwY@)ixGIMPe)8Txq9R-X zBsI%ENC`82AK+;-RrwF04Rr}V!P(|pmUaZ+8|;0F=U|1;uhzlxk!2D?+6X!@|6Zf( z;+Y2pw?{}M1dm&I@QlC7&wa0ukhRq&8N0tHaf#-FG!1bp~8bU_tEt6q%E` z8pDS5A;F$OZVF+}NzrBpw8W%>sS*IJ%J5a+G!tT8jGu-Z(s#JA4wgtMIo|sO8S(tP zldLs9UiwR>i73v>V&QQX@BMLdoZAR@CvgJ}Bh&?0Fd`H=)24ph{Bi0bE=0h?7$Xi- zMti4u5H4tqRs*F%H$(Ug!=v{6^F*8k%PJ&%=m0>P%+zLFP&W{giImK0E+#jS`v}Us zit!YBfc*5gmv4Fg?EaAkKhfsf_wnr^zTL~WckpeCe~ZuSL2rv~3Wot|*|(fQfk;@u z_=e$QGYjwrD;v$XWgaVYtgmzjl=PZ+U4Kn)5?it@qR(L4rXfrkp%F?m7jp!?D zfaV4o-oQOYXd8gLNTr2_W&3HmY?MDDU)gfcvCtx1p$)8_O>M1#1QLkog))M#-8%ay zrZQAK5fWgzE?O1`^x)?Nz;g%^On5zlfL*?a+1o^s0u%)CmyJx1??qcojBbQ@L4Cme zijm8L`i)Yq8N>htfmRne4B@4>kQxd)&rVRD2WnP=OnrY1u_H<&_2Xp zfKnq~q@g|h@TrHPlo5)jib7a;>)5F=U~72D((#tyatfn3A>4`MV9z>e0{yTXI)w~( z1c?UT-Udg=AhrcDai>M$c>(Sp_I3dd+f#%a6DdO0I2d6G@B` z^yXv+p`gEXcF?`J}d!x4BqUYr|}F8 zccZl{crCw3i@TZi%rd(7rP{fzl`)v@OGpX`&P%PVY<4O>&^#bK{_{4PdU{ER4R={z zdWqidW}fuAGBgO7P8n(GWj=+3o-V>E{aC-Rjd_7bz*NBt3WuL#(onx+!r%!sed(nq zj4@j>;NcnX&oEoIjRHl2=3$<>%51-ByC7}j&)ar{JZ3U_=A|ZjH*+DQV=`lM{jc`= zW_KG4^XG24gvEs(2aSE{dGo2v5;`1n$1CFrUUKdak{Sg9${3FszsBfyu+lzFAvx3_ zgFjF2o8+d-i4C7U-r7s708Vcj{RiPRr}fg0)5>g{MqXe_6+~U{KMtx&z_$(T=jWXL zp0v&DS(;BBeu=hsGmYCkp`VTTI0r~1$+J}6a{{Rc%pvH5CMZJxm#IE2U@e1xKRea$ zW-js=@0UaOx3RAP9;XQ8z4<`AydwIa_!Sv;4fbj>DjV^#3R&L}uVhX>lmBkj+<-X4 zjn;S|-RC-<0T%$h>@zJKghrpQ7h}Fbbzt(PZpID9+{*YSnzWvpoNLJ#scI%eJ~#Y1 zv38_Y^Ba9v8IzB>p&5X}ZvZ10Qr1om%N_(C7|CQt?$a~ft^0TS0047&JJ$z#GjHJm z;xeq`;5EQ&yh}*x>!T6_gj{yRi*OUlNaqUE(*@iY28|zW-S$VI1^BDH;N1twK+G}< z8^>Ww1KvHH2^P(PKub26pfQf-(9l?Jj@QcoAQuQv95;C4SGSN;=|$N3R|$x0EO$MD#>^xJPZ<34UFBz7k#{KqxEw?rUYPCwH&pa=|AS?Gt#u= zpyq$iGnNSBAQu2A$i<)e5eXR^SZD0#e!vjawPnj8%Js$(va$R@0yygV-}7)f$N)gl z&;DR07y|OkY~sq zIvEL~NJe^g8`0iQQ8h~3z(YVUr>KUQH%Q$;%PwnCn@Fg9Zp0w$#CHt3g{lA57b3OE zt;YF2zpZs!qNfcuq+!hL!^W^*v3p+rO4SBds!<;D%5vQfTKcj^*5Fc`jHxd!8_UsH zl9zR&Ijr~b?$h++E+0%&X3v9o!B7OVzA$?g*F~+mn=hL@u zHRuILlgsT_YS-XkN|r3VBo6im^D-j!@<$RPph=J97bUY>H0Y)H;10AgOg;_U*2Z8* z4$5Aajpz1GJY|SjFWi9yOh~kX`N&wud{_s&k8No9E1ITcjK7*_BOrm!A)F(2{*-&5DyR54=r~a}| z(;fw)pTB(OFPq|r(pw9?~h*!I&Jl&8`9wkmjxbimWrO@8Ege+m zQP>fwXZi}J!F75irNNf4U+kBqm^Xd<_)<~x>P~GMZzl1<%fS^HvZi~cj z-r98YA&V53Z?})*Tl)=Q!L1hT7{DtvWN?9cfi-B38FHQZ$S;3gR?!qUG$H3+lpz^f zkeAd!Z8eaz@TDs(NmET=XyJEKR+>9Rd^bl5;DS#eEXqq;U4<37wI;VT@Y@i^Dlp!F zY(-0wB2iy_QT~jr+di1U8)h2^*d;Y_=c0VErVh&OR8M-wvVUt;?zCRKykXw#Rq#>L zLKA^Qi(d?aU{!9n61)@+S%S`D0E=9i9uIc!l~E-p9-H*I-?2NfrM`3UA9n0Am`YShdkQ|%Z@;*7e{Ng`Mz{-qyQ#>EN66pNQXbkZ`JGMRf4Nm=@2#pc47fM zih|OS${uKk+mx{d~BkHH~cYa;q>te2#5qO z?8DY8pSj*1wnvU2h`QaZqcq&&na{(2JCb;{w)i~XVXtOq_Ej3r1IcKC_zi;Ouq{NB z-Pt@#7BERn$5J;2au|*PTe$$KB74v_QQ+DJ`5}@Ig?THoz-NiJ5Lu-cVQ>L2QKGQVd~|b!n{qY{PpEWO zzG*0|&vWh+CY?&r4D@;`6bShRY`jBXtaY+d^5U7D;cwOiE~WeSi4j z?*N!%P&hs${o^~~kONK?td&71F~tz$wz|u^N+0_fm{GD{{0$%wGvviGg85@o^(=NNlHXt( zoDcLixc?Gdm^L^u*V~M0zGBwkAGp$ApmhrTHV`(B46F28pw4{I;7DzUBUOz$1YVO_ z?liA|``f(;Dj0(hN{JY=9K3x9wMQfk&N%2C6bk%ykESM8wloy$9lC7@KCv3JfDG_? zT8CR(8@@4Ka6))B!yg8>ga7$fMh{b>fa|KIUQg%FoXLKLJZ-joZd)il-l(fNE%!lk znBJ;6!Q*4iNovDgqU1$8D^aE?iTtuKFA-%@RyL4z?#rJ^e442~-@i0|VDsgC^+rSc zOyV;MX2*wrIsH#IpYQSp*WkEQLphS1l{dcr4cDI|_b#HJU3d%Dfd218 zw-PNB@w5U(xrzAC|B5w)U_n=0D_0gApoojsGWV}00_lJkD*TjiVNT3R0=`O#*Ygv$d+jHVzl&WQ+GAYg4hHZguifT!2!j928|n9~2${9xg&(G0+>2t^g5Yr4 z>|T7bd8`!bZpGK{eL}w%M<}w5?uP5}T`POzpXtZ{TW>kJm!A_I0@ZfG;WIu#bU5uc zuV};9MT80p_!53+57vNDFtQDb;livT7hi<|m3{q|();0~> zRtwB;n1~LgHnsOG_x=&3?83{K$9msFVcv{9%P7>1v@blZUZnp{(}&i+`I!Naw%aY* z)HnB<@K_~*fWvJmW-VF?H2ps)K%WzU$|+YcovHza&pRD=g}D4ch5-k=p=g3 zkKtgJHZtn)vec*$hZE>>xVU19BliOXydpZ)r&OR;aLVs$>xk6rg1oe}db8cu+f)S9 z0PTN>;iB&$=B2ER;LUKOrOB&5e+kJtzRsFS6gx$-#T>fj`S5|>S`wstJ><)wFHGj@ zgrg!QN-;~X!Ur6leLGoNoe~*_;(zm``s#6&Gw8mTeXCy%r~MA~o^chKK>NqRCpKH! zK`1f#Fe3Ye$$k*vYf{O28=*N^_rUvV?a%+bM&76(v>f-Bn$2{rH2-3Ah2Rv;4SJcP z1-(<+d>b)hAS6sY1TaFTz#n3PFX09}K7mSl7zwA5=98!QsrQKTn10H{W}&2FaLku@ zk;hF$1I}N|gZvUOn*;rnSsS_VpXAgWs3soz&-vHkQ|Q-!HNeE-BS(gh04H{cv35dn zSwHsmMCdmp=e5_mIO}V1hgMpml!Kq5DzW0oIn(gi1sCa{^t5`S_ce;i0J)WZhd!Td zX)7qW1bn@vQKhUjS?;h~;m*FM3RR+tQyjc-A%&pY&M_u&)6gbeG@K6sU-~$OBLWNQ z@VVzotJU}1fU2)Aa2NxIhSd3#CioVC5CMdE#kvW69w1<$m=mitz zS1l*}3v+W=(vU0kO;J&UxKSc}(rbS|f50^~J&kp6IVG`}^J3>**f9mrd-%6C_~iOr z1b*nE@i_=zNP>p^mS8-B=(i%u9{*{?!EYfKDKfQRDcE4F6cEE!DTn}HvocW<_MFG# zj>@NA@rqNj8&zqd?)Y7;yW;Mz)#o02qI!M)l>Fq|DlGNYKL$&<`oR;GGCMAK?)QQp z%q)gNi!*k&!+XEi;kM6Tb=AE6+`-Y&gS`(Hhw%1`%QxS=Y%K>%Cx_7`az27L>2k>ewlOoZo`CcFtk zhL{0(d_iV$POXhe9Gk;9;Gin z0iZvalRXNuN`GJh8 z_s?VD(7^o#z%r4ID5gAy4uCn&qb4zSKt)9iS|w}7L=m&W{n{T{S$GPAruXW@iMv>< zqce-jBU_?h>Lf>+E6jmGLmHO&h!ujSvdZf&J>D5fwxHZKWpv{EBXFIWvz$URK(p~& zc~Mr7JPpf>WW8L#Dha5F2k&p>^y%jwB0(8Z!wxPV3wZ^M(+sZxC**ObMD#UHv^xZw zWG_?}#)lHj?E^@%+5}BykMh`z`umgCUt;a0%6K~SQwvIsKsru&!VB?zXSslUEdUr3 z7Dlv17GMH%i(aSA84hRmxY=6}8IZ`mp)lq4%9Yb%4T%~&9%LPOZWftI5@$K*GeQq# zE)fv9CBN}vkW?)xPwTYHwa;E9zal9#YRH z|KTC^A=bo+-%LND?ooSd>Z|zi1sq4qX>`5|wFQk6WIFs5@+JX9iv>))VogO&!e9T) z@`IgZ^4Q$L>+aE#a~Iw@`hm|Z&ox^6K9W4PD@fWbI{J=LG|wDsCz?qzydh;&h+Wr; zU~scL&1XoOh1^q?5=ti{9HB%hP(b@zv|XiX+-mVHv@ctkc(8KJ`v{oGn>I+Ri#g`NuhhDJOQR1hrImN^ zA%1pcNv}6_B6vt#W@hzbcp5{q3ie65s6GkUlHRkl2zeeMLdG@VgKe@qdW&*Tw}6f* z8F_O{W(QT!5gbc5<>W@^u@^QhL&M}xE0DAthMlKx;Uq;cO<+P0bfQm*t^^?}sD%uS zz_lKgO@&AGI9F;wlZ#Q~NqwKw``Qjtts8m|>@8s-;L1LvfVu;ze>u6u17b!(f?=Dv zhM9$@8D<+>35Ew}0RbtRZ-_vIN1;tYsIdYV2X!F2ZkwOeUiIMkh4JI#y&tN~JN}h> z)qDSAYs!6(pTu$F?1g)A8rW@M>d^!s@&6J)Dor~QZXqWj8w)9&c@Yb)i8k{aU@>JW z%>Zdoe9yer`>X!wkT2HzvzTw_jb{@F<^Xc>Vt72Uh*bV&rAH*nLneF3Y&FsBA+e+`>Ra~k%75XY( z_n%kKr&Zy!D)xSzu8#cyk8$STHv|pR6>MP8p$KCL*G2*kXi|GnXIZZt{TeadVguZ&l_|j zaeVOml;xsjohB&1)rFLPm{TD`TWQ7?@0@*zo|m|4h_%n0I`ck6ZzH~&Y9y+5bYyKR2fl#3Pi&;L3*J+1jOn?PQqEZD~+&Bbs2h&~#S&NCdo#8p2aNy`GO9lM#nMzD}DCA1ous@*+nB1HWKqj>3G{ z`~`NcG5jy^3p5&(WuDr=i(r`rH2H6EvV(}cB2PJ0K~`9VjUwk1p*ebkK)hfzQQV_E zWyD5WLw1e0YmY8FO3Ae5^hG_<%+(V|_a{pG5(^VU4wp+NoD=^MhdaA)^*B`Po?D{H z;qkOr3H$A#@X%03&c-H2pry+2%P?YQz#-`tfRP~|oBBn}!_f9*AmCA?UHskVY8!N) zrahF3^6b}_Dl#->0ulL+>U!z2% zzKb1AM%jrHWETBWjT9fU1$D8nKWPL+zOu$)f3^84-fbA0tvcsj+0Qe>c!a?L;@#@ay| zA>;=rR(M^(3LB#|8QS8?!kM%CX0P$Rztdrr>7cG7ea6DLb^J?bUUzoi^Z~MIKYLXs zsnr25-UYCA5ANW{Ooe7MS3?akq<2A1&<$B$3Oa4p*<;x8JM>k*!+Q2jt0Z`n=8l>r zpkYV~GlHZum~RU8ze%5nHX2Q1%S)QBNgbdxQUE0`p;buZt?SKBXM-O}gqD`Lp`HIU zMafgX8H!-vELLUWNWs9CbL=LbF6`=o?FK|+WEXRmNl5-R{sF&du0{%MLM%MWvp~g( z2@j%85!_f7l*E-RX%&%%3+mo&0I3dmnwAAAQKCv6q+)G%nwzEPwI*fVeNs+av(jTv zy4_FGGg9K)Mrnl%eEnrh$rT14i&U|Lf%*Nk3FbqZw9R~2^K<{9@8AO5H~6DpzHfAc zldED`f_H|6?p2hq}T$`y$+GCgUG2k=;b(+ zT36%F&^PDkKK&P12l8#A@@!rK$fwzmN8TI03y>!&GFNMXXo}n>&9%*h0U&Tg98sD~ zbEx6yP*RR2)o3{7kZdl|C)s_aV*!shSn@6h-M*03d&8KI`Q2Wp%Qohe1d<0r2|;qo zwwRxd`W1V#73Kd<`aSOWows_zAXr4GyPd@ z7CGTS@wv{zOn)Zw^k?F>^k>Tw@}D)NZ3)ocB_RXa2c#EIfd-QUZVYC_g{RHHf9QZ9 zO5??)ZOFc$+vLweQWoiCEM_huOaNg0%G{(i=eHuA9p;D9_ii!p&0mZygu{u6;c;>! z7!PNX2j-5!#pS1pMK0z_l?qW9`!)K=KPVMCC*gyw z%xRmExS0;-umIreN!L}`gNdPNZtrlRP^ubx%X^1M=MzJ*iEL^A+}!?R@kB|q+pJ^z z_Rnd@tJA95>cZNXC7?w0E8 zFzO;xsbpN&E@5~-B)t^91G zX!q1T_F@zDCBUWPVLcqvDf2~lHf?j9^LWlVZ0T7rzXFmgeHV`rfW(+WiiB${_uz4= z5Dw6{N;z$p#A=ZUOHqaQ+kv(OOY;@L8@d#qkxFyPH0;{^0|zNi>ac$^QU%ZDPO^S2AWT*{X8dTp_= z$CC@Y0=anJ7YI3p;fU9zy5g_|GU*|nTIVh?5_SrqfL9EKL~kG@xFV<-6;%Ysq(g{> zzv4@KeQsphAmi=3#puCuT55R`aWNXX$yby|llVDrWLU5zZSnlHTazH}c)f9!l6h*L zY}D&X_>w{(AS8VWk2e~L%5s!X1dV+HJxGNeEaW<1z@refZSe8JAellnyZ&bN1{fo! z_5z335_fRfmtDWC)_;n8CrSS`aMI+vNEp!d5i2Q0@y^LapNjYv9r z5rYAR4jiy*)nWlm2e*cOoU&A+hq)k+j^~MTFf24PrD(J--Oa_8MMGQhu8WaP+g~Y6K*k9MVpOR5pH~nGt!@mK)LKr!h z?V?={$hLb0yTgVb5pAPs<5vQ~arza?@fs9^k3r$;SuQQh|2KDcdW6^Dy%E3jJ=pjf zof7DSi8)N1O|}UV7LH{P0*Rra1o9J79z1dYO>@jr+k6{fq7VN!h~2_ zflCwMG1lrz`xdSUzha6fzmegoi3JQ5XQNc7Y~2j&yUi8kKE8cG*PUlB2rjpfObYJ6 zg)@FGG0^HJBQ|k2g?uf|C!nVo^p>IGx)3TiJx=ggt8M;|qyTb6G!+P|tCa1qsde~K zz4z4n;Qs>Kngt-H_y2=KN>C|mfTy}}M{Ya^RRRDaN5EQ+_yS4{VYx;Hb4CCqa71}g zKe5=mwD|w}0z*M>zz2x<6H;;>{-erujg4?Aq3ekfYD`Q;ru_~M%E+n{b7~n~pV_8I zq1u+f*OsjjspVx84Q?vXjgrpS9Nq0(_htAzFsfZLN>Lg~d}OLn_%Pr5FJ_)Uz0Z&B zcs5W=qLft!Hc`??bJ8Smh7ZA|0BY99%jj9SazdqndSIbMb<{PXK#ihIxJIj}_PEaK z@^yj0b@IfkktTC=uR|Vo9MH4_j$zrccT^@VES~K=mgXwxG@*_l2jp0bMTkXQdLRj+ zui@ZS8tMfsN{%~FPysX&mPJo7kk1E-at2BoZQ*oE^2bAhx9k-{asOh#xqm#se1%{> zA1uu4vRs0BsD65Z4ebwmBQx-CLc#5shJyy9;hqwyif#uscOO6WwsJnpR>oR~@0uFIbYDI>Nol=|-j=ab2r zcf5?Hu%&LJv<((ZpFDB0M1E1|IZn?=u-C^IpzheMo=YzY!d~Ph`jjB-!yCJsj*ov< zy;1!#KJF8QXN)%t)hu#peG}?clEjkuw3+a`(4UTQOd+x%ky6cJFsVH5O6N|d!w@E24&wLSAoqhwS2?ksYb8k?>(SQ;~8sS2*I7?Fx{z$ZVxdaQWfP9LE)W&jZ z{WhPViZR>iqcc_)8##K!N5l%l6I?YLW5>rl ztRcI6qzY|IqvR1`D!Qi9<(+ny=G{X?7>DZjjAi-F+OmBZL>}4T)@UKI*5L8ZQ?mcErOLj6Jf&ncBWnqK2Lu2%yzt{STJ3^J3PtoW4uI6N8~5Aut&?}% zzuz9%ozPF-_4SamI9YmN{*Ywue0cxL$yVO>l1q377yL=_++Ul8E;ri=BjmZ zJHw`xVT9O8r3lbL`Z>T7LzdtF{RV&~TnQJ(-~d=zvN|199Uwg9DE=cib4Xm3e4__h zmm7Y!B8|>F*iuCh-Bv&#DL8`hqfR9%ZihaKO!;v#0x&Atz(5xAxrhSN0E}0FC=YK@ zQ4&F<*q?sk_}#s~{lWqL)#LlWVE2Da(!UUw{;QtOHV;Ht{GOA}yLx|qPw@=X?#ZgR zj*PrIoO*2JFa5UCcZ=G@3hq^e%-CiBAGioP4VQB6P3|_PII25!Jp<=gwiTFA)lReZKFO>xX>h8xCDM?wyM7PugN0#UBZZH>S^t z9!OBB_*4f6-{C^_Pn z9v#s~GQ+RVdgCLqT=0eSswAbR{%|JXaXwo31x=0*Wzzpcx>u@6pC7(uTrSk* zDb>v{MZZBGV70KHfRyY)vWZtf^MJxDB;k;9v?x(CFgYruT> zV$qax;0v(HlQSB*0T%@fF-ReNU`$N*gY39%VKPvj(30oWs}(D=29Eeb0hdq+%66L~ zz=;&c9LybK$V3WnSDORuCaM)&(U>?<9M{50UpT2MxNUU!?q?0TBb^-|56n)q?uk#` zsGeM84!bpspA`kWO${k7xK6}!e!&J;*W*V66SuuC*VbAWk-t0|uqm$5d?qk)1GnR$ zE9#b0+-?Q8<_J-7Kk5w$U}H5r3ZCIj+11^0M4jX614|mq1$ai z)xJs^k<|`hJc6AtUrag`;z9!t*sM^G7oj!<35Ne42@n_+S;-d)Sn%Sk$rO>Vyrefz zJ{TDHzhckiHS)rx9iNRAOSRfd|P6bE5Lu!MbQF*Y~Dn3&kU+@LQ za=z&cIsxe_A+U*n_NvpWW>v0IlP!s29m04a&w~ zBo)kx&X0>8N78BYc=w3bWGElk4Q;^IOr{jru*bovjEDt#p@KB|=H3WTLS19;35|u& zAO9nC8ru;2aHrJiw(HKD?&JADp_sexrlS<;G`K`kkRqn>!|=I<{9Gs&=jIj!UPigx@kz`~Pu|xKN=yXeLPp`p;gRo);7@3I5ED7_9 zVHTsOtwEj9r5wH;_(Pz+Pqz-s8dijLH%cS6J16J)>TBW`49^N6Ba#oP#|+0Cm|5Wj z&s`d+J_gUr3O!v3I`B|@2$^Af|BTHLik9<084mQ|!OArSO%Op^eP|`}DRI@0&jK`S zES)|^P-?P_?gQ}RGB!;aU?VU~bSW3nDTXgG5qL%R!Ku{wS}r>|oXFOc2z$5@h%!n{ z48%~nUY~bN%y|+s$tmZgiwV}o8*EDTJbHz2K4~9mLS%4vm;+c9;^i!7h50M)%6$`! zh~*6-hd?2Dx`0h($wmQq0dY$-blFjX&5FUeAUU8%vo8soyT`Y7*ErNiY7p@;$>DR_ zUAFq@G%L*xd!v5IG2|%SEoM-(s{k+dU}7X5jwC~u??7gPL~$$@$)Ugye&kKzV-usN zf)Qsp%h-O@2AeB@-EOa!%@zH~FHMXALkgBlV>vjUL}B5`+hUe39A?&1e#!rtfaFKr z3!ZJBbp6nZ0=?_Hwrx;#3W}=t{V=TD_6&orCM&E}6+R+d** z7_vee{|2~O5S%fC;Rc?@cvYe3DndLa$sWO~V7GuY7|y~R)Ap7YKD;nFKR?Oe-U7fq zJKOsTHpK$7OrDGE+7-RwRX0TG?QreUn)lERhrE1KdldI04dfRw#df1y<7==8Awg70 zNHhGViHkw2E8?bvv4C2DUG1ATESnC$W6t zq&|`_7P!7aq@E<;D5JN*au6NH7b`yo9^@dok$90vhgso75EUU0JH6}?e__HM&N;(R zS%a=z*fU<}Iz;%RJA|+!hK%rmqUgs?NOU+HKC$y(+JZ=YePN!^M zx7U?)xeBS2FYaW!J}znZ1SW{OM)K!=IP}?%%7K6!_z>UziC@UOW%oK>c}IX5PR*(Y$N(}E|IbDn zSDJsn9awqV?M9wt&r>S_44GksC!;>Ot8o7vSZH`-nY^<(6plvvqZ%yqN?F81K$hZ< zXg&*A;#z5qC2hH&JGhQl%5Gm9L(5BvME{?Z0)(F+HW*gjPd{M`gr-$ou-G2~xW*YwTWbs5t zSJ1ab(oI8eEy63eqVylN|Cq4h(=CXbMHQF`;EqC#*ivk>_S%{hj-$Mjd@>aet%c&L zXn+?!4)p%0RBy#lj9QDtfOfx@&5AIZ3BqLH&9eMTclv8Im%f&E3y$D9YVbL~VApk6 z#lg@Il}d-i446Oxtne?m{a`nrL|N(r;)b;xs80o<8pH-5*ABib5}*YT4-xUr_mOM? zlwV_)47ufq$0x@j>(9_YnUsVVy{bAJ#J@Cc>ugu@rFWPM-$)kB(o>t)S1+vNR<7CQMSH z#B&)$?PV@Do1Gvz$^?z%5N|{|a=LP(FOBG!F-BKzpd&FmF~hh<3EEZw3MO?{7x%Ar zRzP>zqmOo1VD9WbdVAI&az+d*Wr4AfI6yi*tW^c3KulFk92_Ko=C?i_A5JUwgReMf zSJL_TJy%_I2%*fW11ZEgZ&*j-%CLQ6VPV2PtRQS?{d;eD3uM4>7(vc_MQUsveMZU{ zsNcy-2h;N`%}o$hD9$37f%HKTC#}>yWe3(L>c_;}Yo+&x0-n7i;<&ElQ)8tPiqw=! zsa)?njRvAJ^-^b-7;*>v(I6`%#!~XWvC+}7eR687^E_k+b0Io`wTyU1t|$a>H8h5_ zIJWli+?-CZT|+~uc)TDrJ^_A+CCU=dNA5=L0jhmHi`=Q=|Ujk>PYWk&HpZ z7L_9ZVd$A@^&8SB&1%Yi0sW8ZF>KmAF{26DVA75t)dF|v>wBrqa$b$npvEM2aD~$I zD=XQs5AGbx%b-d?SM{YO9fGIH4^Sa!R6&m&dKlFJ`$W!$BD1s{3Q(RQii zkv#abx&r0sSD&59dm1IeOsupe#FO#aM?ySFPFau~1z@7{i;bMRr}wozYRtb6t<^;Ye+ z^i`#+(zj{1s#l%ed4NeTcxv-ntZ)hAx52dsl+S{q+R5>90E^NpHc3Hl9{-?w^Z6I9f|DC z@`KSSe=-}}Jjfn6bpBA(9~+Y7(%zD^5Uyl*9^f!d2Lt>g-Xl=J7eq)YkUDEn6hY*y z&COOJ>4`KHuPMKIVfulY*UiibQl`9bagiOq<=Xl8rXNqUL*C z!Jyntn?ErU`#Jyfz!*vE#_+8`$mWuQueLDRoRS|0E zO{gkz^r-0*zk32sP=lZTfR57<73Xlp;3q7EL4QCLa(`iez$^IwUGDeCr5OXga<6nI zN}Rv*Zjxq0rdt4OwkG#3A*@mB@X5%2>A)AQu^=t0xOW6u7v9LH_GTCdx!s%D<0c`> zAIFj5G24|D*qF_M5}Rzy>WG}q z3D!}(Tl?=WTE+N#^WPbu$i_V+6tqic3t zH?4SlehXs>U_1k`q9O6+U`f` z%_t%DOVBcOlfBjCnvv0waAz0JykyTIGt;VW)c!MTS*<$NNZ?S z)@lt!iBMdUPTb6LIau3s zO7Z5QgLfX7ojq{Fqe%g-rpZS!IuuC$P4-O?DCle$Q1)yHU`^y^WR4+uJ`3%cXI7w9 zleKRSJ-(qelFajr)ccY4OtU0?Gx@~L+7IhP_$}RHfC3xD778w?)F>JXM1WrTP*>A7 zv<_0?0accolxeIk(N^b}jXVUp+%m&m*&yQxxhbotkmeHaT!D#-G>VMRMF>Fj4nPZC zYF4flYT(Hrp+&4#z$(mJGQC9=_EW~DrApZt;kGbm+Z>h@=mJ|wXq@4 zMnSgwB!z{ir=0#Fr|7b}hMCoCwWr45{w`8#ss)Pov)W|4U3J{|nB8`5=oXv(Z3hlH ztalXmI;`{8y~`!Boa~P}>>hE*&uk8xeIx{9U%=_G@~(k16;#+V*}k|@7LqxhpdVt6 zIbX?>1PAa&S}dHZ044*3tpJd%5bDAP!LQI?5O2{}RyVX39p)Rd@5jS1#&N@S6GOU+ z$Oc-&G^li!5MOOoWO**wU<{^-i&zNyDPyzVxpawb0Q>RZW7r~~z9f+Yr;%!)&6Pux zZyn7?+YF5m_CyjcX#NwAk}%dd$>8^gp_S!My@g_(eA>4(Sda8oSdicj3^9HkDY)o} zu5so~;bj}#)fXLvl8yK+a6SAMlFe`JA3=zpN_v)l9TP5eUYU*!Jlbm5}~8yt^L%sgGpq$ z9ow8HSw0!@$S5BUN`PTShAncV?ya|s*?}|#BrA|JK|j;0PN~%}1&wS6Eja2TUs(&2 z$0P|7@b?UiWJF&TQnets1_aE|pH!8cK*LMOn+Cfea@7XMq&Qb7&T);qEC~W@Iy{bx z7h~F(&kt2b=B{71?Y?S`@HZeaCqQo#iiOh2Jp-1vPqcruClz=@_4`fv_1*G0uMPq}mAY^Q8&?g{=B!`d` z0_p}EBD)w!dg7tC$!g$4P?h5$Zy?OrL0e)h4z20tAF1Z>>V2dMF%D|qx7wqDywmN9 zM4cf~gpx8Gu}7RXTjT|fp9p1>qUeYQ`|k)X7jF;86*aJgyUrj@ix$U_#0tvRJ#q6U zzbo$C3CDddr|-^}zSFiAoEx|$-5Tr3uz8R?6Cy?(5z!xD%NPb&jc6ievB#aM=!~dZ zrRnLJ8BAlmVFJ|_Y_-{Mr9Dxxgh#O(~b>-FN~kXHio&ve z>PyRtQ(tKDIB_@LDg7G}D9Zg2|2ytx!~Jep$6QTxh6q1${H(2WR$|B{Q@p^Cf+yyb z#aKC*P_&YuUICebWf@^+JdAC@iexqetBN(Vo{_1Tu18{_R5+Xp#Ui>Mn;P+C>-k*= zv)O~Y@*OgB;MK{7)u{dRT3pN`&M}0`qggSoecm2b!&zNVSH~1(teV!_G|s?)K6Hc$ zUE*MOR7$pig@dV%|7abB)nOXfsKt|3TMk199V#6b5Tmp06JR`j2BCyEo)oR&dcw~W4`Rh-Iik^%4D9w= zI2+FT=&;+X4}Lfz(x1)gqe=Q#>&;18g{W) zEkZxENz4JDND+@Cl=q!$+`!yJv+P?TcmRbFn`ezu=2Pdeld_gZkpR^ewhLP)DbcAo zBH|KemEewQ#o257#5y_`r`j@_Xdq zg`m7AFYJm%N+#VP-+iJI_fBO$=m-WKAIwhucPT4OO$k}(wy@ajL=uQJfP|Z5A%a_z zhPVtOje6wy9N93C!UI9Ko8*d?I!%haQe&3HvpC0d4t3<=p{A4Y)}!42A-!sV?*jcV>`Csk;yPDS7H~W zz9%TWja9s1ZB0jJi}js+f-879`qThky0GHJ$WfiqnkQCdBS8Su7y;fzauntO2Gh7d zvkl^a>o(z7h2NnajKCxo1x@v1iYtmCA(+ zc$Ki9z%i!tw`AflKYXELe#UQ`u+xQ*GyHahi$5VS#}UG{kb$_EmDeFZVR^uPxgCER zJ8h$jSt}lI<72Od^8>S`pVW;DR5T$Jg3MbxeGv;k&ot1>(t5oMpxo79l#7Sk=p5Ds zAzer3b-N|wNC@XPMJ#giNkLVDz$?Z*^rWnk6DwKXcml`9r0g?HlM9kp3NaFWNoq<< zOq1j&2|ce19UBK{ip9VOQ!_(DGbwdCm70!ZPKFj(7h!Tu;T)xzDNNH9#KV4SNlmMp zmv)-t@!>u{Bgw%SrBO1fL;zpKq9Qu*s$oAwAFv}5@fM;WokT8SF9+XK#ETVGt>DFI zGw^zg7!rRXiZlH;d2()Yjy>ML;*hZRpl36Gcgyg;b2+7WpnQ|F5@5RGXBIQRZ_lLh0LVT zOV>tdg1~0MfsukpYD`Opx1zBth!V-l5E^LGv(=TAUQ2}Wfywi+^rE6HrZWrd^KQu- z9*KsvlHXrK1jL+TwIPasqq(vCWbcpcNC)ZjhuKot@9%wsWkk2V_Z-}l11`-KaJs!r zG_w2z*$_2hv{-!z9ocR z)7AcP9RYAM(I=fUN}DNS40twRisF`Dz!6!7rwLXzYsbSx(MFO;OOzbxb-TD#KRc5} zop4T+O4vN0mFfea*U6thL+MT!%MK#7GEpv5F&&*_rcm89{hfPsLYak|fu zwBK6GLMr0OrIAZ8P1>qVoIJHRM_hXJ@O)(Yn)#%Yb* z(1c)8D;{dVwWxODaG%EQg+#Y z!ws?5y3Zi?ZLhlwg=AcvO%Khe5X8Km=xCHN4zm7)Z$pN7W=LVa?k58g?X8~bNJ#?I zZC&FFXnG0DTvG}PV?$+CogTV`??G2G@84zo4xA6UG-zz=9N7Wgf!Z{I9BG>6;JmXR z9fIkcr8SFTfKx{QQMn-3$B%~3s{rzd4uHHvgpmSNO(Ap@No6pv8#>r7-OlG?EHwf? z<&{;J3wbR@#prH{wvq{Gp~48q!8vhxD2132yI}WLvyi+>4A8_rqAS(W#HFA zGSuZ!wzIwaRJ+r5ELsYL1y5NmOEcksOFU+~!o&ZqYPTO1oWanHgbO`FI8cfnvpEO+ z04QKQjdo3O^s z{BCZ?yQgs>U7Nx-n0XgnRoau0GMpOMAsth)IBJ_lRX3qluE76Z!NLW11c&8YNi>N`hUYG6g;`nm%ke^{9H|GB%mXtPnzZmR|U`z;8Bp^ zjGGjodBW2}wOT}=hm1YwhA@^^zNY{{!dDhcm2%Qyy0O;kDwt63ppK;m+^7*o96daz zYQy{MA3DCY^x%URXdsXXjNmNSP<3=rpLz+ak-%g_Q!7`E&eZjhSZQpmG>Ujbol_CR zG(mb280i_b%Qcj`08Jn!+!v>n&}@iR^pbwTO#Na3bZB;q-k>)`L6G-Y%hdt`!r0e89Zq=d_Oui$B{WW8{7&zuoy_a* zbO302P+z~{@u(w_k4hPbBUDff{@`^L9v32hf5g4KjJt0w#LJc;mfO|4v)SEOkN4lP zuC_k#gJ`=B9S&h832x`$+k}TW^Tq}(M&gk|0V~AdX~0oe*a7N8|G{&-F7ZhwVZ2x? zHJvMw(2W|zF0V!+cnL#!2}8srLmmO8U0Va(?{W#A$KbpATaw>!_o2Rr{;VA8IB_a`LRC_`!##g z#g7_TjaiSvTisKPdt~B+_TInN2r)rtl1Fa)Uk-b8B$;W@se#AyK}@z7qIazi&_Jvp zaU*IEIcIsaT(MGFAps6a8x08dd?s@VzcGQ-8BRc-($VqMzVbK;N9I9)Myacjk!~~GoYknUhkRP zPu+0_Sq22`|I?Y#WL%A>TW3bocu#_el$~LF@f3683unE!e%O2Fj#GD>MKvURVc2_1 z{~O=ze`B45H{^vXo&sv6MbHIkqO`E1Xs;zw<1I1;Mu31pVG+$lAMqwri@#E9*VLNV z+s18b_o}DN-D}k^w`;lhp^Ty`nX8qi!d_!sIgCrawX%9`4d0;MQ)(PnmNGFlmice7 zrh-YT0mpR#ZqHlpw>*Lgi;7?&NRGvV-v+A5Nv8nf2~|TCF0!?1RZ(rV>ZBFwdV;nK z$S5cK?GW*+1T6eE1$uiB)=6w+CDJG4w z064*LfI+@=qe>9~9jZ+E{7%vCcG{2|!R2v#LVmwL;C5MqisZ3bJ&0tp+dYyTWC0{F zbA}?J0KRB@4{_tI81Eq`BHHkRGto~i0adgKJ_L7(ZX{*&ij0Zyskh^6E~K5ZBPtic z#tyqL;75fkpA@m#yb;Og^@V)6-YuZ8g2(HDI@ckJXr0&QblaS+q>u0`NrwhKfK7OV z-x9Y)Mi+XdBTLlG`p z(&-wqA?KLGs!|g9;Il`55k!q$qu!jJy!pQ_vk(6!6m9llpGUR1@QtL)ndCbu(PMMS z{`n)1fM)joA$_wtar1j_hAzXP(i@-{LI&_Y0)o>!Pu33@z%HEeXiX`6@39>j^`WjC#==q=Ay$O_KcYWupt9{?EmRhbEWRc(J_y6CkQdPH!GjGnB_g;5Ny1Mu3-v9kCzvcVeo~b+}9}j&xl1M~8 z(={@YWFp)=`-2YlzDg~Wx7_1Tgh>Dq2nBvJ8!0euZQEkuh$xH%-u8ziT92sh_gnYO zT4z5yV86ruZPbl|b@!}wP8#b>4l&?~E0mLeSn8c9jE|mGT7b|<^mL)cC<72Xg{7); zd5^5Ets7mWEPXK`Mf@f@?R7Q9OhsOjPaXOTHB-?+xT$f4Q-V`tn#Ay*s;{p0%6lepfiKIS%uqM_Mw!z6+zH=R8AHTFn)bkX-oS^0JJo7;G410AO*tao=}Q~a{0qM_C{yt0x?OF^|5%Y zYz#YFO1{&92|;={kO#|wofvKF{@&xpUH4m?#-??DoljPh7`nurWItk#K=|eC(71&<@+2aC*VuSzG)W{RC6Ei%oZ%i_1eqAk)rte(x{kRC%M0I-hR+rsQfqd$t4qQ>VlEJAeLJ7g|AViEw$*2=rbyY|yCp_wo=Ze~qhN zw1JO|EsDMMgAy;e*AUI1|ErE;+1rqZ(FK6_5G_jTVUB=A-k=HqOLVF>KB=Bp&(gw2 zPdyT9HkAzo6c`u)U|3nr=HNd2k#@p&#In6-h3R^kU`(wqVrk?t3TKvkRDW{pku5S7 zbhY6z*88qJRH~eazARBh2`Xj^g-oWvkB~=?7dl<%L6B%WTS{9J-AO%`55Y~S>>dv_ zN2uKyDc;o57PP~lAY;HX@vA4p&$U0dDnDSP^s0LNCo!TWr@Z-uhW}m{oGNBUJls*TM#}6?#mT@gz#o3%mO)IwRN_mf2iO4sGg)4Mo4uSo>;d= z88TNz&%Yxpq7o?nfJ(+3#BRuZ#2HHQaJxZ0I^Hf$y z0Y>mB>md-R%Bm0_1b;xj!nT#BDC~Q{0b!+;&!Ns7bUqmPxu6=(@3Ur>ul&B%%H{J! zgC7yYi+zC_x9000l_0&lk~=1d3dc`KSV5COTOpUuH%JU$MHSCW3Mf1}Q?qlmg0WVp z&CQZF%Sd|M3B#MFDy-qLsN5Rxr@hnN#Bs^5pDxN7nt1% z#IwVsq)!cJo*EB z(jNyWYOOL0#W6BCXim9U`9%hmVG zw1))$o?~8X9}lH`nVbEY2rIn2u`-|RZOX!(k-3?&crADF5jC z*;q!|cC=|VN-^?VT|dN%ahS3+s{%f|?iJ;?*0=ASqK0R5-s4|@y9u9=UgVuw>Og8ai`*)vFS6R+030CXjj_1b}hFqKN zG%FMc17fA{C|zQr_&qFu{CmZ!Wu3APj<`4{1I}z8w@Rl3A{LnP8E^q&EnwwmbA#KQC;JsikSQ_v4U?d4cwK9*AR@ZsIbS-JJ8zHu zd-PN&u9gwBQ^oQ#m~|Sl3<9n_nR*}Telng+##^BYbL$yrW<973zs#fF_GVWu(cSEH z~CCDM_u9?&OdpFA=DeMHRp(-iiUXq zfEtg_nS4=O^#;m?s0`bv3^*=iEbpQcj)WjD;He7uBJMi=dt&9WVREEVs5Uh`R*w1I z(NOOXLs7T!o@Bi~X(|z?YffUU4J4z{B+F@o!NyFY;)o|P2oGf9kcR?qUs%Klf*)n8 zS`(i*nFe_hZt3BM0&D`a)7N+xohnZFf6qTrjQC&lA_|j5vca??Q*7j9+!`CZ-FSF< zcz8M-jAn9~1bKswXrUwe|FX6?SiO`WkVW9CEUHBn@Ejl^AX%(5$65t?B~HddfQ*^t z{Ae?Gw(oRiQ;QGn+p4U$O`ItFZBAU(-n+!f`Lo8kL0TZcxJO&8)Q@_9J)Ha7!U^Tp z25FWM#%)H<3p`L}fl@6kB^hs-t-_hrf|ErD3=bT$0#v(gtUZ>AB%+C98lB_ zeguXK(%M1u!0gg)KXH}?$Mr?q5FIsxXO`FP?h^#LMXwN3&LzqYSz@!aD^uo7{p~4M>Bx z4ZG~{&feAq{{5|Gt=?bi{a0fR-M>R^@os}WxySFf#J5(l9%=J7B3oI2eC7mCzF3tQ zE3pG>0ACD*n9R5fI4P?JaSmh|$h2BhnlauYc`Svl-M2+f&W6p%=B)A6=y(FWEtxyp$ok?E^8NRrk^n42x* zcOEcT9sr@94ZOsf6_xI+HXP)R-_>4iTX&{sAMkT9<$vI{Kl;FmDPR2QU$o|8ke;*F zaf}RB{`j3%d-d8o)9N~Y{{yqHh19rIhF9@I5i4*DHR23T-{%#WXyXSkb5V&d5B8AR ztmeo;%Pgg~Rb77q~>du_qU3gpxkeX>_yE9GS`*-Db1f zXk?@9Sf+cvE!vbuRR0X&N=p3_Zl2LoiJ&E(M>1!K%)*l~Tx^rJO;~VE5}oo@;8H|x z?3OJ)l{P6d(1a*eq$pUCzaz^_`5#Z$3uVl#IC7L?xP!!pqhBxOhbv`k$jW}!?{B-y z-vTk6#Y59DJ`f)Y22)Xg7&{8eQzn@k4*SwE4j4~HWBI98sXmPiQyv)tcL@f*Zdqrh z7du?)hN<$g50l)+pDXo#8?baXHk$B9d>;sp9HxvxGQ>j$i zGZCna=EtxV9Fl%^9C7cbsix#3RH_h(XJWxZ+KeR3awZn7vfv$Q+k?NFfQaI=R%XyN zUcUl*A<;_AG!Ntow*_d7O=~19ik<3(DKwi?mUR^@#oi1rIh!es8{URU1XyueQtC}5 z;MK`h(T0uHM)ApdeH$Nt^@k%Hg`0Za7N@JEO8A=9CC;oXN93)+rhJEv2{|v>NOgf$ zOF)dNCzg1xi72B{F8ob=GzfB*$JR74p10LJNuI1yf;5+QhDS$Qxf}EGiF6y^RA7PmspAZbG(F(@B zt5!FLSA$b(LA=c+b^j=c=rl_D3Y1omF4Az~dlR6D(L|029`QssNwp@6A`r;so7GH{ zg|fmS_V{Wf9A5Fs4nS_+YJLy9@+)#GKh|EbC(Y7C;bOy+sD%DpHh*+~voKLI%_l16 zh?(jAMJ3^Bc#K;;A=x;Y8_8DU-!VsdkIM<^57zIoZheV5=@I$aR}XI*x2g-DP`|uN z?sT$X^6>_BeZ#G;@(h=%#Q)DXaxKMuHLr;vec-kOrx8L%j#XxsvaTqpT8q|wjw!;n zSW6pQgw1YIm|00?u=9@WDgG!4T*-BXvmn!h2vDr0GR?$dssv29y?hH#+VuI8;~4JQi!U-?Yf<{cks1qG(i!$PQsPI*e!}g4k=1v z{9(I`i}Gu+WtxjT4U0uk?d`4Ap_`v|HQsLh+RcWmX}x`G^|e$VKR$G>TdZGe{n|O> z9mS?Kb@up=9BxlWnnJ?TR?|ZVv2w_ZsG4K!I_>E_E$tDvKrM5GS;9KlRY@I+n~)(? zem>Dc!nehZ`o;P`ea(0Aldo+_#Xck(WOpycg^zr@E-~v4N$^7wBn{EDP_c@}J!(q= zf8h2OSgKY7@?L8>@{{A!X)`#)X`$(U!<8J3ye=|&^xp^FKkvR>f4M8fcIezboK$?g z&$cG6-X`aLq@GBn9&k1in}gU>Z)f1-iT;56K8sDIOMTqN#@%vAF zqiiiA9u^mSUpli=Z2xHQNnFl~vuc0ud+Flh1Lxc2w%0gSOmktAo)s{69%e3t5M3l6 zs6wI@`;u+=l)?*E5RlNw$LuP{C7NYm{_nno?f)uLX zWwSrjh^XH(Mf9NVLEEeNfI%mX3C)3l-r%rU#8N8XDyW;|`ho2gH}U~)h4#%ZWAiSJ zIN#;-MnhzN_jm%KsMn`L_nx$FzS){T6$pg_yk@NVdFy6lM}TI-jRiRhN}%>#xgbj{qK)kYdd>F7%+L&_x8wcB}&EyH`ruLT>4!V5u*9eY7<4d zB@ly@TQ%0i+phbLoyJ;y>)i6$v$q_P=H20{8J{IOr=`uf-^4EBpc+%AZ%otgGuAR~48>Xjk zSRQ?U_Vnp&`;M`(JEVyF%nNT=42KtQc;QU}1W zgsqSSbRkilND`oynJM|$U}}9+mC?K=b#wW#Av|Trj^p34@~4x+J&)wGrtms?fi_2;a)yGwgAgy}N1u#}Hl*DyL%Exy}2%J3C} zfe*<8;j8BJ`|PXlx?PC55|p5bNkBR1^v9*9R18JC)o>|Sx7|)L^@qTki^Rdc0a=ef zY)JeW8#}nO;>0Df-?)56@70IYJETRh7C{KDl5z&~SDJ?w_eNghgQnfO6OjS|siM6z5wE6=Q+u%kvv0;udKWM1w+BU9GQt3g}2 z;-lh&rk*vEyk&d)flxYh_=(#*F_VIu`y&4QbYhYF-{A2??$uT`{p8{iDzjxzeB>qW zcR~?ANA-nb=UKe$9NdFIQ9G~)@`)IXFXS%d{dK;h4V?4szE2DVOVhrSgQ3_bebc4j zP{J9TRO6`sN5%j+`0bHfbNZJYj75@HPwt!1Cy%BgF+G@^lDqZDxXvc0m%4ZhPV)o@ z<vS+Hup94=5xNA>*Ko|BZ7Z!DxK5S5gPoSQ@#w@8WC2gQcTqwar zQaBS*1WK*6h<6kifK6vWsbytgkyMJcNL|KLD7`NzifvD9gb!Iy33_Zsmm8w^Dyt#i z*ZjUalNq{X6`l6BT@4l#AF@u#0KaAV$=B9T>3!d?KgBLjI2F7zk{V@_IdMaAWjR5P z=(i>7Cz~7|t`kC8lvj^EqUeI8tAthv(OFsf&3j3bqy{teUZ*`e6@{7Wnx+^`@-<^4 zNEJ=B)}p!liMQ@;8`wf+>g$H>?&`V7H@LXtRaAgwT#FmXZLSx&?t|tz>NNKjG=V7x zf2DDGi3O7up+d1&??jPWA&^W<8M17U8YNo1rJqMX!QeLJ^AXE8oQ`DzVV^(hw){h~ zjUmtzT} z*Xs@6=k@qP8Jyt482d5-K6my#tE5-Nz${V5FSe2AHwxX}R5-XqzzTCl(IP4@fRfS@ zX$~W7K$sX2Pm#OK)2-Br6RFl|^RCF6Y1WOgU;3q}zj-7ue`BR`<9y&q(?1l8{U&o2 zCr(1jcbTQvyWZ*gAahlWxga;s!>HS8Mg zx92J?o@3xb#+>Exl>mi&SX}*;Xv}X={Lk>mBNe~L^7_h#QTBN+JM<$mop>33g3GgB zPsZ@&saS1zt6rQQgPwvH!={H|qpXJwZy}(L`Mlnsw}71FzE^S_^ZNFZ-wW>v1Peaj zvd>M;C1%)^FO+cmpYzBG$7=K+5+26coAh|bkih&N+!%(4nhzVEagQhI#XocZkk?yu zdoi+l$2^9*Gj|`5^+gq=2sp!oi~`7HN4|+CllU~W1X=9EZ?&4hxi()1@ofsTVvlK@ zCGKrM2yO+~FP*T=V#UHYxZRn$zG)RrE0Gq?^-OYPs7U?Wp%EQ2w^`mEUdUS1q?tK8 zT*|J#d#!CXZ>UYSi&l1FSh$&H`q~JngCT^+E7V45zd|vfZ_3lqHv6?r5-gzm%NhdF z#w+1cx`=xPz6xyg_AV*A;s*R@6I$wc6#dWeCo=Hb_&0hI85`&vN5zRKFOeaznzwwA zbi1*=#=0hen)$4WTZb&(zSJNx(5&zQaDWyu>dN@yqzC}UYC^*XZN6wO2wS6Y-Y_LY=5~vPjw0dRYlfB{=tRQKi83hu8K1IGDoXh-CF!0%! zmE@f3jJJ(U_0O1^wNEJNqrpHq8aM7qIoIcMMSX`yxcFz~E_TO@h%11{^>n;=qR3-u z`4&Z4v68`L4J&zv3j=hBFvFVS1AfRu9UluhHg@?O9VusL57^d2=LTU6)3Nm$ca9B@ zNb8(mhsO@v(oYTi@N-Ut-+sQCX`-L5XK-$Y;w$w;t$YUJ%Flyimc}qxXpD(^5Qn9U z&r^$+7Tcx&{r>5Q(=z$Ah7+mDj2!7X4i5h^(7cIF1?%pI-DM_I@eynA`6APPKLh^` zCopw;;OCTD=qgOAgHy;hTas{Gv_f%e%qtU}2pX3&W*$Z0XOtZ%$RNjdwh86vtgT%* z#51E}-8;OK1S_3(!&#!v=S5YT-udQyGLK9p_U{75jR?{rfcXLCZ;ooZlv*nwKebL(KFNZ-jJw{(`SxOde`>)X-M{c-OP4FwC%bx zQgzY4MIKlsQ0KeGciD>3gDrwU1hLHH)goH@jjuvsVJXdd}0p%-?gJl z^3%DkT<*+SkRaP0?07RhST1j#KMTfZP^m~z;EU?oEN3JNkq`rMPXM`1*_)&~QPXgZ zE{%nKp>V2_ojkEv^7=+sZ=28OB0*nhVrj&1Rj)e|^QKY&Cm!$EQhRctbF$)dC)3{e z(#Z&$)8;h|giK zV9ix(Ocz;kvgAMt(M7~5PpJSc$>G;ui#2j`Nqs7&0;N&4F@5^)tOvX+@oYAZyps0J zmCkL$7}I46d4)94;vM%ECNBJBWrVYq#@lA+n}1h&z?Y5xmv}ZFowv@R!4$HS1<#mA zV3~3*7#ho#GOzeaD;s~~8`mTpK*0Gux>*vW0UlR6fXDK)Iu}T%-J_{;*$kvPH}I zbnh3jW?-GK5qG^Ew}ukE#~X9M^{13{-a+>{wP^M3HZsNH=3HZS^IcN_Z~9Spjo)Xu z%TRnC6_0J{ZXIE$5GN<75G_Z73j4$zrH2j?_2(~6m%Fu7sp4xqAQ+LI#ojkk#h|}V zi+;L{Qz24{+g(m@EHPxf@XQ3p6&x!(uZcv7n(Y0mVCgQr-WoLT{<7PRI0F_^E{=#1 zl?kL{zn)^!mzY4*=s-af;6*V>fz#1NaAuQMo8oy<1%AasN6VJ92%)43G!+&m2lHJ= zMlS<>2hP4al!!!A^-THKe%{(T>UT#%A1p=_#Z)}!owi$)K6-hCWDkh>+*319K7xib1)IE0NpMu^ELGPv|rG)6@bep`y z`&XP%)Yg$!zT&Wbo=#EmR6HQ|IFYyXtDY&3MW2!oeYiU~1YAOIx=AQzBjK*mU)KS03?;T0Z7e=l= zVUP2Fw0^mmo_mY+mrSfercld)!VS$>zL~(7kv$EzO>H&emkB^G{FpP!r>tL@OBdg4 ziCvah6@=NDAtr0C#sye4`&=xq(g`0BqshbvE6GD74l}Q7(J)Xd95&^A_AYL1ZAmSF zhU-<3%104Ua=?p6(7Q0~iukp!c{z$#-{C>Q4S>e1OPN;8@X7(DEWjQ(oPGRqO>Adu zG+!JUDdtDVdT&x6Y6q5;WF9>~n@^_yl$ZWyL?kCkbU#PQN6VWtw~Xcs*HtRl74oCE z%-A3H&O(Dw!xfSunfYYnoxBSDJxr3e?WT*<3#fwNiUQT`Y~Og1KxpFBw{N&eVDv@$ z+c`7ARFPO91>)MoSo|UIaM2>?L~|^lxH#c8)JGHuP1$p8zx_3%aS1Oe1i?XDAP|UB zt9HBXwxqigzu%s z-28X%^*#J~EJ%xmVjj&i!jD<%a_fT|NnSRp>X>>w__kGOi2ZAVxeE zVyGNsj3TfG);>DB2BU^cDB%WOl4S@iH(~r&k7xcRi!Z&Gz|ZKwrm^i#r6=6+-fzYA zhH-UV(UJyaVwX{MRis;6$k`zD08C=|#iE!+KmgA%KI8nFx;|WnU%QWA={_FMKx2`R zU=KhhX13&3jOv7&8_c^gj=5%TpUL>sX@7=|fo)?u81!VWJ9+ZDj0cO@z%~;@n{v0| z+9d!i;ndomAcP4)#wJWMM8cr_72#4?1)HMu_cYQ7fV%@7aujz1-=7{OLUy->Sc&bV zrnPx}LKmB3V~^S4a^2x}p}fqq6mD?c!-EOf$i#a-v1t<%YQ*%srEyHyD@3O`tu`Kh zeqm`=>W_b5TpCb2k7+dipU0#fSRL9c?ux6!afup?KpWh?Y;im)yc6B`MK%w8v8@MR zzB>NS2{}9bN!tX=7DI(3DOD+bm~@V0Bzj|&_+IFQM{96O@)i6azXzQ|6gMNWOv(Co zo&f8aT8)2mn*IbGM|T`IlAqKjEuIyKs79Yu)B<=Nf-{sS+Py#b$ppd zjmXJk=RK8#reqh={P&^`aY?CgmxeoEZBTx(QgCl5vxU(Cyzi%w7J|*M$ljY8Hl^OG zIh^vx8C#eC#b(O5yc{Qa6`dieufvHQnEqPe|;4ezgEld}mCIz(rE75*m zM025*g~d~i^?_b^6#zSh&ln?Bl;(x2wEQaO+Yr$C&5NALt8_A+5!Uc)SF*_MFe zFDJ~f?{=H4d|<9PT?nK{v&mtuGLapgiA8gjf`44XM8&T`;AY8Q3iaXgKEqlZO%@Rl z?Py6`mJ(lfF(ioapj1n^A~QyrlqIhP&iO5di}Zam!26jePW84fvP{W21OIgFR8pFO ziOU%lxKoO-)!-uQy?4HRz^!9zq2Vk~hn0NwIQX40BC z#J8~iv0oBy1>{{0@FFpb@$p%*ryQS~Ju785{~MwB&Dmxs^tD9dRCp*H3Y|*4I~I#h z#Gb;99v{C)XJfI|xw&(A$bTWksmq+ym2<{xWJ>XPtjiKa}mvynhk?xwUd4VDO#$@(*Lrm0)erL4Y%vXrMz$$iz|I2 zluz;KD;+!dyXSxAK&D7i+O}o(Q>%8-XU6_Z%=De1D$xIxlSTSmZ>!IBK>gweAC(ED z)FY(Q4i3{KVauh8{~U?OBab&^UHg4re_aAX<<*dHvbXa;bO^LdlWm>Vzr>U}#vqAW z)n6E5rAv+B-*0#H5sbTjKNSd+l7GlYYtXe_m$dyp6=HB0T*%HmuRB6THN+}<7O>=^BCX9X0v>h_nVRt|1m9|D; zLzm_BLP);^B}E`p_w(dDIFnP+_Zqq$tB0wo<|~MbHgV;%Su>yGNUg?96@0f=tJdUe zwS_+c{GusaEBX8i@61_{le~Q8H#pNr)9Gl8gpk(qbiqCCMJXi~ds8JU9!t9oaAwmV z#5g@pbZ{_0>~PBMq4Y&sZEy*8k7KtE1Wd0S${5CJeZgq@&AHl=wc?j3)%Hu%H_eL8 zZ&@eAAOXwl^pT~V5AP_){8IcU=karFl${>BMninN%2SwBRNCP} z%o#9m?MbC5`a}lG$=uMks9KAdGLTU%`Q`WS8#*>7)`E1Z6p4*2lt|+CEo-5_bHVz2 zy7+RpXX;elxcz)8E$GYGv7vH$rZ9QUd@MvN*l$=1{rwA8?@4;=<)KV?=B5Q79Kk`z z#PLgId0Dg>^P%_B`Ks;*DJ4p!HqHjRb^7sr%+=P6B!8L`lNnt4QC88x06ZR+Y1V{9~ zHo0){{Z{W=YLggVP|xM-xoxG3iUEPvz5iOm&F7Nd^)`3Z|UQznx3F-7bdJP4#X((Lb$s(e^T+ z1o#D!5!;uT7Y)248a#~SxD`XHA#hIdSP%1Gd3=kIEhs$A5yJ(|k@OV`wbFqEV4{dN zk^o<1n~jdt(Fx|5UCu`1ywkBFigiqdM@boS1x4XebpE{RThX|8)#RHHB*s`&{s0;f zM*nN#20hV)oYM+r89=&fF=h_pTE4ovRlT}gU#rb`*HkItr{`;cmi$L~ekV>s=6@Cmo@Z1uytT+wC13y>=#u0wmC9W0&Te~iv)ygf zyWN*PaMjH_?|wIpm+Cv;gAK^qS>~G%6Iv`YobFRffUILQlt8scT%y)rlmX%f4W^V#eb7TgexSRC2+{f|Gtg^?k?qmhoA*d58xn(tM19Eev{KQ8F{7 zp|rimcjG>BIkmpOv$JcpuClJ;kBF?F-q|rsWZW8e{tl-6+U5AU(zJ7sv(#Pne9D09 zN!D+;@t~W-fy^gZB@modJUq8ogbg7c31xr!*e2_!twmiEnM?#na{0(@-qq}wc|$Nk z*af*g`m@oQmHjk8-E?-z>YN+8DrrVv8J##X1Pe}Q0`QcqIe`BQgI`lC_*VTIh_i#JoI>$L8j%o*3L>+KcC7_p)^xrfe`zCK3>$qJ#LZ$wK zdW;1sx#ll4Bk58mqyDm~X75RkyMC$`lTbMnD&C+mySv6alleTS=g%}#W~P+Zzlk)B z>w41WlVa7#jLxMw&!>mig7&IjTVqI|54W;Khse)<{ zuw4g5+nZd?kH)gOY;2^kIyrN0^!7+Bmz*!<+9IVBHTzS^Tr6_?=s8`bhW`9Y-5MEB zB*sUq`sCQcm^T|q<|9-YLV(Xu12q}Rdf6@MQXHBt3)*EUPB(^Ch?VyD6YiQ9rN82iR6GS)x)&EjjleYq zwrTu&@5fR57Z_h!r4(`BQxDJ_(@+DO)) z&BU|C41cj~#-AM-cz!7(HKpQCNC>3C$w4|Mooln~B{61CEU(}+rC6mzC~6p0DP{_4 z__FY8YDpB=imyuNGojl6 zh-x>_c8&7HO&d)`oMa#x#UE~p|Co+r*@IQwfKqp_>(#Eeu-LIyiAeTu%m^voJ9_Am zPzE%@iRU~pSp4HF&of!%EB#>|AD0~&$;#_(TDSL;6HN2=>unQ=vH5%wM-DmBc4d7z zYFIlc0V<}f5!6BlrWzOtk$FU9xQwlf2Gf#Mpa;15Biq~PB2u|Sg*?c08H`=TQFc1& z7=8$N6cH}~Uv|<+?pXI5cl92Zgp!gSW&?+XZE;v2i6mzU*|A*}jJEPzP?y_4J6C4` zC?kA9o$RBw;{wmohU|z?US{i*TuzveEbxF@<(i<2{Aoi@IxiwtN8z0LysBPdF4WyP zNqey1(hPhdLAk?`*jUC|j26cxNA`$mEcU*iDkfv8U|=K_%lK017^(J#GNzT!n12nx z&<^E*)AOE4tUMH)8KHj4ui#X}vY_{4IiEk7NQWrGSWG4Ixy1XsiZMyc1$q(xw?h;e z;Z6N#5v%_PvIf+aTdfz%>mYivapR3QHh9r>4w(@ zmwB*JUu!(}AkXI9U&k#U65b>u_hq8lG&OoJ6Tfi7uu1qX9VJ=4B=aI6SNmempa|4Y z&<#V^7<^Of8c0fdHlXY{f-`x5^r|qrnQ~VAj-JHRDEzbOqVhg^TXw!!I$C&TM^18< zB%cPk&c><45&U)_MY6A7RZd6OM53AWD|zl8v(0x|*Er2&RwI^*D1k0vt6^iLIFtA% zQl8bw6uet+<0Xz8HoT(uGe=LmPal2hi;kXjpFH}*T@t2*qB-;|K#MoN@#7!f*!VEL zp`G`>rg~#oeBq3-yo`_v{3GRnhVF2F5ZWp)$#(O-tsgn{Dqpd8_mB@Qu6UxdVIigNVmK^J|Ab|H>}!q2D~Pf`^gJxp%b&-1-p^xf5`*k}m~dl;t)sxd)TQwe-({`dbun*(t4D zU#*^MmBJCYw!{Po+_$yG?2Sfy-*w=uuCvkcO|Fy+3suuSbyYAvckG{LZfcH5^tzPIpL% zMr)YmNHg|-W4E^k3U9xRjrGUYSJr7lTk(Ry615tq6GyhgmIqlJc6PLh<}tSoc{P_z zWqWYsf6h{@NeLYK4R=nsT~{SH*{=8YOq&Nbc1>gBfZilvo&b3AUdQ;Zes7w)JX{$J zTRSLZ6y(lb!~v0eH3c3KkVM2$1=-jJ4u#t&T7sOeMHEgaOn!H3as-@eWU{_?rVMh^ z5NO?buZufvop*x@-Y}()H5wla&VG@+S-JAgj-cwMyfqr)cx#rB-9?nzGro_vn*%^*XZjb)wovpZw$igm!gvXv znyXfQIA4;Xa&lp)IF%nAIxQV5=QLqR(gSjKa= zc!}g7pMe0>n|MO_uq;Jrwf(1v9{c4-@{;s~@*{&)!!%~)0Er5Gr`|uYa@+h$kPNKR z;GLnEXDDC1ai-dt55>ZPTO*tWy1b>{sb+6BB+Ie9n~gtNnZIo%7`ZhNj)msdsxvnh zbHgM`2;CKk8cDZGETh0wojhg_^M^(;sf?oOF)I^2dE7q=(3L^B04*T!zC~rB7RGI( zSr%!#E*S{QXJ74(`iUBS^~+M3`n4&4-FS6zia1igFG~F{D;FmJaqm|H{4;J?j``m4 z{#4ZW{&zq|w~-!j(q#^W;TO;VoFGVE88A9qZ7Bi^L7`*`$sr|hzsxFqMw!?J@2d&W zCrDo)FJK?SvWDXJmIF6WojyHvb6~l@^~`PM#UCphuGL%8r%I($sasd=t@JI^x0jB* zUGgHBga|xKQ_^fH#|YvM`aYM+SE@Ndl#6fW^59U`bCso@&yz@n_Z-IO%M$hu0vT81(sOSo->i$NO^I zwr+Gc)T9+*h9o~*%M>^FNVI3f=N=$g$Y7A%j69WN5lMOUhq6MP@_}M#m1~`)*6dJ`!lfs8O0*0G$~^{&qw2A7CO+o zAE^{WtSW({hL!>gU^~!uG6%MedK=b9!4dul*&*j*rJQo@X2XU?q~EgM~W~_tt7^qa+J=1q+z4^?d8R zL+c(S1eDowCYzi7tQPP{+}$8Ng1_8-jRzTKZ5t7bNOc@TLtZRT{B$9PiW<^JO%Ah`uG&i_vt1)ysuzp(QrdX% z?9^l|G(USfKOgdvZ1rp~RyldkYgRGQ7#G|zfsJGC3umLg@O=LCEJSc}N~|}lues-B zB^EqOZ9_L$NZa_?zLtq$1Tk57F1-Nc1;U}aB_F^dh<)^>i(8AOYB*G#9s7=YA5lAu z4=rvl=5K76wN&8+3sW~NIU7Z_pWAe~O_$rG1WW+&gSgw$3~`pq8oDsz?qULNZ?#Jc zBdDLmZk3ypz8`8de#kf3EO$5BnPQez(_z(o$M}x&fUMDPO{lJ{7!(}wuy^V<6UXCAM7$K{M@fn+CechUywPyL7v*wJ(hy2C4_SE`EKC&K&1}MEGC#8yiXw7j{ zpQa|5qmzr~DhSmfy<9m%2s;xFb(yNkO1q z=F(#iKKSuBz3HbOe6S4x>~*QA66#C95f!S^#2WBIG85e^(pW~Qhp;0N8|jul)?tEP zKIb7^u8`49ByZB@*|r257MakxBJ+c#!Q+WI#^#dQwL9|_@hDNZ#MMUQTiaLIN431R ztn_DHP4P`>h+hi+v0pXKTzj22str1e?KECAemDdUHPODbF}U-BN;J&H)=hwPbtRua zQjSE*?KTcwX1Qaca%?bBHkFfa23%Jv1LAq8HKp#=5G}QBIvAHk0s<|X1 zDUU3#0neZBT_gi?Hx!ixNlk}06{H)F`R2kXk@Y!$b!09+M8ww@FLjey{EaBawnG~6V!N1zSZ6X2YYKYn zgxkA{2%BK);xcqv=CWiKFj=WBQbYPB%jb&JJ$CR@l@~^hfjH8TZ-0OKB7%}55qcr= z#h$9Is9aYdy*Ocf%UP-S*1Z!2%I+o4YAc9T3+(t7*ZWXNhwoa@9DPkY-5B7v1bJuXHTPNyOW*o5}U(-&+CTw&_& zkux}bk)8p$$U0eXIe$^W3@J~+8JtoZfTjm2;dAZJ4^Ybks@MR=VEm>(JmwwA8(y-R z_;NmZFC=R@$=z0#x7<`R&%PMPc=s0KN%H^OsolohsaRp)ht&DdKNNJ^h>QbPlF|FsFsswpa+@`hSJaHa`{HvImh{=Cb!yDtkDFhX&9u@(t;Suz zIeV5&Ag|OECpKko4blMgx}uHQiz@{4K&B z%8fUWEj!{*g{O-YgMPoWdM-Tkj3^*x!atHB(=8s+tMA`fIlDG==Jn~xbo$)OuH|ra zGCQ1BGOq}((&8#f(If_Spw$5n4i&7`8WWf_uvMkfG4E7?-IPkMG|8Drha$a6b&DDyDKAij=(}PtFq{!%oo0N6r%xS5>Bz zgX>Aa{G>|xaL#on;refIy%RTKaHbU--NL0oo+)6*5Rn$YS0r|ko4V+Zh9=n#0b@?$!U&_VDtW3rlivvRf^#DHY?ut?{TaScGKHn^g0R&V8JpoJetbU4mBKfnxb+Ce% z>YJHmS zC+l|!#w8KW4p<_DPILQeO~4ieINnH+peE$RN~`9tRjW)uRp5IK~=olHUVsPv!YH`*41CHlM!`k(jN>WGHhYnFL4*6j_Sr3L}+cF@xzA92Eoa zXb^QZVkHVgj;oS3 z;``p{2mHPcF6e;>jlO;|uqFqc82f>6+fgyi@{fEROtdyi><&t-dh zv@aS^bnQIeTiRm*6%n!)i27pZ!QS?bY<~s6FQ+HQGYoSC`=h=>!JsBC{XRB6H1F&? zqlN>7Z)n_b4I0{*q#G>OO{S~kd5c(L3^04?)ytT?5}G}bECG}OeN-`Mym}R%Z%DKI z9G)+~ST0{*E+^aVX1Q#1HGfyx$81?Hq`o}s+QC7%*?W42Mmfyv|8KdOwEw?k$&e@u z-0LMr1`|gwMDk+LrPR+{UPSDII{@cnV%O;~j=A09OB@cTdw+DQe#_%{jty5DlKkQr z$weik%a{IT!2HLJ*?N68IBR{Seu|#FT(HB9=}J-^rS0%V|5wC1&5tN-~orw>urvJJ-P+`lF?U`j7on{wwh^q1V)qu5m1P?J_;{*YwsUR#ij0i zsUm5qB=wxpb++sSM)Oe^!CPNgxi){KJ3o5cT>Uh;t{UFaxuatPo6ccqvg5xf-tC8( z0o+LVzhfwE0-3Hk9Hngdu(mX`Wo0@ckOG|*4krqrV~ITG3b^40-_7i#Wdqc~dh$&nw&LF6g8WqdP|5r4H7?t|V&( zoWyDI%0DnD2P~F)F_2(CtivNay={J>O!h8(NH4#MWN9~S7*t#KDFWTTfHNF5O zFaL#f!5A-((*^bV6Esb^AG9yxRJ$)UJXeU2_;KHe740@AvxFEk0HAsBBi0VDG5eEH zmI=|Kg;#m(Pc&-%oo5zGE9c9L%_Wh=ah{WJyu>-jKpn+kx~<-ybzwRsn55BotWB)V zd3jS?lw|3UBTr)B#J~yxgao<>Mj_|)rq~$Q_z_6!`EKtSc~@_}ZKN~yi=~u->Aax) zOxY-x`-J-`TvsIl_ks$Df+UFO+d>CdGDjZpQe{Ky$BC(|RobIpQUyuMoc~nHEsxBc z8=C7bWmhLMljrL7N80R?#Foi;n_Ou>_SH~GoK!NC?`e2r6iU65>>lb@F2A*hYl%J+@ zhESkQ1dk0KHKkS)y`IN?3-2uzTGF9Q{$=&Z#N^`YsUwa05isQKt6z5P*vlTc=_Yl* z4XDT_6x9-^=!_mM88Iq>?IzPN1GP*_8%ZoM*rI_3P4sE2 zO;Z`fB_DHB=BM-OY;;ht(#2pr9+cGe$cAn8)^7LqQ0Mq#K4KDKPBIybY30A6Agr#O z$6KQ-)z;)6ech(7cj)Va@So>w8Cl=73aCguEP$4=7}^_a6m}rDMm(Oz%MC4jUGBl# z=6X}A6&+~7n$ik&D;nB5qiLU`cqq$HOGQy(DdR5Ol&-+4cu4Ws?!jj|gdY@(Ps$B> zz2dOu(FIIEq%HEHrRB?15B=aV5w+75Q zPio+kDWuaR+{x}>bYAA6>DokD*Z?>iS5abDz9`NYeU%^gMfqm8!Y~^hEI6vuc-xfD zq=M5XA8U0|y&k-w>TBk$G({m`dJ#xuiv&#~+Fg0BgB)JI0KoKQZ5W$}CjRe9vR$UR zOm&&`?KX}QhbMk}U?Iq69g+|3?<@unEOI}TQ=*^kmMLvQbu@!7ts2~6x5zWF5@bc7 zG)R3Cy#^jg}w>377(Z@`14_yW6-EDF*yCf ze3$%w#pJ3GFqr<}G= zP;35oI6pgX>PM|-$IsOT5o@rE)73b3-~v)J0#VQq%3|8>py>{YK?Fp&9c* z`*f-(!~$AIq)qPnFO%+LY1vv^4kq00pcJcwnm~DEo{5nA+eeQ3&DdSR7sTDcU`UYX zK@+JqXG^HUpm`L@Ccr?72l0UMle7mrTU#b{`x1~@-_}{^UBGuAaRG^}i-h@*LXX75 zoOT-zRd;u*pEtfx+1;&tK`nYsPvcOW71v3gTP&~)C1p2Ty6sPzHx7JYI! zS0>^0aJWCqWY#lp9Q?`tyw366G0qZhdH?zI_Y-;fKD9jTABZ;8>pDo3^J$drdD`cc zJ5WstWpbjukvs!BnAe^=YKr0MfI~OF+!Ujv6IHmLbf)1pXD(6+Vj$~rZs@9Fd^J8) z5t3O)cQD>|&ExBv17}R^ZdR)sni=lfCM6e?Ky)WuXR-g^Z%?2;CWet)u_ZmzYXjSZ z=D+8&za@-KBscQy+G*KU2U(}v611gq;if!vP7L0*nX$#-;+AwwE zEmqMca}GuV$(D!-#i|ZY=Rlt#Aq;m&D=4?w;?2_RN>q|qsJAWcHwe$VsN4z%7?g!< zbVQ^g9ZJ9mE2LXZToKGvNELLWCY=qZSY8nmgZ>f_X++42Y3x8AIj zn~VGmM!|0Em!l!>+{Fu?IMA3ebc_?Et`~xZi;A zn!q<#xTq3Q_9+PS0IOVHs$HoZy%1>RYH@~d`D>(~ATwa|z`#CPzuC$~V(BrnY~E6N zOD^q?`g7LJiKADijLE6mg|-vcP58?lR^s>`2VXI5~Cy=>PU*gS25vj=MA7DCVSpbH&CZozAXfx?UH; zw-39dXpoEI849@&!9zRDF!^D&O{h7kxkna`kBj#edWyZ!b{|=vx^}Kmn7ejr{V6m? z*{ys>M33KN{YqTK^|%e6<>IRP=yN!g!{7%!9R|G^GU&eA0SsljrtC3Iqy4SiSDwau zd`9KuHC*Zgq3j8pynoUD{IS)@V&d4b#A0N1&YR_*LC8LiKHIX^Bsp&^xLtg$BZxSk zhUfTgi;30M#Nuto=T2s`H)W^bg>BG@9qb13EJ_NIArp^&;C`(%h^WCp%5F9H`s1j4 zYK4xd`2{o4YM&B3jcpcxC?)|w!sm4iDlG$}y3%fAQ?)t=mAN3pdQsY;ev7OC!3e(HkE2# zXRl%X^eGRS?a48}27^$}8xZNbonQXZyeWiO?KX1**HetBa#%CVLw~tPlXBn!Ef`&8 zZqPP|Mwff^c3CHTGR4-^Y|G!7-|JH8XXpI+oTy8#Xa9vn0HT_dw4^K1nSnkb(CdG2 zRe17EDibbT?OvSoX68IKiD$ID$YhY}HPaMw2q`GOLN<8ab8q$Ja@m7BuD5>O?RN(b ze4Dw~*boZgs3#ZHPxzTpzV{kWdHG~z>4nE90=?<|?fAX)iOC|^V-aM;4KE|)Rj4}C zUeEhnP6|?hvd~+aqLELU6(SF#LP%u8hCDVePL9A8FTxT>CM8>NPX+6-OUyMwRzp(W zt0-ALh-oQsfUkw%EO`sSMtDfk4E3bf?;M6K(zP435=|QttL;e2A*a7))r!?CR4AL; z-xMtiY6tFyq655O+m|IT7d2NQpF6~Iv~jf~v=Bmr&W9dHNP4@y3A%yZeaq2aG;_=# zV~D5XVez-QFiwsl%*Vp9(ExI-CSvu9?3v(@cy5YffM#$wvaMlcr;_P}Kb|M!Tx2A% zI#P(rM%*}l949P}TtOea&`2cH^9yFdTuetI#_X!4x8_z?8%9zN(Ot4|cIhrDAT1rH z7pHbt5yxIdtr%oUx*-%oaUwyCjraHd4(2npTq?I31qqqVj-S~zB9RC>RPW2G3g=ES z{nk=zrii_7x>d??j%Zz|&}|{Nmn8nsVM97&AN;1zsHI?i6ZVK%6QW?#(?Nd^bW$h5 z?^>p?o6oM1WC!XlA#p6`5Y8ru}WPaMwjqo1YpR+Rq2`2lx+-AUHr@`oL7P`Mg@Rr-~i@ z>#Y*k5dPlrZ*QE;k|W48`+e^y_H-BP1E9j;^FkaI!*@2oR`L2%F$;1)UP@@c^D z&$neI9s;qZRPKXaDbw(D0xV)*SeywD zC!QV|Px*=GgL*lc7UZ)lo>y%pBTDTuQRO8`hh~j9P72rQvq80`lN4xbI@nYx1!8>E zn~YqFB)u~#FkC4a!C3DZxhJnL+MoYD_wAg4|N0@3wsU#o+DhEV361^~mppO05#B_* zas&cUtX#8YS?v2gxZi7dt&|N{nGeBI?AyO#prat{D8)kG4|Nb71XySgfv`)RMd$6yuk);!#HsTBd zRicktP?xy-G9ludGJ03f|7B%c-uQC4%&;pMTjek3AK-PhZ1?$&#$<#&9F}VKE5{8O zyDz)BLh&-GzsfaV#Y@!@%UphcjoMkw++U?KCwWPWttO4wx3!D*A{f5Sp5V}dJV_C3 z^%cpAya@1PBDMGPO@5;H_X9?E%!YRr8>f&h_p?`i;*kN9JBG;5>x6_2g)Ce#$AvNn z9G25g5c7Lkj*Ck|&m7=Hj1esr5q`yfltHw?QBfuxbrAvViuXH=jZXBT#__91fFCbw z%N1ZzsZ`zn+mz?lluV}!aaD-15ec8_utF(h6>cg487yPB(b$j(D2axWi1~lZZ!tq3 z{H>GeMQ7>58lvw^{(u8_SN(t<_`34zC?9Eb_kh!or|dv1@N(T0n8;uWvWTn9tWkQQ z$ZGYhZ`<=(#Pkm>1A4&pmVvvL^&SDVs-%6__o71Abqnc!Ve3 zAf{Io4i(cYM6;qmojgsFxY16xv)O5Ycu5+C7jo_|U?q@5euAnCxFNFiFIZ3AZN25Z z`o#xi`>pjsG*Fy?@QgjY^a7&71Zr2D8P`fUF?!48Q(#Mc11@N+X2$pfyn)33MNn`F zToSHTqc=!<$VMPXqHJV8YCZ={K9L-1A`uW4ZO(bbkG5q>=pN?5cNeZM7wYMD!&A&y zv2@AG6g>@3`W@w~3#C-OP{(lF75Py7h3coKrcN23(r3h8&nZ^Ae!(gnE$8dE+ZXt> z;0K>+C^=C(4*3>tnjtML3ja1nwHFnTBgQAmDXWzrM55}$WX97)AJ9HUCrw-A z=S_^HpJPAwrbrqYZl$h-80pbcHxpR-Tk5r*RiYNFU`Jd_FZ331cIKBH!+*^@4f0RUY`O{A9-ZGJaY5Hv+w#yBH-az!Y`3J zQ!ZV&HHvoLB)G&i7!1)Q6cnj_KwFc$f*>4Xi1^{^1kTG6RPw20M3-6o-Dp1Q@rHus zSX}IEBhCB+g;wu(=gqu)t(+X5hgBLQ<`GraG+#^ZMH0FYW83YC7NXh7R4Lya5iKqr zdwo3d6Z69-EAlOG&RfQNdygkm!obP45gbZE^V&*6cG6Hu@x6TwTQn)O5HTjGwY)^| zj?uX!L_Y-~tIjf><+23620H7@1sJjvqz;JBB1A+5Oa7+_BMJRVf}3aLZ!v1&=y z!`kN>pLjkRAM9rr~Dd&%YZ1_ z71)ttFv$&!&OYL00OaPZ~o;Hb_yV#rhI-+fXqp}50D)^b8Wgx_dHdqJT zS-ORo@lGM#$OsI^9~ofM)o%tu>5$*gTfmRoGE6vRylP}7{LOEMXGRLOLZNn|*WK=> zr-noR8*cE2oc9OF<+fW)Kj05R_RsLVPpIb|^lVelt?W8D#RnJ?WU5+4ws|S8#$x%2 zs#X0t{n2~Us#>+0RV7=XVYaQBRr`MX9*%#T{ok&Ys&s|}^XLp@HYbzyg3e(NxZ%=E z1XDvykPl%8kpu@O zPkXr|4%yZ=ka?852k_t_PZ%b)BizZXkpx#AgcrwZ1BoWcL~D9%w*sUFbD$d=K9E$> zijo6%*;_2rmDa+_;>yb6(gK`mkr%43q0&f;AkxqK6o~&y{6&LSs!$*t2wha~u_T$~ zDev;7xSvmNGPbAex(XaqAlci2n+_1q{}>F1gTRWb3^AfDK$P-y1Fxv6*l#=xNi z7ZwlDfeWi^4qWm#&RVngScfk59hKYo3iE8>Lj7shZ`}nw%?>o{QoW(4SqF7_o6!_Q zG_r-VJDY+@*|-#IQ)CXYl~HFHOEeCb`hzV}+w{N6-nF%XS>mLX7hk0PE6W}1s}J14 zzKg>6?eE@7nm(jUS! z&Hb;k7nxfxrwv;+lWtQMM0|zY2>kpR=Gw)zwTo)RHxY6~h=bHBA;&%y4xsyj?*K>Y zXS*Qm$aMCv*R-{9Unv&1GvzVB>N=!XVM7dHek7}md;Eq8;ZDNb?9W2>-rUrk^*fC_ z?)&b*Zgse~v%0#sCxW{2r_u&ysTVt=+$ztx?vS8(Ff>J>Wgf^kKnwAg7osh@fXw?{ zKuQLaFKS3hrBYKuoFlD?hG(~Q_ski=SnBonpDh=a&+jb?QSO4j%LLh7=X@~Bx_}MB^POQo6YV@qai;whOW8h2H;x# zYY@|&TJ6Gx{*(Tp3JDQM33<}%T`!QZIaPOW|M^4@9DFu1Ru6Q9Ppy`w8czz0T0~i` z5K%yYiRBSylK0P%2{;pTp0B+Bc<*x_oQsW_OGU*#zJ~1{? z`oGD0_b^A!vrbf>E>)7MN>Zs*Rl1gLEvZ}T?&-^@HJ6?l&BZgG8QU{$vANmh#(U-kPvWikB<{zCx#@;^b&FahX)d%mpCkmVSx=jkn;eK$u8u<4T0>Q zuqOu|<^107t5R3@*qgA2^VgYasjjNacX{vc?|tFXY^SVU#_M@6Dqhli|0Qas4qK=t z`44I~&aOBU6i>&Z7WQ4pT*BT9jM*Kk{CE56 z-wvRr+qk})udl!3OD~P?W$zCDz5ycn&kRQt9rRYST&-V>w$ns~I$mJC(~7{tu(IuNf~`>;30$ znt?CIQjuxs_ZhW|(F>e%{tEyhp^v$C*XLe&G6=c$Ob*1!O<}O2&}`$g6QeCaLFVK< z^pF(Ejfg;Uwn5S4@Z+tU9zvoC>%tnH&MBm)iBU8TCrl)*ZEIridAi$Z7%#SJeB)iZ z*66F4Y{)|I3Ow^AICkm>b}3irW<1%dDe%$FRXj6x`8cFP06g4$fmX+zP@rYZhF|O= zP`ul(j9J_kZ7#9O4j#vi)f;HKK8SCfj{rm@clqo_N7j*>E=)e-_vD>#Qbat69Gyp< zPM^zWrGh_p7U4@ITOg1Lm@sciRm>%`vUY|uSd-J94)@avcev75x)-6T(F>{xluud9sCS z%1fEfo6F-|9aOv_^(Nb4&-)X0oSfL3c}daO;qo|dr($%n{4(fE6G)j}B)t8_3H}U% z^5l336n}A=OQN72gki8v!8%DN5YW`4>#4jN(=u_^j%T!(nt#`DxJoWf@`oK&4Cxz6 z1|`9jZvb@SsGfsfw%UhVSHvppj(HK1m$Ks_- z6ikBm!-V+uzlU}&$r)yP3{Kcx(#TMZ+Ti&QInV5eXQs1c#>>cWCA1XDcE!W+S~7LN64W{>vRsC zOA;CUOF!+qxc^4px_A9&yx+Okd9C~VgnQrHU0)SllbnfL;w~|5#e4p7EUm&H5D#{V-3X2wQT(5(v4$_)z5ky+-Cr^;r`x_Nd^hQZ)MqL;FORj0-3m%1E%j+ zRL_OGV2L6{g~xzhL?j-)x)i<ofmef2NCM8{yU)QIa z^>JMa`W&v&Rr{;3l3=Udaj(y>-tO~Lcz^WSe}+PxgaUPv*D3RaB{#6LlHxM?V{NLf^9!Y06j z{S}PcC z1z~5fagxkRADz@zb9Jz~*5>w+;R-4Gh-chf?YCD6eR{wU+=wm}K3S6560o?!HEi(L zvpHT0#t*FESS7O%%v$~zwsFgi;oz5h`cLQwwA0JkY{wa>Y4z@L|0!1NS%s^Vu4L!Xs9wCG z2A;?S1)CV=Hd zj*0&Hzdiq<1(bGeoo`7$fem#*;_K=E^&hgpMc9pc{0pU} zY-O%cn5$%$O0JH`Hj|pM?^LUGYM-GcJvGoLFbc1^Yc?hsp2F0<*tBh*d2i=9vtB+5 zfy8qX#IY=40*P6I@0(qvH+#$1$7iE@u~~r65#kZ$-AJL6y`%lY4ROO zj3*T z*1Hl=xP&?ejmM+sHsxZGO5mf5ULMw=YRuP(^y7~v9n>V z?s_RK0ghXznsjSwn&01dRQj4Zcgsn%*W_x3Qk4Nh+{y}>Wp7kjNeAKBCF z@f+&Sonl4pop=7bqhHXSJs-JnLBH_TUK3}vdi>VEeXG$Q&c0`cP7H^g zPz*HDbB6tEBG>q@dKNFbdw_ty!oJ)S7~6PbH#P+f7yc<1i4nbm;q$VQak-|P&&qWc zQ8I~SF`J8J?PM@+XPQP<4c1spPsnMlSZwA~aKYUiQ}yY5A*kl@lZ39O(kUYrilwq? zma;P8LOyI{B8jl3N}7^P#kHno77|phUYLLg!Ni2fvLDekaf2g zh_Ob97Y$a#(Thdy!@HJgH4|Bq3{^Fx$zv4661>d|Wf5!MHcse8_<3|XvQ2X1LXOXP zHvuAoxcnGWZb%^fYWx^Lup-iJ_@?7x&D$1d#8Lah7r9Rnlp;lY_vnRaNKp?rNh?P= zq`=DzxEt56Q`xNTnU;gx+rD{TK>7k3g;w3uXOTg)_%cDEcI(Jg!wdPGfJ&tQ?pvg-4$PmeYYBc?!Sdk1&9iLu#D`Kf?Fm5n#;p6CXHjWS~|s0V?stS1@jUl zh$^RZTNe{XVQ3)`N`*%~j@s$E90`U|v)!cYLOEoyD2u>AgeCIvqoxF$;%Fom(&9+a zH+Y$MIVO;%gs@`g4{g^i1x?3*0ZlIkmVfZhvU%(;-)@LYR7 z93(BSh1oY&D2YkQxYdvfN{OtKk7@~Y{O_%HpA+fa{CnRDGuhLmppXp%rHaX_a`kHE zjPIP%wM!J0>kYsJ^xHe|AifY6bQcVCbaO(P^hui(Pe_j<+)VCKPlP9l8Asu->8SCx zm_QVtY8g=Eg)JzVC>s`b5!0@hovh;ta9AzZ(Pqd9HKb2}n$PImn{Z}vF72oYa^t=< zqpCXTxgvHCsC{S8l^na@aMgi&qi;K!wgX5Dc~3Z2lRiqufFyQOe2q>cW_GhW^~vB#O6z)vMDI4LQ$7z!s@ zIVoH+%zErs`u#6NqbBg|Yl_?o5fCV<-w5;Gj)}SlIV=RN=#3XQ2t@|B0Wl|P?s;!X zWI)detTnrZz!g+}_8GQ5H!dN*z0w{G+Q_K#=V=Ztz$l~69js06%BMT`B36JxXN3c= z44;JSZY3)dlqX^b)Q;RF0UHHz0Ah(q;Y3d5YPVCNMj2efN>qFH2_!N-y@l*eR1iX- zqPJo^aj5*-r@^~S2(A>fN46MBxfIBf+@=*Gz9V>1bJ4es{QspM*f2RhVah;w=psUU zVVK0fAx#cY{pX4DWBm{QEjZ4(#<{Eap6uLSipo}s=cU3HwmMq#B8|M|sv2K2uWq!T z-J2|B$c*AmqA1VJI0m*_=e`NtZC4kCd?TqxqfRpGd-r0LQEV!wt6ZnE;dVgY8$)&+ zTiH%8%RL#_5|kM?9ZyGs!Ae9na0KIYTq6|V zE6GGW3~Og5rl#UiBdN#KbUvxZDkS!?PGAGd0lCqk>}@-YF`}pqKauZbC)=0Oxg>xZ z*~16-@4t?CHqAUz@)42(W*V4CLlA*&yc)b=Z|_1E);`h`x2Xjb0iq>%caO|*ECftZ znwWFaJh1l3q6-NegLwxTVjs72ehS;Xr5KGd`I<)xXldy1@qtvpYYQJb5Vjq&s{rtt zsdbgXDPSp;xT%gUNRsqK@s_4v6Uo`&8cZsAG>Vo`G0G{_e&RYQuB<6e+PJ1*<}&=B zP#NH~E2K-fb|=+}p@qm4^d=Q z-lXaz;3cc6WFQo=sK>PK|%t> z3X2(l!X}<_=Gub%pf|8M!TNM#-EXtlRqNxAR83Q#ABZ!!VS}?=L8mBCUL=FmWfSk# zl|di6cw@4lK#Hle^Vi<;mTPb6y!zd*#@}@!7Hk7M-g50jwByw?Xkg5hLEtD)#^Sh< ztSj4H*AgR}!mx#xpjdlQCd-Cq1J#>?08m^9k@FZsKbuLH?ZV`VHVW+^j1{&&9IY(X zBh%8J)07jEznCZ!gTn0nrfP;B^ z{Dz3W%WF`x3Ml*)^UFpBm37Z1(u#>7p4AS;jZhfWjXsYvINP6-;Jw1I8J>>MzzLB~ znDNvev(iCm2vC~3X19{kqD_P&q+&9n5;zwSPIm%-b|5Z8=OUy?zfaT_qX;dJ2?aD0 zQc;Mypd)r2+S+CVw|h|U>xuv3a)jGGO!)OA8Pvv10J5(O_U;3K_wVGiu+RI6%y)#* z3X#Hn3IYhgqd4JtZc6T9{E_P5;|lDPb0~ghX!)7MYGtV`V=PB6cP>vXZ(O>>QTsvu z*~PhpB1ws~ZB)9|)ZD(M=|ZRT_RLzPgF>}qfnj^T8R%aMu7f+brPzP>yFo=V?l!4rOgg%P4!c*F-ZgxNHDJ*c~hSf)+%ufIQr&wS(Kn*@W z&7n59ndZ<{TO^kFi43mkoOPV#U4#WigjSr}upjiqYuj;lg7CPJq44H5#z@0h8+!~0 zxvO&nZUk6khBVx~5=Fi#E)ZQ>UJ#G%)|=TOiGJ}n)HG~N>TiJMJfn_2<2s_5_Bl1D zKa<9O^%<=`7`t(a5d_#qFn|c1N`R6`spc8ytCS{$vanD%7Ig?C{s~1zj%aw$hdnoS z|IEz&Q;Kt}0@Lru?4dvH*J!Dn2Fw^QSnB7~wy?eX(gYXK0ZqbIuVapb|5_fyt*jpDD zvo>IO4(h2!Bc(Tg1wdhF1vVcVnWyPG0OL4 zBB8~_a5!^cg@uE`aIiAo^SUxNA;k-`IllYSd7ASvs>>8YvH2LS9GnLFJVDPHez z)4Be^;hA8U3UrA=7aRkkBd!wH&~+qu zLa86!&VQ1Bea)-Ayy68=P}~KN&+oJ$8#2Uh{@g2{vnEdUellLN==3x}FLXM#kL|C*23gaI3YG$=3t zpih7nLP>+gl5K9h#IBpp%(OF&zZqwG3$VMRuX}V52-S_;w zKfL=zgkFctit&9%|GoYCZuj-=-`;+JHK1}^8Dttv6^2dD zQ$I|27;Gm`T>14arWf;5s=8A8u z?X*jbzPWLci?2c~^drECYmMm;)C*83c;9)NB2gv!?2sDnqCwC{*fY$i{M*fv=F-Nu z12^vFq05yDr-6i{w8`Uc4s>kzqQRpb7c4cA<|Bhd z)D8Fo@=!*pZYBA|NV*rkfbUw0wp*Z;P=BiC*s4#Zm_!lEgjb8{_U&DX!MC9cu>eK= za*N7A3IE_8LrEp8<%tStz46XpT{(1S;(Aw(y~K#CCMIxW51@<|e2%Vonj{HKZj- zICc)&0}9Xr(ZR+#?ZqKl;U{!P*ZC@T6Upals;4o=cu=;zNb*&$wb+vZjNXH*yWV1f z%<^1j@7~PZa%S(x-n($+%EEg;wwE0{R`0i3{rcwh3(r3E(6bk=^QkIW&A-CM!pKwa zu-`#X65{${ZhD>#l08grk`QFU0>&-1OFc_oTv}?%5~L*jhm5pDhu}bv{9aLnm3sCg zZck!QrI-509lNH4^D}zHE~GK1ecNv?A3vB5g|tYuI9|Jt1_yn7IU8(Hp48!DXjrF? z%{}~vJ>^L_3TX4zqu5+avuatAOGlPczT@(CjK?M*3U|eb4m@yI^YUd3Xiu3T z`UzaB|6i(JeqC1hc!-LRwOJ@35Q-?H83jwIMi~(ik;r)a<33=gz~*hv?7hw@wClFL zCc<6&{1VW!$bap{TY%t_b7k91O2(rmL@!>qOAm(pX2)ICyU0ojkC!Oh^&>GO?zemH zDBeXzQe#5L6Rly^tzyn_D(U?6$%>(^k=U}PWy%mq;mtXBj`MUOL{K7PiTf8I_4LGJQrqyx zp(l@!l3b6tJO@&Qo1z2(0Ms4n(;UtoH}CTY7=68i$lAwAIqwcQI{DJd%VFTZ#M&@? zwKc@o@Iid6$td(4j$afGq^R-P1IHVL3p_0xLyU@7;yf7Q7lH^ zM9L1J<4Sryoz6o(fH%a#O%rLpKvq_NcbN*12Vx>GV$hJ)0HGV)wC{GH7&N3U_%v17 z^x61rnDHrk6s(Sa;W42LQydxlDJg~&sls$FH(f~Nl@rdIT`t>Jx%_}vdo0Pv4VJS{xZ5{Z9d>2ZQ}FvRLmmsyh^& z(KAQpS@^_}h0#B;^e&xelLdbLsoZ)=#O{p+`hpp9`G)m z*tF!R?EmXX1T?bauY=>eckkZDPiWV0*H7F2ON;e3PT65^5IPcpoPzEV*euykhz`nC z#D-9JvP(q6ewK=KZM56}78EVP+T-+~Q#knZ9k$ZX;J|y_tRM`YKIq$@g4$9jZ8dNV z*T>+t#mt2ug)t7I=IwwT3!AcxER>}d%&govN!kPdBas`zPOHf-P8_yvW1&=BOxyP1 z$po1_lXkq20(|6Mj-#g2tb5mNHyTXAnte}94Hc~1sp;m*EUN0tcc^TmfS+5IVcUiK z6S|(TDZ0#d9PO=3d+uC{D(7T4x@K3J)2DJ)A*9Ccfpt6?;_Y=e=N%;oMkfHYjvQ{h z56NQRZODyfFCy&b8 zirYv1TTRzBE%yv5k8Bm^6=u_ArJNSI8hmxOfZaUkX8I0X;P3?bDQgaL0oFnN$n6Rv zzXjbCbk9pInS{i59x|Uu-u2##-1+0T?7_w~&!3+PR&wu~7nEcmm|841s68VweN<~1O(Slz1KYwI2X7VV|5oZ*S)_JbbvlP zoArtYXlE^x(Lz#2i>JcjR6LQ9f^=$7$|U%nKl1}E{4T#rCWC%}JvJDC2rMCX1M)-< zPm8ypP)EwUf@p&mf^)}xa|@#zA_e*#2hr=BD`XQ`v6`rUcfFJA6v=RBWs<4Qey5MW z0c4ARF3wHF7TWErrNs$3N!mg(l1Ozz91y=@;iIqXowicPYupVsV=uN6{sekGJ!bx->qeyBA&5qWAQo zZpe{^o-*gCYk{zb>)ZU5tq3R<^=OxPI9BNdbh}KeV%8>t5%S{Uf^=iV0xfkdSKn+B zjfSh!rFw|Ej<^Z}bx9!zH5`7e=dq>DP=rZx7!MVWhZRXRbR`%x3VFRz zD8?e)z9PdOm5hYqNFHL5kRnH7;b2;0ECRTwm?p=zkEwDb8V=d1h?F?AClV_bveQK^ zQfx$$X)_*=!`W&_wBq!vW-FF~ma!%*DwBeRp30btt$_8R+e75KdpSNX&ulMk9@EPZS8(d@JaAvyWt{f4r;Oyv6hl3Z&*9X@) zJryKO0X-!+5Z_3Gd4P+WUT_+6nO!Bf?j}94ZW(S``dst0OmEp<5j=Lqv)8bIIJ0bd zx~#Vp#zogw10mjHl!TlCHz!1-R)aintsd(!_RNFM@HS`k%lF(ibRL{#I>Gq`uTkdS`pQ-63(TLH;2 z`oh=KZ5Y1Yq>@`#b8hG=)wC7(9Jhb{>o4`c-hmA)M=2$%tDZ3t?MrDko9xSQD-dW0 ze+F0S;^nAYRC-Cz$dn+#zC3!ZQ$?w9mOC}NmRnf>6lE^*)SI85VV`iSF@?0QliwH& z;1c5L& zc3AoH-b!gc#Tcl&_xz-a7SN8<++KyY!vmAWg?~twL?}Mj?`<4gpjbWG&hXHht`3gC zqxoq0$*;6#NuWaN!RVi_43776%d?#zTX691MYwBDnD?xjv&hN%N((l8{H1eO_5euz z(CjDY9kfG{g$N#`!$R#7=E@0k4;h67DrNaMz5^b?Y-WD$!0y-xT3b8)2KbfjQXLl||e7C$X5Oq9>OEBm9MUl^U_&)fk2 zq$JiB*T`*1M%#(3lt6GZ7sXy#a9Z~E=B4JRZDcZ~o9R&B$42w!_dfV$&R_yn%(R__otp>-PP)QJCfN*IyGnGsN2svRb0&ql^ z(+4C0vj?K}CkPVr&V-qcAUP;;C#q=Vv~XCNBXL}woqN0v1#uz*{7+RRF7*bUmDc85X3-zZT&aG*^ zudvWQBv=n`|5Z%Qhu73zr-$|xBbYp78ptZ)b0T+x(l_|@ud){5(dhJE$VKik6@kPP z>g>|{kt^^yc1LmaIXzdz$or#{i_itJ?{re%2 ztf3thn7ewok7y=RMJyWw4TFy;O+uPS5GkY}Il=#Grde}JCrkKqY9{%PX!d@6riIdVNUA_O zh4_wHT5G0tVx|-+Cd0w*@`O@6Q7oQo9-GT=R2s=hJfc_%_&NQf5)f1bf<5lhkZ%VJ zg(PYSuJnO4tr$r&dQUPLVZlP>T=9t0kN;96l~Nu^XJ$ccDLTOfv)JOyq75uQXcT@Q zbfYfY28`Uijd(M``t3H;yhUhbk}RR0+{QtSm7D8;uz#X~5WXROqA?&n*oT9#=~2ib za>S-*_F8ZAw+Yt0wkpn-<8jd>5a|->Y8)PUs|9Iqsq8FIl=qoh{&UH0T7u(!!)?k# zd+pI>uSG=r{9&rqF+c7Vr5!JiwOXE9@-acMsecuIkTrBYNcgLeZcJL6n$;J$~JQ6}`G}G~fw#dV_ zmU`^x=7;n5;3_$_T2&u&9+PyLud;c5K+0*+s7Cw68s}_+3W~%O1XMOKo9l2{89sU_ zhqh_pVi!XeHUD1@EepbD9;!R@NE@gm-`FuXHZaXx!gqS~WkKt* zrFO}#CF0WTL$_is3GwfFZj;SGbm7syNFS2{CPuZ+d{n;$G!Fx05E&e6%dd8RxRZBr z*Vy}4AFVmHN0;xp!mcc@9elMjb5G~WS3Rt@ckJOuzs}kn+>oNZwt@jn-f7r(?&fHV zT(8H3gQky+T@Y1^BthtwLK(MWX3~X%^DQ<_GpDbC)P$W@Iqnkol_!H0er zU%?-K2wzA#JY!UIiGR2)Cf$24pqIBH@8Sp)19$-RaG~_V{0NGTKjPd(qu^wz+P|hW zEr|Z6{%)2|MUD6aVB^10TF9gfmfOd!=oXAER#SPm?!>~;@Xvsy|7J*6qE335xO(3e ze3NiZHhE0>F4Kz)Rt7GDwxi@VczZw(u&e6r+yM&l?#RUmD(7jx3a47+7S_InwzdNX z2o&O*7lBpv+;cJYOZf10JcT#NVmyyzhmO&r`rmX<2*yNz&6be$2}T3*K1SQ~cwsS= z{_z&NZzU3q2T$GdX3`@%?eJY~zlPDdgYF8%>#48338M4YI$wV-BHi^SJc9|QvE@1= z=P01$I4H+8k=LA>Ye>N>Z|>M zs;8BGrk%(nhv8GuQ18K`fCV@L+I2HAyfFm8kaS` z2eQV~+;7l=cmFsVMW~CIq8PX~ULMSo;^2vTQKE$4sCx;-QQkh@hDWMemLutP%R#2_Uz%6 z?Ny-OxRhrTS^{NqL5DH;1Iglb+{g2_pqPpbJMm^RY=gd+`BX?#%Q^%p0>Y%HP3v>e zUmTza@z)C7qbUS`NrrZ2DT?a_NEX$KF%2k8{*cv!`8lXE&bnGmx^Jc^R(9IpIGg+p zFeU?m0R-T6L>QGJj1!#a4h4QTXlJ$`Y-f|ppdX9o`ov*sIpK7GIsP|bgG!R6=}ZQB zQUyG|p81M%8UeZ9yzrLm7EZ0hoR5<&JYhLY=s~Dyg4E&Due%+iqmSXW&LvSoMp)st zZKw#IiNr6E`!h^?5UfagC)LJd>tOwMZ&8+PXxl9k#>g`Rx(K330}Mdc;0vbL(eEUv z4xn)Sq6^t^9QM0HQo65|KHMnHDGEf$cXlVH78Vt$blgfrqB2s`C$lfulUg|b_}dPf zXU9_L==(V62LXS$pR=-(816q*n&?#Wc_}rpkKLskueno7%W(;{LNIcHkr=O>IkkuL z^ECT92e$0;P{w0u5}$PpHuBayw<+}OZf^;%B+I=eBrSll+Vd7(4o)^F*s!76QIH{w z4>F2vx*Yeja&6igeI$N2{?{%iv{WKu%_MWubUS`3ehN~G48ODO#77^tq7iHA=RXwx z@oa9eZE5%!%ZbaEoq|(zlvgi6)hZ@WMuQ3MqE@yY8$UKDr84gEJ#sR6BK_>FGkdUS zV4}1GC0;jAK@Z=87xML~(L~?v3H4sK=UT+TTaXPUyr>DeNdC9o|!!OqVAn%IW@G`P>VY2hJwqvZ<59 zXwd0XgwSYx_?82?wWzj7cI>cSuGb2wcJYAKFHJ@Z1q0#=0*XtzxeUn^iuNF2U<#2n zU{^y!DTR`1^`LuDqmq%A=(q4y!tyW4JLeC`0!hX_nJHdNU&-bdb<}bShXCG?j0evc zGo4ozOyD)Z=8~Gx%tI69In4rotdz*lG&;>1dya@O^u5vVlru-oSV#&bq#&&I!M!Ki z4^*^BOo|7i><8O@$kC2fi>cwbk$UKK@>65>`67>uUJ1PJyVliZ;JRVB5NmI?=)1)s zu|P&_1g`clBcP_^1bis&N4A0O(S1clorluk4Q`#gGnSI!To77mJYJqJ=C#z6r37Q~ z+0JtI%-dzaWM~VesasZK@q8|}TStGv(|p$|{ktShLdrK3(~#L|K^u?7jwz;GmZ$1_ ztzax#&6PS+*1m|Aj8LGvkoX8VKLx8DMXVCzozz22ljKy&mjL|c0 zck71Gw|FD8kSqIPZrg4=|DR5czQ#eI*e8DcMoz@_#N*A+kAD3mMU*PBD$HxI+T7%Z zEAsqO%NrPg2-R+ZN+OI*L~vsgvA}ur)P;$O3#Uxhcw7C-mHOMBSzi9txqA;sS5~5j z@BNiGTs?pO>Kn8l`?1|uBhw!)1@#IvT;$!^Y!g3zhF|7^?du-IuQh(1^7y)VqP}a* zC83t84p+EMcL6~Rz-@#g02$2|=3EidW17ev=Cu`cQu_{4jBB$+M)Dp$gf_Z18uH4N zB=e45;&JUrj9zW8B4HX5+yEg7SkS-g*H>^-p8WB=DhIneGO<)%St&0~L`Eo?ftOu% zl_jb}8(`#pC%F-FB1n-=mOqRU9=O_)9`e%-%jzl*5=2$;t1Yk{)a=oJ*#*uGS5*+GOH0z!Qkn&SI>j~U{z`FKQb&Eo!9 z5*u_}Yy4SpjVr6GR~lA@%Et*f(JhSRBE&Mc+P1;N17YPRuRJtLTSk9^ zp`%CXnt%zQ&W+$>BI{!l#?GiloFJwRhMj)C$yS>A-+op5f!{8R6bqz!P}r^(<6oTz zYscnmrQiMCQtd+djGf6GhJenYM7lg#iCzRqat3%9bsRqMhY?;DxeMq?T7;g7FN_?L zwD^HaF8cUREXUVEi5J~i4qMm4KeT<7%+NJ)`vh>9UxR}h;oQ4NP3|Jn8C(IXY~qCC-x#p zBM?6_6h+!VnM-mu;9Ey2BGE$_LTIShEx&2FfB7u3lP`6U@>veDb8Y><+JNhPD z8QwsVvOXd0il=%GxuYwXVldYW?=TNUqyWTMj5G8?6?^C!f_TMH?V0E#EIFnia&Kr_ zZpZVD!}gG0yB%zZP(e3*5c_!K;5caT*^(SB6m!?E<%)%N_@~6_6CU>qfs^z6Je_dY`*Wf$UKouJF%qIAZvhZzFdf0qxL7@&spvNr z7|%nq`uN?vMabWiNH|V;60bk$I8Gv__$IHy2L1+%x{U=ujClU7S4gt3dU;Y4%wuWve6Bj2L zB(CuLk&7G;hTEY9*~aTM3s5?_^roeK2noNG^BZ_C3YYhh{`q+dBclXKLAL%q+Eez( zsd(H57f(V$NZH)LztP7~hwZiHC-^sn9$3qG4Ytvr(;hGjyF1AJ2 z`ab;fUgsVB`(-aB*c#Px$;13Zg5oYtVo)ceW1%9-u&vQBCn~cjV$Xn}vO< zTrr+I17;1>B#Y07KA%pcdI7E%4d9ML(Nah+C7s6H8q%m5wy{`8sLZgBAqM;X2m@uU z108Y={YW$OIn2x$qA%(^*Am#_@Ilp*A@n6I0>sN{%n?OL7xYkmlv@**dORNuZBM`y z%_cTI?hi)}`om@)wpA6@HO(qNfA90v@_e3%V5(#!)ry`O{eCKK*V9T?hoF~ck+du! z@-9_IZA&{lk&b6mYMj+<;Fma>W;tJY?ekA$t7)Q+u|!PPB9(aYmRMHL&p=66<2meR~;75X1`> zSfeI1Q4SR2sROK^KTS#!YPU*B=dqc`VDBNU3K7IJ?A$oYkKlwukIg>DZHImKc{b!T zPQfUm1WHU28WXs0z2O6S#;yBX_yW8SIaq#%?U{qfo9hqwCq$ z?2N9Y7%G?{wNpe_r;_!*>!*vEL`W@Xz7@kxBRz+%z%OC$c&&3L+}Ckb4x&SeM170f z1SsMh$>v@Xw}DJ<7zQ9>{_3+=kixxq<=MqQpSJDG(1f% zMM2!xaM2k!5ssljC zJkpLFJvv@nKC<8-7=PJU(zU_L@hLFje+3{eljT$!4wgo1g9#?gvv zB0phL!E3ZaCs5((h&Foh3|O>|swG4myP;h?RB!>Z5_;2hydkdu z_74p9-v3?eRS`X2+g}gP$g>W*tWo?M)@GguftJBgP>sYQo+pl$=g)8U3-`8%!TSCh zeqIIYc@Y-ytTQXW3a6_0iGL8|f}WcW%YReoZ=S!G#BMUHZ3F|9a|$c0vW7O{x%0UrCEL;Wt6KhG%0*IVefS*?*!c z(4YM)sv-SXU!dIg!1AJ^WWai5bzdWu}ZMtl^2Qk%S{7m?=jK)qZ8)>2~|{z6vb| zgVI9NsurR(3!%?yGM!U0#bO3=*U`8gS1M+Xg|(zrRurRDg#{vBGs2mKad5)B04=+N zl_jgWP^vE*$xKMW??BPgiE!M~5t1DX$t5GVXz6(4i*6Sj#u7wPs5oQ*;q;R4A$I%n zD_#^T&R`!`k_t2&)2Nv**A4UiiHZJv0VE))ybCPMn#hL!nmXeXe@Gqhho9c=j7>VR zfFFE7p<+Rvikn6T0@xcAYl>cTWdgE1n#clj?OL3RBZkey&~8y8#SM-(y@0XEUJT0_F-& zQGGiFgEaTH|Kcy=<}*)Fp0+C%cc7EI*{1yY?pt=2XP)3@Dhd?agamIO{-G6^<6cj& z@dbF<Xa$Q_(**K03o3$V>k-qeRFMTv5&5cD!-fVUH{};_>cu?auw3J5(hW zS3jmHhdP6mp`)i`%7?7WB`cXRZ(-)1%$uzeAuEVz1&YcxsA3Yg5OKX3#ifx*K|KaL zfy4u4=+WH(Eaa<+xU8F3EK4GfE~tb!hi!rKAQ^geMl2tHFi-#bCywTyMh>7Ay+8Ru zq!C!rcPD?6Z~tWSGT(kylhq_(d7_&9YTB`e-&b&<8}4%dgZZN;`ut)~%NEYKfD0k9 zkS>JFMWb{f3wee=tD|sWiUOu^AspbUAZazE3L-z042Lb5=q!&%>cf~bKyjkg!58m- z{npjW)yHr2*9IFub@?2A=;4(RtO{l#$(Z;ZdXyw8NGH^xTu+z{8m`Dn-Uk7`oqX)% z$=Yh?!IKwCuj{Srgbn*PR}~jf-0kLD4xVgZsy=Y=LVGc%uM-U)J?;gYah})-Qku^s z2aHDAT7z;{wmFE6x&$y@FZFB~;YfIZ2gjm$2bgvm^x#FZ@3G))_XKN8JOSOYwD;ts zlPS&Q4E>3;`9oIMsV&bIgZ4`8;Ebxy9IVw2POIwl!J36U7R02)y>yUofuDHnXX?!U ziLhPM_8h7KjrIvO_Cvan>l~=cd1&*+=`3)1OM!wx03;oct*>{6V;%Z)1N?){&C9gj1a=z`dB}vkih_u1XtH@^^PWX$>+1uL zq1iz0JFqJKpNZClFJ^^JT$mA^Sfr$jd+Qax1-O*vY+hL~L zS(yb>*|_qhkQz$&PEA!RrG4%8zEY(!b*h)f&aj@-aYe)`x3XAWO3faqM&qHNHFdBR ze$=a}aZsn4gpsg*(A)FI*1;(&2>kl$f!UM{p5u*mvU!eKDTY=TqiTD!R7+1&pZnnD z?# z|7N;Sh+czJH=Ub4P^})A&OKTxX^B!P(RXugC_$~&zUJ(yS&@iU+vCtlI9W?*{7g6F z#+~^WF}fs}@e#7a`!@nj89G}B8L^`gCO%vF_v&o1I2#{gRg`K+)CR_o2E`kB?AvJ_ z$kB(B)J;{9Fi@IHsHjt%J5;M3nk$a}8PLq(e3eQpN%ri7#Nur8$xD+*XS3Paqm!53 zEKAvf!bsu_rdw5+Y<*sMyv}1Jkv30&dDL3`!##Mg{*k4Dk~+w74#l25l0%}#74wZMEO)e|PM98eQ zV#Te>3V)U%ikJ4$2m}X5K`&gQaV=~#`EfIO_tS7yaS^ct^f)AuqP5_DfW!g9+v&R! zyJmDcm$~e&MX|2}8-2UoM-XABPeMKGyLtdD!x#Hq{sLGf0PenmLc`sdW>z5V#|Y*( z;Km9O%2y5C9+)u{{e_^c9RiL_1#n3nn|0}d%xO;3CM5-ua3^y@Xg{B3iN}ri+ zWvM{m?DV;$uA`2SVbqQ$^bXJx(Ou*t!CCmjk2d5)rl`ZZM%veJ=^&{cJ!Cgbh;08! zs{!RDl@pnv$mzw{jX^RY*pD7`X}G75u`%WwmJLA+F|fd^B4$NAfm^lyV17P5f5m^qO<3XdL}0}b$^>RU zb=D$c{wTqgWOBrWvMbp=^#}}o;p*OFjoG{VM!HuzxW<HXcu&)lN4?&yA5J}l!0|4sc}3nrUkg;26!VPs2hALkhhat-}uS;j$G;Ei`9PhmTu*d|U=Rhm_Te&aq>T zj~ihZmzrL@=o~%jpm$f%U_1@GMAfdm`K>g)FSKkH_>#| zak!JmQGut|0{jAAnZ_(+Lar=>GLqcKPL(G)tEwE_Qwp8Ec=1fAzORZ2d*o;)Em7K6 z#fpA!r6w4b)jrs`c(G2hV5{-qvXNF`QKk4|w89bG{r7Qq6D@E&@CYW4m?OB&e0`2f zP$ZMOVGXo*aeHqamRpj&cJFQ=frwfO4=>C30-xm)>=@ftn*R|gq{O3@Xj}2uAZAXV zs~lKc&i8Beql>9o{V0K~!g0lw1_gtZY@BdzAO{4D8~hSv0*;sO^4UOrcr?oByL!k? z?r^{Q-9M>>;cIdV;1vKnNL7^qV&Kx6nuIj|@w)6=_n%|?_j|0YCoHKLL>On%s;5$+ zkdK=fwBfDvZ(2FCi2#DaY$>%|uXHCOxt5*p40om#sTWAffVkkfR=w?aApD@TPz^g& zSs_@M${{o#UD64(`HPA=XM|SaS~orQgN8bde%YO@G;#gws2yXO^R8GnzZZ7lo!jgO zA`{(8eK}Q{E#MJ0aa%|Y?n8goeOPUScF@;_t0d~s7rTVGrn(cZE|l=rNIl3+6~2rn z!Ry6TYMWPB;VmAY3-0Wu;>7exO5@_=%Tx5Hui_sfl3sntDW82A%6uH_q({xRJ3?I$Ql!BcCJf4_e``}Z5KaK1M*$7Slb z2e~)2$AjJ5F&^}6NFBC z({Le61}GyG5Zi`ToFcnLs3e)nAhD8x<7LY&{)v@7o`Zvo%-b91QH!nOsODLtW77_x zU)SEk@QiT7su#?Z*L!$*zbE6!!wOf#&fuLMlR;G z?=E%Br<g@YqG}(AQ1cRU<}JxFt!&k)f+@OXk?!;JyQ2N^sM2j#iF*t6A-(|F{n zhtj84AdfJdrL;0O{^EqksQ1ZXK&#No^p61<2xAtMI_ z8c4!KZ^kOSO((++i8h4E-Za^BF0y*ogrsVc?rXxou_YYBNmOOSr)OqYj8tas&HlKR zpDI)}NtJlS$~8mll5rL=t!Lv}JY=FaA_RYq95|Ehw>6TP3jD-V}n;K$*{V$%I!V1Cj}P2#Se7r|w=b z0I_4+0FY@GK$?4f< zJUf$SR(3KMG;29>BU2+0`alVM24*?LY;c_()T-`*j2^PrNJI>J|OhYGClYu1Q5OKgO7f}p9~w54mkU~ zWLPw95s}<~g(-R5g^5F@P*akdauX0<03n+P7tSoAlfi|1@N>1Ae713}4BH(>BYI!L zNU(qh-9yblr0n`lPdlP7KiZjNKu}$b$ZQS;3`-I#?kfP?E6&n-Fo?oEtoODhj8@d^ z3C8qTkU>W+?kh66-u!DF5MjD)zc&T!8?3VrWnxTKWLZ&JEOYcdN0?cNv9tk4H340P zaFtvRUm(q_wt63_kTc+=AgF!5eWIqNw4n>{CMD_m;r*SbBgV+ zxwNBd*}w1{+jqX(e4M!X zXOdziiTY^7(qLu|!OSca_c%9BQj8T0aYO}L@ET*1&%?e0?#TvgYpuK1R@Uwsw$>IO zn>z8x79#uto0~(pi#Kn5cGc{|M8pAJVDJ1MXeMKp0Y(BALb<}d*0$YOFcs6r;O=@1 zh_e|KMz&x#1_$23dEoY>q+LHRqWmi0SNt-C!Es-CI)Q?aYN!({lHXqJ?ZhW+vmn+B zuv;tS+ZRXmVyqKVl8%}fpRGC8g7t17(|OMS2xN0JnMmObaZ-pSGx_jrq;83As~(vR z=QBx62eAV`MKq>4r8gp26&JGfhN^O&WJ0Xjg8lb?PTW931x@7|qiYEzOK+DrH1{%~ zFWggHxgI(R&K}D*r0IGa=ru9E`4v8X@??taYpF_#s9EZkTf`EZwD-o2t((qegG&}s zGb9z^+Y%eJCMcs=b9Z~^xb}D9Sf!za0fdM){!QeVZ8|GguT|dr_Qv2^WjHwTDsYAe z$`5?-W0fm!p5nW1yWJredNO$uU=jH~c$r%R;JIAA@$?%Id&Fp=DbQAEBG)9!^*A&E zv^L@feJXCU#lt@6s|8qh{9Q#qWz!^o8CkuA>?dKP=7#DGI-xs+oKot<-ba$$`(m9E zgc)?67kpyC$w-+`kfPv6qzB@KE9wZJLPwyxY^YF67LQzNvSaq~NJ5hu-zOrmhuZ6@ zcF<6h?BgLIH(~!j&b?1n&+xeDRXDI#mAUuHk%&xtaM#zNDSi%3Q3)(#QXL2`_2%Xv z#r5Wv;MO21j8yu?dEBvw$yFyEf|wr_OUL}dDx|pPA2U4%yz5pOrE%kSyY|+o$`+)^ zX^`&U)y^NSSds8l1a3sYIHGK8+*zo};mB4n6t-qs2|H&c;?dC;!_n`Pq7N+}`d}E0 zDP$LIEYodt0=j7`Fa<>7KS5w&i=*R1q@iacpc62&r5+^4mTe*5l^zNQaR@?X1lE5j zfkF~Ptcpa9M(1#GY;h4MH`$q^fcOOG>W5X!I8PB4=MuSR`k^p(0RsP=R;_5~3`=40 zxk6eMo;WRCnOCDxb-t3;ygh|E$kf;RkjH{YLoxXr9X~Js{?SmVugd3X>zo{0LI_zb zc2rxS`^?jNUz^jaR7LwDI^ws$&uiqlX~3Y2DT?q1e`Exn9kCg3Cb+LJ$dyfJ(q!iI znEh6ksR`AH6>5c<17&AF<@4`%OjE6+@^>P9S*aC`Vhokq6PYA}Q)b%jnc24d!B{Gp z$n+=c2ivyYIWSQ_(6%EP$0%g?rnB*ACX}$%aQ_IImU2@*la&H*@(h%y$1!+B>=p*d z!V*MFdi*9N4A&C7GmdLoEkYM})Y zpxB$6jdYuc$py|Cj0ZY93>!u;sM;99v1G{xes(IuNCXQZ%0dcl1$*&KJfuh=G(s>h zM`UP~!B{F90{RCQHBI(ZPPWiTAu^I!xzZ8Qu4 zFOh(n$$k=OvT`_!u!4qGQX_zum4o@IJ##I4irt+?PB}8Ck&+%Y+o5nYR!m?$STVXB(d3o0G$Z&;mtQJ61CCf z=r;U;K%&jXHxbH~dkx-+=t^-GO%VL?FZw1yoc`#>{DDXqvB|DRDFTc0^R!8S8T2)d z(IW(9$oXRT9QzMJ9s7b|RS!pjgsX(17Y38Du-VAx8)i6`#HJKhfWj07&QmxTwJaU! z`jVaq1w&Cui<-%(QnGCrQ-CU`NdW8(C3HzGNLd-czQJh3Hsf|a9M0P@%hE!jpd7U^ zW*EvDR8?G61#T|>MNzg>gHt%D%Aqt!kArU1FscxS$`6KED6ZlO)v6Ybu}{j1meC`j zs1i#g5v`oiawUK}B$MfIyp+S3XG%PY3@V`X>KRRu6RH%&brcC|hZI5WUO9qi2urv( zURy<{0B{3Z3Bw=^g@8?r2MGdpijVF{NY3SzG%!9wp$KLv0}nFerX39>G%XQ|;ss4B zjNNoFBu67@C7+81BNQ3l$DrB3pmA}+f!skvjz}-jBOam#ZcXHmO9uck@pMJLjfnJS zR@g1@y)lk~uv@?BGc&MN-^SDaSPB0+hVXV|6BOCqMrWJGCPte(xG;Xgqy);K9niZm z)}R!MQANYZ%w%qIO80<>447s_@Fu}25^)xnn2L%PT+4fn7MF}@oM!m!k)%^jhFK&S zy4fE6q&hj%P9Xh6kto+BuAnaw#fbi3>|hMP0a7#qGYhh+0>CgBW?_hU_n?_SiDsq% z+&OCj4~trEys4?B?Jik4y=LyBxx1iV>_H$n$JJx3Vp|a9(nZ8I*Y=emG8ubvR)t-O zM1a9F`X5%gYNv~8?fAQfHhBX)p{f@C0fNC<<3Y4g6dQD|JS zS9CZPsG^RwDcl6X*FBS6zkdCVY9;;uwD;{%j$HMbD!rh9^6 zTJz}XDSLXxW6zAS4QewCHe(y}7}<^q*uX-F)^Qes10j#@9A`-|K8ZQ$PRJgDfz866 zPVgoW!zMg>NU{mXXAglKH_1tsB)bVj-tW7&O0DjhF(%9YvuAros!}~})xGz3fA2@C z6nUeYjYZ$Q-#cDt6vn;xD{sB?&ZS5!7CB0@JU*Yi^D|4~2prfSei)AMk?_)IKn|+t z_J2dSW!_*UL|rbb&c36c6GT{Tdv|elnULH&lW!>&nVHG zcqx7;w<)9ZMXfehC?85&IUwk06ceD$h_h(qfM^Mqe!!eF#s8w$TbhqgmE9}cEmqki zB>Jyn7IIJ+y&WUK9}ly&o5WAZF~NX-WiE>503QZD`WOe1(A<%g&E@oL4+ z4aB2> zbzJ(3W~qGS?BwCu`-}PVk#m!cbG<*!`BT>gt@&|#rZAGr*_G)>i} z$@4DH&tY_hNI{<7fHhW_5ds()0|PQI#?9FwIfB^=n1d)p$1$Nx|1y&YohiBc}T8q3&%P1f1{c6H662EpP`A(=TdhZ+Z z`ISTzX?fy)M6AKNBRZl>T7fTHz^VU!> zeL50pT1UaCUBNSNYxUH36ALGPY3L&##=03+^7zJupbYtbt1R?fp$E zeMdtnv(%{=Fs{~}7ip8B3R3YPE5i$iOQB_;rosK7ZmDB~olgev7@GZ|MG#&q{Dusl z%5A}g3-OE=JSsP7=x2q}7d-HZLnd9tLou!2gB_@fX$WY-{sesno&%kZihsM$f!8P5 z7)j!kZbx{%blMwy(#Ez>J*Ly&J=rYrL8a!&+Ja*)!ZEn+2yh19-v&h-4r5+kfw)FTQ#Q!(?%ek_Hkggv{h!h+@d8#yXRvUcZTEJN zja)dz(&zPwBb9hjti8HOI?cpQP*&@UR8E5g)`Zz}UTf76n1oTz=q)_>p3=)#tE0u^ z$Fe&ATE%v|dP4z!zlsb8_moG%26${OtGA9U0#6@ruUOP#t!{|Cm|L7>d z2?-9k*oazSE2p_r!%L+yFWioj&3@?8m~9%v80-;jRaIL$Y^97^?Q_U z`;m#W$0tLf$>V1y9{F4<2|JHIH$CQu_AX;((pmqoFbYd###*~$B4h46fM^gB>Ii!W z$1G6`Jj z5&~=v&czDi0-RlNkQzpV`MwLV4&jZMVUb~UFi0DNI1d9?uk5he_m)c0n)b0JhC9c!7~P06}@I z)z!6*j0R}~Vm5)2=yuME0r)7O5177+0_4!?ZFKN0?^NL3&ASC$x4}kkLOg=MUz$>g zG%^U0OxhKQK!_eV?L2}I9SlE?0(S^&1BE9I2*$m;e{CCSY&2xfLs?h&LuAwGEaDs( zO$iUzs~lz0n+|e!ts(#d7a=7MVhn;q!LnwFY+1Kn<9L$y00+-|UJjpMngLWe!bL?6 zfQow53wLlqjS=Mt{Za7n+bRzndf>yKDt+pWhaNbjY(4nk2mazON)J9L=EBBYYysrp zAPWYqPv;mf;gdK&E!dy5(ZQ>a9-Rh&MsePI@S0_ z&FhwDi@hxb7Smdg%}2bnEa1@%K>0S-yeTSuO#3;`M#eKSMnwwCHff~`;#JIlj>Z6rrH5(?m)hAjA&l-Dp z;3^G7RCkADvW!rO3M{OB^JWGD;Lc|jkKto1T}Atjvl`GAhofhpr!FQZEw9f zks585%S+2At%;T8<72o);1{lA%Hv58D47FKc+v`cNEv?o#3*HmoxRixYN4?o-OZg#u94dm}44zaho$R1}s^pK#^1ZvIG#gn>lf3Kk%6^h(aI;1WK zWj%nR0m6HSa_eKE%4|Wpd=+LZAr_kbR(1P1GXwi?u!oqjUOkh1IKZAUU_=B z4c960!CrgMFB=CGOcDO@Sh?wEGF-z8kAqx@gcZP|lKbJ3!K(sy&9nA{)a(JX^+_5R z^ja4A;83DTIuY5IWO2JxRycHVJ=6LNC#WMCNuyE zbV(@0Gx$8gZ@CK#=(GPij;yc?ueeiLld49NFB&0fkj5Jd_2ZsnpZ+bWhNSs2`CBMM zBmg&sH{Nps7}Y%?mb@eZV;ru&dJ6A^RRauw^+FRI?8wUlA(r#EFOEmGK*`FzEoYSi zdSra@_Ic%Ed;|q)H0E8+cvs_*TWtH5NPN|sp+)Qf=KgD#dwODHb)ZRTDP`REB1|;l}EPV-e-be2r4rj%J!XbatnE|l1D`%#5I6v z2eTd#5xQbv@$MwazCkEG5YS_Ypt;^&wbwav{3tI&6}AXCGp5;+fV!JHfKfDvYI6Bb zA}C4uAjr9#kN_LOX%>?TFve{g8=y#1lJRVAV!k>ZjCZ&1uPoAP(UWRZR0B?lOstEZ z>sj;@PpTy4L&(?)uk?Wj4N7){FEDt#N<1p;cBIl^g0~eU5%_YKv0n}8Zs>YWM_c=T z_kPcHWdh6ahow!tw{35tUKywq-45+*?{r7?P2P+z;4&BZnWT%!tFA}asGS;M+|gA~ zQQ@2%L_!qdnjl>e(Q(ZHdtC>v24(=4(IWp*M`v~eHgmmy86S@&R5h`hJ1`SOJnQU% zw-4z-GiMmN=Mb=r;)H>{ZgxnP5J{>nH5omN9N3}YUBR$XTuS<455Dr1*;}C7TZA1! zped57=YT`V2T(|o#!x|_9RF@%%13^`#a7d(YX;(I7?LIGS3!mus9%-PLtE>Jqht0p zjt@&(?H0i@zykdK#gVqIwJ%}VEYJU=)ouM?bfvo<3m1yG>#AgR9T`-34N_-`eA_J% zZ4EkTa2G*JVykp6UvBIsjBA{ZMo}*~YT8bAqg&)p6AM`rVq^~^jw$&Sag`a>j*N^P z!Dogy;RBw;h0-My5`G0t756d{AHob45QSqZ)ui?v5b5sH9t2L`#n^%m1|U;_#tmv; z@nU)V>lW)6cT~7w3G$=?4$(n7!HV(_lB%utlL#ULbn%fWcP6$ai^n)iIspNE}?NZdjd|1)gXgpeS)n)KOkMtGZ0mQ zmu9#7`d|3T`;;~CLoZ;pNS)X=sNMvkCr)!Pp=>~8Zv}P^H#7o$7ilS+I7$NpCsvk& zw=kAOT%b4-bt_u^RMWJPJi+0!Sy6M;T+EpHll6&H3#Pen%Ex@&H1Q)fX2gW(5W+C9 zm|?r^vfkY488g?fakvR-6M|+WB;2&|B_gcRVK=AekO;^(V1WW-RY&req|!Rq`<~)I z2VSmsxuM*BuEAaA>=ixl0Bfv4`e5)b(h87t`YI|mNR8Ok7DnDSvhd(yYSKHYn46um zXO+fpzw@2*pkExd-Fun2Zs1;W!nmCp%K5=IzHZydUuf;N1KH9>Q*Qq845WCfOo(Ek z3U*aN&_Kb8rt?fkj)>paD=&H?UitGOWD}^m0KqM=9Y=aT<+(5xVR=c%{7Y}6wCcp z4F3&MSl@BS9f!D5g$T?wK&mSZ@+cTB*adKK_xPY~{x3#Y(-fI5l~oj=%cV9pdZ5%)39d5dAU!&p_8tk6 zKwv|Hl<5n>2jXdDVa3|7G?nfSv_Potx~Z&Ly&W!oyU_*i={k260Xo1DEe*^FJ|syZ z;TX~YLC>u=w{SC(gv}N#B2wIMD<|J^5n(QK$W(VH)Sg6<4@}HW%umeqn|&5(YUp%L zg=YoUCa__6A(7IDiU>ODI;4><{y;S`@2sX+qcg#(-_YI|O?%J0YA6)}oMdZ56Vao! zQWND-OHD6ajOWV4Q9Wtr=V5VOInx`J;#NLnXJ%=O10R) z;5fvWsW>FI3o50@n0*o*zKEDngqvQxC^Q|)7ELc0IX(k#vb81wxZho=`aqwArdg-0 zDdt5EtP0F67zE5hB{Z&IR6M5=>Osp_njcMk;OGa=6dL{wrIR)+3m<5Y*VdqKw9u;i z=16}p>OkxwbG)qJZEg&tFXhDzydFRNz zxbNP7BkuB8c;*)FVCD6S@*N=z2@R!?+GS7%K(=Z41TUi2;ihdtBg=fk>kpUScJTP< zaRit`TMCcUjjs04L%sj;cI&u#d`2t>sh(moF-g-M3lOaaX>tVUj)5HA`@HjB(b1Zv zE^@70VJHLucXq4+(w6}HumT9)x6GU590ZWjY9ZEM3&~3$I+{?=!DEUjjry@^@7CaI zD)}RMBRUcTObdP?HWCG|?SI2E=r7C7(7uy< zIxq(&^2!bfk4{J11lqf=FEteQlj#9n*oEyKhVW~2ONoS~aUvWECc=CB7f!q%y$dIT z*SKbHFW=ykmJnYEnPLYzJCuU;1!V$5S3SR{zYWjXtMvDp6Q=71Q3lx&C_!GNlP@xN zFSU33rl~)N{|EgdE*+Q_U_F2!!ap#fb@azoDDIu&JuvyiUZ@)#fXV-B{i4!MTG5hX z?W$BQQlw(iTCjgD&{a$dLGc6aQ(ap;WD}a*G7`aE2e8njm66D%IWGsN1)L2ZFKu2}?Y-+fn^O5CMdxn$Qu62phACS0eiXj*H+O4i;cl+uV`<(4$9 zv`T4rwe&E{-t0cFil;HX(5{9G;7Qe!5WZX%4D8t6EPqS1$B94I*BHq4*L6KSn5}jU z?911|zJRw^geQRVBVYd!{0BF(wT1I?g>KUV$lPl9hj004EExO(sn#~_j=h1;CcdpT z4BncBC@UmPbFDTk74Jc6+906z-=0PgsMj;R!#dWU2!cl7sriSn- zhT??CfVPt5tHDvsvHN05o)|P5Ilddq$|1A&`EOt4i~|0A_kYJV3itkAX_>vxtzY#d zriS76--g*YN(P*4Ex1^LN}yquHccg zk=|>Kv$~1)x@Z_%z1OkK=BYYmhPG3|U4XJJj2_O|L7eG9py?5%X`Z@B#hnmYsR&Ng zIKZ7y3;`2SV_pqIg;BuJ7cp3ibzyiIQ*RBLc|*?yE5?~K#&-{+)HM9fUw>-YuReT2oI^4RT&#Fs6_t z&9p9+iZZ?38rFS>J#0y-)$JwhYod!+@68Ux(|z6kK{`nNAUekJ1jjVb%G!8AFIt=y@THL{rf>*~{(Ru^PvW^Nx_zVyXw_7&(t_^xfjp}Eetb23Rd z>IGE+lf5rpHWimZ5d+-o4vn>klM}O#o;maAtm2s{l((q}sv8KlKxO!r*$M{f1O!!7 zDz}Zia^=Fr+~LD>FL)-Bhb!_rm~?|dTp7|Mw|D`{>!N36wj`ZMxpPUeHa12SO(LZ{Lk-H;T;mFxCGe1}gVW-&T z`31|Zqzi>;N{uB$%9s~%rHzap^2Uv9D3>iD&Jws(^6pRv~bPG_*;+kXdBVuZo+dOw7I^bc?BcAtrehFig zbVP~45EyM>4PgZP(%|6Q>gPBF-!*tI(gpUfXUQj5k{rBdaDTAyL{q z8gN>Cm2><_=P5rcUqn?Nb#|8A3!I1D<5<*w**T7Nj6{N1)my@sm0UOl99c^1IFf$c zfT@AP7pixx1m^=drHS1A$t|-Q4gQ9sv*wzHNOkcOIyl(-p+1BUd84<)@Sn^~fGaiYQTlVp}$Wk7D4Bf-&LNKmzKAw9nmikSk6%)Q2h*b*3fErx2D=Smg z@wPA#7_>wVXf3Z$-ov+GjohrO_v02x3f)vM^apR#@;Go!_8*b`UtWV9jL{}A9AqtE zIA)3;z;Kj_D`07{Ku}hpkKk4tbN+NBlJ?K-;<%?*SKkwk#lr7Fdln=|T2pm;p;Tdl zqywhRu!F%B;(CRw9B>`jRmdptH^D%xZqOaezGSwn7HvpEGKCK;+_mkF*?Ro(mWjq) zi+qY6Ikd*_HjX#P>-HP&TwY&iyO+_b)-ew?4$;cqLH=x-TT;+MJB`Z9fZG@WrnaRU zF~T
m`*(rf@bFyItoCu_$+p)L}J*hW29GFOpOxVlu~Alo+7oXXnPdZ)9#wWVm_ zwf&=`t6*!OaRL!kyuNPPYwMuU8U~&N)qgA*2)M+N3lvNf_+R!9Yy<|5sGsgN zSAXpG7PRqr>JA@@x4QD79eZaTaW@f|#LSjg4mblpT;hU?}sk6H#)s`aT7pBNDJ zvp}h3c0FYa{>~i2Uug|0ub~!D8nsKc|B$Msd?BCV`=4)tBP4xaSZ3V4@}up4SMAj9 zO;yuAToMxCBGvRYR{KzzUnG-@>#kx`04ZxcvK6Bqg7@d9t@U zdGkzhY2NI4sU`5($6`r5SBy0!G)+>%S zCJ&bret)8Tc(QTy6)p1{@T7_aV{t?wo8^&!OlM*X(NGnhx$ui@f?Y{gu%lrIj@nyy z-1GW7KKp9?25{UUjpusNwD3bhmL>g^Kc@(jL#3@8GisH8>)5SZ{IWip{=*K@cAJ; z;|py5A%5+9#^1I}?LWi^z+eM+Yymo_nG1w|7^?8@3(U^Lph6Lpf*H3n(?KLNLlioX z!o9bhF^za|$S5G~v!09$`K_Ry8xH66pyiLJQ$s`Pbj)uleih}CkiI5A986}y!|7x& zJfdt(Tz?C60%ddd=+Qaz&|NFT!z*_k%1qU>x%yB##p{3kNZv z6nEKjk1jgNHdD zVq=~;=4Als1&FD5Q9)Mv<1B``KeUK1??ZsN)Rl6mz!sNg^!ng2L3nWj%|2UdGzoa{ zOxoRhLO3EX_NS+bJ*eo#QRJ@S#BJ-t5@J{>!r8;zlu#~0PL;dIsS<`1QBeX!6g(7_u}oyMVyQ@zHSO@i>b5BK&|KmixOq)VdYDx~ zW9#(naOzQ_jOUutxIwMwq$6E?Bs|(K#p;^0oaUgmgVV%d8OFwCYtt~Lcgt|N)HY)Y z83m@-vv@^W0p%+qm4Gl4C}L5=XyTX)U@}4RpA*V*AlG}7Sq^~OB> z+}eGhvp0R7uQYx?Ej>?81K2#CElfT~p$Pm1rN`hnpcE-p0pgi_u7g2w09+&9=8WvW z(zr-`Skg<;pYK#lH3i-VPUqnR*tvM-%tZh>oIij?+3hYyz9UvIomxcegE&%jbYShu zp1ZcDnK8vvvKF~$#7aZ`6|wN_5*#K=koc~)@ZNk;(BW=d9z`$ws|G9qHAgKK+yg%Fw*s9YviZt?=$&B3zCoU z)P+F>;DxD0l~~l-0qI+FntX7fxB{ibEK9#VqdfEC_{bX>!pFaB|>VQ2tu-E$a_oY&4|TGhCmegPe=@&_f;L zl?FI4hscXnVq=ErV#!W14rhO-9CSd=bx*Lxw}c95m0|INRkM2Amph%!&6nCV!H=Ik zO@E}@wZ;GaO$#m5KD;>wyeVKQEs>>*JL}9iM_f+vz)(KzxBm1Oh%Z|%_FR$R>r=WY zZuA|Z%a)5gR}|zt<9bx^FsX52{Md~Q258Mwz7TEK=?UnF^DP-uMzp=yOw*?cJ}uOR z32crf*I$fvST68Vi^dp?!t(XdoC;4UCIBPgqRsleYzb{_zbh0c!H9?2(tc9_50cJ8 z?8pB_;CI?u!N{cIbHj0JHI>sE(Eg8RlGhE#nHRx(FdTBKHOpC(Vp85-13g{P_6q z=M(izW+Ik{^L%09TeD)><7MXk z4ciShS0TZJn}P;M1+8ogbGtCP zqbNJQD+ez_RH}O+km|t2{TsF$VkJv7E=egO83u2<@bsGHc3Y6Uh5z=LR5b{0`l^h(n8PZSRVjksLQVjl9nQ1@GF9ZA$$vQO5atkRA zHZbVbY@jF5a1xVT?-?rxRp%xY*Fy7cS&yfzZ>20h(81B1)p*>>Sx3LQvb558d}Ur9VlW&XhdI1u#C zQAc570w99aK1zNB1QGirjV{p;>RKt|_O>@SpDW?-vCYjUw*-Y35Sd8bt%!u)Ry-$5 zrIFQqX{4Pm392cTehgQka81o~vYc#bty!&w;1fQLpLsrUyN8qkD@i-~O$0Do)@2}c z^i%O*0PWIy-}`JEf5Nm5Py(T#=K#%$>LS#L!oaB3lNIQ3)z1rUZDOJxM>ckF0G2vF zrT@0r_50(o$Hqp%7nFNnZWl(w0kqh~(%FqIi|i(~$Cuxd@E*WN;lC?(k<*=_>cl4iHa>9!?Km6&Y%ccUTi*8l+uJkg`& z)TPZ$W}@&YTM|o(@AFm?<+U+UOmVRlj&xCa2iJ7awKa4tiNS(mR~lmBU!5_41%AqW zz2iBOd%gKq8^0>|mua6b-(TSo=l> zbt_AtU9H~an$oEFp@9Zc(vb_@!>{hFbvH-s6W4d&aDDeovx~bncY6byfS7!A1)4#% z26uyo^ereHn2e7e8@H8d*_Y|D!&9T7QgznpPTLud`J|j-;i+vbwsx+#U&4uVe{BZ% zNAg6^3N?|aGoZ|vaP#7U^sn@}aE1q<*n2scZ?+hj)+=b~w z68Cop5>YQ)Fjv!AZ!{55o{bjg&n=D|o=YU=4v#FJn=eK`;V{I%6FqpOn1~whdY2JR z6ptKaflUJ27nCo+xLO9NT@RD9Ck@Rx=4sSB1J&uWuLk-~X}~wje2qqHv0hg}^;OnG&Mr zv)Z`f_hu80UzE~j?JiWwMwPNh9!VHJUv^xBi$$uOiDw+wsXb2~aO5GF!hA@Zk<|4- z-a@Rn04O;2{BRykXeY1^q0}RE;h;%aL7Ejsz3TOD-;mQyNmgL05yG?v>kr4%on<^j zMsLZnl$jNzFRM(qa2_Wx2oxaLI6C4zv zPr4tA+Je*_@nwWKrrZ}A9xp)0OvVKpfQC+^H*DXCq{8bdq2WRTNm-}xNEV&JAHd3} z-%q^R6?MD?d#ov2U?C!4TM_GD6-3+d)Ky)N-I{bvf}^S<2~u!Tl3$8G1@ZAf^Au-*`Q-e2YIWyYgUKdpXGQ^D8#B2u1*A{UtP z{(&Hrz{8p3u=kd?23g+ip7`A=JTcU}6Zbg3<@RIpmQpFIKtO)YdNhhG{I7}*4Mpz{ zrs^2IFanO)2&=E%lek-K??z*&eEKnE^|1#~G!K%TKI;Di9I>ni{IcZoFl!gv7^!VQ;t(xHNWLTF3)P@7 zC6vyCf*tf%ol9`3c;=bbX~I5cWH%dyg+yHRi#UxE-p=aad{CaERfUehOzpHR_y(Hf z=!*a_;!YCUIbbP{G9nOaz5$m3vOTcD@Jfl*q`qL!?=5&zH0cS`+_V)vZ6=OH_25z< zNd8tbw{ZB*VGqB>p^wND;#+wrfTC9Ltg?Gs$BZ%EAM?X*-}_bfTBjt5yknpZA^i`b zZ`6`)Vlx~rzco6-Km_u35!JopUqtr znd?+YC94LJm42ua;ox0bfRA9%nALSaO57U^#=XXIA1qv)=~V95FDCAaMty!m@h|Fj zaRR=YH(cj-zmWS$;Y1GosPx9m|^CKIY3rUvq1I^+f%QKm?3_c6=id1lfNo zlH*Vtf{?9Bz0Q1C@@aN=y>R~6Q~6IINb9C`5%$b8)1C71i{|^bw>4O+K*PKq%uWL7 zr`t$xaR=%`-s^dzNW=`(f+Wd4W_(nGPP7NeJpfLQI*Buhr@(!}6i4||U5vBsNlGycnk0EwS^4T3uJmuVnfM?9~j z76Y1gdb(EvfZaNDl63OvtFgpc@I<%(l#HXv(()wra5F&J0Iq6!I0zFHc@|z_8xF zf0ruI_t_=KkMYvXj4@%9vWbLIN|!S6d^mPw2~CvXZ99@2O;-wsnv>cZ zx1UV1I4FR%#5-T5e}Wk#_&5+S(9hk@ZS*eN*XmT0Jwe9?`X>8@{HHJ0qZxK1Q_Adi z49jZ`;v0G;^xoh;9pplfRkCzgY%0*Of;>kX#2qlLg`!a4LtVE?KvJMvho0T+(KhkJ zY3c>fOKS=|=J$K6m-tdIp{30q+BbUXRWc_aFF_ly$`S-trQV?qn-JeXV=@jXgimNJY{Bboj5KO=0d@sVI|_8d3oJ z3zF9N>=5pA;1Yq@nS2qcNP*RMKTJi#W6GwTD#YwaESG{QDwq7xY$Rs)pnY}!s8WRz zIj#={M*@1Z_Xm7?N)5fua6pUxlSS<`Rjv3qifU;`*haRz2U)+h3PGuYjMMbL?{66$ zN0&7Q{O{Q|ab^9=gJ7wI*iAAd8gd&z;2E0^R_e<8jIxbF#Jzn>hyFYjL!m%N1D)Em`mCcMV=yO|&p<+-h{fIdni=`96P$1n=ht$FU zjbJFa?|%d5OM}N6L;eq^>UVxIU%Lq<1cH`4_rW(QL1djj?I@{sAkGA!riz0~QKMLg zCK987ND-J4kzTV|SMi&lrgBs3=iBYO7EzT?*|-Fw>|=|I7ynG3El(96zVTe)k-~-d zeXhgw*E+>4E<}$LrK19oa_OKN3qXjhf^@k9+bu$G6wmCVeuSu$-_f|I*}MlSYZ+yu zc;*iORVww)(Xlb+SlMli7GtL|EHN&*E1Mh97Yc<1{nh&${2YtMUMRgtlL5gyyAFZ_ zZ`k{eZ0uNJrCMDn?7rlEe8Xk9Wn{qF5;C`dGNivgvwKT-YdEX9@&XnHlnoFWFwl^g z8T}(-b-+(m5T_>Gu-jwUo;?e@FL&UVEw<-2*Th=kv2*A4o!q^8`;sn239xe*xM}$J zp7gwyvrDng5bk?|T^0n59NblRh_yuZX^4T~WGhZ3>HwA2^%{gNS#86BLI%?s%#8YV zC7ebjpujs4qxuf{EPXm&b$}J-5$D5_fQldCLg7h-m2m&zb z7nZI0!^_s(r<|>FiP}%oU!E%>3k?DZatB7fa!NmZgLYVc@?NjG@Saq}7m4_M z(P3W%9x7fdBmOLJqoH7~4Es*356Nf*lfJuDx&e5IbND+6)G zcS_e0c*Y3&p~c*f>F0y58&3Eqg_o`35u4=LU(*7FkFqmxW3k)rXxgPfkS8NyeZkhX zNVqF_U8Lv+$NPSe6E`&9ofaS(<|aJ}i4kenVb`e4O#7q=2!CS~$}({vKmVk(P8*Mq0H zSn&p{2S*OlWg8p6WOj;KuZmDQsWy%dBlmr_s5~1U9UskP@J0R4CtMEd4G}$@I($>Z zO;psl>2NBY({Db=2HEhzn}1BUT3Sqnv=|CaNj5Gy8i{G4)S_6kZD5Q|&_HMigx~5O zJrNA0K%kg(sI{rsMoKQEfF3L}(B8ITvc^Yll+s1^S86FPwx55fTCJWsg)e7|33(MB z^b{t9zHL>ZG!=ZSA(7Jn!1(rnbxR#2r^rNcWW3vj#l``W=;)$m#=*hX5Y%)E*JrD|0y1&{JQDAK4# zoq>hFjdch@S%b<#1e&3spW#qNx*=GT2nSV zBFt5)b*aPt5{(JsgQUGmM`*n4TuP{spystZ;2Cg57;yuo5>TFv$8G^Q7!PB4+}sqR z*cN%It6`byyip#EzZ}$a(W+_CzK0i8e!-s@ettii>3#Xn_1^#TyHK&^?!48s%`e~s zQ9uz6$z7pa(}fe-X2-rrxElz_RI<4EPJG5X4h#);;~2UH@cq|xp^n$bqWghf-d-}z zv*t^B@9!>+j-E9^vL-!~%2$=IVh-Y1m@=_#3z<)$0c|l;5GYEk4vY>_u?6P?)mU6K zqzpOg#UV(QEx0Jq{YiyGJ1@mzL{U7foBbN!+bv%%ZAMe0W;*Aye5oHV9m$%h#>cZq zO4&xrbdGAyRX@Autap$W?8sB=rnvJq=LVD+W2@1>m51+>7hT?W_T7UGf$Xj!1w#iJ zCg5UlMdG%#!D~fg(f$E&UDC?W#PY0~Gg#)t=W2|ksw_yB8m>RPWllEx?G$H&(|Ubh zfs+?J1Luo}r&pHh0%uFXpMGkdvwR%z`?AuAwp+$ut05air0i} G{l5W@A9e8n literal 0 HcmV?d00001 diff --git a/ui-ngx/src/assets/fonts/material-icons.css b/ui-ngx/src/assets/fonts/material-icons.css new file mode 100644 index 0000000000..fe6f64850d --- /dev/null +++ b/ui-ngx/src/assets/fonts/material-icons.css @@ -0,0 +1,33 @@ +@font-face { + font-family: 'Material Icons'; + font-style: normal; + font-weight: 400; + src: local('Material Icons'), + local('MaterialIcons-Regular'), + url(MaterialIcons-Regular.ttf) format('truetype'); +} + +.material-icons { + font-family: 'Material Icons'; + font-weight: normal; + font-style: normal; + font-size: 24px; /* Preferred icon size */ + display: inline-block; + line-height: 1; + text-transform: none; + letter-spacing: normal; + word-wrap: normal; + white-space: nowrap; + direction: ltr; + + /* Support for all WebKit browsers. */ + -webkit-font-smoothing: antialiased; + /* Support for Safari and Chrome. */ + text-rendering: optimizeLegibility; + + /* Support for Firefox. */ + -moz-osx-font-smoothing: grayscale; + + /* Support for IE. */ + font-feature-settings: 'liga'; +} diff --git a/ui-ngx/src/index.html b/ui-ngx/src/index.html index 946d96f1b7..da8d9f6568 100644 --- a/ui-ngx/src/index.html +++ b/ui-ngx/src/index.html @@ -24,7 +24,7 @@ - +